pax_global_header00006660000000000000000000000064146032405450014515gustar00rootroot0000000000000052 comment=b641a797febee7a0bb8a44d40cec92f2c894297f gopter-0.2.11/000077500000000000000000000000001460324054500130765ustar00rootroot00000000000000gopter-0.2.11/.github/000077500000000000000000000000001460324054500144365ustar00rootroot00000000000000gopter-0.2.11/.github/workflows/000077500000000000000000000000001460324054500164735ustar00rootroot00000000000000gopter-0.2.11/.github/workflows/build.yml000066400000000000000000000006051460324054500203160ustar00rootroot00000000000000on: [push, pull_request] jobs: build: runs-on: ubuntu-latest strategy: matrix: go: [ '1.15', '1.14', '1.13' ] name: Build on go ${{ matrix.go }} steps: - uses: actions/checkout@v2 - name: Setup go uses: actions/setup-go@v1 with: go-version: ${{ matrix.go }} - run: go build -v ./... - run: go test -v ./... gopter-0.2.11/.gitignore000066400000000000000000000004701460324054500150670ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof bin/ *.iml .idea/ coverage.txt .pkg.coverage gopter-0.2.11/.travis.yml000066400000000000000000000015451460324054500152140ustar00rootroot00000000000000sudo: false language: go go: - 1.x script: make all coverage refreshGodoc before_install: - pip install --user codecov after_success: - codecov notifications: slack: secure: M0PgOUB0Kzn0maWtd6NNtiKYINxMY/7zgbbDpb8mAa6NTPYuypEYkUgmo6HC74BzDWSjkJaLQOeZrumrOuJUKbGdT+eEYR1pXColp2qb/WxnSCAwlL9iM/k7pj6nIRUdlP7l6WX0QB/DNh+BC/9STHrcSKjBpUu38oO9CwT7klSj2hfPMjzcx7EO4f8pjSfwCrIyYbANKxLzP0lr4PcbdY/ZeGbc8R5/m9torzPjS2YXDl0tQQ7pvSS8UVToLfL0m+omp9A/lOu0n6FpdNIkof2Eu9qWJqsI7jy+Pi+8DGbfEyxSLKAhDiTn0nfO/5nwqWIBhUaVACBDxpaH6ewpiuMbs4RO+wNaEEuVEH8QMKZOx9PGgnzNJ3zZ5Hfm+FP8zBrwrKlsjUoy31waGFjgua2ne4X0wa+Ld4iFEsj+XoMKa1oxRKRXYFhyEywalwgBVjXH2+ZCMlFGV3QxaV5gVuYcfEuNQ4pOlJpk+WSgm7yfXEX2qosOk2p91yGyX2Msbe3B7Ov3PXVzs2CshIsYasHr46pLplMvG6Z+712TPsrFS0zhb8FAsm/Vd7xX2xxmNS/uffh3RgFzeZxg8S9/ObVq+JBkZAtK4j0SwLVsOkjI4W3yUVgfxvhnAM1iLzzeSyD64BSo1VyUZu1eSJ9YxJ1+K6ldo0u0hj2VHwO1vUE= gopter-0.2.11/CHANGELOG.md000066400000000000000000000054711460324054500147160ustar00rootroot00000000000000# Change log ## [Unreleased] ### Additions - `gopter.GenParameters` now has a `CloneWithSeed(seed int64)` function to temparary copies to create rerunable sections of code. - Added `gopter.Gen.MapResult` for power-user mappings - Added `gopter.DeriveGen` to derive a generator and it's shrinker from a bi-directional mapping (`gopter.BiMapper`) ### Changed - Refactored `commands` package under the hood to allow the use of mutable state. Re-runability of commands is provided by invoking the `commands.GenInitialState` generator with the same `gopter.GenParameters`. Of course `commands.GenInitialState` is supposed to create the same state for the same parameters every time. - Fixed a bug in `commands` that might lead to shrinked command sequences not satisfying the precondtions. - `commands.Command.PostCondition` was called with the state before running the command. It makes much more sense to first do `commands.Command.NextState` and then `commands.Command.PostCondition` - `commands.Commands.NewSystemUnderTest` now takes has an argument `initialState commands.State` to allow implementators to create/bootstrap a system under test based on an arbitrary initial state. So far examples were just using a constant initial state ... which is a bit boring. - Fixed: Actually use `commands.Commands.InitialPreCondition` as sieve for `commands.Commands.GenInitialState` - Gen.Map and Shrink.Map now accept `interface{}` instead of `func (interface{}) interface{}` This allows cleaner mapping functions without type conversion. E.g. instead of ```Go gen.AnyString().Map(function (v interface{}) interface{} { return strings.ToUpper(v.(string)) }) ``` you can (and should) now write ```Go gen.AnyString().Map(function (v string) string { return strings.ToUpper(v) }) ``` - Correspondingly Gen.SuchThat now also ccept `interface{}` instead of `func (interface{}) bool` This allows cleaner sieve functions without type conversion. E.g. instead of ```Go gen.AnyString().SuchThat(function (v interface{}) bool { return HasPrefix(v.(string), "P") }) ``` you can (and should) now write ```Go gen.AnyString().SuchThat(function (v string) bool { return HasPrefix(v, "P") }) ``` - Gen.FlatMap now has a second parameter `resultType reflect.Type` defining the result type of the mapped generator - Reason for these changes: The original `Map` and `FlatMap` had a recurring issue with empty results. If the original generator created an empty result there was no clean way to determine the result type of the mapped generator. The new version fixes this by extracting the return type of the mapping functions. ## [0.1] - 2016-04-30 ### Added - Initial implementation. [Unreleased]: https://github.com/leanovate/gopter/compare/v0.1...HEAD [0.1]: https://github.com/leanovate/gopter/tree/v0.1 gopter-0.2.11/LICENSE000066400000000000000000000020641460324054500141050ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 leanovate Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gopter-0.2.11/Makefile000066400000000000000000000020721460324054500145370ustar00rootroot00000000000000PACKAGES=$(shell go list ./...) all: format @go get github.com/smartystreets/goconvey @go build -v ./... format: @echo "--> Running go fmt" @gofmt -s -w . test: @echo "--> Running tests" @go test -v ./... -count=1 @$(MAKE) vet coverage: @echo "--> Running tests with coverage" @echo "" > coverage.txt for pkg in $(shell go list ./...); do \ (go test -coverprofile=.pkg.coverage -covermode=atomic -v $$pkg && \ cat .pkg.coverage >> coverage.txt) || exit 1; \ done @rm .pkg.coverage @$(MAKE) vet vet: @go vet 2>/dev/null ; if [ $$? -eq 3 ]; then \ go get golang.org/x/tools/cmd/vet; \ fi @echo "--> Running go vet $(VETARGS)" @find . -name "*.go" | grep -v "./Godeps/" | xargs go vet $(VETARGS); if [ $$? -eq 1 ]; then \ echo ""; \ echo "Vet found suspicious constructs. Please check the reported constructs"; \ echo "and fix them if necessary before submitting the code for reviewal."; \ fi refreshGodoc: @echo "--> Refreshing godoc.org" for pkg in $(shell go list ./...); do \ curl -d "path=$$pkg" https://godoc.org/-/refresh ; \ done gopter-0.2.11/README.md000066400000000000000000000047231460324054500143630ustar00rootroot00000000000000# GOPTER ... the GOlang Property TestER [![Build Status](https://travis-ci.org/leanovate/gopter.svg?branch=master)](https://travis-ci.org/leanovate/gopter) [![codecov](https://codecov.io/gh/leanovate/gopter/branch/master/graph/badge.svg)](https://codecov.io/gh/leanovate/gopter) [![GoDoc](https://godoc.org/github.com/leanovate/gopter?status.png)](https://godoc.org/github.com/leanovate/gopter) [![Go Report Card](https://goreportcard.com/badge/github.com/leanovate/gopter)](https://goreportcard.com/report/github.com/leanovate/gopter) [Change Log](CHANGELOG.md) ## Synopsis Gopter tries to bring the goodness of [ScalaCheck](https://www.scalacheck.org/) (and implicitly, the goodness of [QuickCheck](http://hackage.haskell.org/package/QuickCheck)) to Go. It can also be seen as a more sophisticated version of the testing/quick package. Main differences to ScalaCheck: * It is Go ... duh * ... nevertheless: Do not expect the same typesafety and elegance as in ScalaCheck. * For simplicity [Shrink](https://javadoc.io/doc/org.scalacheck/scalacheck_2.11/1.14.1/index.html#org.scalacheck.Shrink) has become part of the generators. They can still be easily changed if necessary. * There is no [Pretty](https://javadoc.io/doc/org.scalacheck/scalacheck_2.11/1.14.1/index.html#org.scalacheck.util.Pretty) ... so far gopter feels quite comfortable being ugly. * A generator for regex matches * No parallel commands ... yet? Main differences to the testing/quick package: * Much tighter control over generators * Shrinkers, i.e. automatically find the minimum value falsifying a property * A generator for regex matches (already mentioned that ... but it's cool) * Support for stateful tests ## Documentation Current godocs: * [gopter](https://godoc.org/github.com/leanovate/gopter): Main interfaces * [gopter/gen](https://godoc.org/github.com/leanovate/gopter/gen): All commonly used generators * [gopter/prop](https://godoc.org/github.com/leanovate/gopter/prop): Common helpers to create properties from a condition function and specific generators * [gopter/arbitrary](https://godoc.org/github.com/leanovate/gopter/arbitrary): Helpers automatically combine generators for arbitrary types * [gopter/commands](https://godoc.org/github.com/leanovate/gopter/commands): Helpers to create stateful tests based on arbitrary commands * [gopter/convey](https://godoc.org/github.com/leanovate/gopter/convey): Helpers used by gopter inside goconvey tests ## License [MIT Licence](http://opensource.org/licenses/MIT) gopter-0.2.11/arbitrary/000077500000000000000000000000001460324054500150755ustar00rootroot00000000000000gopter-0.2.11/arbitrary/arbitraries.go000066400000000000000000000021241460324054500177320ustar00rootroot00000000000000package arbitrary import ( "reflect" "time" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) // Arbitraries defines a context to generate arbitrary values of any kind. // Values are generated by either providing a generator for a specific type // or by creating a generator on the fly using golang reflection. type Arbitraries struct { generators map[reflect.Type]gopter.Gen } // DefaultArbitraries creates a default arbitrary context with the widest // possible ranges for all types. func DefaultArbitraries() *Arbitraries { return &Arbitraries{ generators: map[reflect.Type]gopter.Gen{ reflect.TypeOf(time.Time{}): gen.Time(), reflect.TypeOf(&time.Time{}): gen.PtrOf(gen.Time()), }, } } // GenForType gets a generator for a generator for a type func (a *Arbitraries) GenForType(rt reflect.Type) gopter.Gen { if gen, ok := a.generators[rt]; ok { return gen } return a.genForKind(rt) } // RegisterGen registers a generator func (a *Arbitraries) RegisterGen(gen gopter.Gen) { result := gen(gopter.MinGenParams) rt := result.ResultType a.generators[rt] = gen } gopter-0.2.11/arbitrary/doc.go000066400000000000000000000017731460324054500162010ustar00rootroot00000000000000/* Package arbitrary contains helpers to create contexts of arbitrary values, i.e. automatically combine generators as needed using reflection. A simple example might look like this: func TestIntParse(t *testing.T) { properties := gopter.NewProperties(nil) arbitraries := arbitrary.DefaultArbitraries() properties.Property("printed integers can be parsed", arbitraries.ForAll( func(a int64) bool { str := fmt.Sprintf("%d", a) parsed, err := strconv.ParseInt(str, 10, 64) return err == nil && parsed == a })) properties.TestingRun(t) } Be aware that by default always the most generic generators are used. I.e. in the example above the gen.Int64 generator will be used and the condition will be tested for the full range of int64 numbers. To adapt this one might register a generator for a specific type in an arbitraries context. I.e. by adding arbitraries.RegisterGen(gen.Int64Range(-1000, 1000)) any generated int64 number will be between -1000 and 1000. */ package arbitrary gopter-0.2.11/arbitrary/example_arbitrary_struct_test.go000066400000000000000000000045351460324054500236100ustar00rootroot00000000000000package arbitrary_test import ( "fmt" "time" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" ) type MyStringType string type MyInt8Type int8 type MyInt16Type int16 type MyInt32Type int32 type MyInt64Type int64 type MyUInt8Type uint8 type MyUInt16Type uint16 type MyUInt32Type uint32 type MyUInt64Type uint64 type Foo struct { Name MyStringType Id1 MyInt8Type Id2 MyInt16Type Id3 MyInt32Type Id4 MyInt64Type Id5 MyUInt8Type Id6 MyUInt16Type Id7 MyUInt32Type Id8 MyUInt64Type ATime time.Time ATimePtr *time.Time } func (f Foo) ToString() string { return fmt.Sprintf("For(%s, %d, %d, %d, %d, %d, %d, %d, %d, %v, %v)", f.Name, f.Id1, f.Id2, f.Id3, f.Id4, f.Id5, f.Id6, f.Id7, f.Id8, f.ATime, f.ATimePtr) } func Example_arbitrary_structs() { time.Local = time.UTC parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice arbitraries := arbitrary.DefaultArbitraries() properties := gopter.NewProperties(parameters) properties.Property("MyInt64", arbitraries.ForAll( func(id MyInt64Type) bool { return id > -1000 })) properties.Property("MyUInt32Type", arbitraries.ForAll( func(id MyUInt32Type) bool { return id < 2000 })) properties.Property("Foo", arbitraries.ForAll( func(foo *Foo) bool { return foo.ATime.After(time.Unix(0, 0)) })) properties.Property("Foo2", arbitraries.ForAll( func(foo Foo) bool { return foo.ATimePtr == nil || foo.ATimePtr.Before(time.Unix(20000, 0)) })) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! MyInt64: Falsified after 6 passed tests. // ARG_0: -1000 // ARG_0_ORIGINAL (54 shrinks): -1601066829744837253 // ! MyUInt32Type: Falsified after 0 passed tests. // ARG_0: 2000 // ARG_0_ORIGINAL (23 shrinks): 2161922319 // + Foo: OK, passed 100 tests. // ! Foo2: Falsified after 1 passed tests. // ARG_0: {Name: Id1:0 Id2:0 Id3:0 Id4:0 Id5:0 Id6:0 Id7:0 Id8:0 // ATime:1970-01-01 00:00:00 +0000 UTC ATimePtr:1970-01-01 05:33:20 +0000 // UTC} // ARG_0_ORIGINAL (40 shrinks): {Name: Id1:-67 Id2:27301 Id3:-1350752892 // Id4:7128486677722156226 Id5:208 Id6:28663 Id7:4178604448 // Id8:16360504079646654692 ATime:2239-08-20 23:46:28.063412239 +0000 UTC // ATimePtr:5468-08-19 13:09:39.171622464 +0000 UTC} } gopter-0.2.11/arbitrary/example_parseint_test.go000066400000000000000000000014571460324054500220320ustar00rootroot00000000000000package arbitrary_test import ( "fmt" "strconv" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" ) func Example_parseint() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice arbitraries := arbitrary.DefaultArbitraries() properties := gopter.NewProperties(parameters) properties.Property("printed integers can be parsed", arbitraries.ForAll( func(a int64) bool { str := fmt.Sprintf("%d", a) parsed, err := strconv.ParseInt(str, 10, 64) return err == nil && parsed == a })) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // + printed integers can be parsed: OK, passed 100 tests. } gopter-0.2.11/arbitrary/example_quadratic_test.go000066400000000000000000000043261460324054500221600ustar00rootroot00000000000000package arbitrary_test import ( "errors" "math/cmplx" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" "github.com/leanovate/gopter/gen" ) type QudraticEquation struct { A, B, C complex128 } func (q *QudraticEquation) Eval(x complex128) complex128 { return q.A*x*x + q.B*x + q.C } func (q *QudraticEquation) Solve() (complex128, complex128, error) { if q.A == 0 { return 0, 0, errors.New("No solution") } v := q.B*q.B - 4*q.A*q.C v = cmplx.Sqrt(v) return (-q.B + v) / 2 / q.A, (-q.B - v) / 2 / q.A, nil } func Example_quadratic() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice arbitraries := arbitrary.DefaultArbitraries() arbitraries.RegisterGen(gen.Complex128Box(-1e8-1e8i, 1e8+1e8i)) // Only use complex values within a range properties := gopter.NewProperties(parameters) properties.Property("Quadratic equations can be solved (as pointer)", arbitraries.ForAll( func(quadratic *QudraticEquation) bool { x1, x2, err := quadratic.Solve() if err != nil { return true } return cmplx.Abs(quadratic.Eval(x1)) < 1e-5 && cmplx.Abs(quadratic.Eval(x2)) < 1e-5 })) properties.Property("Quadratic equations can be solved (as struct)", arbitraries.ForAll( func(quadratic QudraticEquation) bool { x1, x2, err := quadratic.Solve() if err != nil { return true } return cmplx.Abs(quadratic.Eval(x1)) < 1e-5 && cmplx.Abs(quadratic.Eval(x2)) < 1e-5 })) properties.Property("Quadratic equations can be solved alternative", arbitraries.ForAll( func(a, b, c complex128) bool { quadratic := &QudraticEquation{ A: a, B: b, C: c, } x1, x2, err := quadratic.Solve() if err != nil { return true } return cmplx.Abs(quadratic.Eval(x1)) < 1e-5 && cmplx.Abs(quadratic.Eval(x2)) < 1e-5 })) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // + Quadratic equations can be solved (as pointer): OK, passed 100 tests. // + Quadratic equations can be solved (as struct): OK, passed 100 tests. // + Quadratic equations can be solved alternative: OK, passed 100 tests. } gopter-0.2.11/arbitrary/forall.go000066400000000000000000000017231460324054500167060ustar00rootroot00000000000000package arbitrary import ( "fmt" "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) /* ForAll creates a property that requires the check condition to be true for all values, if the condition falsiies the generated values will be shrunk. "condition" has to be a function with the any number of parameters that can generated in context of the Arbitraries. The function may return a simple bool, a *PropResult, a boolean with error or a *PropResult with error. */ func (a *Arbitraries) ForAll(condition interface{}) gopter.Prop { conditionVal := reflect.ValueOf(condition) conditionType := conditionVal.Type() if conditionType.Kind() != reflect.Func { return prop.ErrorProp(fmt.Errorf("Param of ForrAll has to be a func: %v", conditionType.Kind())) } gens := make([]gopter.Gen, conditionType.NumIn()) for i := 0; i < conditionType.NumIn(); i++ { gens[i] = a.GenForType(conditionType.In(i)) } return prop.ForAll(condition, gens...) } gopter-0.2.11/arbitrary/gen_for_kind.go000066400000000000000000000262761460324054500200650ustar00rootroot00000000000000package arbitrary import ( "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func mapBoolish(to reflect.Type, v interface{}) interface{} { value := reflect.ValueOf(v) result := reflect.New(to).Elem() result.SetBool(value.Bool()) return result.Interface() } func mapIntish(to reflect.Type, v interface{}) interface{} { value := reflect.ValueOf(v) result := reflect.New(to).Elem() result.SetInt(value.Int()) return result.Interface() } func mapUintish(to reflect.Type, v interface{}) interface{} { value := reflect.ValueOf(v) result := reflect.New(to).Elem() result.SetUint(value.Uint()) return result.Interface() } func mapFloatish(to reflect.Type, v interface{}) interface{} { value := reflect.ValueOf(v) result := reflect.New(to).Elem() result.SetFloat(value.Float()) return result.Interface() } func mapComplexish(to reflect.Type, v interface{}) interface{} { value := reflect.ValueOf(v) result := reflect.New(to).Elem() result.SetComplex(value.Complex()) return result.Interface() } func mapStringish(to reflect.Type, v interface{}) interface{} { value := reflect.ValueOf(v) result := reflect.New(to).Elem() result.SetString(value.String()) return result.Interface() } func (a *Arbitraries) genForKind(rt reflect.Type) gopter.Gen { switch rt.Kind() { case reflect.Bool: return gen.Bool().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapBoolish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapBoolish(reflect.TypeOf(bool(false)), v)) }, Shrinker: gopter.NoShrinker, } }) case reflect.Int: return gen.Int().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapIntish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapIntish(reflect.TypeOf(int(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapIntish(reflect.TypeOf(int(0)), v)).Map(func(s interface{}) interface{} { return mapIntish(rt, s) }) }, } }) case reflect.Uint: return gen.UInt().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapUintish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapUintish(reflect.TypeOf(uint(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapUintish(reflect.TypeOf(uint(0)), v)).Map(func(s interface{}) interface{} { return mapUintish(rt, s) }) }, } }) case reflect.Int8: return gen.Int8().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapIntish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapIntish(reflect.TypeOf(int8(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapIntish(reflect.TypeOf(int8(0)), v)).Map(func(s interface{}) interface{} { return mapIntish(rt, s) }) }, } }) case reflect.Uint8: return gen.UInt8().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapUintish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapUintish(reflect.TypeOf(uint8(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapUintish(reflect.TypeOf(uint8(0)), v)).Map(func(s interface{}) interface{} { return mapUintish(rt, s) }) }, } }) case reflect.Int16: return gen.Int16().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapIntish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapIntish(reflect.TypeOf(int16(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapIntish(reflect.TypeOf(int16(0)), v)).Map(func(s interface{}) interface{} { return mapIntish(rt, s) }) }, } }) case reflect.Uint16: return gen.UInt16().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapUintish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapUintish(reflect.TypeOf(uint16(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapUintish(reflect.TypeOf(uint16(0)), v)).Map(func(s interface{}) interface{} { return mapUintish(rt, s) }) }, } }) case reflect.Int32: return gen.Int32().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapIntish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapIntish(reflect.TypeOf(int32(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapIntish(reflect.TypeOf(int32(0)), v)).Map(func(s interface{}) interface{} { return mapIntish(rt, s) }) }, } }) case reflect.Uint32: return gen.UInt32().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapUintish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapUintish(reflect.TypeOf(uint32(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapUintish(reflect.TypeOf(uint32(0)), v)).Map(func(s interface{}) interface{} { return mapUintish(rt, s) }) }, } }) case reflect.Int64: return gen.Int64().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapIntish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapIntish(reflect.TypeOf(int32(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapIntish(reflect.TypeOf(int64(0)), v)).Map(func(s interface{}) interface{} { return mapIntish(rt, s) }) }, } }) case reflect.Uint64: return gen.UInt64().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapUintish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapUintish(reflect.TypeOf(uint64(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapUintish(reflect.TypeOf(uint64(0)), v)).Map(func(s interface{}) interface{} { return mapUintish(rt, s) }) }, } }) case reflect.Float32: return gen.Float32().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapFloatish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapFloatish(reflect.TypeOf(float32(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapFloatish(reflect.TypeOf(float32(0)), v)).Map(func(s interface{}) interface{} { return mapFloatish(rt, s) }) }, } }) case reflect.Float64: return gen.Float64().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapFloatish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapFloatish(reflect.TypeOf(float64(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapFloatish(reflect.TypeOf(float64(0)), v)).Map(func(s interface{}) interface{} { return mapFloatish(rt, s) }) }, } }) case reflect.Complex64: return gen.Complex64().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapComplexish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapComplexish(reflect.TypeOf(complex64(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapComplexish(reflect.TypeOf(complex64(0)), v)).Map(func(s interface{}) interface{} { return mapComplexish(rt, s) }) }, } }) case reflect.Complex128: return gen.Complex128().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapComplexish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapComplexish(reflect.TypeOf(complex128(0)), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapComplexish(reflect.TypeOf(complex128(0)), v)).Map(func(s interface{}) interface{} { return mapComplexish(rt, s) }) }, } }) case reflect.String: return gen.AnyString().MapResult(func(result *gopter.GenResult) *gopter.GenResult { return &gopter.GenResult{ Labels: result.Labels, ResultType: rt, Result: mapStringish(rt, result.Result), Sieve: func(v interface{}) bool { return result.Sieve == nil || result.Sieve(mapStringish(reflect.TypeOf(string("")), v)) }, Shrinker: func(v interface{}) gopter.Shrink { return result.Shrinker(mapStringish(reflect.TypeOf(string("")), v)).Map(func(s interface{}) interface{} { return mapStringish(rt, s) }) }, } }) case reflect.Array: if elementGen := a.GenForType(rt.Elem()); elementGen != nil { return gen.ArrayOfN(rt.Len(), elementGen) } case reflect.Slice: if elementGen := a.GenForType(rt.Elem()); elementGen != nil { return gen.SliceOf(elementGen) } case reflect.Ptr: if rt.Elem().Kind() == reflect.Struct { gens := make(map[string]gopter.Gen) for i := 0; i < rt.Elem().NumField(); i++ { field := rt.Elem().Field(i) if gen := a.GenForType(field.Type); gen != nil { gens[field.Name] = gen } } return gen.StructPtr(rt, gens) } return gen.PtrOf(a.GenForType(rt.Elem())) case reflect.Struct: gens := make(map[string]gopter.Gen) for i := 0; i < rt.NumField(); i++ { field := rt.Field(i) if gen := a.GenForType(field.Type); gen != nil { gens[field.Name] = gen } } return gen.Struct(rt, gens) case reflect.Map: keyGen := a.GenForType(rt.Key()) valueGen := a.GenForType(rt.Elem()) return gen.MapOf(keyGen, valueGen) } return nil } gopter-0.2.11/arbitrary/gen_for_kind_arrays_test.go000066400000000000000000000011621460324054500224700ustar00rootroot00000000000000package arbitrary_test import ( "reflect" "testing" "github.com/leanovate/gopter/arbitrary" ) func TestArbitrariesArrays(t *testing.T) { arbitraries := arbitrary.DefaultArbitraries() gen := arbitraries.GenForType(reflect.TypeOf([20]int{})) value, ok := gen.Sample() if !ok { t.Errorf("Invalid value %#v", value) } if _, ok = value.([20]int); !ok { t.Errorf("Invalid value %#v", value) } gen = arbitraries.GenForType(reflect.TypeOf([10]string{})) value, ok = gen.Sample() if !ok { t.Errorf("Invalid value %#v", value) } if _, ok = value.([10]string); !ok { t.Errorf("Invalid value %#v", value) } } gopter-0.2.11/arbitrary/gen_for_kind_slice_test.go000066400000000000000000000011541460324054500222670ustar00rootroot00000000000000package arbitrary_test import ( "reflect" "testing" "github.com/leanovate/gopter/arbitrary" ) func TestArbitrariesSlices(t *testing.T) { arbitraries := arbitrary.DefaultArbitraries() gen := arbitraries.GenForType(reflect.TypeOf([]bool{})) value, ok := gen.Sample() if !ok { t.Errorf("Invalid value %#v", value) } if _, ok = value.([]bool); !ok { t.Errorf("Invalid value %#v", value) } gen = arbitraries.GenForType(reflect.TypeOf([]*int64{})) value, ok = gen.Sample() if !ok { t.Errorf("Invalid value %#v", value) } if _, ok = value.([]*int64); !ok { t.Errorf("Invalid value %#v", value) } } gopter-0.2.11/arbitrary/gen_for_kind_struct_test.go000066400000000000000000000023171460324054500225160ustar00rootroot00000000000000package arbitrary_test import ( "reflect" "testing" "unicode" "github.com/leanovate/gopter/arbitrary" "github.com/leanovate/gopter/gen" ) type DemoStruct struct { Value1 int64 Value2 string Value3 []uint Value4 int32 } func TestArbitrariesStructs(t *testing.T) { arbitraries := arbitrary.DefaultArbitraries() arbitraries.RegisterGen(gen.Int64Range(10, 100)) arbitraries.RegisterGen(gen.Int32Range(1, 10)) arbitraries.RegisterGen(gen.Const([]uint{1, 2, 3})) arbitraries.RegisterGen(gen.AlphaString()) gen := arbitraries.GenForType(reflect.TypeOf(&DemoStruct{})) for i := 0; i < 100; i++ { raw, ok := gen.Sample() if !ok { t.Errorf("Invalid value: %#v", raw) } value, ok := raw.(*DemoStruct) if !ok { t.Errorf("Invalid value: %#v", raw) } if value.Value1 < 10 || value.Value1 > 100 { t.Errorf("Invalid value.Value1 out of bounds: %#v", raw) } for _, ch := range value.Value2 { if !unicode.IsLetter(ch) { t.Errorf("Invalid value.Value2: %#v", raw) } } if !reflect.DeepEqual(value.Value3, []uint{1, 2, 3}) { t.Errorf("Invalid value.Value3: %#v", raw) } if value.Value4 < 1 || value.Value4 > 10 { t.Errorf("Invalid value.Value4 out of bounds: %#v", raw) } } } gopter-0.2.11/arbitrary/gen_for_kind_test.go000066400000000000000000000072111460324054500211100ustar00rootroot00000000000000package arbitrary_test import ( "reflect" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" ) func commonGeneratorTest(t *testing.T, name string, gen gopter.Gen, valueCheck func(interface{}) bool) { for i := 0; i < 100; i++ { value, ok := gen.Sample() if !ok || value == nil { t.Errorf("Invalid generator result (%s): %#v", name, value) } else if !valueCheck(value) { t.Errorf("Invalid value (%s): %#v", name, value) } genResult := gen(gopter.DefaultGenParameters()) if genResult.Shrinker != nil { value, ok := genResult.Retrieve() if !ok || value == nil { t.Errorf("Invalid generator result (%s): %#v", name, value) } else { shrink := genResult.Shrinker(value).Filter(genResult.Sieve) shrunkValue, ok := shrink() if ok && !valueCheck(shrunkValue) { t.Errorf("Invalid shrunk value (%s): %#v -> %#v", name, value, shrunkValue) } } } } } func TestArbitrariesSimple(t *testing.T) { arbitraries := arbitrary.DefaultArbitraries() gen := arbitraries.GenForType(reflect.TypeOf(true)) commonGeneratorTest(t, "bool", gen, func(value interface{}) bool { _, ok := value.(bool) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(0)) commonGeneratorTest(t, "int", gen, func(value interface{}) bool { _, ok := value.(int) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(uint(0))) commonGeneratorTest(t, "uint", gen, func(value interface{}) bool { _, ok := value.(uint) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(int8(0))) commonGeneratorTest(t, "int8", gen, func(value interface{}) bool { _, ok := value.(int8) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(uint8(0))) commonGeneratorTest(t, "uint8", gen, func(value interface{}) bool { _, ok := value.(uint8) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(int16(0))) commonGeneratorTest(t, "int16", gen, func(value interface{}) bool { _, ok := value.(int16) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(uint16(0))) commonGeneratorTest(t, "uint16", gen, func(value interface{}) bool { _, ok := value.(uint16) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(int32(0))) commonGeneratorTest(t, "int32", gen, func(value interface{}) bool { _, ok := value.(int32) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(uint32(0))) commonGeneratorTest(t, "uint32", gen, func(value interface{}) bool { _, ok := value.(uint32) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(int64(0))) commonGeneratorTest(t, "int64", gen, func(value interface{}) bool { _, ok := value.(int64) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(uint64(0))) commonGeneratorTest(t, "uint64", gen, func(value interface{}) bool { _, ok := value.(uint64) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(float32(0))) commonGeneratorTest(t, "float32", gen, func(value interface{}) bool { _, ok := value.(float32) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(float64(0))) commonGeneratorTest(t, "float64", gen, func(value interface{}) bool { _, ok := value.(float64) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(complex128(0))) commonGeneratorTest(t, "complex128", gen, func(value interface{}) bool { _, ok := value.(complex128) return ok }) gen = arbitraries.GenForType(reflect.TypeOf(complex64(0))) commonGeneratorTest(t, "complex64", gen, func(value interface{}) bool { _, ok := value.(complex64) return ok }) gen = arbitraries.GenForType(reflect.TypeOf("")) commonGeneratorTest(t, "string", gen, func(value interface{}) bool { _, ok := value.(string) return ok }) } gopter-0.2.11/bi_mapper.go000066400000000000000000000062301460324054500153640ustar00rootroot00000000000000package gopter import ( "fmt" "reflect" ) // BiMapper is a bi-directional (or bijective) mapper of a tuple of values (up) // to another tuple of values (down). type BiMapper struct { UpTypes []reflect.Type DownTypes []reflect.Type Downstream reflect.Value Upstream reflect.Value } // NewBiMapper creates a BiMapper of two functions `downstream` and its // inverse `upstream`. // That is: The return values of `downstream` must match the parameters of // `upstream` and vice versa. func NewBiMapper(downstream interface{}, upstream interface{}) *BiMapper { downstreamVal := reflect.ValueOf(downstream) if downstreamVal.Kind() != reflect.Func { panic("downstream has to be a function") } upstreamVal := reflect.ValueOf(upstream) if upstreamVal.Kind() != reflect.Func { panic("upstream has to be a function") } downstreamType := downstreamVal.Type() upTypes := make([]reflect.Type, downstreamType.NumIn()) for i := 0; i < len(upTypes); i++ { upTypes[i] = downstreamType.In(i) } downTypes := make([]reflect.Type, downstreamType.NumOut()) for i := 0; i < len(downTypes); i++ { downTypes[i] = downstreamType.Out(i) } upstreamType := upstreamVal.Type() if len(upTypes) != upstreamType.NumOut() { panic(fmt.Sprintf("upstream is expected to have %d return values", len(upTypes))) } for i, upType := range upTypes { if upstreamType.Out(i) != upType { panic(fmt.Sprintf("upstream has wrong return type %d: %v != %v", i, upstreamType.Out(i), upType)) } } if len(downTypes) != upstreamType.NumIn() { panic(fmt.Sprintf("upstream is expected to have %d parameters", len(downTypes))) } for i, downType := range downTypes { if upstreamType.In(i) != downType { panic(fmt.Sprintf("upstream has wrong parameter type %d: %v != %v", i, upstreamType.In(i), downType)) } } return &BiMapper{ UpTypes: upTypes, DownTypes: downTypes, Downstream: downstreamVal, Upstream: upstreamVal, } } // ConvertUp calls the Upstream function on the arguments in the down array // and returns the results. func (b *BiMapper) ConvertUp(down []interface{}) []interface{} { if len(down) != len(b.DownTypes) { panic(fmt.Sprintf("Expected %d values != %d", len(b.DownTypes), len(down))) } downVals := make([]reflect.Value, len(b.DownTypes)) for i, val := range down { if val == nil { downVals[i] = reflect.Zero(b.DownTypes[i]) } else { downVals[i] = reflect.ValueOf(val) } } upVals := b.Upstream.Call(downVals) up := make([]interface{}, len(upVals)) for i, upVal := range upVals { up[i] = upVal.Interface() } return up } // ConvertDown calls the Downstream function on the elements of the up array // and returns the results. func (b *BiMapper) ConvertDown(up []interface{}) []interface{} { if len(up) != len(b.UpTypes) { panic(fmt.Sprintf("Expected %d values != %d", len(b.UpTypes), len(up))) } upVals := make([]reflect.Value, len(b.UpTypes)) for i, val := range up { if val == nil { upVals[i] = reflect.Zero(b.UpTypes[i]) } else { upVals[i] = reflect.ValueOf(val) } } downVals := b.Downstream.Call(upVals) down := make([]interface{}, len(downVals)) for i, downVal := range downVals { down[i] = downVal.Interface() } return down } gopter-0.2.11/bi_mapper_test.go000066400000000000000000000014131460324054500164210ustar00rootroot00000000000000package gopter_test import ( "testing" "github.com/leanovate/gopter" ) func TestBiMapperParamNotMatch(t *testing.T) { defer expectPanic(t, "upstream has wrong parameter type 0: string != int") gopter.NewBiMapper(func(int) int { return 0 }, func(string) int { return 0 }) } func TestBiMapperReturnNotMatch(t *testing.T) { defer expectPanic(t, "upstream has wrong return type 0: string != int") gopter.NewBiMapper(func(int) int { return 0 }, func(int) string { return "" }) } func TestBiMapperInvalidDownstream(t *testing.T) { defer expectPanic(t, "downstream has to be a function") gopter.NewBiMapper(1, 2) } func TestBiMapperInvalidUpstream(t *testing.T) { defer expectPanic(t, "upstream has to be a function") gopter.NewBiMapper(func(int) int { return 0 }, 2) } gopter-0.2.11/commands/000077500000000000000000000000001460324054500146775ustar00rootroot00000000000000gopter-0.2.11/commands/actions.go000066400000000000000000000106611460324054500166720ustar00rootroot00000000000000package commands import ( "fmt" "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) type shrinkableCommand struct { command Command commandSieve func(v interface{}) bool shrinker gopter.Shrinker } func (s shrinkableCommand) shrink() gopter.Shrink { return s.shrinker(s.command).Filter(s.commandSieve).Map(func(command Command) shrinkableCommand { return shrinkableCommand{ command: command, shrinker: s.shrinker, } }) } func (s shrinkableCommand) String() string { return fmt.Sprintf("%v", s.command) } type actions struct { // initialStateProvider has to reset/recreate the initial state exactly the // same every time. initialStateProvider func() State sequentialCommands []shrinkableCommand // parallel commands will come later } func (a *actions) String() string { return fmt.Sprintf("initialState=%v sequential=%s", a.initialStateProvider(), a.sequentialCommands) } func (a *actions) run(systemUnderTest SystemUnderTest) *gopter.PropResult { state := a.initialStateProvider() propResult := &gopter.PropResult{Status: gopter.PropTrue} for _, shrinkableCommand := range a.sequentialCommands { if !shrinkableCommand.command.PreCondition(state) { return &gopter.PropResult{Status: gopter.PropFalse} } result := shrinkableCommand.command.Run(systemUnderTest) state = shrinkableCommand.command.NextState(state) propResult = propResult.And(shrinkableCommand.command.PostCondition(state, result)) } return propResult } type sizedCommands struct { state State commands []shrinkableCommand } func actionsShrinker(v interface{}) gopter.Shrink { a := v.(*actions) elementShrinker := gopter.Shrinker(func(v interface{}) gopter.Shrink { return v.(shrinkableCommand).shrink() }) return gen.SliceShrinker(elementShrinker)(a.sequentialCommands).Map(func(v []shrinkableCommand) *actions { return &actions{ initialStateProvider: a.initialStateProvider, sequentialCommands: v, } }) } func genActions(commands Commands) gopter.Gen { genInitialState := commands.GenInitialState() genInitialStateProvider := gopter.Gen(func(params *gopter.GenParameters) *gopter.GenResult { seed := params.NextInt64() return gopter.NewGenResult(func() State { paramsWithSeed := params.CloneWithSeed(seed) if initialState, ok := genInitialState(paramsWithSeed).Retrieve(); ok { return initialState } return nil }, gopter.NoShrinker) }).SuchThat(func(initialStateProvoder func() State) bool { state := initialStateProvoder() return state != nil && commands.InitialPreCondition(state) }) return genInitialStateProvider.FlatMap(func(v interface{}) gopter.Gen { initialStateProvider := v.(func() State) return genSizedCommands(commands, initialStateProvider).Map(func(v sizedCommands) *actions { return &actions{ initialStateProvider: initialStateProvider, sequentialCommands: v.commands, } }).SuchThat(func(actions *actions) bool { state := actions.initialStateProvider() for _, shrinkableCommand := range actions.sequentialCommands { if !shrinkableCommand.command.PreCondition(state) { return false } state = shrinkableCommand.command.NextState(state) } return true }).WithShrinker(actionsShrinker) }, reflect.TypeOf((*actions)(nil))) } func genSizedCommands(commands Commands, initialStateProvider func() State) gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { sizedCommandsGen := gen.Const(sizedCommands{ state: initialStateProvider(), commands: make([]shrinkableCommand, 0, genParams.MaxSize), }) for i := 0; i < genParams.MaxSize; i++ { sizedCommandsGen = sizedCommandsGen.FlatMap(func(v interface{}) gopter.Gen { prev := v.(sizedCommands) return gen.RetryUntil(commands.GenCommand(prev.state), func(command Command) bool { return command.PreCondition(prev.state) }, 100).MapResult(func(result *gopter.GenResult) *gopter.GenResult { value, ok := result.Retrieve() if !ok { return gopter.NewEmptyResult(reflect.TypeOf(sizedCommands{})) } command := value.(Command) return gopter.NewGenResult( sizedCommands{ state: command.NextState(prev.state), commands: append(prev.commands, shrinkableCommand{ command: command, commandSieve: result.Sieve, shrinker: result.Shrinker, }), }, gopter.NoShrinker, ) }) }, reflect.TypeOf(sizedCommands{})) } return sizedCommandsGen(genParams) } } gopter-0.2.11/commands/command.go000066400000000000000000000044551460324054500166540ustar00rootroot00000000000000package commands import "github.com/leanovate/gopter" // SystemUnderTest resembles the system under test, which may be any kind // of stateful unit of code type SystemUnderTest interface{} // State resembles the state the system under test is expected to be in type State interface{} // Result resembles the result of a command that may or may not be checked type Result interface{} // Command is any kind of command that may be applied to the system under test type Command interface { // Run applies the command to the system under test Run(systemUnderTest SystemUnderTest) Result // NextState calculates the next expected state if the command is applied NextState(state State) State // PreCondition checks if the state is valid before the command is applied PreCondition(state State) bool // PostCondition checks if the state is valid after the command is applied PostCondition(state State, result Result) *gopter.PropResult // String gets a (short) string representation of the command String() string } // ProtoCommand is a prototype implementation of the Command interface type ProtoCommand struct { Name string RunFunc func(systemUnderTest SystemUnderTest) Result NextStateFunc func(state State) State PreConditionFunc func(state State) bool PostConditionFunc func(state State, result Result) *gopter.PropResult } // Run applies the command to the system under test func (p *ProtoCommand) Run(systemUnderTest SystemUnderTest) Result { if p.RunFunc != nil { return p.RunFunc(systemUnderTest) } return nil } // NextState calculates the next expected state if the command is applied func (p *ProtoCommand) NextState(state State) State { if p.NextStateFunc != nil { return p.NextStateFunc(state) } return state } // PreCondition checks if the state is valid before the command is applied func (p *ProtoCommand) PreCondition(state State) bool { if p.PreConditionFunc != nil { return p.PreConditionFunc(state) } return true } // PostCondition checks if the state is valid after the command is applied func (p *ProtoCommand) PostCondition(state State, result Result) *gopter.PropResult { if p.PostConditionFunc != nil { return p.PostConditionFunc(state, result) } return &gopter.PropResult{Status: gopter.PropTrue} } func (p *ProtoCommand) String() string { return p.Name } gopter-0.2.11/commands/commands.go000066400000000000000000000056551460324054500170420ustar00rootroot00000000000000package commands import ( "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) // Commands provide an entry point for testing a stateful system type Commands interface { // NewSystemUnderTest should create a new/isolated system under test NewSystemUnderTest(initialState State) SystemUnderTest // DestroySystemUnderTest may perform any cleanup tasks to destroy a system DestroySystemUnderTest(SystemUnderTest) // GenInitialState provides a generator for the initial State. // IMPORTANT: The generated state itself may be mutable, but this generator // is supposed to generate a clean and reproductable state every time. // Do not use an external random generator and be especially vary about // `gen.Const()`. GenInitialState() gopter.Gen // GenCommand provides a generator for applicable commands to for a state GenCommand(state State) gopter.Gen // InitialPreCondition checks if the initial state is valid InitialPreCondition(state State) bool } // ProtoCommands is a prototype implementation of the Commands interface type ProtoCommands struct { NewSystemUnderTestFunc func(initialState State) SystemUnderTest DestroySystemUnderTestFunc func(SystemUnderTest) InitialStateGen gopter.Gen GenCommandFunc func(State) gopter.Gen InitialPreConditionFunc func(State) bool } // NewSystemUnderTest should create a new/isolated system under test func (p *ProtoCommands) NewSystemUnderTest(initialState State) SystemUnderTest { if p.NewSystemUnderTestFunc != nil { return p.NewSystemUnderTestFunc(initialState) } return nil } // DestroySystemUnderTest may perform any cleanup tasks to destroy a system func (p *ProtoCommands) DestroySystemUnderTest(systemUnderTest SystemUnderTest) { if p.DestroySystemUnderTestFunc != nil { p.DestroySystemUnderTestFunc(systemUnderTest) } } // GenCommand provides a generator for applicable commands to for a state func (p *ProtoCommands) GenCommand(state State) gopter.Gen { if p.GenCommandFunc != nil { return p.GenCommandFunc(state) } return gen.Fail(reflect.TypeOf((*Command)(nil)).Elem()) } // GenInitialState provides a generator for the initial State func (p *ProtoCommands) GenInitialState() gopter.Gen { return p.InitialStateGen.SuchThat(func(state State) bool { return p.InitialPreCondition(state) }) } // InitialPreCondition checks if the initial state is valid func (p *ProtoCommands) InitialPreCondition(state State) bool { if p.InitialPreConditionFunc != nil { return p.InitialPreConditionFunc(state) } return true } // Prop creates a gopter.Prop from Commands func Prop(commands Commands) gopter.Prop { return prop.ForAll(func(actions *actions) *gopter.PropResult { systemUnderTest := commands.NewSystemUnderTest(actions.initialStateProvider()) defer commands.DestroySystemUnderTest(systemUnderTest) return actions.run(systemUnderTest) }, genActions(commands)) } gopter-0.2.11/commands/commands_test.go000066400000000000000000000053341460324054500200730ustar00rootroot00000000000000package commands_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/commands" "github.com/leanovate/gopter/gen" ) type counter struct { value int } func (c *counter) Get() int { return c.value } func (c *counter) Inc() int { c.value++ return c.value } func (c *counter) Dec() int { c.value-- return c.value } var GetCommand = &commands.ProtoCommand{ Name: "GET", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { return systemUnderTest.(*counter).Get() }, PreConditionFunc: func(state commands.State) bool { _, ok := state.(int) return ok }, PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult { if state.(int) != result.(int) { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} }, } var IncCommand = &commands.ProtoCommand{ Name: "INC", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { return systemUnderTest.(*counter).Inc() }, NextStateFunc: func(state commands.State) commands.State { return state.(int) + 1 }, PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult { if state.(int) != result.(int) { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} }, } var DecCommand = &commands.ProtoCommand{ Name: "DEC", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { return systemUnderTest.(*counter).Dec() }, PreConditionFunc: func(state commands.State) bool { return state.(int) > 0 }, NextStateFunc: func(state commands.State) commands.State { return state.(int) - 1 }, PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult { if state.(int) != result.(int) { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} }, } type counterCommands struct { } func (c *counterCommands) NewSystemUnderTest(initialState commands.State) commands.SystemUnderTest { return &counter{value: initialState.(int)} } func (c *counterCommands) DestroySystemUnderTest(commands.SystemUnderTest) { } func (c *counterCommands) GenInitialState() gopter.Gen { return gen.Int() } func (c *counterCommands) InitialPreCondition(state commands.State) bool { return state.(int) >= 0 } func (c *counterCommands) GenCommand(state commands.State) gopter.Gen { return gen.OneConstOf(GetCommand, IncCommand, DecCommand) } func TestCommands(t *testing.T) { parameters := gopter.DefaultTestParameters() prop := commands.Prop(&counterCommands{}) result := prop.Check(parameters) if !result.Passed() { t.Errorf("Invalid result: %v", result) } } gopter-0.2.11/commands/doc.go000066400000000000000000000006321460324054500157740ustar00rootroot00000000000000/* Package commands contains helpers to create stateful tests based on commands. Testers have to implement the Commands interface providing generators for the initial state and the commands. For convenience testers may also use the ProtoCommands as prototype. The commands themselves have to implement the Command interface, whereas testers might choose to use ProtoCommand as prototype. */ package commands gopter-0.2.11/commands/example_circularqueue_test.go000066400000000000000000000215561460324054500226620ustar00rootroot00000000000000package commands_test import ( "fmt" "github.com/leanovate/gopter" "github.com/leanovate/gopter/commands" "github.com/leanovate/gopter/gen" ) // ***************************************** // Production code (i.e. the implementation) // ***************************************** type Queue struct { inp int outp int size int buf []int } func New(n int) *Queue { return &Queue{ inp: 0, outp: 0, size: n + 1, buf: make([]int, n+1), } } func (q *Queue) Put(n int) int { if q.inp == 4 && n > 0 { // Intentional spooky bug q.buf[q.size-1] *= n } q.buf[q.inp] = n q.inp = (q.inp + 1) % q.size return n } func (q *Queue) Get() int { ans := q.buf[q.outp] q.outp = (q.outp + 1) % q.size return ans } func (q *Queue) Size() int { return (q.inp - q.outp + q.size) % q.size } func (q *Queue) Init() { q.inp = 0 q.outp = 0 } // ***************************************** // Test code // ***************************************** // cbState holds the expected state (i.e. its the commands.State) type cbState struct { size int elements []int takenElement int } func (st *cbState) TakeFront() { st.takenElement = st.elements[0] st.elements = append(st.elements[:0], st.elements[1:]...) } func (st *cbState) PushBack(value int) { st.elements = append(st.elements, value) } func (st *cbState) String() string { return fmt.Sprintf("State(size=%d, elements=%v)", st.size, st.elements) } // Get command simply invokes the Get function on the queue and compares the // result with the expected state. var genGetCommand = gen.Const(&commands.ProtoCommand{ Name: "Get", RunFunc: func(q commands.SystemUnderTest) commands.Result { return q.(*Queue).Get() }, NextStateFunc: func(state commands.State) commands.State { state.(*cbState).TakeFront() return state }, // The implementation implicitly assumes that Get is never called on an // empty Queue, therefore the command requires a corresponding pre-condition PreConditionFunc: func(state commands.State) bool { return len(state.(*cbState).elements) > 0 }, PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult { if result.(int) != state.(*cbState).takenElement { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} }, }) // Put command puts a value into the queue by using the Put function. Since // the Put function has an int argument the Put command should have a // corresponding parameter. type putCommand int func (value putCommand) Run(q commands.SystemUnderTest) commands.Result { return q.(*Queue).Put(int(value)) } func (value putCommand) NextState(state commands.State) commands.State { state.(*cbState).PushBack(int(value)) return state } // The implementation implicitly assumes that that Put is never called if // the capacity is exhausted, therefore the command requires a corresponding // pre-condition. func (putCommand) PreCondition(state commands.State) bool { s := state.(*cbState) return len(s.elements) < s.size } func (putCommand) PostCondition(state commands.State, result commands.Result) *gopter.PropResult { st := state.(*cbState) if result.(int) != st.elements[len(st.elements)-1] { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} } func (value putCommand) String() string { return fmt.Sprintf("Put(%d)", value) } // We want to have a generator for put commands for arbitrary int values. // In this case the command is actually shrinkable, e.g. if the property fails // by putting a 1000, it might already fail for a 500 as well ... var genPutCommand = gen.Int().Map(func(value int) commands.Command { return putCommand(value) }).WithShrinker(func(v interface{}) gopter.Shrink { return gen.IntShrinker(int(v.(putCommand))).Map(func(value int) putCommand { return putCommand(value) }) }) // Size command is simple again, it just invokes the Size function and // compares compares the result with the expected state. // The Size function can be called any time, therefore this command does not // require a pre-condition. var genSizeCommand = gen.Const(&commands.ProtoCommand{ Name: "Size", RunFunc: func(q commands.SystemUnderTest) commands.Result { return q.(*Queue).Size() }, PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult { if result.(int) != len(state.(*cbState).elements) { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} }, }) // cbCommands implements the command.Commands interface, i.e. is // responsible for creating/destroying the system under test and generating // commands and initial states (cbState) var cbCommands = &commands.ProtoCommands{ NewSystemUnderTestFunc: func(initialState commands.State) commands.SystemUnderTest { s := initialState.(*cbState) q := New(s.size) for e := range s.elements { q.Put(e) } return q }, DestroySystemUnderTestFunc: func(sut commands.SystemUnderTest) { sut.(*Queue).Init() }, InitialStateGen: gen.IntRange(1, 30).Map(func(size int) *cbState { return &cbState{ size: size, elements: make([]int, 0, size), } }), InitialPreConditionFunc: func(state commands.State) bool { s := state.(*cbState) return len(s.elements) >= 0 && len(s.elements) <= s.size }, GenCommandFunc: func(state commands.State) gopter.Gen { return gen.OneGenOf(genGetCommand, genPutCommand, genSizeCommand) }, } // Kudos to @jamesd for providing this real world example. // ... of course he did not implemented the bug, that was evil me // // The bug only occures on the following conditions: // - the queue size has to be greater than 4 // - the queue has to be filled entirely once // - Get operations have to be at least 5 elements behind put // - The Put at the end of the queue and 5 elements later have to be non-zero // // Lets see what gopter has to say: // // The output of this example will be // // ! circular buffer: Falsified after 96 passed tests. // ARG_0: initialState=State(size=7, elements=[]) sequential=[Put(0) Put(0) // Get Put(0) Get Put(0) Put(0) Get Put(0) Get Put(0) Get Put(-1) Put(0) // Put(0) Put(0) Put(0) Get Get Put(2) Get] // ARG_0_ORIGINAL (85 shrinks): initialState=State(size=7, elements=[]) // sequential=[Put(-1855365712) Put(-1591723498) Get Size Size // Put(-1015561691) Get Put(397128011) Size Get Put(1943174048) Size // Put(1309500770) Size Get Put(-879438231) Size Get Put(-1644094687) Get // Put(-1818606323) Size Put(488620313) Size Put(-1219794505) // Put(1166147059) Get Put(11390361) Get Size Put(-1407993944) Get Get Size // Put(1393923085) Get Put(1222853245) Size Put(2070918543) Put(1741323168) // Size Get Get Size Put(2019939681) Get Put(-170089451) Size Get Get Size // Size Put(-49249034) Put(1229062846) Put(642598551) Get Put(1183453167) // Size Get Get Get Put(1010460728) Put(6828709) Put(-185198587) Size Size // Get Put(586459644) Get Size Put(-1802196502) Get Size Put(2097590857) Get // Get Get Get Size Put(-474576011) Size Get Size Size Put(771190414) Size // Put(-1509199920) Get Put(967212411) Size Get Put(578995532) Size Get Size // Get] // // Though this is not the minimal possible combination of command, its already // pretty close. func Example_circularqueue() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice properties := gopter.NewProperties(parameters) properties.Property("circular buffer", commands.Prop(cbCommands)) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! circular buffer: Falsified after 96 passed tests. // ARG_0: initialState=State(size=7, elements=[]) sequential=[Put(0) Put(0) // Get Put(0) Get Put(0) Put(0) Get Put(0) Get Put(0) Get Put(-1) Put(0) // Put(0) Put(0) Put(0) Get Get Put(2) Get] // ARG_0_ORIGINAL (85 shrinks): initialState=State(size=7, elements=[]) // sequential=[Put(-1855365712) Put(-1591723498) Get Size Size // Put(-1015561691) Get Put(397128011) Size Get Put(1943174048) Size // Put(1309500770) Size Get Put(-879438231) Size Get Put(-1644094687) Get // Put(-1818606323) Size Put(488620313) Size Put(-1219794505) // Put(1166147059) Get Put(11390361) Get Size Put(-1407993944) Get Get Size // Put(1393923085) Get Put(1222853245) Size Put(2070918543) Put(1741323168) // Size Get Get Size Put(2019939681) Get Put(-170089451) Size Get Get Size // Size Put(-49249034) Put(1229062846) Put(642598551) Get Put(1183453167) // Size Get Get Get Put(1010460728) Put(6828709) Put(-185198587) Size Size // Get Put(586459644) Get Size Put(-1802196502) Get Size Put(2097590857) Get // Get Get Get Size Put(-474576011) Size Get Size Size Put(771190414) Size // Put(-1509199920) Get Put(967212411) Size Get Put(578995532) Size Get Size // Get] } gopter-0.2.11/commands/example_commands_test.go000066400000000000000000000073021460324054500216030ustar00rootroot00000000000000package commands_test import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/commands" "github.com/leanovate/gopter/gen" ) type BuggyCounter struct { n int } func (c *BuggyCounter) Inc() { c.n++ } func (c *BuggyCounter) Dec() { if c.n > 3 { // Intentional error c.n -= 2 } else { c.n-- } } func (c *BuggyCounter) Get() int { return c.n } func (c *BuggyCounter) Reset() { c.n = 0 } var GetBuggyCommand = &commands.ProtoCommand{ Name: "GET", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { return systemUnderTest.(*BuggyCounter).Get() }, PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult { if state.(int) != result.(int) { return &gopter.PropResult{Status: gopter.PropFalse} } return &gopter.PropResult{Status: gopter.PropTrue} }, } var IncBuggyCommand = &commands.ProtoCommand{ Name: "INC", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { systemUnderTest.(*BuggyCounter).Inc() return nil }, NextStateFunc: func(state commands.State) commands.State { return state.(int) + 1 }, } var DecBuggyCommand = &commands.ProtoCommand{ Name: "DEC", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { systemUnderTest.(*BuggyCounter).Dec() return nil }, NextStateFunc: func(state commands.State) commands.State { return state.(int) - 1 }, } var ResetBuggyCommand = &commands.ProtoCommand{ Name: "RESET", RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result { systemUnderTest.(*BuggyCounter).Reset() return nil }, NextStateFunc: func(state commands.State) commands.State { return 0 }, } var buggyCounterCommands = &commands.ProtoCommands{ NewSystemUnderTestFunc: func(initialState commands.State) commands.SystemUnderTest { return &BuggyCounter{} }, InitialStateGen: gen.Const(0), InitialPreConditionFunc: func(state commands.State) bool { return state.(int) == 0 }, GenCommandFunc: func(state commands.State) gopter.Gen { return gen.OneConstOf(GetBuggyCommand, IncBuggyCommand, DecBuggyCommand, ResetBuggyCommand) }, } // Demonstrates the usage of the commands package to find a bug in a counter // implementation that only occurs if the counter is above 3. // // The output of this example will be // // ! buggy counter: Falsified after 45 passed tests. // ARG_0: initial=0 sequential=[INC INC INC INC DEC GET] // ARG_0_ORIGINAL (9 shrinks): initial=0 sequential=[DEC RESET GET GET GET // RESET DEC DEC INC INC RESET RESET DEC INC RESET INC INC GET INC INC DEC // DEC GET RESET INC INC DEC INC INC INC RESET RESET INC INC GET INC DEC GET // DEC GET INC RESET INC INC RESET] // // I.e. gopter found an invalid state with a rather long sequence of arbitrary // commands/function calls, and then shrank that sequence down to // // INC INC INC INC DEC GET // // which is indeed the minimal set of commands one has to perform to find the // bug. func Example_buggyCounter() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("buggy counter", commands.Prop(buggyCounterCommands)) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! buggy counter: Falsified after 43 passed tests. // ARG_0: initialState=0 sequential=[INC INC INC INC DEC GET] // ARG_0_ORIGINAL (8 shrinks): initialState=0 sequential=[RESET GET GET GET // RESET DEC DEC INC INC RESET RESET DEC INC RESET INC INC GET INC INC DEC // DEC GET RESET INC INC DEC INC INC INC RESET RESET INC INC GET INC DEC GET // DEC GET INC RESET INC INC] } gopter-0.2.11/commands/replay.go000066400000000000000000000011631460324054500165230ustar00rootroot00000000000000package commands import ( "github.com/leanovate/gopter" ) // Replay a sequence of commands on a system for regression testing func Replay(systemUnderTest SystemUnderTest, initialState State, commands ...Command) *gopter.PropResult { sequentialCommands := make([]shrinkableCommand, 0, len(commands)) for _, command := range commands { sequentialCommands = append(sequentialCommands, shrinkableCommand{command: command, shrinker: gopter.NoShrinker}) } actions := actions{ initialStateProvider: func() State { return initialState }, sequentialCommands: sequentialCommands, } return actions.run(systemUnderTest) } gopter-0.2.11/convey/000077500000000000000000000000001460324054500144015ustar00rootroot00000000000000gopter-0.2.11/convey/doc.go000066400000000000000000000001731460324054500154760ustar00rootroot00000000000000/* Package convey contains special assertion that come handy when using groper properties with goconvey. */ package convey gopter-0.2.11/convey/go.mod000066400000000000000000000002321460324054500155040ustar00rootroot00000000000000module github.com/leanovate/gopter/convey go 1.12 require ( github.com/leanovate/gopter v0.2.8 // indirect github.com/smartystreets/goconvey v1.6.4 ) gopter-0.2.11/convey/go.sum000066400000000000000000000026201460324054500155340ustar00rootroot00000000000000github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/leanovate/gopter v0.2.8 h1:eFPtJ3aa5zLfbxGROSNY75T9Dume60CWBAqoWQ3h/ig= github.com/leanovate/gopter v0.2.8/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopter-0.2.11/convey/should_forall.go000066400000000000000000000027061460324054500175720ustar00rootroot00000000000000package convey import ( "bytes" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" "github.com/leanovate/gopter/prop" ) // ShouldSucceedForAll checks that a check condition is be true for all values, if the // condition falsiies the generated values will be shrunk. // // "condition" has to be a function with the same number of parameters as the provided // generators "gens". The function may return a simple bool (true means that the // condition has passed), a string (empty string means that condition has passed), // a *PropResult, or one of former combined with an error. func ShouldSucceedForAll(condition interface{}, params ...interface{}) string { var arbitraries *arbitrary.Arbitraries parameters := gopter.DefaultTestParameters() gens := make([]gopter.Gen, 0) for _, param := range params { switch param.(type) { case *arbitrary.Arbitraries: arbitraries = param.(*arbitrary.Arbitraries) case *gopter.TestParameters: parameters = param.(*gopter.TestParameters) case gopter.Gen: gens = append(gens, param.(gopter.Gen)) } } var property gopter.Prop if arbitraries != nil { property = arbitraries.ForAll(condition) } else { property = prop.ForAll(condition, gens...) } result := property.Check(parameters) if !result.Passed() { buffer := bytes.NewBufferString("") reporter := gopter.NewFormatedReporter(true, 75, buffer) reporter.ReportTestResult("", result) return buffer.String() } return "" } gopter-0.2.11/convey/should_forall_test.go000066400000000000000000000042651460324054500206330ustar00rootroot00000000000000package convey_test import ( "errors" "math" "reflect" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" . "github.com/leanovate/gopter/convey" "github.com/leanovate/gopter/gen" . "github.com/smartystreets/goconvey/convey" ) type QudraticEquation struct { A, B, C float64 } func (q *QudraticEquation) Eval(x float64) float64 { return q.A*x*x + q.B*x + q.C } func (q *QudraticEquation) Solve() (float64, float64, error) { if q.A == 0 { return 0, 0, errors.New("No solution") } v := q.B*q.B - 4*q.A*q.C if v < 0 { return 0, 0, errors.New("No solution") } v = math.Sqrt(v) return (-q.B + v) / 2 / q.A, (-q.B - v) / 2 / q.A, nil } func TestShouldSucceedForAll(t *testing.T) { Convey("Given a check for quadratic equations", t, func() { checkSolve := func(quadratic *QudraticEquation) bool { x1, x2, err := quadratic.Solve() if err != nil { return true } return math.Abs(quadratic.Eval(x1)) < 1e-5 && math.Abs(quadratic.Eval(x2)) < 1e-5 } Convey("Then check with arbitraries succeeds", func() { arbitraries := arbitrary.DefaultArbitraries() arbitraries.RegisterGen(gen.Float64Range(-1e5, 1e5)) So(checkSolve, ShouldSucceedForAll, arbitraries) Convey("And test parameters may be modified", func() { parameters := gopter.DefaultTestParameters() parameters.MinSuccessfulTests = 200 So(checkSolve, ShouldSucceedForAll, arbitraries, parameters) }) }) Convey("Then check with explicit generator succeeds", func() { anyQudraticEquation := gen.StructPtr(reflect.TypeOf(QudraticEquation{}), map[string]gopter.Gen{ "A": gen.Float64Range(-1e5, 1e5), "B": gen.Float64Range(-1e5, 1e5), "C": gen.Float64Range(-1e5, 1e5), }) So(checkSolve, ShouldSucceedForAll, anyQudraticEquation) }) Convey("Expect fail", func() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice result := ShouldSucceedForAll(func(i int) bool { return i > 500 }, gen.Int(), parameters) So(result, ShouldStartWith, "! : Falsified after 1 passed tests.\nARG_0: 0\nARG_0_ORIGINAL (1 shrinks): -642623569") }) }) } gopter-0.2.11/derived_gen.go000066400000000000000000000053131460324054500157020ustar00rootroot00000000000000package gopter import ( "fmt" "reflect" ) type derivedGen struct { biMapper *BiMapper upGens []Gen resultType reflect.Type } func (d *derivedGen) Generate(genParams *GenParameters) *GenResult { labels := []string{} up := make([]interface{}, len(d.upGens)) shrinkers := make([]Shrinker, len(d.upGens)) sieves := make([]func(v interface{}) bool, len(d.upGens)) var ok bool for i, gen := range d.upGens { result := gen(genParams) labels = append(labels, result.Labels...) shrinkers[i] = result.Shrinker sieves[i] = result.Sieve up[i], ok = result.Retrieve() if !ok { return &GenResult{ Shrinker: d.Shrinker(result.Shrinker), Result: nil, Labels: result.Labels, ResultType: d.resultType, Sieve: d.Sieve(sieves...), } } } down := d.biMapper.ConvertDown(up) if len(down) == 1 { return &GenResult{ Shrinker: d.Shrinker(CombineShrinker(shrinkers...)), Result: down[0], Labels: labels, ResultType: reflect.TypeOf(down[0]), Sieve: d.Sieve(sieves...), } } return &GenResult{ Shrinker: d.Shrinker(CombineShrinker(shrinkers...)), Result: down, Labels: labels, ResultType: reflect.TypeOf(down), Sieve: d.Sieve(sieves...), } } func (d *derivedGen) Sieve(baseSieve ...func(interface{}) bool) func(interface{}) bool { return func(down interface{}) bool { if down == nil { return false } downs, ok := down.([]interface{}) if !ok { downs = []interface{}{down} } ups := d.biMapper.ConvertUp(downs) for i, up := range ups { if baseSieve[i] != nil && !baseSieve[i](up) { return false } } return true } } func (d *derivedGen) Shrinker(baseShrinker Shrinker) func(down interface{}) Shrink { return func(down interface{}) Shrink { downs, ok := down.([]interface{}) if !ok { downs = []interface{}{down} } ups := d.biMapper.ConvertUp(downs) upShrink := baseShrinker(ups) return upShrink.Map(func(shrunkUps []interface{}) interface{} { downs := d.biMapper.ConvertDown(shrunkUps) if len(downs) == 1 { return downs[0] } return downs }) } } // DeriveGen derives a generator with shrinkers from a sequence of other // generators mapped by a bijective function (BiMapper) func DeriveGen(downstream interface{}, upstream interface{}, gens ...Gen) Gen { biMapper := NewBiMapper(downstream, upstream) if len(gens) != len(biMapper.UpTypes) { panic(fmt.Sprintf("Expected %d generators != %d", len(biMapper.UpTypes), len(gens))) } resultType := reflect.TypeOf([]interface{}{}) if len(biMapper.DownTypes) == 1 { resultType = biMapper.DownTypes[0] } derived := &derivedGen{ biMapper: biMapper, upGens: gens, resultType: resultType, } return derived.Generate } gopter-0.2.11/derived_gen_test.go000066400000000000000000000126761460324054500167530ustar00rootroot00000000000000package gopter_test import ( "reflect" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) type downStruct struct { a int b string c bool } func TestDeriveGenSingleDown(t *testing.T) { gen := gopter.DeriveGen( func(a int, b string, c bool) *downStruct { return &downStruct{a: a, b: b, c: c} }, func(d *downStruct) (int, string, bool) { return d.a, d.b, d.c }, gen.Int(), gen.AnyString(), gen.Bool(), ) sample, ok := gen.Sample() if !ok { t.Error("Sample not ok") } _, ok = sample.(*downStruct) if !ok { t.Errorf("%#v is not a downStruct", sample) } shrinker := gen(gopter.DefaultGenParameters()).Shrinker shrink := shrinker(&downStruct{a: 10, b: "abcd", c: false}) shrunkStructs := make([]*downStruct, 0) value, next := shrink() for next { shrunkStruct, ok := value.(*downStruct) if !ok { t.Errorf("Invalid shrunk value: %#v", value) } shrunkStructs = append(shrunkStructs, shrunkStruct) value, next = shrink() } expected := []*downStruct{ {a: 0, b: "abcd", c: false}, {a: 5, b: "abcd", c: false}, {a: -5, b: "abcd", c: false}, {a: 8, b: "abcd", c: false}, {a: -8, b: "abcd", c: false}, {a: 9, b: "abcd", c: false}, {a: -9, b: "abcd", c: false}, {a: 10, b: "cd", c: false}, {a: 10, b: "ab", c: false}, {a: 10, b: "bcd", c: false}, {a: 10, b: "acd", c: false}, {a: 10, b: "abd", c: false}, {a: 10, b: "abc", c: false}, } if !reflect.DeepEqual(shrunkStructs, expected) { t.Errorf("%v does not equal %v", shrunkStructs, expected) } } func TestDeriveGenSingleDownWithSieves(t *testing.T) { gen := gopter.DeriveGen( func(a int, b string, c bool) *downStruct { return &downStruct{a: a, b: b, c: c} }, func(d *downStruct) (int, string, bool) { return d.a, d.b, d.c }, gen.Int().SuchThat(func(i int) bool { return i%2 == 0 }), gen.AnyString(), gen.Bool(), ) parameters := gopter.DefaultGenParameters() parameters.Rng.Seed(1234) hasNoValue := false sawEven := false sawOdd := false for i := 0; i < 100; i++ { result := gen(parameters) val, ok := result.Retrieve() if ok { ds := val.(*downStruct) if ds.a%2 == 0 { sawEven = true } else { sawOdd = true } } else { hasNoValue = true } } if !hasNoValue { t.Error("Sieve is not applied") } if !sawEven { t.Error("Sieve did not pass even") } if sawOdd { t.Error("Sieve did pass odd") } } func TestDeriveGenMultiDown(t *testing.T) { gen := gopter.DeriveGen( func(a int, b string, c bool, d int32) (*downStruct, int64) { return &downStruct{a: a, b: b, c: c}, int64(a) + int64(d) }, func(d *downStruct, diff int64) (int, string, bool, int32) { return d.a, d.b, d.c, int32(diff - int64(d.a)) }, gen.Int(), gen.AnyString(), gen.Bool(), gen.Int32(), ) sample, ok := gen.Sample() if !ok { t.Error("Sample not ok") } values, ok := sample.([]interface{}) if !ok || len(values) != 2 { t.Errorf("%#v is not a slice of interface", sample) } _, ok = values[0].(*downStruct) if !ok { t.Errorf("%#v is not a downStruct", values[0]) } _, ok = values[1].(int64) if !ok { t.Errorf("%#v is not a int64", values[1]) } shrinker := gen(gopter.DefaultGenParameters()).Shrinker shrink := shrinker([]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(20)}) value, next := shrink() shrunkValues := make([][]interface{}, 0) for next { shrunk, ok := value.([]interface{}) if !ok || len(values) != 2 { t.Errorf("%#v is not a slice of interface", sample) } shrunkValues = append(shrunkValues, shrunk) value, next = shrink() } expected := [][]interface{}{ {&downStruct{a: 0, b: "abcd", c: false}, int64(10)}, {&downStruct{a: 5, b: "abcd", c: false}, int64(15)}, {&downStruct{a: -5, b: "abcd", c: false}, int64(5)}, {&downStruct{a: 8, b: "abcd", c: false}, int64(18)}, {&downStruct{a: -8, b: "abcd", c: false}, int64(2)}, {&downStruct{a: 9, b: "abcd", c: false}, int64(19)}, {&downStruct{a: -9, b: "abcd", c: false}, int64(1)}, {&downStruct{a: 10, b: "cd", c: false}, int64(20)}, {&downStruct{a: 10, b: "ab", c: false}, int64(20)}, {&downStruct{a: 10, b: "bcd", c: false}, int64(20)}, {&downStruct{a: 10, b: "acd", c: false}, int64(20)}, {&downStruct{a: 10, b: "abd", c: false}, int64(20)}, {&downStruct{a: 10, b: "abc", c: false}, int64(20)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(10)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(15)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(5)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(18)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(2)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(19)}, {&downStruct{a: 10, b: "abcd", c: false}, int64(1)}, } if !reflect.DeepEqual(shrunkValues, expected) { t.Errorf("%v does not equal %v", shrunkValues, expected) } } func TestDeriveGenVaryingSieveAndShrinker(t *testing.T) { gen := gopter.DeriveGen( func(a interface{}) interface{} { return a }, func(a interface{}) interface{} { return a }, gen.OneGenOf(gen.AnyString(), gen.Int()), ) parameters := gopter.DefaultGenParameters() parameters.Rng.Seed(1234) for i := 0; i < 20; i++ { result := gen(parameters) sample, ok := result.Retrieve() if !ok { t.Error("Sample not ok") } if stringval, ok := sample.(string); ok { // check that the Shrinker doesn't panic result.Shrinker(stringval) } else if intval, ok := sample.(int); ok { result.Shrinker(intval) } else { t.Errorf("%#v is not a string or int", sample) } } } gopter-0.2.11/doc.go000066400000000000000000000016321460324054500141740ustar00rootroot00000000000000/* Package gopter contain the main interfaces of the GOlang Property TestER. A simple property test might look like this: func TestSqrt(t *testing.T) { properties := gopter.NewProperties(nil) properties.Property("greater one of all greater one", prop.ForAll( func(v float64) bool { return math.Sqrt(v) >= 1 }, gen.Float64Range(1, math.MaxFloat64), )) properties.Property("squared is equal to value", prop.ForAll( func(v float64) bool { r := math.Sqrt(v) return math.Abs(r*r-v) < 1e-10*v }, gen.Float64Range(0, math.MaxFloat64), )) properties.TestingRun(t) } Generally a property is just a function that takes GenParameters and produces a PropResult: type Prop func(*GenParameters) *PropResult but usually you will use prop.ForAll, prop.ForAllNoShrink or arbitrary.ForAll. There is also the commands package, which can be helpful for stateful testing. */ package gopter gopter-0.2.11/example_biggest_test.go000066400000000000000000000022001460324054500176150ustar00rootroot00000000000000package gopter_test import ( "fmt" "reflect" "sort" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func wrong_biggest(ns []int) (int, error) { if len(ns) == 0 { return 0, fmt.Errorf("slice must have at least one element") } return ns[0], nil } func Example_biggest() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("Non-zero length small int slice", prop.ForAll( func(ns []int) bool { result, _ := wrong_biggest(ns) sort.Slice(ns, func(i, j int) bool { return ns[i] > ns[j] }) return result == ns[0] }, gen.SliceOf(gen.IntRange(0, 20), reflect.TypeOf(int(0))). SuchThat(func(v interface{}) bool { return len(v.([]int)) > 0 }), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! Non-zero length small int slice: Falsified after 1 passed tests. // ARG_0: [0 5 0] // ARG_0_ORIGINAL (1 shrinks): [0 7 5] } gopter-0.2.11/example_fizzbuzz_test.go000066400000000000000000000040071460324054500200750ustar00rootroot00000000000000package gopter_test import ( "errors" "math" "strconv" "strings" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) // Fizzbuzz: See https://wikipedia.org/wiki/Fizz_buzz func fizzbuzz(number int) (string, error) { if number <= 0 { return "", errors.New("Undefined") } switch { case number%15 == 0: return "FizzBuzz", nil case number%3 == 0: return "Fizz", nil case number%5 == 0: return "Buzz", nil } return strconv.Itoa(number), nil } func Example_fizzbuzz() { properties := gopter.NewProperties(nil) properties.Property("Undefined for all <= 0", prop.ForAll( func(number int) bool { result, err := fizzbuzz(number) return err != nil && result == "" }, gen.IntRange(math.MinInt32, 0), )) properties.Property("Start with Fizz for all multiples of 3", prop.ForAll( func(i int) bool { result, err := fizzbuzz(i * 3) return err == nil && strings.HasPrefix(result, "Fizz") }, gen.IntRange(1, math.MaxInt32/3), )) properties.Property("End with Buzz for all multiples of 5", prop.ForAll( func(i int) bool { result, err := fizzbuzz(i * 5) return err == nil && strings.HasSuffix(result, "Buzz") }, gen.IntRange(1, math.MaxInt32/5), )) properties.Property("Int as string for all non-divisible by 3 or 5", prop.ForAll( func(number int) bool { result, err := fizzbuzz(number) if err != nil { return false } parsed, err := strconv.ParseInt(result, 10, 64) return err == nil && parsed == int64(number) }, gen.IntRange(1, math.MaxInt32).SuchThat(func(v interface{}) bool { return v.(int)%3 != 0 && v.(int)%5 != 0 }), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // + Undefined for all <= 0: OK, passed 100 tests. // + Start with Fizz for all multiples of 3: OK, passed 100 tests. // + End with Buzz for all multiples of 5: OK, passed 100 tests. // + Int as string for all non-divisible by 3 or 5: OK, passed 100 tests. } gopter-0.2.11/example_flatmap_test.go000066400000000000000000000022611460324054500176240ustar00rootroot00000000000000package gopter_test import ( "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func Example_flatmap() { type IntPair struct { Fst int Snd int } // Generate a pair of integers, such that the first // is in the range of 10-20 and the second in the // in the range of 2k-50, depending on the value of // the first. genIntPair := func() gopter.Gen { return gen.IntRange(10, 20).FlatMap(func(v interface{}) gopter.Gen { k := v.(int) return gen.IntRange(2*k, 50).Map(func(m int) IntPair { return IntPair{Fst: k, Snd: m} }) }, reflect.TypeOf(int(0))) } parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("Generate a dependent pair of integers", prop.ForAll( func(p IntPair) bool { a := p.Fst b := p.Snd return a*2 <= b }, genIntPair(), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // + Generate a dependent pair of integers: OK, passed 100 tests. } gopter-0.2.11/example_labels_test.go000066400000000000000000000026261460324054500174470ustar00rootroot00000000000000package gopter_test import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func spookyCalculation(a, b int) int { if a < 0 { a = -a } if b < 0 { b = -b } return 2*b + 3*(2+(a+1)+b*(b+1)) } // Example_labels demonstrates how labels may help, in case of more complex // conditions. // The output will be: // // ! Check spooky: Falsified after 0 passed tests. // > Labels of failing property: even result // a: 3 // a_ORIGINAL (44 shrinks): 861384713 // b: 0 // b_ORIGINAL (1 shrinks): -642623569 func Example_labels() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results parameters.MinSuccessfulTests = 10000 properties := gopter.NewProperties(parameters) properties.Property("Check spooky", prop.ForAll( func(a, b int) string { result := spookyCalculation(a, b) if result < 0 { return "negative result" } if result%2 == 0 { return "even result" } return "" }, gen.Int().WithLabel("a"), gen.Int().WithLabel("b"), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! Check spooky: Falsified after 0 passed tests. // > Labels of failing property: even result // a: 3 // a_ORIGINAL (44 shrinks): 861384713 // b: 0 // b_ORIGINAL (1 shrinks): -642623569 } gopter-0.2.11/example_libraries_test.go000066400000000000000000000047661460324054500201700ustar00rootroot00000000000000package gopter_test import ( "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" "github.com/leanovate/gopter/gen" ) type TestBook struct { Title string Content string } func genTestBook() gopter.Gen { return gen.Struct(reflect.TypeOf(&TestBook{}), map[string]gopter.Gen{ "Title": gen.AlphaString(), "Content": gen.AlphaString(), }) } type TestLibrary struct { Name string Librarians uint8 Books []TestBook } func genTestLibrary() gopter.Gen { return gen.Struct(reflect.TypeOf(&TestLibrary{}), map[string]gopter.Gen{ "Name": gen.AlphaString().SuchThat(func(s string) bool { // Non-empty string return s != "" }), "Librarians": gen.UInt8Range(1, 255), "Books": gen.SliceOf(genTestBook()), }) } type CityName = string type TestCities struct { Libraries map[CityName][]TestLibrary } func genTestCities() gopter.Gen { return gen.StructPtr(reflect.TypeOf(&TestCities{}), map[string]gopter.Gen{ "Libraries": (gen.MapOf(gen.AlphaString(), gen.SliceOf(genTestLibrary()))), }) } func Example_libraries() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results parameters.MaxSize = 5 arbitraries := arbitrary.DefaultArbitraries() arbitraries.RegisterGen(genTestCities()) properties := gopter.NewProperties(parameters) properties.Property("no unsupervised libraries", arbitraries.ForAll( func(tc *TestCities) bool { for _, libraries := range tc.Libraries { for _, library := range libraries { if library.Librarians == 0 { return false } } } return true }, )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // + no unsupervised libraries: OK, passed 100 tests. } func Example_libraries2() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results arbitraries := arbitrary.DefaultArbitraries() // All string are alphanumeric arbitraries.RegisterGen(gen.AlphaString()) properties := gopter.NewProperties(parameters) properties.Property("libraries always empty", arbitraries.ForAll( func(tc *TestCities) bool { return len(tc.Libraries) == 0 }, )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! libraries always empty: Falsified after 2 passed tests. // ARG_0: &{Libraries:map[z:[]]} } gopter-0.2.11/example_panic_test.go000066400000000000000000000014161460324054500172730ustar00rootroot00000000000000package gopter_test import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func Example_panic() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("Will panic", prop.ForAll( func(i int) bool { if i%2 == 0 { panic("hi") } return true }, gen.Int().WithLabel("number"))) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! Will panic: Error on property evaluation after 6 passed tests: Check // paniced: hi // number: 0 // number_ORIGINAL (1 shrinks): 2015020988 } gopter-0.2.11/example_sqrt_test.go000066400000000000000000000017671460324054500172030ustar00rootroot00000000000000package gopter_test import ( "math" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func Example_sqrt() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("greater one of all greater one", prop.ForAll( func(v float64) bool { return math.Sqrt(v) >= 1 }, gen.Float64().SuchThat(func(x float64) bool { return x >= 1.0 }), )) properties.Property("squared is equal to value", prop.ForAll( func(v float64) bool { r := math.Sqrt(v) return math.Abs(r*r-v) < 1e-10*v }, gen.Float64().SuchThat(func(x float64) bool { return x >= 0.0 }), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // + greater one of all greater one: OK, passed 100 tests. // + squared is equal to value: OK, passed 100 tests. } gopter-0.2.11/flag.go000066400000000000000000000005701460324054500143400ustar00rootroot00000000000000package gopter import "sync/atomic" // Flag is a convenient helper for an atomic boolean type Flag struct { flag int32 } // Get the value of the flag func (f *Flag) Get() bool { return atomic.LoadInt32(&f.flag) > 0 } // Set the the flag func (f *Flag) Set() { atomic.StoreInt32(&f.flag, 1) } // Unset the flag func (f *Flag) Unset() { atomic.StoreInt32(&f.flag, 0) } gopter-0.2.11/flag_test.go000066400000000000000000000005551460324054500154020ustar00rootroot00000000000000package gopter_test import ( "testing" "github.com/leanovate/gopter" ) func TestFlag(t *testing.T) { flag := &gopter.Flag{} if flag.Get() { t.Errorf("Flag should be initially unset: %#v", flag) } flag.Set() if !flag.Get() { t.Errorf("Flag should be set: %#v", flag) } flag.Unset() if flag.Get() { t.Errorf("Flag should be unset: %#v", flag) } } gopter-0.2.11/formated_reporter.go000066400000000000000000000074651460324054500171640ustar00rootroot00000000000000package gopter import ( "fmt" "io" "os" "strings" "unicode" ) const newLine = "\n" // FormatedReporter reports test results in a human readable manager. type FormatedReporter struct { verbose bool width int output io.Writer } // NewFormatedReporter create a new formated reporter // verbose toggles verbose output of the property results // width is the maximal width per line // output is the writer were the report will be written to func NewFormatedReporter(verbose bool, width int, output io.Writer) Reporter { return &FormatedReporter{ verbose: verbose, width: width, output: output, } } // ConsoleReporter creates a FormatedReporter writing to the console (i.e. stdout) func ConsoleReporter(verbose bool) Reporter { return NewFormatedReporter(verbose, 75, os.Stdout) } // ReportTestResult reports a single property result func (r *FormatedReporter) ReportTestResult(propName string, result *TestResult) { if result.Passed() { fmt.Fprintln(r.output, r.formatLines(fmt.Sprintf("+ %s: %s", propName, r.reportResult(result)), "", "")) } else { fmt.Fprintln(r.output, r.formatLines(fmt.Sprintf("! %s: %s", propName, r.reportResult(result)), "", "")) } } func (r *FormatedReporter) reportResult(result *TestResult) string { status := "" switch result.Status { case TestProved: status = "OK, proved property.\n" + r.reportPropArgs(result.Args) case TestPassed: status = fmt.Sprintf("OK, passed %d tests.", result.Succeeded) case TestFailed: status = fmt.Sprintf("Falsified after %d passed tests.\n%s%s", result.Succeeded, r.reportLabels(result.Labels), r.reportPropArgs(result.Args)) case TestExhausted: status = fmt.Sprintf("Gave up after only %d passed tests. %d tests were discarded.", result.Succeeded, result.Discarded) case TestError: if r.verbose { status = fmt.Sprintf("Error on property evaluation after %d passed tests: %s\n%s\n%s", result.Succeeded, result.Error.Error(), result.ErrorStack, r.reportPropArgs(result.Args)) } else { status = fmt.Sprintf("Error on property evaluation after %d passed tests: %s\n%s", result.Succeeded, result.Error.Error(), r.reportPropArgs(result.Args)) } } if r.verbose { return concatLines(status, fmt.Sprintf("Elapsed time: %s", result.Time.String())) } return status } func (r *FormatedReporter) reportLabels(labels []string) string { if labels != nil && len(labels) > 0 { return fmt.Sprintf("> Labels of failing property: %s\n", strings.Join(labels, newLine)) } return "" } func (r *FormatedReporter) reportPropArgs(p PropArgs) string { result := "" for i, arg := range p { if result != "" { result += newLine } result += r.reportPropArg(i, arg) } return result } func (r *FormatedReporter) reportPropArg(idx int, propArg *PropArg) string { label := propArg.Label if label == "" { label = fmt.Sprintf("ARG_%d", idx) } result := fmt.Sprintf("%s: %s", label, propArg.ArgFormatted) if propArg.Shrinks > 0 { result += fmt.Sprintf("\n%s_ORIGINAL (%d shrinks): %s", label, propArg.Shrinks, propArg.OrigArgFormatted) } return result } func (r *FormatedReporter) formatLines(str, lead, trail string) string { result := "" for _, line := range strings.Split(str, "\n") { if result != "" { result += newLine } result += r.breakLine(lead+line+trail, " ") } return result } func (r *FormatedReporter) breakLine(str, lead string) string { if len(str) <= r.width { return str } result := "" for len(str) > r.width { idx := strings.LastIndexFunc(str[0:r.width], func(ch rune) bool { return unicode.IsSpace(ch) }) if idx <= 0 { idx = r.width } result += str[0:idx] + "\n" + lead str = str[idx:] } result += str return result } func concatLines(strs ...string) string { result := "" for _, str := range strs { if str != "" { if result != "" { result += "\n" } result += str } } return result } gopter-0.2.11/formated_reporter_test.go000066400000000000000000000043541460324054500202150ustar00rootroot00000000000000package gopter import ( "bytes" "errors" "testing" "time" ) func TestConsoleReporter(t *testing.T) { var buffer bytes.Buffer reporter := &FormatedReporter{ verbose: false, width: 75, output: &buffer, } reporter.ReportTestResult("test property", &TestResult{Status: TestPassed, Succeeded: 50}) if buffer.String() != "+ test property: OK, passed 50 tests.\n" { t.Errorf("Invalid output: %#v", buffer.String()) } buffer.Reset() reporter.ReportTestResult("test property", &TestResult{ Status: TestFailed, Succeeded: 50, Args: PropArgs([]*PropArg{{ Arg: "0", ArgFormatted: "0", }}), }) if buffer.String() != "! test property: Falsified after 50 passed tests.\nARG_0: 0\n" { t.Errorf("Invalid output: %#v", buffer.String()) } buffer.Reset() reporter.ReportTestResult("test property", &TestResult{ Status: TestProved, Succeeded: 50, Args: PropArgs([]*PropArg{{ Arg: "0", ArgFormatted: "0", Label: "somehing", OrigArg: "10", OrigArgFormatted: "10", Shrinks: 6, }}), }) if buffer.String() != "+ test property: OK, proved property.\nsomehing: 0\nsomehing_ORIGINAL (6 shrinks): 10\n" { t.Errorf("Invalid output: %#v", buffer.String()) } buffer.Reset() reporter.ReportTestResult("test property", &TestResult{ Status: TestExhausted, Succeeded: 50, Discarded: 40, }) if buffer.String() != "! test property: Gave up after only 50 passed tests. 40 tests were\n discarded.\n" { t.Errorf("Invalid output: %#v", buffer.String()) } buffer.Reset() reporter.ReportTestResult("test property", &TestResult{ Status: TestError, Error: errors.New("Poop"), Succeeded: 50, Args: PropArgs([]*PropArg{{ Arg: "0", ArgFormatted: "0", }}), }) if buffer.String() != "! test property: Error on property evaluation after 50 passed tests: Poop\nARG_0: 0\n" { t.Errorf("Invalid output: %#v", buffer.String()) } buffer.Reset() reporter.verbose = true reporter.ReportTestResult("test property", &TestResult{Status: TestPassed, Succeeded: 50, Time: time.Minute}) if buffer.String() != "+ test property: OK, passed 50 tests.\nElapsed time: 1m0s\n" { t.Errorf("Invalid output: %#v", buffer.String()) } buffer.Reset() } gopter-0.2.11/gen.go000066400000000000000000000206421460324054500142020ustar00rootroot00000000000000package gopter import ( "fmt" "reflect" ) // Gen generator of arbitrary values. // Usually properties are checked by verifing a condition holds true for // arbitrary input parameters generated by a Gen. // // IMPORTANT: Even though a generator is supposed to generate random values, it // should do this in a reproducible way. Therefore a generator has to create the // same result for the same GenParameters, i.e. ensure that you just use the // RNG provided by GenParameters and no external one. // If you just plug generators together you do not have to worry about this. type Gen func(*GenParameters) *GenResult var ( // DefaultGenParams can be used as default für *GenParameters DefaultGenParams = DefaultGenParameters() MinGenParams = MinGenParameters() ) // Sample generate a sample value. // Depending on the state of the RNG the generate might fail to provide a sample func (g Gen) Sample() (interface{}, bool) { return g(DefaultGenParameters()).Retrieve() } // WithLabel adds a label to a generated value. // Labels are usually used for reporting for the arguments of a property check. func (g Gen) WithLabel(label string) Gen { return func(genParams *GenParameters) *GenResult { result := g(genParams) result.Labels = append(result.Labels, label) return result } } // SuchThat creates a derived generator by adding a sieve. // f: has to be a function with one parameter (matching the generated value) returning a bool. // All generated values are expected to satisfy // // f(value) == true. // // Use this care, if the sieve to to fine the generator will have many misses which results // in an undecided property. func (g Gen) SuchThat(f interface{}) Gen { checkVal := reflect.ValueOf(f) checkType := checkVal.Type() if checkVal.Kind() != reflect.Func { panic(fmt.Sprintf("Param of SuchThat has to be a func, but is %v", checkType.Kind())) } if checkType.NumIn() != 1 { panic(fmt.Sprintf("Param of SuchThat has to be a func with one param, but is %v", checkType.NumIn())) } else { genResultType := g(MinGenParams).ResultType if !genResultType.AssignableTo(checkType.In(0)) { panic(fmt.Sprintf("Param of SuchThat has to be a func with one param assignable to %v, but is %v", genResultType, checkType.In(0))) } } if checkType.NumOut() != 1 { panic(fmt.Sprintf("Param of SuchThat has to be a func with one return value, but is %v", checkType.NumOut())) } else if checkType.Out(0).Kind() != reflect.Bool { panic(fmt.Sprintf("Param of SuchThat has to be a func with one return value of bool, but is %v", checkType.Out(0).Kind())) } sieve := func(v interface{}) bool { valueOf := reflect.ValueOf(v) if !valueOf.IsValid() { return false } return checkVal.Call([]reflect.Value{valueOf})[0].Bool() } return func(genParams *GenParameters) *GenResult { result := g(genParams) prevSieve := result.Sieve if prevSieve == nil { result.Sieve = sieve } else { result.Sieve = func(value interface{}) bool { return prevSieve(value) && sieve(value) } } return result } } // WithShrinker creates a derived generator with a specific shrinker func (g Gen) WithShrinker(shrinker Shrinker) Gen { return func(genParams *GenParameters) *GenResult { result := g(genParams) if shrinker == nil { result.Shrinker = NoShrinker } else { result.Shrinker = shrinker } return result } } // Map creates a derived generator by mapping all generatored values with a given function. // f: has to be a function with one parameter (matching the generated value) and a single return. // Note: The derived generator will not have a sieve or shrinker unless you are mapping to the same type // Note: The mapping function may have a second parameter "*GenParameters" // Note: The first parameter of the mapping function and its return may be a *GenResult (this makes MapResult obsolete) func (g Gen) Map(f interface{}) Gen { mapperVal := reflect.ValueOf(f) mapperType := mapperVal.Type() needsGenParameters := false genResultInput := false genResultOutput := false if mapperVal.Kind() != reflect.Func { panic(fmt.Sprintf("Param of Map has to be a func, but is %v", mapperType.Kind())) } if mapperType.NumIn() != 1 && mapperType.NumIn() != 2 { panic(fmt.Sprintf("Param of Map has to be a func with one or two params, but is %v", mapperType.NumIn())) } else { if mapperType.NumIn() == 2 { if !reflect.TypeOf(&GenParameters{}).AssignableTo(mapperType.In(1)) { panic("Second parameter of mapper function has to be a *GenParameters") } needsGenParameters = true } genResultType := g(MinGenParams).ResultType if reflect.TypeOf(&GenResult{}).AssignableTo(mapperType.In(0)) { genResultInput = true } else if !genResultType.AssignableTo(mapperType.In(0)) { panic(fmt.Sprintf("Param of Map has to be a func with one param assignable to %v, but is %v", genResultType, mapperType.In(0))) } } if mapperType.NumOut() != 1 { panic(fmt.Sprintf("Param of Map has to be a func with one return value, but is %v", mapperType.NumOut())) } else if reflect.TypeOf(&GenResult{}).AssignableTo(mapperType.Out(0)) { genResultOutput = true } return func(genParams *GenParameters) *GenResult { result := g(genParams) if genResultInput { var mapped reflect.Value if needsGenParameters { mapped = mapperVal.Call([]reflect.Value{reflect.ValueOf(result), reflect.ValueOf(genParams)})[0] } else { mapped = mapperVal.Call([]reflect.Value{reflect.ValueOf(result)})[0] } if genResultOutput { return mapped.Interface().(*GenResult) } return &GenResult{ Shrinker: NoShrinker, Result: mapped.Interface(), Labels: result.Labels, ResultType: mapperType.Out(0), } } value, ok := result.RetrieveAsValue() if ok { var mapped reflect.Value shrinker := NoShrinker if needsGenParameters { mapped = mapperVal.Call([]reflect.Value{value, reflect.ValueOf(genParams)})[0] } else { mapped = mapperVal.Call([]reflect.Value{value})[0] } if genResultOutput { return mapped.Interface().(*GenResult) } if mapperType.In(0) == mapperType.Out(0) { shrinker = result.Shrinker } return &GenResult{ Shrinker: shrinker, Result: mapped.Interface(), Labels: result.Labels, ResultType: mapperType.Out(0), } } return &GenResult{ Shrinker: NoShrinker, Result: nil, Labels: result.Labels, ResultType: mapperType.Out(0), } } } // FlatMap creates a derived generator by passing a generated value to a function which itself // creates a generator. func (g Gen) FlatMap(f func(interface{}) Gen, resultType reflect.Type) Gen { return func(genParams *GenParameters) *GenResult { result := g(genParams) value, ok := result.Retrieve() if ok { return f(value)(genParams) } return &GenResult{ Shrinker: NoShrinker, Result: nil, Labels: result.Labels, ResultType: resultType, } } } // MapResult creates a derived generator by mapping the GenResult directly. // Contrary to `Map` and `FlatMap` this also allow the conversion of // shrinkers and sieves, but implementation is more cumbersome. // Deprecation note: Map now has the same functionality func (g Gen) MapResult(f func(*GenResult) *GenResult) Gen { return func(genParams *GenParameters) *GenResult { return f(g(genParams)) } } // CombineGens creates a generators from a list of generators. // The result type will be a []interface{} containing the generated values of each generators in // the list. // Note: The combined generator will not have a sieve or shrinker. func CombineGens(gens ...Gen) Gen { return func(genParams *GenParameters) *GenResult { labels := []string{} values := make([]interface{}, len(gens)) shrinkers := make([]Shrinker, len(gens)) sieves := make([]func(v interface{}) bool, len(gens)) var ok bool for i, gen := range gens { result := gen(genParams) labels = append(labels, result.Labels...) shrinkers[i] = result.Shrinker sieves[i] = result.Sieve values[i], ok = result.Retrieve() if !ok { return &GenResult{ Shrinker: NoShrinker, Result: nil, Labels: result.Labels, ResultType: reflect.TypeOf(values), } } } return &GenResult{ Shrinker: CombineShrinker(shrinkers...), Result: values, Labels: labels, ResultType: reflect.TypeOf(values), Sieve: func(v interface{}) bool { values := v.([]interface{}) for i, value := range values { if sieves[i] != nil && !sieves[i](value) { return false } } return true }, } } } gopter-0.2.11/gen/000077500000000000000000000000001460324054500136475ustar00rootroot00000000000000gopter-0.2.11/gen/array_of.go000066400000000000000000000033701460324054500160030ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) // ArrayOfN generates an array of generated elements with definied length func ArrayOfN(desiredlen int, elementGen gopter.Gen, typeOverrides ...reflect.Type) gopter.Gen { var typeOverride reflect.Type if len(typeOverrides) > 1 { panic("too many type overrides specified, at most 1 may be provided.") } else if len(typeOverrides) == 1 { typeOverride = typeOverrides[0] } return func(genParams *gopter.GenParameters) *gopter.GenResult { result, elementSieve, elementShrinker := genArray(elementGen, genParams, desiredlen, typeOverride) genResult := gopter.NewGenResult(result.Interface(), ArrayShrinkerOne(elementShrinker)) if elementSieve != nil { genResult.Sieve = func(v interface{}) bool { rv := reflect.ValueOf(v) return rv.Len() == desiredlen && forAllSieve(elementSieve)(v) } } else { genResult.Sieve = func(v interface{}) bool { return reflect.ValueOf(v).Len() == desiredlen } } return genResult } } func genArray(elementGen gopter.Gen, genParams *gopter.GenParameters, desiredlen int, typeOverride reflect.Type) (reflect.Value, func(interface{}) bool, gopter.Shrinker) { element := elementGen(genParams) elementSieve := element.Sieve elementShrinker := element.Shrinker sliceType := typeOverride if sliceType == nil { sliceType = element.ResultType } arrayType := reflect.ArrayOf(desiredlen, sliceType) result := reflect.New(arrayType).Elem() for i := 0; i < desiredlen; i++ { value, ok := element.Retrieve() if ok { if value == nil { result.Index(i).Set(reflect.Zero(sliceType)) } else { result.Index(i).Set(reflect.ValueOf(value)) } } element = elementGen(genParams) } return result, elementSieve, elementShrinker } gopter-0.2.11/gen/array_of_test.go000066400000000000000000000013651460324054500170440ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestArrayOfN(t *testing.T) { genParams := gopter.DefaultGenParameters() genParams.MaxSize = 50 elementGen := gen.Const("element") arrayGen := gen.ArrayOfN(20, elementGen) for i := 0; i < 100; i++ { sample, ok := arrayGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.([20]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) > 50 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, str := range strings { if str != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } } gopter-0.2.11/gen/array_shrink.go000066400000000000000000000024651460324054500167010ustar00rootroot00000000000000package gen import ( "fmt" "reflect" "github.com/leanovate/gopter" ) type arrayShrinkOne struct { original reflect.Value index int elementShrink gopter.Shrink } func (s *arrayShrinkOne) Next() (interface{}, bool) { value, ok := s.elementShrink() if !ok { return nil, false } result := reflect.New(s.original.Type()).Elem() reflect.Copy(result, s.original) if value == nil { result.Index(s.index).Set(reflect.Zero(s.original.Type().Elem())) } else { result.Index(s.index).Set(reflect.ValueOf(value)) } return result.Interface(), true } // ArrayShrinkerOne creates an array shrinker from a shrinker for the elements of the slice. // The length of the array will remains unchanged, instead each element is shrunk after the // other. func ArrayShrinkerOne(elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Array { panic(fmt.Sprintf("%#v is not an array", v)) } shrinks := make([]gopter.Shrink, 0, rv.Len()) for i := 0; i < rv.Len(); i++ { arrayShrinkOne := &arrayShrinkOne{ original: rv, index: i, elementShrink: elementShrinker(rv.Index(i).Interface()), } shrinks = append(shrinks, arrayShrinkOne.Next) } return gopter.ConcatShrinks(shrinks...) } } gopter-0.2.11/gen/array_shrink_test.go000066400000000000000000000016651460324054500177410ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestArrayShrinkOne(t *testing.T) { oneShrink := gen.ArrayShrinkerOne(gen.Int64Shrinker)([1]int64{0}).All() if !reflect.DeepEqual(oneShrink, []interface{}{}) { t.Errorf("Invalid oneShrink: %#v", oneShrink) } threeShrink := gen.ArrayShrinkerOne(gen.Int64Shrinker)([3]int64{0, 1, 2}).All() if !reflect.DeepEqual(threeShrink, []interface{}{ [3]int64{0, 0, 2}, [3]int64{0, 1, 0}, [3]int64{0, 1, 1}, [3]int64{0, 1, -1}, }) { t.Errorf("Invalid threeShrink: %#v", threeShrink) } fourShrink := gen.ArrayShrinkerOne(gen.Int64Shrinker)([4]int64{0, 1, 2, 3}).All() if !reflect.DeepEqual(fourShrink, []interface{}{ [4]int64{0, 0, 2, 3}, [4]int64{0, 1, 0, 3}, [4]int64{0, 1, 1, 3}, [4]int64{0, 1, -1, 3}, [4]int64{0, 1, 2, 0}, [4]int64{0, 1, 2, 2}, [4]int64{0, 1, 2, -2}, }) { t.Errorf("Invalid fourShrink: %#v", fourShrink) } } gopter-0.2.11/gen/bool.go000066400000000000000000000004031460324054500151260ustar00rootroot00000000000000package gen import "github.com/leanovate/gopter" // Bool generates an arbitrary bool value func Bool() gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { return gopter.NewGenResult(genParams.NextBool(), gopter.NoShrinker) } } gopter-0.2.11/gen/bool_test.go000066400000000000000000000003401460324054500161650ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter/gen" ) func TestBool(t *testing.T) { commonGeneratorTest(t, "bool", gen.Bool(), func(value interface{}) bool { _, ok := value.(bool) return ok }) } gopter-0.2.11/gen/complex.go000066400000000000000000000032141460324054500156450ustar00rootroot00000000000000package gen import "github.com/leanovate/gopter" // Complex128Box generate complex128 numbers within a rectangle/box in the complex plane func Complex128Box(min, max complex128) gopter.Gen { return gopter.CombineGens( Float64Range(real(min), real(max)), Float64Range(imag(min), imag(max)), ).Map(func(values []interface{}) complex128 { return complex(values[0].(float64), values[1].(float64)) }).SuchThat(func(v complex128) bool { return real(v) >= real(min) && real(v) <= real(max) && imag(v) >= imag(min) && imag(v) <= imag(max) }).WithShrinker(Complex128Shrinker) } // Complex128 generate arbitrary complex128 numbers func Complex128() gopter.Gen { return gopter.CombineGens( Float64(), Float64(), ).Map(func(values []interface{}) complex128 { return complex(values[0].(float64), values[1].(float64)) }).WithShrinker(Complex128Shrinker) } // Complex64Box generate complex64 numbers within a rectangle/box in the complex plane func Complex64Box(min, max complex64) gopter.Gen { return gopter.CombineGens( Float32Range(real(min), real(max)), Float32Range(imag(min), imag(max)), ).Map(func(values []interface{}) complex64 { return complex(values[0].(float32), values[1].(float32)) }).SuchThat(func(v complex64) bool { return real(v) >= real(min) && real(v) <= real(max) && imag(v) >= imag(min) && imag(v) <= imag(max) }).WithShrinker(Complex64Shrinker) } // Complex64 generate arbitrary complex64 numbers func Complex64() gopter.Gen { return gopter.CombineGens( Float32(), Float32(), ).Map(func(values []interface{}) complex64 { return complex(values[0].(float32), values[1].(float32)) }).WithShrinker(Complex64Shrinker) } gopter-0.2.11/gen/complex_shrink.go000066400000000000000000000015401460324054500172230ustar00rootroot00000000000000package gen import "github.com/leanovate/gopter" // Complex128Shrinker is a shrinker for complex128 numbers func Complex128Shrinker(v interface{}) gopter.Shrink { c := v.(complex128) realShrink := Float64Shrinker(real(c)).Map(func(r float64) complex128 { return complex(r, imag(c)) }) imagShrink := Float64Shrinker(imag(c)).Map(func(i float64) complex128 { return complex(real(c), i) }) return realShrink.Interleave(imagShrink) } // Complex64Shrinker is a shrinker for complex64 numbers func Complex64Shrinker(v interface{}) gopter.Shrink { c := v.(complex64) realShrink := Float64Shrinker(float64(real(c))).Map(func(r float64) complex64 { return complex(float32(r), imag(c)) }) imagShrink := Float64Shrinker(float64(imag(c))).Map(func(i float64) complex64 { return complex(real(c), float32(i)) }) return realShrink.Interleave(imagShrink) } gopter-0.2.11/gen/complex_shrink_test.go000066400000000000000000000113411460324054500202620ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestComplex128Shrinker(t *testing.T) { zeroShrinks := gen.Complex128Shrinker(0 + 0i).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } oneShrink := gen.Complex128Shrinker(1 + 0i).All() if !reflect.DeepEqual(oneShrink, []interface{}{ (0 + 0i), (0.5 + 0i), (-0.5 + 0i), (0.75 + 0i), (-0.75 + 0i), (0.875 + 0i), (-0.875 + 0i), (0.9375 + 0i), (-0.9375 + 0i), (0.96875 + 0i), (-0.96875 + 0i), (0.984375 + 0i), (-0.984375 + 0i), (0.9921875 + 0i), (-0.9921875 + 0i), (0.99609375 + 0i), (-0.99609375 + 0i), (0.998046875 + 0i), (-0.998046875 + 0i), (0.9990234375 + 0i), (-0.9990234375 + 0i), (0.99951171875 + 0i), (-0.99951171875 + 0i), (0.999755859375 + 0i), (-0.999755859375 + 0i), (0.9998779296875 + 0i), (-0.9998779296875 + 0i), (0.99993896484375 + 0i), (-0.99993896484375 + 0i), (0.999969482421875 + 0i), (-0.999969482421875 + 0i), (0.9999847412109375 + 0i), (-0.9999847412109375 + 0i), }) { t.Errorf("Invalid oneShrink: %#v", oneShrink) } iShrink := gen.Complex128Shrinker(1i).All() if !reflect.DeepEqual(iShrink, []interface{}{ (0 + 0i), (0 + 0.5i), (0 - 0.5i), (0 + 0.75i), (0 - 0.75i), (0 + 0.875i), (0 - 0.875i), (0 + 0.9375i), (0 - 0.9375i), (0 + 0.96875i), (0 - 0.96875i), (0 + 0.984375i), (0 - 0.984375i), (0 + 0.9921875i), (0 - 0.9921875i), (0 + 0.99609375i), (0 - 0.99609375i), (0 + 0.998046875i), (0 - 0.998046875i), (0 + 0.9990234375i), (0 - 0.9990234375i), (0 + 0.99951171875i), (0 - 0.99951171875i), (0 + 0.999755859375i), (0 - 0.999755859375i), (0 + 0.9998779296875i), (0 - 0.9998779296875i), (0 + 0.99993896484375i), (0 - 0.99993896484375i), (0 + 0.999969482421875i), (0 - 0.999969482421875i), (0 + 0.9999847412109375i), (0 - 0.9999847412109375i), }) { t.Errorf("Invalid iShrink: %#v", iShrink) } teniShrink := gen.Complex128Shrinker(10 + 1i).All() if !reflect.DeepEqual(teniShrink, []interface{}{(0 + 1i), (10 + 0i), (5 + 1i), (10 + 0.5i), (-5 + 1i), (10 - 0.5i), (7.5 + 1i), (10 + 0.75i), (-7.5 + 1i), (10 - 0.75i), (8.75 + 1i), (10 + 0.875i), (-8.75 + 1i), (10 - 0.875i), (9.375 + 1i), (10 + 0.9375i), (-9.375 + 1i), (10 - 0.9375i), (9.6875 + 1i), (10 + 0.96875i), (-9.6875 + 1i), (10 - 0.96875i), (9.84375 + 1i), (10 + 0.984375i), (-9.84375 + 1i), (10 - 0.984375i), (9.921875 + 1i), (10 + 0.9921875i), (-9.921875 + 1i), (10 - 0.9921875i), (9.9609375 + 1i), (10 + 0.99609375i), (-9.9609375 + 1i), (10 - 0.99609375i), (9.98046875 + 1i), (10 + 0.998046875i), (-9.98046875 + 1i), (10 - 0.998046875i), (9.990234375 + 1i), (10 + 0.9990234375i), (-9.990234375 + 1i), (10 - 0.9990234375i), (9.9951171875 + 1i), (10 + 0.99951171875i), (-9.9951171875 + 1i), (10 - 0.99951171875i), (9.99755859375 + 1i), (10 + 0.999755859375i), (-9.99755859375 + 1i), (10 - 0.999755859375i), (9.998779296875 + 1i), (10 + 0.9998779296875i), (-9.998779296875 + 1i), (10 - 0.9998779296875i), (9.9993896484375 + 1i), (10 + 0.99993896484375i), (-9.9993896484375 + 1i), (10 - 0.99993896484375i), (9.99969482421875 + 1i), (10 + 0.999969482421875i), (-9.99969482421875 + 1i), (10 - 0.999969482421875i), (9.999847412109375 + 1i), (10 + 0.9999847412109375i), (-9.999847412109375 + 1i), (10 - 0.9999847412109375i), (9.999923706054688 + 1i), (-9.999923706054688 + 1i), (9.999961853027344 + 1i), (-9.999961853027344 + 1i), (9.999980926513672 + 1i), (-9.999980926513672 + 1i), }) { t.Errorf("Invalid teniShrink: %#v", teniShrink) } } func TestComplex64Shrinker(t *testing.T) { zeroShrinks := gen.Complex64Shrinker(complex64(0 + 0i)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } oneShrink := gen.Complex64Shrinker(complex64(1 + 0i)).All() if !reflect.DeepEqual(oneShrink, []interface{}{ complex64(0 + 0i), complex64(0.5 + 0i), complex64(-0.5 + 0i), complex64(0.75 + 0i), complex64(-0.75 + 0i), complex64(0.875 + 0i), complex64(-0.875 + 0i), complex64(0.9375 + 0i), complex64(-0.9375 + 0i), complex64(0.96875 + 0i), complex64(-0.96875 + 0i), complex64(0.984375 + 0i), complex64(-0.984375 + 0i), complex64(0.9921875 + 0i), complex64(-0.9921875 + 0i), complex64(0.99609375 + 0i), complex64(-0.99609375 + 0i), complex64(0.9980469 + 0i), complex64(-0.9980469 + 0i), complex64(0.99902344 + 0i), complex64(-0.99902344 + 0i), complex64(0.9995117 + 0i), complex64(-0.9995117 + 0i), complex64(0.99975586 + 0i), complex64(-0.99975586 + 0i), complex64(0.9998779 + 0i), complex64(-0.9998779 + 0i), complex64(0.99993896 + 0i), complex64(-0.99993896 + 0i), complex64(0.9999695 + 0i), complex64(-0.9999695 + 0i), complex64(0.99998474 + 0i), complex64(-0.99998474 + 0i), }) { t.Errorf("Invalid oneShrink: %#v", oneShrink) } } gopter-0.2.11/gen/complex_test.go000066400000000000000000000026041460324054500167060ustar00rootroot00000000000000package gen_test import ( "math" "testing" "github.com/leanovate/gopter/gen" ) func TestComplex128Box(t *testing.T) { minReal := -12345.67 maxReal := 2345.78 minImag := -5432.8 maxImag := 8764.6 complexes := gen.Complex128Box(complex(minReal, minImag), complex(maxReal, maxImag)) commonGeneratorTest(t, "complex 128 box", complexes, func(value interface{}) bool { v, ok := value.(complex128) return ok && real(v) >= minReal && real(v) < maxReal && imag(v) >= minImag && imag(v) < maxImag }) } func TestComplex128(t *testing.T) { commonGeneratorTest(t, "complex 128", gen.Complex128(), func(value interface{}) bool { v, ok := value.(complex128) return ok && !math.IsNaN(real(v)) && !math.IsNaN(imag(v)) && !math.IsInf(real(v), 0) && !math.IsInf(imag(v), 0) }) } func TestComplex64Box(t *testing.T) { minReal := float32(-12345.67) maxReal := float32(2345.78) minImag := float32(-5432.8) maxImag := float32(8764.6) complexes := gen.Complex64Box(complex(minReal, minImag), complex(maxReal, maxImag)) commonGeneratorTest(t, "complex 64 box", complexes, func(value interface{}) bool { v, ok := value.(complex64) return ok && real(v) >= minReal && real(v) < maxReal && imag(v) >= minImag && imag(v) < maxImag }) } func TestComplex64(t *testing.T) { commonGeneratorTest(t, "complex 64", gen.Complex64(), func(value interface{}) bool { _, ok := value.(complex64) return ok }) } gopter-0.2.11/gen/const.go000066400000000000000000000005151460324054500153250ustar00rootroot00000000000000package gen import "github.com/leanovate/gopter" // Const creates a generator for a constant value // Not the most exciting generator, but can be helpful from time to time func Const(value interface{}) gopter.Gen { return func(*gopter.GenParameters) *gopter.GenResult { return gopter.NewGenResult(value, gopter.NoShrinker) } } gopter-0.2.11/gen/const_test.go000066400000000000000000000004171460324054500163650ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter/gen" ) func TestConstGen(t *testing.T) { commonGeneratorTest(t, "const", gen.Const("some constant"), func(value interface{}) bool { v, ok := value.(string) return ok && v == "some constant" }) } gopter-0.2.11/gen/doc.go000066400000000000000000000001231460324054500147370ustar00rootroot00000000000000/* Package gen contains all commonly used generators and shrinkers. */ package gen gopter-0.2.11/gen/fail.go000066400000000000000000000004571460324054500151170ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) // Fail is a generator that always fails to generate a value // Useful as fallback func Fail(resultType reflect.Type) gopter.Gen { return func(*gopter.GenParameters) *gopter.GenResult { return gopter.NewEmptyResult(resultType) } } gopter-0.2.11/gen/fail_test.go000066400000000000000000000003431460324054500161500ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestFail(t *testing.T) { fail := gen.Fail(reflect.TypeOf("")) value, ok := fail.Sample() if value != nil || ok { t.Fail() } } gopter-0.2.11/gen/floats.go000066400000000000000000000037241460324054500154740ustar00rootroot00000000000000package gen import ( "math" "reflect" "github.com/leanovate/gopter" ) // Float64Range generates float64 numbers within a given range func Float64Range(min, max float64) gopter.Gen { d := max - min if d < 0 || d > math.MaxFloat64 { return Fail(reflect.TypeOf(float64(0))) } return func(genParams *gopter.GenParameters) *gopter.GenResult { genResult := gopter.NewGenResult(min+genParams.Rng.Float64()*d, Float64Shrinker) genResult.Sieve = func(v interface{}) bool { return v.(float64) >= min && v.(float64) <= max } return genResult } } // Float64 generates arbitrary float64 numbers that do not contain NaN or Inf func Float64() gopter.Gen { return gopter.CombineGens( Int64Range(0, 1), Int64Range(0, 0x7fe), Int64Range(0, 0xfffffffffffff), ).Map(func(values []interface{}) float64 { sign := uint64(values[0].(int64)) exponent := uint64(values[1].(int64)) mantissa := uint64(values[2].(int64)) return math.Float64frombits((sign << 63) | (exponent << 52) | mantissa) }).WithShrinker(Float64Shrinker) } // Float32Range generates float32 numbers within a given range func Float32Range(min, max float32) gopter.Gen { d := max - min if d < 0 || d > math.MaxFloat32 { return Fail(reflect.TypeOf(float32(0))) } return func(genParams *gopter.GenParameters) *gopter.GenResult { genResult := gopter.NewGenResult(min+genParams.Rng.Float32()*d, Float32Shrinker) genResult.Sieve = func(v interface{}) bool { return v.(float32) >= min && v.(float32) <= max } return genResult } } // Float32 generates arbitrary float32 numbers that do not contain NaN or Inf func Float32() gopter.Gen { return gopter.CombineGens( Int32Range(0, 1), Int32Range(0, 0xfe), Int32Range(0, 0x7fffff), ).Map(func(values []interface{}) float32 { sign := uint32(values[0].(int32)) exponent := uint32(values[1].(int32)) mantissa := uint32(values[2].(int32)) return math.Float32frombits((sign << 31) | (exponent << 23) | mantissa) }).WithShrinker(Float32Shrinker) } gopter-0.2.11/gen/floats_shrink.go000066400000000000000000000020061460324054500170420ustar00rootroot00000000000000package gen import ( "math" "github.com/leanovate/gopter" ) type float64Shrink struct { original float64 half float64 } func (s *float64Shrink) isZeroOrVeryClose() bool { if s.half == 0 { return true } muliple := s.half * 100000 return math.Abs(muliple) < 1 && muliple != 0 } func (s *float64Shrink) Next() (interface{}, bool) { if s.isZeroOrVeryClose() { return nil, false } value := s.original - s.half s.half /= 2 return value, true } // Float64Shrinker is a shrinker for float64 numbers func Float64Shrinker(v interface{}) gopter.Shrink { negShrink := float64Shrink{ original: -v.(float64), half: -v.(float64), } posShrink := float64Shrink{ original: v.(float64), half: v.(float64) / 2, } return gopter.Shrink(negShrink.Next).Interleave(gopter.Shrink(posShrink.Next)) } // Float32Shrinker is a shrinker for float32 numbers func Float32Shrinker(v interface{}) gopter.Shrink { return Float64Shrinker(float64(v.(float32))).Map(func(e float64) float32 { return float32(e) }) } gopter-0.2.11/gen/floats_shrink_test.go000066400000000000000000000056221460324054500201100ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestFloat64Shrinker(t *testing.T) { zeroShrinks := gen.Float64Shrinker(float64(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } oneShrinks := gen.Float64Shrinker(float64(1)).All() if !reflect.DeepEqual(oneShrinks, []interface{}{ 0.0, 0.5, -0.5, 0.75, -0.75, 0.875, -0.875, 0.9375, -0.9375, 0.96875, -0.96875, 0.984375, -0.984375, 0.9921875, -0.9921875, 0.99609375, -0.99609375, 0.998046875, -0.998046875, 0.9990234375, -0.9990234375, 0.99951171875, -0.99951171875, 0.999755859375, -0.999755859375, 0.9998779296875, -0.9998779296875, 0.99993896484375, -0.99993896484375, 0.999969482421875, -0.999969482421875, 0.9999847412109375, -0.9999847412109375, }) { t.Errorf("Invalid tenShrinks: %#v", oneShrinks) } hundretShrinks := gen.Float64Shrinker(float64(100)).All() if !reflect.DeepEqual(hundretShrinks, []interface{}{ 0.0, 50.0, -50.0, 75.0, -75.0, 87.5, -87.5, 93.75, -93.75, 96.875, -96.875, 98.4375, -98.4375, 99.21875, -99.21875, 99.609375, -99.609375, 99.8046875, -99.8046875, 99.90234375, -99.90234375, 99.951171875, -99.951171875, 99.9755859375, -99.9755859375, 99.98779296875, -99.98779296875, 99.993896484375, -99.993896484375, 99.9969482421875, -99.9969482421875, 99.99847412109375, -99.99847412109375, 99.99923706054688, -99.99923706054688, 99.99961853027344, -99.99961853027344, 99.99980926513672, -99.99980926513672, 99.99990463256836, -99.99990463256836, 99.99995231628418, -99.99995231628418, 99.99997615814209, -99.99997615814209, 99.99998807907104, -99.99998807907104, }) { t.Errorf("Invalid hundretShrinks: %#v", hundretShrinks) } } func TestFloat32Shrinker(t *testing.T) { zeroShrinks := gen.Float32Shrinker(float32(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } oneShrinks := gen.Float32Shrinker(float32(1)).All() if !reflect.DeepEqual(oneShrinks, []interface{}{ float32(0), float32(0.5), float32(-0.5), float32(0.75), float32(-0.75), float32(0.875), float32(-0.875), float32(0.9375), float32(-0.9375), float32(0.96875), float32(-0.96875), float32(0.984375), float32(-0.984375), float32(0.9921875), float32(-0.9921875), float32(0.99609375), float32(-0.99609375), float32(0.9980469), float32(-0.9980469), float32(0.99902344), float32(-0.99902344), float32(0.9995117), float32(-0.9995117), float32(0.99975586), float32(-0.99975586), float32(0.9998779), float32(-0.9998779), float32(0.99993896), float32(-0.99993896), float32(0.9999695), float32(-0.9999695), float32(0.99998474), float32(-0.99998474), }) { t.Errorf("Invalid tenShrinks: %#v", oneShrinks) } } gopter-0.2.11/gen/floats_test.go000066400000000000000000000022001460324054500165170ustar00rootroot00000000000000package gen_test import ( "math" "testing" "github.com/leanovate/gopter/gen" ) func TestFloat64(t *testing.T) { commonGeneratorTest(t, "float 64", gen.Float64(), func(value interface{}) bool { v, ok := value.(float64) return ok && !math.IsNaN(v) && !math.IsInf(v, 0) }) } func TestFloat64Range(t *testing.T) { fail := gen.Float64Range(200, 100) if value, ok := fail.Sample(); value != nil || ok { t.Fail() } commonGeneratorTest(t, "float 64 range", gen.Float64Range(-1234.5, 56789.123), func(value interface{}) bool { v, ok := value.(float64) return ok && !math.IsNaN(v) && !math.IsInf(v, 0) && v >= -1234.5 && v <= 56789.123 }) } func TestFloat32(t *testing.T) { commonGeneratorTest(t, "float 32", gen.Float32(), func(value interface{}) bool { _, ok := value.(float32) return ok }) } func TestFloat32Range(t *testing.T) { fail := gen.Float32Range(200, 100) if value, ok := fail.Sample(); value != nil || ok { t.Fail() } commonGeneratorTest(t, "float 32 range", gen.Float32Range(-1234.5, 56789.123), func(value interface{}) bool { v, ok := value.(float32) return ok && v >= -1234.5 && v <= 56789.123 }) } gopter-0.2.11/gen/frequency.go000066400000000000000000000015171460324054500162030ustar00rootroot00000000000000package gen import ( "sort" "github.com/leanovate/gopter" ) // Frequency combines multiple weighted generators of the the same result type // The generators from weightedGens will be used accrding to the weight, i.e. generators // with a hight weight will be used more often than generators with a low weight. func Frequency(weightedGens map[int]gopter.Gen) gopter.Gen { if len(weightedGens) == 0 { return Fail(nil) } weights := make(sort.IntSlice, 0, len(weightedGens)) max := 0 for weight := range weightedGens { if weight > max { max = weight } weights = append(weights, weight) } weights.Sort() return func(genParams *gopter.GenParameters) *gopter.GenResult { idx := weights.Search(genParams.Rng.Intn(max + 1)) gen := weightedGens[weights[idx]] result := gen(genParams) result.Sieve = nil return result } } gopter-0.2.11/gen/frequency_test.go000066400000000000000000000016701460324054500172420ustar00rootroot00000000000000package gen_test import ( "math/rand" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) type fixedSeed struct { fixed int64 } func (f fixedSeed) Int63() int64 { return f.fixed } func (f fixedSeed) Seed(seed int64) {} func fixedParameters(size int, fixed int64) *gopter.GenParameters { return &gopter.GenParameters{ MaxSize: size, Rng: rand.New(fixedSeed{ fixed: fixed, }), } } func TestFrequency(t *testing.T) { zeroNine := gen.Frequency(map[int]gopter.Gen{ 0: gen.Const("zero"), 9: gen.Const("nine"), }) value, ok := zeroNine(fixedParameters(10, 0)).Retrieve() if !ok { t.FailNow() } if value.(string) != "zero" { t.Errorf("Invalid value for 0: %#v", value) } for i := int64(1); i < int64(10); i++ { value, ok = zeroNine(fixedParameters(10, i<<32)).Retrieve() if !ok { t.FailNow() } if value.(string) != "nine" { t.Errorf("Invalid value for %d: %#v", i, value) } } } gopter-0.2.11/gen/helper_test.go000066400000000000000000000015541460324054500165210ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" ) func commonGeneratorTest(t *testing.T, name string, gen gopter.Gen, valueCheck func(interface{}) bool) { for i := 0; i < 100; i++ { value, ok := gen.Sample() if !ok || value == nil { t.Errorf("Invalid generator result (%s): %#v", name, value) } else if !valueCheck(value) { t.Errorf("Invalid value (%s): %#v", name, value) } genResult := gen(gopter.DefaultGenParameters()) if genResult.Shrinker != nil { value, ok := genResult.Retrieve() if !ok || value == nil { t.Errorf("Invalid generator result (%s): %#v", name, value) } else { shrink := genResult.Shrinker(value).Filter(genResult.Sieve) shrunkValue, ok := shrink() if ok && !valueCheck(shrunkValue) { t.Errorf("Invalid shrunk value (%s): %#v -> %#v", name, value, shrunkValue) } } } } } gopter-0.2.11/gen/integers.go000066400000000000000000000130651460324054500160230ustar00rootroot00000000000000package gen import ( "math" "reflect" "github.com/leanovate/gopter" ) // Int64Range generates int64 numbers within a given range func Int64Range(min, max int64) gopter.Gen { if max < min { return Fail(reflect.TypeOf(int64(0))) } if max == math.MaxInt64 && min == math.MinInt64 { // Check for range overflow return func(genParams *gopter.GenParameters) *gopter.GenResult { return gopter.NewGenResult(genParams.NextInt64(), Int64Shrinker) } } rangeSize := uint64(max - min + 1) return func(genParams *gopter.GenParameters) *gopter.GenResult { var nextResult = uint64(min) + (genParams.NextUint64() % rangeSize) genResult := gopter.NewGenResult(int64(nextResult), Int64Shrinker) genResult.Sieve = func(v interface{}) bool { return v.(int64) >= min && v.(int64) <= max } return genResult } } // UInt64Range generates uint64 numbers within a given range func UInt64Range(min, max uint64) gopter.Gen { if max < min { return Fail(reflect.TypeOf(uint64(0))) } d := max - min + 1 if d == 0 { // Check overflow (i.e. max = MaxInt64, min = MinInt64) return func(genParams *gopter.GenParameters) *gopter.GenResult { return gopter.NewGenResult(genParams.NextUint64(), UInt64Shrinker) } } return func(genParams *gopter.GenParameters) *gopter.GenResult { genResult := gopter.NewGenResult(min+genParams.NextUint64()%d, UInt64Shrinker) genResult.Sieve = func(v interface{}) bool { return v.(uint64) >= min && v.(uint64) <= max } return genResult } } // Int64 generates an arbitrary int64 number func Int64() gopter.Gen { return Int64Range(math.MinInt64, math.MaxInt64) } // UInt64 generates an arbitrary Uint64 number func UInt64() gopter.Gen { return UInt64Range(0, math.MaxUint64) } // Int32Range generates int32 numbers within a given range func Int32Range(min, max int32) gopter.Gen { return Int64Range(int64(min), int64(max)). Map(int64To32). WithShrinker(Int32Shrinker). SuchThat(func(v int32) bool { return v >= min && v <= max }) } // UInt32Range generates uint32 numbers within a given range func UInt32Range(min, max uint32) gopter.Gen { return UInt64Range(uint64(min), uint64(max)). Map(uint64To32). WithShrinker(UInt32Shrinker). SuchThat(func(v uint32) bool { return v >= min && v <= max }) } // Int32 generate arbitrary int32 numbers func Int32() gopter.Gen { return Int32Range(math.MinInt32, math.MaxInt32) } // UInt32 generate arbitrary int32 numbers func UInt32() gopter.Gen { return UInt32Range(0, math.MaxUint32) } // Int16Range generates int16 numbers within a given range func Int16Range(min, max int16) gopter.Gen { return Int64Range(int64(min), int64(max)). Map(int64To16). WithShrinker(Int16Shrinker). SuchThat(func(v int16) bool { return v >= min && v <= max }) } // UInt16Range generates uint16 numbers within a given range func UInt16Range(min, max uint16) gopter.Gen { return UInt64Range(uint64(min), uint64(max)). Map(uint64To16). WithShrinker(UInt16Shrinker). SuchThat(func(v uint16) bool { return v >= min && v <= max }) } // Int16 generate arbitrary int16 numbers func Int16() gopter.Gen { return Int16Range(math.MinInt16, math.MaxInt16) } // UInt16 generate arbitrary uint16 numbers func UInt16() gopter.Gen { return UInt16Range(0, math.MaxUint16) } // Int8Range generates int8 numbers within a given range func Int8Range(min, max int8) gopter.Gen { return Int64Range(int64(min), int64(max)). Map(int64To8). WithShrinker(Int8Shrinker). SuchThat(func(v int8) bool { return v >= min && v <= max }) } // UInt8Range generates uint8 numbers within a given range func UInt8Range(min, max uint8) gopter.Gen { return UInt64Range(uint64(min), uint64(max)). Map(uint64To8). WithShrinker(UInt8Shrinker). SuchThat(func(v uint8) bool { return v >= min && v <= max }) } // Int8 generate arbitrary int8 numbers func Int8() gopter.Gen { return Int8Range(math.MinInt8, math.MaxInt8) } // UInt8 generate arbitrary uint8 numbers func UInt8() gopter.Gen { return UInt8Range(0, math.MaxUint8) } // IntRange generates int numbers within a given range func IntRange(min, max int) gopter.Gen { return Int64Range(int64(min), int64(max)). Map(int64ToInt). WithShrinker(IntShrinker). SuchThat(func(v int) bool { return v >= min && v <= max }) } // Int generate arbitrary int numbers func Int() gopter.Gen { return Int64Range(math.MinInt32, math.MaxInt32). Map(int64ToInt). WithShrinker(IntShrinker) } // UIntRange generates uint numbers within a given range func UIntRange(min, max uint) gopter.Gen { return UInt64Range(uint64(min), uint64(max)). Map(uint64ToUint). WithShrinker(UIntShrinker). SuchThat(func(v uint) bool { return v >= min && v <= max }) } // UInt generate arbitrary uint numbers func UInt() gopter.Gen { return UInt64Range(0, math.MaxUint32). Map(uint64ToUint). WithShrinker(UIntShrinker) } // Size just extracts the MaxSize field of the GenParameters. // This can be helpful to generate limited integer value in a more structued // manner. func Size() gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { return gopter.NewGenResult(genParams.MaxSize, IntShrinker) } } func int64To32(value int64) int32 { return int32(value) } func uint64To32(value uint64) uint32 { return uint32(value) } func int64To16(value int64) int16 { return int16(value) } func uint64To16(value uint64) uint16 { return uint16(value) } func int64To8(value int64) int8 { return int8(value) } func uint64To8(value uint64) uint8 { return uint8(value) } func int64ToInt(value int64) int { return int(value) } func uint64ToUint(value uint64) uint { return uint(value) } gopter-0.2.11/gen/integers_shrink.go000066400000000000000000000043741460324054500174040ustar00rootroot00000000000000package gen import ( "github.com/leanovate/gopter" ) type int64Shrink struct { original int64 half int64 } func (s *int64Shrink) Next() (interface{}, bool) { if s.half == 0 { return nil, false } value := s.original - s.half s.half /= 2 return value, true } type uint64Shrink struct { original uint64 half uint64 } func (s *uint64Shrink) Next() (interface{}, bool) { if s.half == 0 { return nil, false } value := s.original - s.half s.half >>= 1 return value, true } // Int64Shrinker is a shrinker for int64 numbers func Int64Shrinker(v interface{}) gopter.Shrink { negShrink := int64Shrink{ original: -v.(int64), half: -v.(int64), } posShrink := int64Shrink{ original: v.(int64), half: v.(int64) / 2, } return gopter.Shrink(negShrink.Next).Interleave(gopter.Shrink(posShrink.Next)) } // UInt64Shrinker is a shrinker for uint64 numbers func UInt64Shrinker(v interface{}) gopter.Shrink { shrink := uint64Shrink{ original: v.(uint64), half: v.(uint64), } return shrink.Next } // Int32Shrinker is a shrinker for int32 numbers func Int32Shrinker(v interface{}) gopter.Shrink { return Int64Shrinker(int64(v.(int32))).Map(int64To32) } // UInt32Shrinker is a shrinker for uint32 numbers func UInt32Shrinker(v interface{}) gopter.Shrink { return UInt64Shrinker(uint64(v.(uint32))).Map(uint64To32) } // Int16Shrinker is a shrinker for int16 numbers func Int16Shrinker(v interface{}) gopter.Shrink { return Int64Shrinker(int64(v.(int16))).Map(int64To16) } // UInt16Shrinker is a shrinker for uint16 numbers func UInt16Shrinker(v interface{}) gopter.Shrink { return UInt64Shrinker(uint64(v.(uint16))).Map(uint64To16) } // Int8Shrinker is a shrinker for int8 numbers func Int8Shrinker(v interface{}) gopter.Shrink { return Int64Shrinker(int64(v.(int8))).Map(int64To8) } // UInt8Shrinker is a shrinker for uint8 numbers func UInt8Shrinker(v interface{}) gopter.Shrink { return UInt64Shrinker(uint64(v.(uint8))).Map(uint64To8) } // IntShrinker is a shrinker for int numbers func IntShrinker(v interface{}) gopter.Shrink { return Int64Shrinker(int64(v.(int))).Map(int64ToInt) } // UIntShrinker is a shrinker for uint numbers func UIntShrinker(v interface{}) gopter.Shrink { return UInt64Shrinker(uint64(v.(uint))).Map(uint64ToUint) } gopter-0.2.11/gen/integers_shrink_test.go000066400000000000000000000104701460324054500204350ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestInt64Shrink(t *testing.T) { zeroShrinks := gen.Int64Shrinker(int64(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.Int64Shrinker(int64(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{int64(0), int64(5), int64(-5), int64(8), int64(-8), int64(9), int64(-9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } negTenShrinks := gen.Int64Shrinker(int64(-10)).All() if !reflect.DeepEqual(negTenShrinks, []interface{}{int64(0), int64(-5), int64(5), int64(-8), int64(8), int64(-9), int64(9)}) { t.Errorf("Invalid negTenShrinks: %#v", negTenShrinks) } leetShrink := gen.Int64Shrinker(int64(1337)).All() if !reflect.DeepEqual(leetShrink, []interface{}{ int64(0), int64(669), int64(-669), int64(1003), int64(-1003), int64(1170), int64(-1170), int64(1254), int64(-1254), int64(1296), int64(-1296), int64(1317), int64(-1317), int64(1327), int64(-1327), int64(1332), int64(-1332), int64(1335), int64(-1335), int64(1336), int64(-1336)}) { t.Errorf("Invalid leetShrink: %#v", leetShrink) } } func TestUInt64Shrink(t *testing.T) { zeroShrinks := gen.UInt64Shrinker(uint64(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.UInt64Shrinker(uint64(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{uint64(0), uint64(5), uint64(8), uint64(9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } leetShrink := gen.UInt64Shrinker(uint64(1337)).All() if !reflect.DeepEqual(leetShrink, []interface{}{ uint64(0), uint64(669), uint64(1003), uint64(1170), uint64(1254), uint64(1296), uint64(1317), uint64(1327), uint64(1332), uint64(1335), uint64(1336)}) { t.Errorf("Invalid leetShrink: %#v", leetShrink) } } func TestInt32Shrink(t *testing.T) { zeroShrinks := gen.Int32Shrinker(int32(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.Int32Shrinker(int32(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{int32(0), int32(5), int32(-5), int32(8), int32(-8), int32(9), int32(-9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } } func TestUInt32Shrink(t *testing.T) { zeroShrinks := gen.UInt32Shrinker(uint32(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.UInt32Shrinker(uint32(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{uint32(0), uint32(5), uint32(8), uint32(9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } } func TestInt16Shrink(t *testing.T) { zeroShrinks := gen.Int16Shrinker(int16(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.Int16Shrinker(int16(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{int16(0), int16(5), int16(-5), int16(8), int16(-8), int16(9), int16(-9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } } func TestUInt16Shrink(t *testing.T) { zeroShrinks := gen.UInt16Shrinker(uint16(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.UInt16Shrinker(uint16(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{uint16(0), uint16(5), uint16(8), uint16(9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } } func TestInt8Shrink(t *testing.T) { zeroShrinks := gen.Int8Shrinker(int8(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.Int8Shrinker(int8(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{int8(0), int8(5), int8(-5), int8(8), int8(-8), int8(9), int8(-9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } } func TestUInt8Shrink(t *testing.T) { zeroShrinks := gen.UInt8Shrinker(uint8(0)).All() if !reflect.DeepEqual(zeroShrinks, []interface{}{}) { t.Errorf("Invalid zeroShrinks: %#v", zeroShrinks) } tenShrinks := gen.UInt8Shrinker(uint8(10)).All() if !reflect.DeepEqual(tenShrinks, []interface{}{uint8(0), uint8(5), uint8(8), uint8(9)}) { t.Errorf("Invalid tenShrinks: %#v", tenShrinks) } } gopter-0.2.11/gen/integers_test.go000066400000000000000000000061511460324054500170600ustar00rootroot00000000000000package gen_test import ( "math" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestInt64Range(t *testing.T) { fail := gen.Int64Range(200, 100) if value, ok := fail.Sample(); value != nil || ok { t.Fail() } commonGeneratorTest(t, "int 64 range", gen.Int64Range(-123456, 234567), func(value interface{}) bool { v, ok := value.(int64) return ok && v >= -123456 || v <= 234567 }) commonGeneratorTest(t, "int 64 positive", gen.Int64Range(1, math.MaxInt64), func(value interface{}) bool { v, ok := value.(int64) return ok && v > 0 }) commonGeneratorTest(t, "int 64 negative", gen.Int64Range(math.MinInt64, -1), func(value interface{}) bool { v, ok := value.(int64) return ok && v < 0 }) commonGeneratorTest(t, "full int 64 range", gen.Int64Range(math.MinInt64, math.MaxInt64), func(value interface{}) bool { _, ok := value.(int64) return ok }) } func TestUInt64Range(t *testing.T) { fail := gen.UInt64Range(200, 100) if value, ok := fail.Sample(); value != nil || ok { t.Fail() } commonGeneratorTest(t, "uint 64 range", gen.UInt64Range(0, 234567), func(value interface{}) bool { v, ok := value.(uint64) return ok && v <= 234567 }) } func TestInt64(t *testing.T) { commonGeneratorTest(t, "int 64", gen.Int64(), func(value interface{}) bool { _, ok := value.(int64) return ok }) commonGeneratorTest(t, "uint 64", gen.UInt64(), func(value interface{}) bool { _, ok := value.(uint64) return ok }) } func TestInt32(t *testing.T) { commonGeneratorTest(t, "int 32", gen.Int32(), func(value interface{}) bool { _, ok := value.(int32) return ok }) commonGeneratorTest(t, "uint 32", gen.UInt32(), func(value interface{}) bool { _, ok := value.(uint32) return ok }) } func TestInt16(t *testing.T) { commonGeneratorTest(t, "int 16", gen.Int16(), func(value interface{}) bool { _, ok := value.(int16) return ok }) commonGeneratorTest(t, "uint 16", gen.UInt16(), func(value interface{}) bool { _, ok := value.(uint16) return ok }) } func TestInt8(t *testing.T) { commonGeneratorTest(t, "int 8", gen.Int8(), func(value interface{}) bool { _, ok := value.(int8) return ok }) commonGeneratorTest(t, "uint 8", gen.UInt8(), func(value interface{}) bool { _, ok := value.(uint8) return ok }) } func TestInt(t *testing.T) { commonGeneratorTest(t, "int", gen.Int(), func(value interface{}) bool { _, ok := value.(int) return ok }) commonGeneratorTest(t, "intrange", gen.IntRange(-1234, 5678), func(value interface{}) bool { v, ok := value.(int) return ok && v >= -1234 && v <= 5678 }) commonGeneratorTest(t, "uint", gen.UInt(), func(value interface{}) bool { _, ok := value.(uint) return ok }) commonGeneratorTest(t, "uintrange", gen.UIntRange(1234, 5678), func(value interface{}) bool { v, ok := value.(uint) return ok && v >= 1234 && v <= 5678 }) } func TestGenSize(t *testing.T) { params := gopter.DefaultGenParameters() genSize := gen.Size() for i := 0; i < 100; i++ { result := genSize(params.WithSize(i)) value, ok := result.Retrieve() if !ok || value.(int) != i { t.Errorf("Invalid gen size: %v", value) } } } gopter-0.2.11/gen/map_of.go000066400000000000000000000052401460324054500154400ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) // MapOf generates an arbitrary map of generated kay values. // genParams.MaxSize sets an (exclusive) upper limit on the size of the map // genParams.MinSize sets an (inclusive) lower limit on the size of the map func MapOf(keyGen, elementGen gopter.Gen) gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { len := 0 if genParams.MaxSize > 0 || genParams.MinSize > 0 { if genParams.MinSize > genParams.MaxSize { panic("GenParameters.MinSize must be <= GenParameters.MaxSize") } if genParams.MaxSize == genParams.MinSize { len = genParams.MaxSize } else { len = genParams.Rng.Intn(genParams.MaxSize-genParams.MinSize) + genParams.MinSize } } result, keySieve, keyShrinker, elementSieve, elementShrinker := genMap(keyGen, elementGen, genParams, len) genResult := gopter.NewGenResult(result.Interface(), MapShrinker(keyShrinker, elementShrinker)) if keySieve != nil || elementSieve != nil { genResult.Sieve = forAllKeyValueSieve(keySieve, elementSieve) } return genResult } } func genMap(keyGen, elementGen gopter.Gen, genParams *gopter.GenParameters, len int) (reflect.Value, func(interface{}) bool, gopter.Shrinker, func(interface{}) bool, gopter.Shrinker) { element := elementGen(genParams) elementSieve := element.Sieve elementShrinker := element.Shrinker key := keyGen(genParams) keySieve := key.Sieve keyShrinker := key.Shrinker result := reflect.MakeMapWithSize(reflect.MapOf(key.ResultType, element.ResultType), len) for i := 0; i < len; i++ { keyValue, keyOk := key.Retrieve() elementValue, elementOk := element.Retrieve() if keyOk && elementOk { if key == nil { if elementValue == nil { result.SetMapIndex(reflect.Zero(key.ResultType), reflect.Zero(element.ResultType)) } else { result.SetMapIndex(reflect.Zero(key.ResultType), reflect.ValueOf(elementValue)) } } else { if elementValue == nil { result.SetMapIndex(reflect.ValueOf(keyValue), reflect.Zero(element.ResultType)) } else { result.SetMapIndex(reflect.ValueOf(keyValue), reflect.ValueOf(elementValue)) } } } key = keyGen(genParams) element = elementGen(genParams) } return result, keySieve, keyShrinker, elementSieve, elementShrinker } func forAllKeyValueSieve(keySieve, elementSieve func(interface{}) bool) func(interface{}) bool { return func(v interface{}) bool { rv := reflect.ValueOf(v) for _, key := range rv.MapKeys() { if keySieve != nil && !keySieve(key.Interface()) { return false } if elementSieve != nil && !elementSieve(rv.MapIndex(key).Interface()) { return false } } return true } } gopter-0.2.11/gen/map_of_test.go000066400000000000000000000040221460324054500164740ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestMapOf(t *testing.T) { genParams := gopter.DefaultGenParameters() genParams.MaxSize = 50 keyGen := gen.Identifier() elementGen := gen.Const("element") mapGen := gen.MapOf(keyGen, elementGen) for i := 0; i < 100; i++ { sample, ok := mapGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.(map[string]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) > 50 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, value := range strings { if value != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } genParams.MaxSize = 10 for i := 0; i < 100; i++ { sample, ok := mapGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.(map[string]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) > 10 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, value := range strings { if value != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } genParams.MaxSize = 0 genParams.MinSize = 0 for i := 0; i < 100; i++ { sample, ok := mapGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.(map[string]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) != 0 { t.Errorf("Sample has invalid length: %#v", len(strings)) } } } } func TestMapOfPanic(t *testing.T) { genParams := gopter.DefaultGenParameters() genParams.MaxSize = 0 genParams.MinSize = 1 keyGen := gen.Identifier() elementGen := gen.Const("element") mapGen := gen.MapOf(keyGen, elementGen) defer func() { if r := recover(); r == nil { t.Error("SliceOf did not panic when MinSize was > MaxSize") } }() mapGen(genParams).Retrieve() } gopter-0.2.11/gen/map_shrink.go000066400000000000000000000077031460324054500163400ustar00rootroot00000000000000package gen import ( "fmt" "reflect" "github.com/leanovate/gopter" ) type mapShrinkOne struct { original reflect.Value key reflect.Value keyShrink gopter.Shrink elementShrink gopter.Shrink state bool keyExhausted bool lastKey interface{} elementExhausted bool lastElement interface{} } func (s *mapShrinkOne) nextKeyValue() (interface{}, interface{}, bool) { for !s.keyExhausted && !s.elementExhausted { s.state = !s.state if s.state && !s.keyExhausted { value, ok := s.keyShrink() if ok { s.lastKey = value return s.lastKey, s.lastElement, true } s.keyExhausted = true } else if !s.state && !s.elementExhausted { value, ok := s.elementShrink() if ok { s.lastElement = value return s.lastKey, s.lastElement, true } s.elementExhausted = true } } return nil, nil, false } func (s *mapShrinkOne) Next() (interface{}, bool) { nextKey, nextValue, ok := s.nextKeyValue() if !ok { return nil, false } result := reflect.MakeMapWithSize(s.original.Type(), s.original.Len()) for _, key := range s.original.MapKeys() { if !reflect.DeepEqual(key.Interface(), s.key.Interface()) { result.SetMapIndex(key, s.original.MapIndex(key)) } } result.SetMapIndex(reflect.ValueOf(nextKey), reflect.ValueOf(nextValue)) return result.Interface(), true } // MapShrinkerOne creates a map shrinker from a shrinker for the key values of a map. // The length of the map will remain (mostly) unchanged, instead each key value pair is // shrunk after the other. func MapShrinkerOne(keyShrinker, elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Map { panic(fmt.Sprintf("%#v is not a map", v)) } keys := rv.MapKeys() shrinks := make([]gopter.Shrink, 0, len(keys)) for _, key := range keys { mapShrinkOne := &mapShrinkOne{ original: rv, key: key, keyShrink: keyShrinker(key.Interface()), lastKey: key.Interface(), elementShrink: elementShrinker(rv.MapIndex(key).Interface()), lastElement: rv.MapIndex(key).Interface(), } shrinks = append(shrinks, mapShrinkOne.Next) } return gopter.ConcatShrinks(shrinks...) } } type mapShrink struct { original reflect.Value originalKeys []reflect.Value length int offset int chunkLength int } func (s *mapShrink) Next() (interface{}, bool) { if s.chunkLength == 0 { return nil, false } keys := make([]reflect.Value, 0, s.length-s.chunkLength) keys = append(keys, s.originalKeys[0:s.offset]...) s.offset += s.chunkLength if s.offset < s.length { keys = append(keys, s.originalKeys[s.offset:s.length]...) } else { s.offset = 0 s.chunkLength >>= 1 } result := reflect.MakeMapWithSize(s.original.Type(), len(keys)) for _, key := range keys { result.SetMapIndex(key, s.original.MapIndex(key)) } return result.Interface(), true } // MapShrinker creates a map shrinker from shrinker for the key values. // The length of the map will be shrunk as well func MapShrinker(keyShrinker, elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Map { panic(fmt.Sprintf("%#v is not a Map", v)) } keys := rv.MapKeys() mapShrink := &mapShrink{ original: rv, originalKeys: keys, offset: 0, length: rv.Len(), chunkLength: rv.Len() >> 1, } shrinks := make([]gopter.Shrink, 0, rv.Len()+1) shrinks = append(shrinks, mapShrink.Next) for _, key := range keys { mapShrinkOne := &mapShrinkOne{ original: rv, key: key, keyShrink: keyShrinker(key.Interface()), lastKey: key.Interface(), elementShrink: elementShrinker(rv.MapIndex(key).Interface()), lastElement: rv.MapIndex(key).Interface(), } shrinks = append(shrinks, mapShrinkOne.Next) } return gopter.ConcatShrinks(shrinks...) } } gopter-0.2.11/gen/map_shrink_test.go000066400000000000000000000024731460324054500173760ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestMapShrinkerOne(t *testing.T) { mapShrink := gen.MapShrinkerOne(gen.StringShrinker, gen.Int64Shrinker)(map[string]int64{ "two": 2, }).All() if !reflect.DeepEqual(mapShrink, []interface{}{ map[string]int64{"wo": 2}, map[string]int64{"wo": 0}, map[string]int64{"to": 0}, map[string]int64{"to": 1}, map[string]int64{"tw": 1}, map[string]int64{"tw": -1}, }) { t.Errorf("Invalid mapShrink: %#v", mapShrink) } } func TestMapShrinker(t *testing.T) { mapShrink := gen.MapShrinker(gen.StringShrinker, gen.Int64Shrinker)(map[string]int64{ "two": 2, }).All() if !reflect.DeepEqual(mapShrink, []interface{}{ map[string]int64{"wo": 2}, map[string]int64{"wo": 0}, map[string]int64{"to": 0}, map[string]int64{"to": 1}, map[string]int64{"tw": 1}, map[string]int64{"tw": -1}, }) { t.Errorf("Invalid mapShrink: %#v", mapShrink) } mapShrink2 := gen.MapShrinker(gen.StringShrinker, gen.Int64Shrinker)(map[string]int64{ "one": 1, "two": 2, "three": 3, "four": 3, }).All() if len(mapShrink2) < 10 { t.Errorf("mapShrink2 too short: %#v", mapShrink2) } for _, shrink := range mapShrink2 { _, ok := shrink.(map[string]int64) if !ok { t.Errorf("mapShrink2 invalid type: %#v", mapShrink2) } } } gopter-0.2.11/gen/one_of.go000066400000000000000000000013141460324054500154420ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) // OneConstOf generate one of a list of constant values func OneConstOf(consts ...interface{}) gopter.Gen { if len(consts) == 0 { return Fail(reflect.TypeOf(nil)) } return func(genParams *gopter.GenParameters) *gopter.GenResult { idx := genParams.Rng.Intn(len(consts)) return gopter.NewGenResult(consts[idx], gopter.NoShrinker) } } // OneGenOf generate one value from a a list of generators func OneGenOf(gens ...gopter.Gen) gopter.Gen { if len(gens) == 0 { return Fail(reflect.TypeOf(nil)) } return func(genParams *gopter.GenParameters) *gopter.GenResult { idx := genParams.Rng.Intn(len(gens)) return gens[idx](genParams) } } gopter-0.2.11/gen/one_of_test.go000066400000000000000000000023231460324054500165020ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestOneConstOf(t *testing.T) { consts := gen.OneConstOf("one", "two", "three", "four") commonOneOfTest(t, consts) fail := gen.OneConstOf() if _, ok := fail.Sample(); ok { t.Errorf("Empty OneConstOf generated a value") } } func TestOneGenOf(t *testing.T) { consts := gen.OneGenOf(gen.Const("one"), gen.Const("two"), gen.Const("three"), gen.Const("four")) commonOneOfTest(t, consts) fail := gen.OneGenOf() if _, ok := fail.Sample(); ok { t.Errorf("Empty OneGenOf generated a value") } } func commonOneOfTest(t *testing.T, gen gopter.Gen) { parameters := gopter.DefaultGenParameters() parameters.Rng.Seed(1234) generated := make(map[string]bool, 0) for i := 0; i < 100; i++ { value, ok := gen(parameters).Retrieve() if !ok || value == nil { t.Errorf("Invalid consts: %#v", value) } v, ok := value.(string) if !ok { t.Errorf("Invalid consts: %#v", value) } generated[v] = true } if !reflect.DeepEqual(generated, map[string]bool{ "one": true, "two": true, "three": true, "four": true, }) { t.Errorf("Not all consts where generated: %#v", generated) } } gopter-0.2.11/gen/ptr_of.go000066400000000000000000000023421460324054500154700ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) // PtrOf generates either a pointer to a generated element or a nil pointer func PtrOf(elementGen gopter.Gen) gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { element := elementGen(genParams) elementShrinker := element.Shrinker elementSieve := element.Sieve value, ok := element.Retrieve() if !ok || genParams.NextBool() { result := gopter.NewEmptyResult(reflect.PtrTo(element.ResultType)) result.Sieve = func(v interface{}) bool { if elementSieve == nil { return true } r := reflect.ValueOf(v) return !r.IsValid() || r.IsNil() || elementSieve(r.Elem().Interface()) } return result } // To get the right pointer type we have to create a slice with one element slice := reflect.MakeSlice(reflect.SliceOf(element.ResultType), 0, 1) slice = reflect.Append(slice, reflect.ValueOf(value)) result := gopter.NewGenResult(slice.Index(0).Addr().Interface(), PtrShrinker(elementShrinker)) result.Sieve = func(v interface{}) bool { if elementSieve == nil { return true } r := reflect.ValueOf(v) return !r.IsValid() || r.IsNil() || elementSieve(r.Elem().Interface()) } return result } } gopter-0.2.11/gen/ptr_of_test.go000066400000000000000000000020651460324054500165310ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func TestPtrOf(t *testing.T) { genParams := gopter.DefaultGenParameters() elementGen := gen.Const("element") ptrGen := gen.PtrOf(elementGen) for i := 0; i < 100; i++ { sample, ok := ptrGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } if sample == nil { continue } stringPtr, ok := sample.(*string) if !ok { t.Errorf("Sample not pointer to string: %#v", sample) } else if *stringPtr != "element" { t.Errorf("Sample contains invalid value: %#v %#v", sample, *stringPtr) } } } type Foo string func TestPtrOfFoo(t *testing.T) { parameters := gopter.DefaultTestParameters() properties := gopter.NewProperties(parameters) properties.Property("PtrOf", prop.ForAll( func(foo *Foo, ) bool { return true }, gen.PtrOf(GenFoo()), )) properties.TestingRun(t) } func GenFoo() gopter.Gen { return gen.SliceOfN(16, gen.Rune()).Map(func(v []rune) Foo { return Foo(v) }) } gopter-0.2.11/gen/ptr_shrink.go000066400000000000000000000017361460324054500163700ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) type nilShrink struct { done bool } func (s *nilShrink) Next() (interface{}, bool) { if !s.done { s.done = true return nil, true } return nil, false } // PtrShrinker convert a value shrinker to a pointer to value shrinker func PtrShrinker(elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { if v == nil { return gopter.NoShrink } elem := reflect.ValueOf(v).Elem() if !elem.IsValid() || !elem.CanInterface() { return gopter.NoShrink } rt := reflect.TypeOf(v) elementShink := elementShrinker(reflect.ValueOf(v).Elem().Interface()) nilShrink := &nilShrink{} return gopter.ConcatShrinks( nilShrink.Next, elementShink.Map(func(elem interface{}) interface{} { slice := reflect.MakeSlice(reflect.SliceOf(rt.Elem()), 0, 1) slice = reflect.Append(slice, reflect.ValueOf(elem)) return slice.Index(0).Addr().Interface() }), ) } } gopter-0.2.11/gen/ptr_shrink_test.go000066400000000000000000000006651460324054500174270ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestPtrShrinker(t *testing.T) { v := 10 shinks := []int{0, 5, -5, 8, -8, 9, -9} intPtrShrink := gen.PtrShrinker(gen.IntShrinker)(&v).All() if !reflect.DeepEqual(intPtrShrink, []interface{}{nil, &shinks[0], &shinks[1], &shinks[2], &shinks[3], &shinks[4], &shinks[5], &shinks[6]}) { t.Errorf("Invalid intPtrShrink: %#v", intPtrShrink) } } gopter-0.2.11/gen/regex.go000066400000000000000000000042421460324054500153120ustar00rootroot00000000000000package gen import ( "reflect" "regexp" "regexp/syntax" "strings" "github.com/leanovate/gopter" ) // RegexMatch generates matches for a given regular expression // regexStr is supposed to conform to the perl regular expression syntax func RegexMatch(regexStr string) gopter.Gen { regexSyntax, err1 := syntax.Parse(regexStr, syntax.Perl) regex, err2 := regexp.Compile(regexStr) if err1 != nil || err2 != nil { return Fail(reflect.TypeOf("")) } return regexMatchGen(regexSyntax.Simplify()).SuchThat(func(v string) bool { return regex.MatchString(v) }).WithShrinker(StringShrinker) } func regexMatchGen(regex *syntax.Regexp) gopter.Gen { switch regex.Op { case syntax.OpLiteral: return Const(string(regex.Rune)) case syntax.OpCharClass: gens := make([]gopter.Gen, 0, len(regex.Rune)/2) for i := 0; i+1 < len(regex.Rune); i += 2 { gens = append(gens, RuneRange(regex.Rune[i], regex.Rune[i+1]).Map(runeToString)) } return OneGenOf(gens...) case syntax.OpAnyChar: return Rune().Map(runeToString) case syntax.OpAnyCharNotNL: return RuneNoControl().Map(runeToString) case syntax.OpCapture: return regexMatchGen(regex.Sub[0]) case syntax.OpStar: elementGen := regexMatchGen(regex.Sub[0]) return SliceOf(elementGen).Map(func(v []string) string { return strings.Join(v, "") }) case syntax.OpPlus: elementGen := regexMatchGen(regex.Sub[0]) return gopter.CombineGens(elementGen, SliceOf(elementGen)).Map(func(vs []interface{}) string { return vs[0].(string) + strings.Join(vs[1].([]string), "") }) case syntax.OpQuest: elementGen := regexMatchGen(regex.Sub[0]) return OneGenOf(Const(""), elementGen) case syntax.OpConcat: gens := make([]gopter.Gen, len(regex.Sub)) for i, sub := range regex.Sub { gens[i] = regexMatchGen(sub) } return gopter.CombineGens(gens...).Map(func(v []interface{}) string { result := "" for _, str := range v { result += str.(string) } return result }) case syntax.OpAlternate: gens := make([]gopter.Gen, len(regex.Sub)) for i, sub := range regex.Sub { gens[i] = regexMatchGen(sub) } return OneGenOf(gens...) } return Const("") } func runeToString(v rune) string { return string(v) } gopter-0.2.11/gen/regex_test.go000066400000000000000000000013611460324054500163500ustar00rootroot00000000000000package gen_test import ( "fmt" "regexp" "testing" "github.com/leanovate/gopter/gen" ) func TestRegexMatch(t *testing.T) { regexs := []string{ "[a-z][0-9a-zA-Z]*", "AB[0-9]+", "1?(zero|one)0", "ABCD.+1234", "^[0-9]{3}[A-Z]{5,}[a-z]{10,20}$", "(?s)[^0-9]*ABCD.*1234", } for _, regex := range regexs { pattern, err := regexp.Compile(regex) if err != nil { t.Error("Invalid regex", err) } commonGeneratorTest(t, fmt.Sprintf("matches for %s", regex), gen.RegexMatch(regex), func(value interface{}) bool { str, ok := value.(string) return ok && pattern.MatchString(str) }) } gen := gen.RegexMatch("]]}})Invalid{]]]") value, ok := gen.Sample() if ok || value != nil { t.Errorf("Invalid value: %#v", value) } } gopter-0.2.11/gen/retry_until.go000066400000000000000000000015331460324054500165600ustar00rootroot00000000000000package gen import "github.com/leanovate/gopter" // RetryUntil creates a generator that retries a given generator until a condition in met. // condition: has to be a function with one parameter (matching the generated value of gen) returning a bool. // Note: The new generator will only create an empty result once maxRetries is reached. // Depending on the hit-ratio of the condition is may result in long running tests, use with care. func RetryUntil(gen gopter.Gen, condition interface{}, maxRetries int) gopter.Gen { genWithSieve := gen.SuchThat(condition) return func(genParams *gopter.GenParameters) *gopter.GenResult { for i := 0; i < maxRetries; i++ { result := genWithSieve(genParams) if _, ok := result.Retrieve(); ok { return result } } resultType := gen(genParams).ResultType return gopter.NewEmptyResult(resultType) } } gopter-0.2.11/gen/retry_until_test.go000066400000000000000000000013351460324054500176170ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestRetryUntil(t *testing.T) { genParams := gopter.DefaultGenParameters() origGen := gen.IntRange(0, 100) retryGen := gen.RetryUntil(origGen, func(v int) bool { return v > 50 }, 1000) result := retryGen(genParams) value, ok := result.Retrieve() if value == nil || !ok { t.Errorf("RetryGen generated empty result") } if value.(int) <= 50 { t.Errorf("RetryGen generyte invalid value: %#v", value) } noMatchGen := gen.RetryUntil(origGen, func(v int) bool { return v > 500 }, 100) result = noMatchGen(genParams) _, ok = result.Retrieve() if ok { t.Errorf("RetryGen nomatch generated a value") } } gopter-0.2.11/gen/sized.go000066400000000000000000000010641460324054500153150ustar00rootroot00000000000000package gen import ( "github.com/leanovate/gopter" ) // Sized derives a generator from based on size // This honors the `MinSize` and `MaxSize` of the `GenParameters` of the test suite. // Keep an eye on memory consumption, by default MaxSize is 100. func Sized(f func(int) gopter.Gen) gopter.Gen { return func(params *gopter.GenParameters) *gopter.GenResult { var size int if params.MaxSize == params.MinSize { size = params.MaxSize } else { size = params.Rng.Intn(params.MaxSize-params.MinSize) + params.MinSize } return f(size)(params) } } gopter-0.2.11/gen/sized_test.go000066400000000000000000000010161460324054500163510ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestSized(t *testing.T) { sizedInt := gen.Sized(func(size int) gopter.Gen { return gen.IntRange(0, size) }) for i := 0; i < 100; i++ { value, ok := sizedInt.Sample() if !ok || value == nil { t.Errorf("Invalid sized int: %#v", value) } v, ok := value.(int) if !ok { t.Errorf("Invalid sized int: %#v", value) } if v < 0 || v > 100 { t.Errorf("Sized int out of range: %d", v) } } } gopter-0.2.11/gen/slice_of.go000066400000000000000000000063211460324054500157630ustar00rootroot00000000000000package gen import ( "reflect" "github.com/leanovate/gopter" ) // SliceOf generates an arbitrary slice of generated elements // genParams.MaxSize sets an (exclusive) upper limit on the size of the slice // genParams.MinSize sets an (inclusive) lower limit on the size of the slice func SliceOf(elementGen gopter.Gen, typeOverrides ...reflect.Type) gopter.Gen { var typeOverride reflect.Type if len(typeOverrides) > 1 { panic("too many type overrides specified, at most 1 may be provided.") } else if len(typeOverrides) == 1 { typeOverride = typeOverrides[0] } return func(genParams *gopter.GenParameters) *gopter.GenResult { len := 0 if genParams.MaxSize > 0 || genParams.MinSize > 0 { if genParams.MinSize > genParams.MaxSize { panic("GenParameters.MinSize must be <= GenParameters.MaxSize") } if genParams.MaxSize == genParams.MinSize { len = genParams.MaxSize } else { len = genParams.Rng.Intn(genParams.MaxSize-genParams.MinSize) + genParams.MinSize } } result, elementSieve, elementShrinker := genSlice(elementGen, genParams, len, typeOverride) genResult := gopter.NewGenResult(result.Interface(), SliceShrinker(elementShrinker)) if elementSieve != nil { genResult.Sieve = forAllSieve(elementSieve) } return genResult } } // SliceOfN generates a slice of generated elements with definied length func SliceOfN(desiredlen int, elementGen gopter.Gen, typeOverrides ...reflect.Type) gopter.Gen { var typeOverride reflect.Type if len(typeOverrides) > 1 { panic("too many type overrides specified, at most 1 may be provided.") } else if len(typeOverrides) == 1 { typeOverride = typeOverrides[0] } return func(genParams *gopter.GenParameters) *gopter.GenResult { result, elementSieve, elementShrinker := genSlice(elementGen, genParams, desiredlen, typeOverride) genResult := gopter.NewGenResult(result.Interface(), SliceShrinkerOne(elementShrinker)) if elementSieve != nil { genResult.Sieve = func(v interface{}) bool { rv := reflect.ValueOf(v) return rv.Len() == desiredlen && forAllSieve(elementSieve)(v) } } else { genResult.Sieve = func(v interface{}) bool { return reflect.ValueOf(v).Len() == desiredlen } } return genResult } } func genSlice(elementGen gopter.Gen, genParams *gopter.GenParameters, desiredlen int, typeOverride reflect.Type) (reflect.Value, func(interface{}) bool, gopter.Shrinker) { element := elementGen(genParams) elementSieve := element.Sieve elementShrinker := element.Shrinker sliceType := typeOverride if sliceType == nil { sliceType = element.ResultType } result := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, desiredlen) for i := 0; i < desiredlen; i++ { value, ok := element.Retrieve() if ok { if value == nil { result = reflect.Append(result, reflect.Zero(sliceType)) } else { result = reflect.Append(result, reflect.ValueOf(value)) } } element = elementGen(genParams) } return result, elementSieve, elementShrinker } func forAllSieve(elementSieve func(interface{}) bool) func(interface{}) bool { return func(v interface{}) bool { rv := reflect.ValueOf(v) for i := rv.Len() - 1; i >= 0; i-- { if !elementSieve(rv.Index(i).Interface()) { return false } } return true } } gopter-0.2.11/gen/slice_of_test.go000066400000000000000000000107671460324054500170330ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestSliceOf(t *testing.T) { genParams := gopter.DefaultGenParameters() genParams.MaxSize = 50 elementGen := gen.Const("element") sliceGen := gen.SliceOf(elementGen) for i := 0; i < 100; i++ { sample, ok := sliceGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.([]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) > 50 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, str := range strings { if str != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } genParams.MinSize = 10 for i := 0; i < 100; i++ { sample, ok := sliceGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.([]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) > 50 || len(strings) < 10 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, str := range strings { if str != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } genParams.MaxSize = 10 for i := 0; i < 100; i++ { sample, ok := sliceGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.([]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) != 10 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, str := range strings { if str != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } genParams.MaxSize = 0 genParams.MinSize = 0 for i := 0; i < 100; i++ { sample, ok := sliceGen(genParams).Retrieve() if !ok { t.Error("Sample was not ok") } strings, ok := sample.([]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) != 0 { t.Errorf("Sample has invalid length: %#v", len(strings)) } } } } func TestSliceOfPanic(t *testing.T) { genParams := gopter.DefaultGenParameters() genParams.MaxSize = 0 genParams.MinSize = 1 elementGen := gen.Const("element") sliceGen := gen.SliceOf(elementGen) defer func() { if r := recover(); r == nil { t.Error("SliceOf did not panic when MinSize was > MaxSize") } }() sliceGen(genParams).Retrieve() } func TestSliceOfN(t *testing.T) { elementGen := gen.Const("element") sliceGen := gen.SliceOfN(10, elementGen) for i := 0; i < 100; i++ { sample, ok := sliceGen.Sample() if !ok { t.Error("Sample was not ok") } strings, ok := sample.([]string) if !ok { t.Errorf("Sample not slice of string: %#v", sample) } else { if len(strings) != 10 { t.Errorf("Sample has invalid length: %#v", len(strings)) } for _, str := range strings { if str != "element" { t.Errorf("Sample contains invalid value: %#v", sample) } } } } } func TestSliceOfNSieve(t *testing.T) { var called int elementSieve := func(v interface{}) bool { called++ return v == "element" } elementGen := gen.Const("element").SuchThat(elementSieve) sliceGen := gen.SliceOfN(10, elementGen) result := sliceGen(gopter.DefaultGenParameters()) value, ok := result.Retrieve() if !ok || value == nil { t.Errorf("Invalid value: %#v", value) } strs, ok := value.([]string) if !ok || len(strs) != 10 { t.Errorf("Invalid value: %#v", value) } if called != 20 { t.Errorf("Invalid called: %d", called) } if result.Sieve(strs[0:9]) { t.Error("Sieve must not allow array len < 10") } strs[0] = "bla" if result.Sieve(strs) { t.Error("Sieve must not allow array with invalid element") } } func TestSliceOfOverride(t *testing.T) { genParams := gopter.DefaultGenParameters() genParams.MaxSize = 50 sliceType := reflect.TypeOf((*baseType)(nil)).Elem() sliceGen := gen.SliceOf(gen.OneGenOf(genA(), genB()), sliceType) result := sliceGen(gopter.DefaultGenParameters()) value, ok := result.Retrieve() if !ok || value == nil { t.Errorf("Invalid value: %#v", value) } _, okType := value.([]baseType) if !okType { t.Errorf("Invalid type: %#v", value) } } type baseType interface { String() string } type specA struct{} type specB struct{} func (a specA) String() string { return "specA" } func (b specB) String() string { return "specB" } func genA() gopter.Gen { return gen.Const(specA{}) } func genB() gopter.Gen { return gen.Const(specB{}) } gopter-0.2.11/gen/slice_shrink.go000066400000000000000000000053461460324054500166630ustar00rootroot00000000000000package gen import ( "fmt" "reflect" "github.com/leanovate/gopter" ) type sliceShrinkOne struct { original reflect.Value index int elementShrink gopter.Shrink } func (s *sliceShrinkOne) Next() (interface{}, bool) { value, ok := s.elementShrink() if !ok { return nil, false } result := reflect.MakeSlice(s.original.Type(), s.original.Len(), s.original.Len()) reflect.Copy(result, s.original) if value == nil { result.Index(s.index).Set(reflect.Zero(s.original.Type().Elem())) } else { result.Index(s.index).Set(reflect.ValueOf(value)) } return result.Interface(), true } // SliceShrinkerOne creates a slice shrinker from a shrinker for the elements of the slice. // The length of the slice will remains unchanged, instead each element is shrunk after the // other. func SliceShrinkerOne(elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Slice { panic(fmt.Sprintf("%#v is not a slice", v)) } shrinks := make([]gopter.Shrink, 0, rv.Len()) for i := 0; i < rv.Len(); i++ { sliceShrinkOne := &sliceShrinkOne{ original: rv, index: i, elementShrink: elementShrinker(rv.Index(i).Interface()), } shrinks = append(shrinks, sliceShrinkOne.Next) } return gopter.ConcatShrinks(shrinks...) } } type sliceShrink struct { original reflect.Value length int offset int chunkLength int } func (s *sliceShrink) Next() (interface{}, bool) { if s.chunkLength == 0 { return nil, false } value := reflect.AppendSlice(reflect.MakeSlice(s.original.Type(), 0, s.length-s.chunkLength), s.original.Slice(0, s.offset)) s.offset += s.chunkLength if s.offset < s.length { value = reflect.AppendSlice(value, s.original.Slice(s.offset, s.length)) } else { s.offset = 0 s.chunkLength >>= 1 } return value.Interface(), true } // SliceShrinker creates a slice shrinker from a shrinker for the elements of the slice. // The length of the slice will be shrunk as well func SliceShrinker(elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Slice { panic(fmt.Sprintf("%#v is not a slice", v)) } sliceShrink := &sliceShrink{ original: rv, offset: 0, length: rv.Len(), chunkLength: rv.Len() >> 1, } shrinks := make([]gopter.Shrink, 0, rv.Len()+1) shrinks = append(shrinks, sliceShrink.Next) for i := 0; i < rv.Len(); i++ { sliceShrinkOne := &sliceShrinkOne{ original: rv, index: i, elementShrink: elementShrinker(rv.Index(i).Interface()), } shrinks = append(shrinks, sliceShrinkOne.Next) } return gopter.ConcatShrinks(shrinks...) } } gopter-0.2.11/gen/slice_shrink_test.go000066400000000000000000000041601460324054500177130ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter/gen" ) func TestSliceShrink(t *testing.T) { oneShrink := gen.SliceShrinker(gen.Int64Shrinker)([]int64{0}).All() if !reflect.DeepEqual(oneShrink, []interface{}{}) { t.Errorf("Invalid oneShrink: %#v", oneShrink) } twoShrink := gen.SliceShrinker(gen.Int64Shrinker)([]int64{0, 1}).All() if !reflect.DeepEqual(twoShrink, []interface{}{ []int64{1}, []int64{0}, []int64{0, 0}, }) { t.Errorf("Invalid twoShrink: %#v", twoShrink) } threeShrink := gen.SliceShrinker(gen.Int64Shrinker)([]int64{0, 1, 2}).All() if !reflect.DeepEqual(threeShrink, []interface{}{ []int64{1, 2}, []int64{0, 2}, []int64{0, 1}, []int64{0, 0, 2}, []int64{0, 1, 0}, []int64{0, 1, 1}, []int64{0, 1, -1}, }) { t.Errorf("Invalid threeShrink: %#v", threeShrink) } fourShrink := gen.SliceShrinker(gen.Int64Shrinker)([]int64{0, 1, 2, 3}).All() if !reflect.DeepEqual(fourShrink, []interface{}{ []int64{2, 3}, []int64{0, 1}, []int64{1, 2, 3}, []int64{0, 2, 3}, []int64{0, 1, 3}, []int64{0, 1, 2}, []int64{0, 0, 2, 3}, []int64{0, 1, 0, 3}, []int64{0, 1, 1, 3}, []int64{0, 1, -1, 3}, []int64{0, 1, 2, 0}, []int64{0, 1, 2, 2}, []int64{0, 1, 2, -2}, }) { t.Errorf("Invalid fourShrink: %#v", fourShrink) } } func TestSliceShrinkOne(t *testing.T) { oneShrink := gen.SliceShrinkerOne(gen.Int64Shrinker)([]int64{0}).All() if !reflect.DeepEqual(oneShrink, []interface{}{}) { t.Errorf("Invalid oneShrink: %#v", oneShrink) } threeShrink := gen.SliceShrinkerOne(gen.Int64Shrinker)([]int64{0, 1, 2}).All() if !reflect.DeepEqual(threeShrink, []interface{}{ []int64{0, 0, 2}, []int64{0, 1, 0}, []int64{0, 1, 1}, []int64{0, 1, -1}, }) { t.Errorf("Invalid threeShrink: %#v", threeShrink) } fourShrink := gen.SliceShrinkerOne(gen.Int64Shrinker)([]int64{0, 1, 2, 3}).All() if !reflect.DeepEqual(fourShrink, []interface{}{ []int64{0, 0, 2, 3}, []int64{0, 1, 0, 3}, []int64{0, 1, 1, 3}, []int64{0, 1, -1, 3}, []int64{0, 1, 2, 0}, []int64{0, 1, 2, 2}, []int64{0, 1, 2, -2}, }) { t.Errorf("Invalid fourShrink: %#v", fourShrink) } } gopter-0.2.11/gen/string_shrink.go000066400000000000000000000005601460324054500170630ustar00rootroot00000000000000package gen import "github.com/leanovate/gopter" var runeSliceShrinker = SliceShrinker(gopter.NoShrinker) // StringShrinker is a shrinker for strings. // It is very similar to a slice shrinker just that the elements themselves will not be shrunk. func StringShrinker(v interface{}) gopter.Shrink { return runeSliceShrinker([]rune(v.(string))).Map(runesToString) } gopter-0.2.11/gen/strings.go000066400000000000000000000104071460324054500156710ustar00rootroot00000000000000package gen import ( "reflect" "unicode" "unicode/utf8" "github.com/leanovate/gopter" ) // RuneRange generates runes within a given range func RuneRange(min, max rune) gopter.Gen { return genRune(Int64Range(int64(min), int64(max))) } // Rune generates an arbitrary character rune func Rune() gopter.Gen { return genRune(Frequency(map[int]gopter.Gen{ 0xD800: Int64Range(0, 0xD800), utf8.MaxRune - 0xDFFF: Int64Range(0xDFFF, int64(utf8.MaxRune)), })) } // RuneNoControl generates an arbitrary character rune that is not a control character func RuneNoControl() gopter.Gen { return genRune(Frequency(map[int]gopter.Gen{ 0xD800: Int64Range(32, 0xD800), utf8.MaxRune - 0xDFFF: Int64Range(0xDFFF, int64(utf8.MaxRune)), })) } func genRune(int64Gen gopter.Gen) gopter.Gen { return int64Gen.Map(func(value int64) rune { return rune(value) }).SuchThat(func(v rune) bool { return utf8.ValidRune(v) }) } // NumChar generates arbitrary numberic character runes func NumChar() gopter.Gen { return RuneRange('0', '9') } // AlphaUpperChar generates arbitrary uppercase alpha character runes func AlphaUpperChar() gopter.Gen { return RuneRange('A', 'Z') } // AlphaLowerChar generates arbitrary lowercase alpha character runes func AlphaLowerChar() gopter.Gen { return RuneRange('a', 'z') } // AlphaChar generates arbitrary character runes (upper- and lowercase) func AlphaChar() gopter.Gen { return Frequency(map[int]gopter.Gen{ 0: AlphaUpperChar(), 9: AlphaLowerChar(), }) } // AlphaNumChar generates arbitrary alpha-numeric character runes func AlphaNumChar() gopter.Gen { return Frequency(map[int]gopter.Gen{ 0: NumChar(), 9: AlphaChar(), }) } // UnicodeChar generates arbitrary character runes with a given unicode table func UnicodeChar(table *unicode.RangeTable) gopter.Gen { if table == nil || len(table.R16)+len(table.R32) == 0 { return Fail(reflect.TypeOf(rune('a'))) } return func(genParams *gopter.GenParameters) *gopter.GenResult { tableIdx := genParams.Rng.Intn(len(table.R16) + len(table.R32)) var selectedRune rune if tableIdx < len(table.R16) { r := table.R16[tableIdx] runeOffset := uint16(genParams.Rng.Int63n(int64((r.Hi-r.Lo+1)/r.Stride))) * r.Stride selectedRune = rune(runeOffset + r.Lo) } else { r := table.R32[tableIdx-len(table.R16)] runeOffset := uint32(genParams.Rng.Int63n(int64((r.Hi-r.Lo+1)/r.Stride))) * r.Stride selectedRune = rune(runeOffset + r.Lo) } genResult := gopter.NewGenResult(selectedRune, gopter.NoShrinker) genResult.Sieve = func(v interface{}) bool { return unicode.Is(table, v.(rune)) } return genResult } } // AnyString generates an arbitrary string func AnyString() gopter.Gen { return genString(Rune(), utf8.ValidRune) } // AlphaString generates an arbitrary string with letters func AlphaString() gopter.Gen { return genString(AlphaChar(), unicode.IsLetter) } // NumString generates an arbitrary string with digits func NumString() gopter.Gen { return genString(NumChar(), unicode.IsDigit) } // Identifier generates an arbitrary identifier string // Identitiers are supporsed to start with a lowercase letter and contain only // letters and digits func Identifier() gopter.Gen { return gopter.CombineGens( AlphaLowerChar(), SliceOf(AlphaNumChar()), ).Map(func(values []interface{}) string { first := values[0].(rune) tail := values[1].([]rune) result := make([]rune, 0, len(tail)+1) return string(append(append(result, first), tail...)) }).SuchThat(func(str string) bool { if len(str) < 1 || !unicode.IsLower(([]rune(str))[0]) { return false } for _, ch := range str { if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) { return false } } return true }).WithShrinker(StringShrinker) } // UnicodeString generates an arbitrary string from a given // unicode table. func UnicodeString(table *unicode.RangeTable) gopter.Gen { return genString(UnicodeChar(table), func(ch rune) bool { return unicode.Is(table, ch) }) } func genString(runeGen gopter.Gen, runeSieve func(ch rune) bool) gopter.Gen { return SliceOf(runeGen).Map(runesToString).SuchThat(func(v string) bool { for _, ch := range v { if !runeSieve(ch) { return false } } return true }).WithShrinker(StringShrinker) } func runesToString(v []rune) string { return string(v) } gopter-0.2.11/gen/strings_test.go000066400000000000000000000067651460324054500167440ustar00rootroot00000000000000package gen_test import ( "testing" "unicode" "unicode/utf8" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestRune(t *testing.T) { commonGeneratorTest(t, "rune", gen.Rune(), func(value interface{}) bool { v, ok := value.(rune) return ok && utf8.ValidRune(v) }) } func TestNumChar(t *testing.T) { commonGeneratorTest(t, "num char", gen.NumChar(), func(value interface{}) bool { v, ok := value.(rune) return ok && unicode.IsNumber(v) }) } func TestAlphaUpper(t *testing.T) { commonGeneratorTest(t, "alpha upper char", gen.AlphaUpperChar(), func(value interface{}) bool { v, ok := value.(rune) return ok && unicode.IsUpper(v) && unicode.IsLetter(v) }) } func TestAlphaLower(t *testing.T) { commonGeneratorTest(t, "alpha lower char", gen.AlphaLowerChar(), func(value interface{}) bool { v, ok := value.(rune) return ok && unicode.IsLower(v) && unicode.IsLetter(v) }) } func TestAlphaChar(t *testing.T) { commonGeneratorTest(t, "alpha char", gen.AlphaChar(), func(value interface{}) bool { v, ok := value.(rune) return ok && unicode.IsLetter(v) }) } func TestAnyString(t *testing.T) { commonGeneratorTest(t, "any string", gen.AnyString(), func(value interface{}) bool { str, ok := value.(string) if !ok { return false } for _, ch := range str { if !utf8.ValidRune(ch) { return false } } return true }) } func TestAlphaString(t *testing.T) { alphaString := gen.AlphaString() commonGeneratorTest(t, "alpha string", alphaString, func(value interface{}) bool { str, ok := value.(string) if !ok { return false } for _, ch := range str { if !utf8.ValidRune(ch) || !unicode.IsLetter(ch) { return false } } return true }) sieve := alphaString(gopter.DefaultGenParameters()).Sieve if sieve == nil { t.Error("No sieve") } if !sieve("abcdABCD") || sieve("abc12") { t.Error("Invalid sieve") } } func TestNumString(t *testing.T) { numString := gen.NumString() commonGeneratorTest(t, "num string", numString, func(value interface{}) bool { str, ok := value.(string) if !ok { return false } for _, ch := range str { if !utf8.ValidRune(ch) || !unicode.IsDigit(ch) { return false } } return true }) sieve := numString(gopter.DefaultGenParameters()).Sieve if sieve == nil { t.Error("No sieve") } if !sieve("123456789") || sieve("123abcd") { t.Error("Invalid sieve") } } func TestIdentifier(t *testing.T) { identifiers := gen.Identifier() commonGeneratorTest(t, "identifiers", identifiers, func(value interface{}) bool { str, ok := value.(string) if !ok { return false } if len(str) == 0 || !unicode.IsLetter([]rune(str)[0]) { return false } for _, ch := range str { if !utf8.ValidRune(ch) || (!unicode.IsDigit(ch) && !unicode.IsLetter(ch)) { return false } } return true }) sieve := identifiers(gopter.DefaultGenParameters()).Sieve if sieve == nil { t.Error("No sieve") } if !sieve("abc123") || sieve("123abc") || sieve("abcd123-") { t.Error("Invalid sieve") } } func TestUnicodeString(t *testing.T) { fail := gen.UnicodeChar(nil) value, ok := fail.Sample() if value != nil || ok { t.Fail() } for _, table := range unicode.Scripts { unicodeString := gen.UnicodeString(table) commonGeneratorTest(t, "unicodeString", unicodeString, func(value interface{}) bool { str, ok := value.(string) if !ok { return false } for _, ch := range str { if !utf8.ValidRune(ch) || !unicode.Is(table, ch) { return false } } return true }) } } gopter-0.2.11/gen/struct.go000066400000000000000000000125611460324054500155270ustar00rootroot00000000000000package gen import ( "fmt" "reflect" "github.com/leanovate/gopter" ) // Struct generates a given struct type. // rt has to be the reflect type of the struct, gens contains a map of field generators. // Note that the result types of the generators in gen have to match the type of the corresponding // field in the struct. Also note that only public fields of a struct can be generated func Struct(rt reflect.Type, gens map[string]gopter.Gen) gopter.Gen { if rt.Kind() == reflect.Ptr { rt = rt.Elem() } if rt.Kind() != reflect.Struct { return Fail(rt) } fieldGens := []gopter.Gen{} fieldTypes := []reflect.Type{} assignable := reflect.New(rt).Elem() for i := 0; i < rt.NumField(); i++ { fieldName := rt.Field(i).Name if !assignable.Field(i).CanSet() { continue } gen := gens[fieldName] if gen != nil { fieldGens = append(fieldGens, gen) fieldTypes = append(fieldTypes, rt.Field(i).Type) } } buildStructType := reflect.FuncOf(fieldTypes, []reflect.Type{rt}, false) unbuildStructType := reflect.FuncOf([]reflect.Type{rt}, fieldTypes, false) buildStructFunc := reflect.MakeFunc(buildStructType, func(args []reflect.Value) []reflect.Value { result := reflect.New(rt) for i := 0; i < rt.NumField(); i++ { if _, ok := gens[rt.Field(i).Name]; !ok { continue } if !assignable.Field(i).CanSet() { continue } result.Elem().Field(i).Set(args[0]) args = args[1:] } return []reflect.Value{result.Elem()} }) unbuildStructFunc := reflect.MakeFunc(unbuildStructType, func(args []reflect.Value) []reflect.Value { s := args[0] results := []reflect.Value{} for i := 0; i < s.NumField(); i++ { if _, ok := gens[rt.Field(i).Name]; !ok { continue } if !assignable.Field(i).CanSet() { continue } results = append(results, s.Field(i)) } return results }) return gopter.DeriveGen( buildStructFunc.Interface(), unbuildStructFunc.Interface(), fieldGens..., ) } // StructPtr generates pointers to a given struct type. // Note that StructPtr does not generate nil, if you want to include nil in your // testing you should combine gen.PtrOf with gen.Struct. // rt has to be the reflect type of the struct, gens contains a map of field generators. // Note that the result types of the generators in gen have to match the type of the corresponding // field in the struct. Also note that only public fields of a struct can be generated func StructPtr(rt reflect.Type, gens map[string]gopter.Gen) gopter.Gen { if rt.Kind() == reflect.Ptr { rt = rt.Elem() } buildPtrType := reflect.FuncOf([]reflect.Type{rt}, []reflect.Type{reflect.PtrTo(rt)}, false) unbuildPtrType := reflect.FuncOf([]reflect.Type{reflect.PtrTo(rt)}, []reflect.Type{rt}, false) buildPtrFunc := reflect.MakeFunc(buildPtrType, func(args []reflect.Value) []reflect.Value { sp := reflect.New(rt) sp.Elem().Set(args[0]) return []reflect.Value{sp} }) unbuildPtrFunc := reflect.MakeFunc(unbuildPtrType, func(args []reflect.Value) []reflect.Value { return []reflect.Value{args[0].Elem()} }) return gopter.DeriveGen( buildPtrFunc.Interface(), unbuildPtrFunc.Interface(), Struct(rt, gens), ) } // checkFieldsMatch panics unless the keys in gens exactly match the public // fields on rt. With an extra bool argument of value "true", it only panics if // there's a key in gens which is not a field on rt. func checkFieldsMatch( rt reflect.Type, gens map[string]gopter.Gen, allowFieldsWithNoGenerator ...bool, ) { if rt.Kind() == reflect.Ptr { rt = rt.Elem() } fields := make(map[string]bool, rt.NumField()) for i := 0; i < rt.NumField(); i++ { fields[rt.Field(i).Name] = true } for field := range gens { if _, ok := fields[field]; !ok { panic(fmt.Errorf("generator for non-existent field %s on struct %s", field, rt.Name())) } delete(fields, field) } if len(allowFieldsWithNoGenerator) > 0 && allowFieldsWithNoGenerator[0] { return // Don't check that every field is present in gens } if len(allowFieldsWithNoGenerator) > 1 { panic("expect at most one boolean argument in StrictStruct/StrictStructPtr") } if len(fields) != 0 { // Check that every field is present in gens var missingFields []string for field := range fields { missingFields = append(missingFields, field) } panic(fmt.Errorf("generator missing for fields %v on struct %s", missingFields, rt.Name())) } } // StrictStruct behaves the same as Struct, except it requires the keys in gens // to exactly match the public fields of rt. It panics if gens contains extra // keys, or has missing keys. // // If given a third true argument, it only requires the keys of gens to be // fields of rt. In that case, unspecified fields will remain unset. func StrictStruct( rt reflect.Type, gens map[string]gopter.Gen, allowFieldsWithNoGenerator ...bool, ) gopter.Gen { checkFieldsMatch(rt, gens, allowFieldsWithNoGenerator...) return Struct(rt, gens) } // StrictStructPtr behaves the same as StructPtr, except it requires the keys in // gens to exactly match the public fields of rt. It panics if gens contains // extra keys, or has missing keys. // // If given a third true argument, it only requires the keys of gens to be // fields of rt. In that case, unspecified fields will remain unset. func StrictStructPtr( rt reflect.Type, gens map[string]gopter.Gen, allowFieldsWithNoGenerator ...bool, ) gopter.Gen { checkFieldsMatch(rt, gens, allowFieldsWithNoGenerator...) return StructPtr(rt, gens) } gopter-0.2.11/gen/struct_test.go000066400000000000000000000163331460324054500165670ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) type testStruct struct { Value1 string Value2 int64 Value3 []int8 Value4 string Value5 *string Value6 interface{} value7 string } func TestStruct(t *testing.T) { structGen := gen.Struct(reflect.TypeOf(&testStruct{}), map[string]gopter.Gen{ "Value1": gen.Identifier(), "Value2": gen.Int64(), "Value3": gen.SliceOf(gen.Int8()), "NotThere": gen.AnyString(), "Value5": gen.PtrOf(gen.Const("v5")), "Value6": gen.AnyString(), "value7": gen.AnyString(), }) for i := 0; i < 100; i++ { value, ok := structGen.Sample() if !ok { t.Errorf("Invalid value: %#v", value) } v, ok := value.(testStruct) if !ok || v.Value1 == "" || v.Value3 == nil || v.Value4 != "" || !(v.Value5 == nil || *v.Value5 == "v5") { t.Errorf("Invalid value: %#v", value) } } } func TestStructWithDifferentValueTypesInSameField(t *testing.T) { structGen := gen.Struct(reflect.TypeOf(&testStruct{}), map[string]gopter.Gen{ "Value6": gen.OneGenOf(gen.AnyString(), gen.Int()), }) for i := 0; i < 100; i++ { value, ok := structGen.Sample() if !ok { t.Errorf("Invalid value: %#v", value) } } } func TestStructDeterminism(t *testing.T) { structGen := gen.Struct(reflect.TypeOf(&testStruct{}), map[string]gopter.Gen{ "Value1": gen.Identifier(), "Value2": gen.Int64(), "Value3": gen.SliceOf(gen.Int8()), }) for i := 0; i < 100; i++ { parameters := gopter.DefaultGenParameters().CloneWithSeed(1234) for _, expected := range []testStruct{ { Value1: "hUeNzDbtiF4xxkidfvLaiczgpwsqfyvbbuhrjjoez4jtewulIKwzMguttazo3qwi5ufIfi6izpqT4evzrmgtmk1gQo", Value2: -2282921689139609493, Value3: []int8{-93, -96, -23, -58, 65, -108, 56, 63, -64, 26, -69, 62, 61, -93, -107, 52, -95}, }, { Value1: "ubJrJEawwnoh63jv1lxd7xhtaqqrEnjawudgiixhhkw6sdmqdgxbabyoxcoE0uviwDupccvYvxcqOv0z8opjk", Value2: -1611599231975617329, Value3: []int8{15, -41, -106, 37, 3, 76, -65, -87, 113, -115, 76, 61, 41, 65, 11, -90, -4, 43, 110, -121, 65, 112, -128, 51, -86, 50, 30, 33, -73, -88, 94, 101, 63, -113, 45, 110, 46, 21, 115, 78, -58, 47, -110, 7, -14, -18, 2, -26, 63, -33, 77, 82, -52, -57, -105}, }, { Value1: "axnbggD6Hgsxyxd6ZwcZ4Bn1uM7hzd0azvsuLvj3wvfvoramjcltivmditt5qhmHYfn0egagcFpuAffzaWxvalEaniojczez", Value2: -345052727922296584, Value3: []int8{-61, 94, 67, 9, 39, 119, 23, 1, 57, -66, 57, -94, 38, -122, 16, 82, -119, 21, -74, -66, -111, 55, -96, 8, -79, 13, -41, 124, 71, -63, 56, 16, 62, 55, -13, -35, -27, 68, -82, 22, -63, -76, 96, 60, -89, -10, -65, -102, -97, 45, 124, 117, -37, 21, 58, -87, 116, 60, -111, 27, 102, -102, -81, -123, -86, -95}, }, { Value1: "lr", Value2: -6442088894944465291, Value3: []int8{-20, 38, 25, -76, -110, -98, -61, 65, -14, 52, -47, 22, -90}, }, { Value1: "un23mggozHs4txZtydz6mIBymnxjxklkjyNzf", Value2: -26686468742269553, Value3: []int8{78, 91, -22, -126, -93, 35, -14, 67, -97, 13, -25, 73, -111, 26, 14, -67, 50, -23, -15, -63, -40, -103, 126, 60, -63, -83, -126, 64, 52, -50, 86, -25, -1, 108, 7, 62, 79, 89, 45, -73, 52, -7, -85, -111, -120, -21, 116, -8, -22, 34, 85, 36, 124, 12, -111, -114, -115, 91, -94, 82, -3, -46, 94, -73, 62, -117, -7, 84, -94, 13, 71, -5, 21, 32, 106, -44, 46}, }, } { value, ok := structGen(parameters).Retrieve() if !ok { t.Errorf("Invalid value: %#v", value) } v, ok := value.(testStruct) if !reflect.DeepEqual(expected, v) { t.Errorf("Invalid value: %#v; expected: %#v", v, expected) } } } } func TestStructPropageEmpty(t *testing.T) { fail := gen.Struct(reflect.TypeOf(&testStruct{}), map[string]gopter.Gen{ "Value1": gen.Identifier().SuchThat(func(str string) bool { return false }), }) if _, ok := fail.Sample(); ok { t.Errorf("Failing field generator in Struct generated a value") } } func TestStructNoStruct(t *testing.T) { fail := gen.Struct(reflect.TypeOf(""), map[string]gopter.Gen{}) if _, ok := fail.Sample(); ok { t.Errorf("Invalid Struct generated a value") } } func TestStructPtr(t *testing.T) { structGen := gen.StructPtr(reflect.TypeOf(&testStruct{}), map[string]gopter.Gen{ "Value1": gen.Identifier(), "Value2": gen.Int64(), "Value3": gen.SliceOf(gen.Int8()), "NotThere": gen.AnyString(), }) for i := 0; i < 100; i++ { value, ok := structGen.Sample() if !ok || value == nil { t.Errorf("Invalid value: %#v", value) } v, ok := value.(*testStruct) if !ok || v.Value1 == "" || v.Value3 == nil || v.Value4 != "" { t.Errorf("Invalid value: %#v", value) } } } func TestStructPtrPropageEmpty(t *testing.T) { fail := gen.StructPtr(reflect.TypeOf(&testStruct{}), map[string]gopter.Gen{ "Value1": gen.Identifier().SuchThat(func(str string) bool { return false }), }) if _, ok := fail.Sample(); ok { t.Errorf("Failing field generator in StructPtr generated a value") } } func TestStructPtrNoStruct(t *testing.T) { fail := gen.StructPtr(reflect.TypeOf(""), map[string]gopter.Gen{}) if _, ok := fail.Sample(); ok { t.Errorf("Invalid StructPtr generated a value") } } func TestStrictStructExtraField(t *testing.T) { defer func() { r := recover() if r != nil { errmsg := r.(error).Error() if errmsg != "generator for non-existent field NotThere on struct testStruct" { t.Errorf("unexpected error message from StrictStruct") } } else { t.Errorf("StrictStruct failed to panic when given an extra field") } }() gens := map[string]gopter.Gen{ "Value1": gen.Identifier(), "Value2": gen.Int64(), "Value3": gen.SliceOf(gen.Int8()), "NotThere": gen.AnyString(), "Value5": gen.PtrOf(gen.Const("v5")), "Value6": gen.AnyString(), "value7": gen.AnyString(), } _ = gen.StrictStruct(reflect.TypeOf(&testStruct{}), gens) _ = gen.StrictStructPtr(reflect.TypeOf(&testStruct{}), gens) } func TestStrictStructMissingField(t *testing.T) { defer func() { r := recover() if r != nil { errmsg := r.(error).Error() if errmsg != "generator missing for fields [Value4] on struct testStruct" { t.Errorf("unexpected error message from StrictStruct: %s", errmsg) } } else { t.Errorf("StrictStruct failed to panic when field was missing") } }() gens := map[string]gopter.Gen{ "Value1": gen.Identifier(), "Value2": gen.Int64(), "Value3": gen.SliceOf(gen.Int8()), // missing Value4 field "Value5": gen.PtrOf(gen.Const("v5")), "Value6": gen.AnyString(), "value7": gen.AnyString(), } _ = gen.StrictStruct(reflect.TypeOf(&testStruct{}), gens) _ = gen.StrictStructPtr(reflect.TypeOf(&testStruct{}), gens) } func TestStrictStructAllowingMissingField(t *testing.T) { defer func() { r := recover() if r != nil { errmsg := r.(error).Error() t.Errorf("unexpected error message from StrictStruct: %s", errmsg) } }() gens := map[string]gopter.Gen{ "Value1": gen.Identifier(), "Value2": gen.Int64(), "Value3": gen.SliceOf(gen.Int8()), // missing Value4 field "Value5": gen.PtrOf(gen.Const("v5")), "Value6": gen.AnyString(), "value7": gen.AnyString(), } _ = gen.StrictStruct(reflect.TypeOf(&testStruct{}), gens, true) // This "true" argument allows a missing value _ = gen.StrictStructPtr(reflect.TypeOf(&testStruct{}), gens, true) // This "true" argument allows a missing value } gopter-0.2.11/gen/time.go000066400000000000000000000021721460324054500151360ustar00rootroot00000000000000package gen import ( "time" "github.com/leanovate/gopter" ) // Time generates an arbitrary time.Time within year [0, 9999] func Time() gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { sec := genParams.Rng.Int63n(253402214400) // Ensure year in [0, 9999] usec := genParams.Rng.Int63n(1000000000) return gopter.NewGenResult(time.Unix(sec, usec), TimeShrinker) } } // AnyTime generates an arbitrary time.Time struct (might be way out of bounds of any reason) func AnyTime() gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { sec := genParams.NextInt64() usec := genParams.NextInt64() return gopter.NewGenResult(time.Unix(sec, usec), TimeShrinker) } } // TimeRange generates an arbitrary time.Time with a range // from defines the start of the time range // duration defines the overall duration of the time range func TimeRange(from time.Time, duration time.Duration) gopter.Gen { return func(genParams *gopter.GenParameters) *gopter.GenResult { v := from.Add(time.Duration(genParams.Rng.Int63n(int64(duration)))) return gopter.NewGenResult(v, TimeShrinker) } } gopter-0.2.11/gen/time_shrink.go000066400000000000000000000011551460324054500165140ustar00rootroot00000000000000package gen import ( "time" "github.com/leanovate/gopter" ) // TimeShrinker is a shrinker for time.Time structs func TimeShrinker(v interface{}) gopter.Shrink { t := v.(time.Time) sec := t.Unix() nsec := int64(t.Nanosecond()) secShrink := uint64Shrink{ original: uint64(sec), half: uint64(sec), } nsecShrink := uint64Shrink{ original: uint64(nsec), half: uint64(nsec), } return gopter.Shrink(secShrink.Next).Map(func(v uint64) time.Time { return time.Unix(int64(v), nsec) }).Interleave(gopter.Shrink(nsecShrink.Next).Map(func(v uint64) time.Time { return time.Unix(sec, int64(v)) })) } gopter-0.2.11/gen/time_shrink_test.go000066400000000000000000000007451460324054500175570ustar00rootroot00000000000000package gen_test import ( "reflect" "testing" "time" "github.com/leanovate/gopter/gen" ) func TestTimeShrink(t *testing.T) { timeShrink := gen.TimeShrinker(time.Unix(20, 10)).All() if !reflect.DeepEqual(timeShrink, []interface{}{ time.Unix(0, 10), time.Unix(20, 0), time.Unix(10, 10), time.Unix(20, 5), time.Unix(15, 10), time.Unix(20, 8), time.Unix(18, 10), time.Unix(20, 9), time.Unix(19, 10), }) { t.Errorf("Invalid timeShrink: %#v", timeShrink) } } gopter-0.2.11/gen/time_test.go000066400000000000000000000022741460324054500162000ustar00rootroot00000000000000package gen_test import ( "testing" "time" "github.com/leanovate/gopter/gen" ) func TestTime(t *testing.T) { timeGen := gen.Time() for i := 0; i < 100; i++ { value, ok := timeGen.Sample() if !ok || value == nil { t.Errorf("Invalid time: %#v", value) } v, ok := value.(time.Time) if !ok || v.String() == "" { t.Errorf("Invalid time: %#v", value) } if v.Year() < 0 || v.Year() > 9999 { t.Errorf("Year out of range: %#v", v) } } } func TestAnyTime(t *testing.T) { timeGen := gen.AnyTime() for i := 0; i < 100; i++ { value, ok := timeGen.Sample() if !ok || value == nil { t.Errorf("Invalid time: %#v", value) } v, ok := value.(time.Time) if !ok || v.String() == "" { t.Errorf("Invalid time: %#v", value) } } } func TestTimeRegion(t *testing.T) { duration := time.Duration(10*24*365) * time.Hour from := time.Unix(1000, 0) until := from.Add(duration) timeRange := gen.TimeRange(from, duration) for i := 0; i < 100; i++ { value, ok := timeRange.Sample() if !ok || value == nil { t.Errorf("Invalid time: %#v", value) } v, ok := value.(time.Time) if !ok || v.Before(from) || v.After(until) { t.Errorf("Invalid time: %#v", value) } } } gopter-0.2.11/gen/weighted.go000066400000000000000000000020771460324054500160040ustar00rootroot00000000000000package gen import ( "fmt" "sort" "github.com/leanovate/gopter" ) // WeightedGen adds a weight number to a generator. // To be used as parameter to gen.Weighted type WeightedGen struct { Weight int Gen gopter.Gen } // Weighted combines multiple generators, where each generator has a weight. // The weight of a generator is proportional to the probability that the // generator gets selected. func Weighted(weightedGens []WeightedGen) gopter.Gen { if len(weightedGens) == 0 { panic("weightedGens must be non-empty") } weights := make(sort.IntSlice, 0, len(weightedGens)) totalWeight := 0 for _, weightedGen := range weightedGens { w := weightedGen.Weight if w <= 0 { panic(fmt.Sprintf( "weightedGens must have positive weights; got %d", w)) } totalWeight += weightedGen.Weight weights = append(weights, totalWeight) } return func(genParams *gopter.GenParameters) *gopter.GenResult { idx := weights.Search(1 + genParams.Rng.Intn(totalWeight)) gen := weightedGens[idx].Gen result := gen(genParams) result.Sieve = nil return result } } gopter-0.2.11/gen/weighted_test.go000066400000000000000000000017041460324054500170370ustar00rootroot00000000000000package gen_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" ) func TestWeighted(t *testing.T) { parameters := gopter.DefaultGenParameters() parameters.Rng.Seed(1234) weighted := gen.Weighted([]gen.WeightedGen{ {Weight: 1, Gen: gen.Const("A")}, {Weight: 2, Gen: gen.Const("B")}, {Weight: 7, Gen: gen.Const("C")}, }) results := make(map[string]int) for i := int64(0); i < int64(1000); i++ { result, ok := weighted(parameters).Retrieve() if !ok { t.FailNow() } results[result.(string)]++ } expectedResults := map[string]int{ "A": 100, "B": 200, "C": 700, } delta := 50 for _, value := range []string{"A", "B", "C"} { result := results[value] expected := expectedResults[value] if result < expected-delta || result > expected+delta { t.Errorf( "Result %d for %v falls outside acceptable range %d, %d", result, value, expected-delta, expected+delta) } } } gopter-0.2.11/gen_parameter_test.go000066400000000000000000000023661460324054500173040ustar00rootroot00000000000000package gopter_test import ( "math/rand" "testing" "github.com/leanovate/gopter" ) type fixedSeed struct { fixed int64 } func (f *fixedSeed) Int63() int64 { return f.fixed } func (f *fixedSeed) Seed(seed int64) { f.fixed = seed } func TestGenParameters(t *testing.T) { parameters := &gopter.GenParameters{ MaxSize: 100, Rng: rand.New(&fixedSeed{}), } if !parameters.NextBool() { t.Error("Bool should be true") } if parameters.NextInt64() != 0 { t.Error("int64 should be 0") } if parameters.NextUint64() != 0 { t.Error("uint64 should be 0") } parameters.Rng.Seed(1) if parameters.NextBool() { t.Error("Bool should be false") } if parameters.NextInt64() != 1 { t.Error("int64 should be 1") } if parameters.NextUint64() != 3 { t.Error("uint64 should be 3") } parameters.Rng.Seed(2) if !parameters.NextBool() { t.Error("Bool should be true") } if parameters.NextInt64() != -2 { t.Error("int64 should be -2") } if parameters.NextUint64() != 6 { t.Error("uint64 should be 6") } param1 := parameters.CloneWithSeed(1024) param2 := parameters.CloneWithSeed(1024) for i := 0; i < 100; i++ { if param1.NextInt64() != param2.NextInt64() { t.Error("cloned parameters create different random numbers") } } } gopter-0.2.11/gen_parameters.go000066400000000000000000000037511460324054500164270ustar00rootroot00000000000000package gopter import ( "math/rand" "time" ) // GenParameters encapsulates the parameters for all generators. type GenParameters struct { MinSize int MaxSize int MaxShrinkCount int Rng *rand.Rand } // WithSize modifies the size parameter. The size parameter defines an upper bound for the size of // generated slices or strings. func (p *GenParameters) WithSize(size int) *GenParameters { newParameters := *p newParameters.MaxSize = size return &newParameters } // NextBool create a random boolean using the underlying Rng. func (p *GenParameters) NextBool() bool { return p.Rng.Int63()&1 == 0 } // NextInt64 create a random int64 using the underlying Rng. func (p *GenParameters) NextInt64() int64 { v := p.Rng.Int63() if p.NextBool() { return -v } return v } // NextUint64 create a random uint64 using the underlying Rng. func (p *GenParameters) NextUint64() uint64 { first := uint64(p.Rng.Int63()) second := uint64(p.Rng.Int63()) return (first << 1) ^ second } // CloneWithSeed clone the current parameters with a new seed. // This is useful to create subsections that can rerun (provided you keep the // seed) func (p *GenParameters) CloneWithSeed(seed int64) *GenParameters { return &GenParameters{ MinSize: p.MinSize, MaxSize: p.MaxSize, MaxShrinkCount: p.MaxShrinkCount, Rng: rand.New(NewLockedSource(seed)), } } // DefaultGenParameters creates default GenParameters. func DefaultGenParameters() *GenParameters { seed := time.Now().UnixNano() return &GenParameters{ MinSize: 0, MaxSize: 100, MaxShrinkCount: 1000, Rng: rand.New(NewLockedSource(seed)), } } // MinGenParameters creates minimal GenParameters. // Note: Most likely you do not want to use these for actual testing func MinGenParameters() *GenParameters { seed := time.Now().UnixNano() return &GenParameters{ MinSize: 0, MaxSize: 0, MaxShrinkCount: 0, Rng: rand.New(NewLockedSource(seed)), } } gopter-0.2.11/gen_result.go000066400000000000000000000033451460324054500156010ustar00rootroot00000000000000package gopter import "reflect" // GenResult contains the result of a generator. type GenResult struct { Labels []string Shrinker Shrinker ResultType reflect.Type Result interface{} Sieve func(interface{}) bool } // NewGenResult creates a new generator result from for a concrete value and // shrinker. // Note: The concrete value "result" not be nil func NewGenResult(result interface{}, shrinker Shrinker) *GenResult { return &GenResult{ Shrinker: shrinker, ResultType: reflect.TypeOf(result), Result: result, } } // NewEmptyResult creates an empty generator result. // Unless the sieve does not explicitly allow it, empty (i.e. nil-valued) // results are considered invalid. func NewEmptyResult(resultType reflect.Type) *GenResult { return &GenResult{ ResultType: resultType, Shrinker: NoShrinker, } } // Retrieve gets the concrete generator result. // If the result is invalid or does not pass the sieve there is no concrete // value and the property using the generator should be undecided. func (r *GenResult) Retrieve() (interface{}, bool) { if (r.Sieve == nil && r.Result != nil) || (r.Sieve != nil && r.Sieve(r.Result)) { return r.Result, true } return nil, false } // RetrieveAsValue get the concrete generator result as reflect value. // If the result is invalid or does not pass the sieve there is no concrete // value and the property using the generator should be undecided. func (r *GenResult) RetrieveAsValue() (reflect.Value, bool) { if r.Result != nil && (r.Sieve == nil || r.Sieve(r.Result)) { return reflect.ValueOf(r.Result), true } else if r.Result == nil && r.Sieve != nil && r.Sieve(r.Result) { return reflect.Zero(r.ResultType), true } return reflect.Zero(r.ResultType), false } gopter-0.2.11/gen_result_test.go000066400000000000000000000010701460324054500166310ustar00rootroot00000000000000package gopter_test import ( "reflect" "testing" "github.com/leanovate/gopter" ) func TestNewGenResult(t *testing.T) { result := gopter.NewGenResult(123, gopter.NoShrinker) value, ok := result.Retrieve() if !ok || value != 123 || result.ResultType.Kind() != reflect.Int { t.Errorf("Invalid result: %#v", value) } } func TestNewEmptyResult(t *testing.T) { result := gopter.NewEmptyResult(reflect.TypeOf(0)) value, ok := result.Retrieve() if ok || value != nil || result.ResultType.Kind() != reflect.Int { t.Errorf("Invalid result: %#v", value) } } gopter-0.2.11/gen_test.go000066400000000000000000000241271460324054500152430ustar00rootroot00000000000000package gopter_test import ( "reflect" "testing" "github.com/leanovate/gopter" ) func constGen(value interface{}) gopter.Gen { return func(*gopter.GenParameters) *gopter.GenResult { return gopter.NewGenResult(value, gopter.NoShrinker) } } func TestGenSample(t *testing.T) { gen := constGen("sample") value, ok := gen.Sample() if !ok || value != "sample" { t.Errorf("Invalid gen sample: %#v", value) } } func BenchmarkMap(b *testing.B) { for i := 0; i < b.N; i++ { gen := constGen("sample") var mappedWith string mapper := func(v string) string { mappedWith = v return "other" } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { b.Errorf("Invalid gen sample: %#v", value) } if mappedWith != "sample" { b.Errorf("Invalid mapped with: %#v", mappedWith) } gen = gen.SuchThat(func(interface{}) bool { return false }) value, ok = gen.Map(mapper).Sample() if ok { b.Errorf("Invalid gen sample: %#v", value) } } } func TestGenMap(t *testing.T) { gen := constGen("sample") var mappedWith string mapper := func(v string) string { mappedWith = v return "other" } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith != "sample" { t.Errorf("Invalid mapped with: %#v", mappedWith) } gen = gen.SuchThat(func(interface{}) bool { return false }) value, ok = gen.Map(mapper).Sample() if ok { t.Errorf("Invalid gen sample: %#v", value) } } func TestGenMapWithParams(t *testing.T) { gen := constGen("sample") var mappedWith string var mappedWithParams *gopter.GenParameters mapper := func(v string, params *gopter.GenParameters) string { mappedWith = v mappedWithParams = params return "other" } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith != "sample" { t.Errorf("Invalid mapped with: %#v", mappedWith) } if mappedWithParams == nil || mappedWithParams.MaxSize != 100 { t.Error("Mapper not called with currect parameters") } gen = gen.SuchThat(func(interface{}) bool { return false }) value, ok = gen.Map(mapper).Sample() if ok { t.Errorf("Invalid gen sample: %#v", value) } } func TestGenMapNoFunc(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func, but is string") constGen("sample").Map("not a function") } func TestGenMapTooManyParams(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func with one or two params, but is 3") constGen("sample").Map(func(a, b, C string) string { return "" }) } func TestGenMapInvalidSecondParam(t *testing.T) { defer expectPanic(t, "Second parameter of mapper function has to be a *GenParameters") constGen("sample").Map(func(a, b string) string { return "" }) } func TestGenMapToInvalidParamtype(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func with one param assignable to string, but is int") constGen("sample").Map(func(a int) string { return "" }) } func TestGenMapToManyReturns(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func with one return value, but is 2") constGen("sample").Map(func(a string) (string, bool) { return "", false }) } func TestGenMapResultIn(t *testing.T) { gen := constGen("sample") var mappedWith *gopter.GenResult mapper := func(result *gopter.GenResult) string { mappedWith = result return "other" } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith == nil { t.Error("Mapper not called") } if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" { t.Errorf("Mapper was called with invalid value: %#v", mapperValue) } } func TestGenMapResultInWithParams(t *testing.T) { gen := constGen("sample") var mappedWith *gopter.GenResult var mappedWithParams *gopter.GenParameters mapper := func(result *gopter.GenResult, params *gopter.GenParameters) string { mappedWith = result mappedWithParams = params return "other" } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith == nil { t.Error("Mapper not called") } if mappedWithParams == nil || mappedWithParams.MaxSize != 100 { t.Error("Mapper not called with currect parameters") } if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" { t.Errorf("Mapper was called with invalid value: %#v", mapperValue) } } func TestGenMapResultOut(t *testing.T) { gen := constGen("sample") var mappedWith string mapper := func(v string) *gopter.GenResult { mappedWith = v return gopter.NewGenResult("other", gopter.NoShrinker) } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith != "sample" { t.Errorf("Invalid mapped with: %#v", mappedWith) } gen = gen.SuchThat(func(interface{}) bool { return false }) value, ok = gen.Map(mapper).Sample() if ok { t.Errorf("Invalid gen sample: %#v", value) } } func TestGenMapResultInOut(t *testing.T) { gen := constGen("sample") var mappedWith *gopter.GenResult mapper := func(result *gopter.GenResult) *gopter.GenResult { mappedWith = result return gopter.NewGenResult("other", gopter.NoShrinker) } value, ok := gen.Map(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith == nil { t.Error("Mapper not called") } if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" { t.Errorf("Mapper was called with invalid value: %#v", mapperValue) } } func TestGenFlatMap(t *testing.T) { gen := constGen("sample") var mappedWith interface{} mapper := func(v interface{}) gopter.Gen { mappedWith = v return constGen("other") } value, ok := gen.FlatMap(mapper, reflect.TypeOf("")).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith.(string) != "sample" { t.Errorf("Invalid mapped with: %#v", mappedWith) } gen = gen.SuchThat(func(interface{}) bool { return false }) value, ok = gen.FlatMap(mapper, reflect.TypeOf("")).Sample() if ok { t.Errorf("Invalid gen sample: %#v", value) } } func TestGenMapResult(t *testing.T) { gen := constGen("sample") var mappedWith *gopter.GenResult mapper := func(result *gopter.GenResult) *gopter.GenResult { mappedWith = result return gopter.NewGenResult("other", gopter.NoShrinker) } value, ok := gen.MapResult(mapper).Sample() if !ok || value != "other" { t.Errorf("Invalid gen sample: %#v", value) } if mappedWith == nil { t.Error("Mapper not called") } if mapperValue, ok := mappedWith.Retrieve(); !ok || mapperValue != "sample" { t.Errorf("Mapper was called with invalid value: %#v", mapperValue) } } func TestCombineGens(t *testing.T) { gens := make([]gopter.Gen, 0, 20) for i := 0; i < 20; i++ { gens = append(gens, constGen(i)) } gen := gopter.CombineGens(gens...) raw, ok := gen.Sample() if !ok { t.Errorf("Invalid combined gen: %#v", raw) } values, ok := raw.([]interface{}) if !ok || !reflect.DeepEqual(values, []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}) { t.Errorf("Invalid combined gen: %#v", raw) } gens[0] = gens[0].SuchThat(func(interface{}) bool { return false }) gen = gopter.CombineGens(gens...) raw, ok = gen.Sample() if ok { t.Errorf("Invalid combined gen: %#v", raw) } } func TestSuchThat(t *testing.T) { var sieveArg string sieve := func(v string) bool { sieveArg = v return true } gen := constGen("sample").SuchThat(sieve) value, ok := gen.Sample() if !ok || value != "sample" { t.Errorf("Invalid result: %#v", value) } if sieveArg != "sample" { t.Errorf("Invalid sieveArg: %#v", sieveArg) } sieveArg = "" var sieve2Arg string sieve2 := func(v string) bool { sieve2Arg = v return false } gen = gen.SuchThat(sieve2) _, ok = gen.Sample() if ok { t.Error("Did not expect a result") } if sieveArg != "sample" { t.Errorf("Invalid sieveArg: %#v", sieveArg) } if sieve2Arg != "sample" { t.Errorf("Invalid sieve2Arg: %#v", sieve2Arg) } } func TestGenSuchThatNoFunc(t *testing.T) { defer expectPanic(t, "Param of SuchThat has to be a func, but is string") constGen("sample").SuchThat("not a function") } func TestGenSuchTooManyParams(t *testing.T) { defer expectPanic(t, "Param of SuchThat has to be a func with one param, but is 2") constGen("sample").SuchThat(func(a, b string) bool { return false }) } func TestGenSuchThatToInvalidParamtype(t *testing.T) { defer expectPanic(t, "Param of SuchThat has to be a func with one param assignable to string, but is int") constGen("sample").SuchThat(func(a int) bool { return false }) } func TestGenSuchToManyReturns(t *testing.T) { defer expectPanic(t, "Param of SuchThat has to be a func with one return value, but is 2") constGen("sample").SuchThat(func(a string) (string, bool) { return "", false }) } func TestGenSuchToInvalidReturns(t *testing.T) { defer expectPanic(t, "Param of SuchThat has to be a func with one return value of bool, but is string") constGen("sample").SuchThat(func(a string) string { return "" }) } func TestWithShrinker(t *testing.T) { var shrinkerArg interface{} shrinker := func(v interface{}) gopter.Shrink { shrinkerArg = v return gopter.NoShrink } gen := constGen("sample").WithShrinker(shrinker) result := gen(gopter.DefaultGenParameters()) value, ok := result.Retrieve() if !ok { t.Errorf("Invalid combined value: %#v", value) } result.Shrinker(value) if shrinkerArg != "sample" { t.Errorf("Invalid shrinkerArg: %#v", shrinkerArg) } mapper := func(v string) string { return "other" } result = gen.Map(mapper)(gopter.DefaultGenParameters()) value, ok = result.Retrieve() if !ok { t.Errorf("Invalid combined value: %#v", value) } result.Shrinker(value) if shrinkerArg != "other" { t.Errorf("Shrinker was lost during Map when the in and out types were the same") } } func expectPanic(t *testing.T, expected string) { r := recover() if r == nil { t.Errorf("The code did not panic") } else if r.(string) != expected { t.Errorf("Panic does not match: '%#v' != '%#v'", r, expected) } } gopter-0.2.11/go.mod000066400000000000000000000001521460324054500142020ustar00rootroot00000000000000module github.com/leanovate/gopter go 1.12 require github.com/smartystreets/goconvey v1.8.1 // indirect gopter-0.2.11/go.sum000066400000000000000000001655051460324054500142450ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= gopter-0.2.11/locked_source.go000066400000000000000000000031411460324054500162450ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Taken from golang lockedSource implementation https://github.com/golang/go/blob/master/src/math/rand/rand.go#L371-L410 package gopter import ( "math/rand" "sync" ) type lockedSource struct { lk sync.Mutex src rand.Source64 } // NewLockedSource takes a seed and returns a new // lockedSource for use with rand.New func NewLockedSource(seed int64) *lockedSource { return &lockedSource{ src: rand.NewSource(seed).(rand.Source64), } } func (r *lockedSource) Int63() (n int64) { r.lk.Lock() n = r.src.Int63() r.lk.Unlock() return } func (r *lockedSource) Uint64() (n uint64) { r.lk.Lock() n = r.src.Uint64() r.lk.Unlock() return } func (r *lockedSource) Seed(seed int64) { r.lk.Lock() r.src.Seed(seed) r.lk.Unlock() } // seedPos implements Seed for a lockedSource without a race condition. func (r *lockedSource) seedPos(seed int64, readPos *int8) { r.lk.Lock() r.src.Seed(seed) *readPos = 0 r.lk.Unlock() } // read implements Read for a lockedSource without a race condition. func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) { r.lk.Lock() n, err = read(p, r.src.Int63, readVal, readPos) r.lk.Unlock() return } func read(p []byte, int63 func() int64, readVal *int64, readPos *int8) (n int, err error) { pos := *readPos val := *readVal for n = 0; n < len(p); n++ { if pos == 0 { val = int63() pos = 7 } p[n] = byte(val) val >>= 8 pos-- } *readPos = pos *readVal = val return } gopter-0.2.11/prop.go000066400000000000000000000053361460324054500144140ustar00rootroot00000000000000package gopter import ( "fmt" "math" "runtime/debug" ) // Prop represent some kind of property that (drums please) can and should be checked type Prop func(*GenParameters) *PropResult // SaveProp creates s save property by handling all panics from an inner property func SaveProp(prop Prop) Prop { return func(genParams *GenParameters) (result *PropResult) { defer func() { if r := recover(); r != nil { result = &PropResult{ Status: PropError, Error: fmt.Errorf("Check paniced: %v", r), ErrorStack: debug.Stack(), } } }() return prop(genParams) } } // Check the property using specific parameters func (prop Prop) Check(parameters *TestParameters) *TestResult { iterations := math.Ceil(float64(parameters.MinSuccessfulTests) / float64(parameters.Workers)) sizeStep := float64(parameters.MaxSize-parameters.MinSize) / (iterations * float64(parameters.Workers)) genParameters := GenParameters{ MinSize: parameters.MinSize, MaxSize: parameters.MaxSize, MaxShrinkCount: parameters.MaxShrinkCount, Rng: parameters.Rng, } runner := &runner{ parameters: parameters, worker: func(workerIdx int, shouldStop shouldStop) *TestResult { var n int var d int isExhaused := func() bool { return n+d > parameters.MinSuccessfulTests && 1.0+float64(parameters.Workers*n)*parameters.MaxDiscardRatio < float64(d) } for !shouldStop() && n < int(iterations) { size := float64(parameters.MinSize) + (sizeStep * float64(workerIdx+(parameters.Workers*(n+d)))) propResult := prop(genParameters.WithSize(int(size))) switch propResult.Status { case PropUndecided: d++ if isExhaused() { return &TestResult{ Status: TestExhausted, Succeeded: n, Discarded: d, } } case PropTrue: n++ case PropProof: n++ return &TestResult{ Status: TestProved, Succeeded: n, Discarded: d, Labels: propResult.Labels, Args: propResult.Args, } case PropFalse: return &TestResult{ Status: TestFailed, Succeeded: n, Discarded: d, Labels: propResult.Labels, Args: propResult.Args, } case PropError: return &TestResult{ Status: TestError, Succeeded: n, Discarded: d, Labels: propResult.Labels, Error: propResult.Error, ErrorStack: propResult.ErrorStack, Args: propResult.Args, } } } if isExhaused() { return &TestResult{ Status: TestExhausted, Succeeded: n, Discarded: d, } } return &TestResult{ Status: TestPassed, Succeeded: n, Discarded: d, } }, } return runner.runWorkers() } gopter-0.2.11/prop/000077500000000000000000000000001460324054500140565ustar00rootroot00000000000000gopter-0.2.11/prop/check_condition_func.go000066400000000000000000000032011460324054500205370ustar00rootroot00000000000000package prop import ( "errors" "fmt" "reflect" "runtime/debug" "github.com/leanovate/gopter" ) func checkConditionFunc(check interface{}, numArgs int) (func([]reflect.Value) *gopter.PropResult, error) { checkVal := reflect.ValueOf(check) checkType := checkVal.Type() if checkType.Kind() != reflect.Func { return nil, fmt.Errorf("First param of ForrAll has to be a func: %v", checkVal.Kind()) } if checkType.NumIn() != numArgs { return nil, fmt.Errorf("Number of parameters does not match number of generators: %d != %d", checkType.NumIn(), numArgs) } if checkType.NumOut() == 0 { return nil, errors.New("At least one output parameters is required") } else if checkType.NumOut() > 2 { return nil, fmt.Errorf("No more than 2 output parameters are allowed: %d", checkType.NumOut()) } else if checkType.NumOut() == 2 && !checkType.Out(1).Implements(typeOfError) { return nil, fmt.Errorf("No 2 output has to be error: %v", checkType.Out(1).Kind()) } else if checkType.NumOut() == 2 { return func(values []reflect.Value) *gopter.PropResult { results := checkVal.Call(values) if results[1].IsNil() { return convertResult(results[0].Interface(), nil) } return convertResult(results[0].Interface(), results[1].Interface().(error)) }, nil } return func(values []reflect.Value) (result *gopter.PropResult) { defer func() { if r := recover(); r != nil { result = &gopter.PropResult{ Status: gopter.PropError, Error: fmt.Errorf("Check paniced: %v", r), ErrorStack: debug.Stack(), } } }() results := checkVal.Call(values) return convertResult(results[0].Interface(), nil) }, nil } gopter-0.2.11/prop/check_condition_func_test.go000066400000000000000000000024401460324054500216020ustar00rootroot00000000000000package prop import ( "reflect" "testing" ) func TestCheckCondition(t *testing.T) { call, err := checkConditionFunc(0, 0) if err == nil || call != nil { t.Error("Should not work for integers") } call, err = checkConditionFunc(func(a, b int) bool { return false }, 1) if err == nil || call != nil { t.Error("Should not work with wrong number of arguments") } call, err = checkConditionFunc(func(a, b int) { }, 2) if err == nil || call != nil { t.Error("Should not work witout return") } call, err = checkConditionFunc(func(a, b int) (int, int, int) { return 0, 0, 0 }, 2) if err == nil || call != nil { t.Error("Should not work with too many return") } call, err = checkConditionFunc(func(a, b int) (int, int) { return 0, 0 }, 2) if err == nil || call != nil { t.Error("Should not work if second return is not an error") } var calledA, calledB int call, err = checkConditionFunc(func(a, b int) bool { calledA = a calledB = b return true }, 2) if err != nil || call == nil { t.Error("Should work") } result := call([]reflect.Value{ reflect.ValueOf(123), reflect.ValueOf(456), }) if calledA != 123 || calledB != 456 { t.Errorf("Invalid parameters: %d, %d", calledA, calledB) } if !result.Success() { t.Errorf("Invalid result: %#v", result) } } gopter-0.2.11/prop/convert_result.go000066400000000000000000000014261460324054500174660ustar00rootroot00000000000000package prop import ( "fmt" "github.com/leanovate/gopter" ) func convertResult(result interface{}, err error) *gopter.PropResult { if err != nil { return &gopter.PropResult{ Status: gopter.PropError, Error: err, } } switch result.(type) { case bool: if result.(bool) { return &gopter.PropResult{Status: gopter.PropTrue} } return &gopter.PropResult{Status: gopter.PropFalse} case string: if result.(string) == "" { return &gopter.PropResult{Status: gopter.PropTrue} } return &gopter.PropResult{ Status: gopter.PropFalse, Labels: []string{result.(string)}, } case *gopter.PropResult: return result.(*gopter.PropResult) } return &gopter.PropResult{ Status: gopter.PropError, Error: fmt.Errorf("Invalid check result: %#v", result), } } gopter-0.2.11/prop/convert_result_test.go000066400000000000000000000030601460324054500205210ustar00rootroot00000000000000package prop import ( "errors" "reflect" "testing" "github.com/leanovate/gopter" ) func TestConvertResult(t *testing.T) { trueResult := convertResult(true, nil) if trueResult.Status != gopter.PropTrue || trueResult.Error != nil { t.Errorf("Invalid true result: %#v", trueResult) } falseResult := convertResult(false, nil) if falseResult.Status != gopter.PropFalse || falseResult.Error != nil { t.Errorf("Invalid false result: %#v", falseResult) } stringTrueResult := convertResult("", nil) if stringTrueResult.Status != gopter.PropTrue || stringTrueResult.Error != nil { t.Errorf("Invalid string true result: %#v", stringTrueResult) } stringFalseResult := convertResult("Something is wrong", nil) if stringFalseResult.Status != gopter.PropFalse || stringFalseResult.Error != nil || !reflect.DeepEqual(stringFalseResult.Labels, []string{"Something is wrong"}) { t.Errorf("Invalid string false result: %#v", stringFalseResult) } errorResult := convertResult("Anthing", errors.New("Booom")) if errorResult.Status != gopter.PropError || errorResult.Error == nil || errorResult.Error.Error() != "Booom" { t.Errorf("Invalid error result: %#v", errorResult) } propResult := convertResult(&gopter.PropResult{ Status: gopter.PropProof, }, nil) if propResult.Status != gopter.PropProof || propResult.Error != nil { t.Errorf("Invalid prop result: %#v", propResult) } invalidResult := convertResult(0, nil) if invalidResult.Status != gopter.PropError || invalidResult.Error == nil { t.Errorf("Invalid prop result: %#v", invalidResult) } } gopter-0.2.11/prop/doc.go000066400000000000000000000001331460324054500151470ustar00rootroot00000000000000/* Package prop contains the most common implementations of a gopter.Prop. */ package prop gopter-0.2.11/prop/error.go000066400000000000000000000005641460324054500155430ustar00rootroot00000000000000package prop import "github.com/leanovate/gopter" // ErrorProp creates a property that will always fail with an error. // Mostly used as a fallback when setup/initialization fails func ErrorProp(err error) gopter.Prop { return func(genParams *gopter.GenParameters) *gopter.PropResult { return &gopter.PropResult{ Status: gopter.PropError, Error: err, } } } gopter-0.2.11/prop/error_test.go000066400000000000000000000006161460324054500166000ustar00rootroot00000000000000package prop_test import ( "errors" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) func TestErrorProp(t *testing.T) { p := prop.ErrorProp(errors.New("Booom")) result := p(gopter.DefaultGenParameters()) if result.Status != gopter.PropError || result.Error == nil || result.Error.Error() != "Booom" { t.Errorf("Invalid error prop result: %#v", result) } } gopter-0.2.11/prop/example_invalidconcat_test.go000066400000000000000000000021431460324054500217750ustar00rootroot00000000000000package prop_test import ( "strings" "unicode" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func MisimplementedConcat(a, b string) string { if strings.IndexFunc(a, unicode.IsDigit) > 5 { return b } return a + b } // Example_invalidconcat demonstrates shrinking of string // Kudos to @exarkun and @itamarst for finding this issue func Example_invalidconcat() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice properties := gopter.NewProperties(parameters) properties.Property("length is sum of lengths", prop.ForAll( func(a, b string) bool { return MisimplementedConcat(a, b) == a+b }, gen.Identifier(), gen.Identifier(), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! length is sum of lengths: Falsified after 17 passed tests. // ARG_0: bahbxh6 // ARG_0_ORIGINAL (2 shrinks): pkpbahbxh6 // ARG_1: l // ARG_1_ORIGINAL (1 shrinks): dl } gopter-0.2.11/prop/example_quadratic_test.go000066400000000000000000000034411460324054500211360ustar00rootroot00000000000000package prop_test import ( "errors" "math" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func solveQuadratic(a, b, c float64) (float64, float64, error) { if a == 0 { return 0, 0, errors.New("No solution") } v := b*b - 4*a*c if v < 0 { return 0, 0, errors.New("No solution") } v = math.Sqrt(v) return (-b + v) / 2 / a, (-b - v) / 2 / a, nil } func Example_quadratic() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice properties := gopter.NewProperties(parameters) properties.Property("solve quadratic", prop.ForAll( func(a, b, c float64) bool { x1, x2, err := solveQuadratic(a, b, c) if err != nil { return true } return math.Abs(a*x1*x1+b*x1+c) < 1e-5 && math.Abs(a*x2*x2+b*x2+c) < 1e-5 }, gen.Float64(), gen.Float64(), gen.Float64(), )) properties.Property("solve quadratic with resonable ranges", prop.ForAll( func(a, b, c float64) bool { x1, x2, err := solveQuadratic(a, b, c) if err != nil { return true } return math.Abs(a*x1*x1+b*x1+c) < 1e-5 && math.Abs(a*x2*x2+b*x2+c) < 1e-5 }, gen.Float64Range(-1e8, 1e8), gen.Float64Range(-1e8, 1e8), gen.Float64Range(-1e8, 1e8), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! solve quadratic: Falsified after 0 passed tests. // ARG_0: -1.4667384313385178e-05 // ARG_0_ORIGINAL (187 shrinks): -1.0960555181801604e+51 // ARG_1: 0 // ARG_1_ORIGINAL (1 shrinks): -1.1203884793568249e+96 // ARG_2: 6.481285637227244e+10 // ARG_2_ORIGINAL (905 shrinks): 1.512647219322138e+281 // + solve quadratic with resonable ranges: OK, passed 100 tests. } gopter-0.2.11/prop/example_shrink_test.go000066400000000000000000000017151460324054500204610ustar00rootroot00000000000000package prop_test import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func Example_shrink() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice properties := gopter.NewProperties(parameters) properties.Property("fail above 100", prop.ForAll( func(arg int64) bool { return arg <= 100 }, gen.Int64(), )) properties.Property("fail above 100 no shrink", prop.ForAllNoShrink( func(arg int64) bool { return arg <= 100 }, gen.Int64(), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) // Output: // ! fail above 100: Falsified after 0 passed tests. // ARG_0: 101 // ARG_0_ORIGINAL (56 shrinks): 2041104533947223744 // ! fail above 100 no shrink: Falsified after 0 passed tests. // ARG_0: 6006156956070140861 } gopter-0.2.11/prop/example_time_test.go000066400000000000000000000034751460324054500201260ustar00rootroot00000000000000package prop_test import ( "time" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func Example_timeGen() { parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice time.Local = time.UTC // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("time in range format parsable", prop.ForAll( func(actual time.Time) (bool, error) { str := actual.Format(time.RFC3339Nano) parsed, err := time.Parse(time.RFC3339Nano, str) return actual.Equal(parsed), err }, gen.TimeRange(time.Now(), time.Duration(100*24*365)*time.Hour), )) properties.Property("regular time format parsable", prop.ForAll( func(actual time.Time) (bool, error) { str := actual.Format(time.RFC3339Nano) parsed, err := time.Parse(time.RFC3339Nano, str) return actual.Equal(parsed), err }, gen.Time(), )) properties.Property("any time format parsable", prop.ForAll( func(actual time.Time) (bool, error) { str := actual.Format(time.RFC3339Nano) parsed, err := time.Parse(time.RFC3339Nano, str) return actual.Equal(parsed), err }, gen.AnyTime(), )) properties.Run(gopter.ConsoleReporter(false)) // Output: // + time in range format parsable: OK, passed 100 tests. // + regular time format parsable: OK, passed 100 tests. // ! any time format parsable: Error on property evaluation after 0 passed // tests: parsing time "10000-01-01T00:00:00Z" as // "2006-01-02T15:04:05.999999999Z07:00": cannot parse "0-01-01T00:00:00Z" // as "-" // ARG_0: 10000-01-01 00:00:00 +0000 UTC // ARG_0_ORIGINAL (45 shrinks): 237903042092-02-10 19:15:18.148265469 +0000 // UTC } gopter-0.2.11/prop/forall.go000066400000000000000000000103041460324054500156620ustar00rootroot00000000000000package prop import ( "fmt" "reflect" "github.com/leanovate/gopter" ) var typeOfError = reflect.TypeOf((*error)(nil)).Elem() /* ForAll creates a property that requires the check condition to be true for all values, if the condition falsiies the generated values will be shrunk. "condition" has to be a function with the same number of parameters as the provided generators "gens". The function may return a simple bool (true means that the condition has passed), a string (empty string means that condition has passed), a *PropResult, or one of former combined with an error. */ func ForAll(condition interface{}, gens ...gopter.Gen) gopter.Prop { callCheck, err := checkConditionFunc(condition, len(gens)) if err != nil { return ErrorProp(err) } return gopter.SaveProp(func(genParams *gopter.GenParameters) *gopter.PropResult { genResults := make([]*gopter.GenResult, len(gens)) values := make([]reflect.Value, len(gens)) valuesFormated := make([]string, len(gens)) var ok bool for i, gen := range gens { result := gen(genParams) genResults[i] = result values[i], ok = result.RetrieveAsValue() if !ok { return &gopter.PropResult{ Status: gopter.PropUndecided, } } valuesFormated[i] = fmt.Sprintf("%+v", values[i].Interface()) } result := callCheck(values) if result.Success() { for i, genResult := range genResults { result = result.AddArgs(gopter.NewPropArg(genResult, 0, values[i].Interface(), valuesFormated[i], values[i].Interface(), valuesFormated[i])) } } else { for i, genResult := range genResults { nextResult, nextValue := shrinkValue(genParams.MaxShrinkCount, genResult, values[i].Interface(), valuesFormated[i], result, func(v interface{}) *gopter.PropResult { shrunkOne := make([]reflect.Value, len(values)) copy(shrunkOne, values) if v == nil { shrunkOne[i] = reflect.Zero(values[i].Type()) } else { shrunkOne[i] = reflect.ValueOf(v) } return callCheck(shrunkOne) }) result = nextResult if nextValue == nil { values[i] = reflect.Zero(values[i].Type()) } else { values[i] = reflect.ValueOf(nextValue) } } } return result }) } // ForAll1 legacy interface to be removed in the future func ForAll1(gen gopter.Gen, check func(v interface{}) (interface{}, error)) gopter.Prop { checkFunc := func(v interface{}) *gopter.PropResult { return convertResult(check(v)) } return gopter.SaveProp(func(genParams *gopter.GenParameters) *gopter.PropResult { genResult := gen(genParams) value, ok := genResult.Retrieve() if !ok { return &gopter.PropResult{ Status: gopter.PropUndecided, } } valueFormated := fmt.Sprintf("%+v", value) result := checkFunc(value) if result.Success() { return result.AddArgs(gopter.NewPropArg(genResult, 0, value, valueFormated, value, valueFormated)) } result, _ = shrinkValue(genParams.MaxShrinkCount, genResult, value, valueFormated, result, checkFunc) return result }) } func shrinkValue(maxShrinkCount int, genResult *gopter.GenResult, origValue interface{}, orgiValueFormated string, firstFail *gopter.PropResult, check func(interface{}) *gopter.PropResult) (*gopter.PropResult, interface{}) { lastFail := firstFail lastValue := origValue lastValueFormated := orgiValueFormated shrinks := 0 shrink := genResult.Shrinker(lastValue).Filter(genResult.Sieve) nextResult, nextValue, nextValueFormated := firstFailure(shrink, check) for nextResult != nil && shrinks < maxShrinkCount { shrinks++ lastValue = nextValue lastValueFormated = nextValueFormated lastFail = nextResult shrink = genResult.Shrinker(lastValue).Filter(genResult.Sieve) nextResult, nextValue, nextValueFormated = firstFailure(shrink, check) } return lastFail.WithArgs(firstFail.Args).AddArgs(gopter.NewPropArg(genResult, shrinks, lastValue, lastValueFormated, origValue, orgiValueFormated)), lastValue } func firstFailure(shrink gopter.Shrink, check func(interface{}) *gopter.PropResult) (*gopter.PropResult, interface{}, string) { value, ok := shrink() for ok { valueFormated := fmt.Sprintf("%+v", value) result := check(value) if !result.Success() { return result, value, valueFormated } value, ok = shrink() } return nil, nil, "" } gopter-0.2.11/prop/forall_no_shrink.go000066400000000000000000000042351460324054500177420ustar00rootroot00000000000000package prop import ( "fmt" "reflect" "github.com/leanovate/gopter" ) /* ForAllNoShrink creates a property that requires the check condition to be true for all values. As the name suggests the generated values will not be shrunk if the condition falsiies. "condition" has to be a function with the same number of parameters as the provided generators "gens". The function may return a simple bool (true means that the condition has passed), a string (empty string means that condition has passed), a *PropResult, or one of former combined with an error. */ func ForAllNoShrink(condition interface{}, gens ...gopter.Gen) gopter.Prop { callCheck, err := checkConditionFunc(condition, len(gens)) if err != nil { return ErrorProp(err) } return gopter.SaveProp(func(genParams *gopter.GenParameters) *gopter.PropResult { genResults := make([]*gopter.GenResult, len(gens)) values := make([]reflect.Value, len(gens)) valuesFormated := make([]string, len(gens)) var ok bool for i, gen := range gens { result := gen(genParams) genResults[i] = result values[i], ok = result.RetrieveAsValue() if !ok { return &gopter.PropResult{ Status: gopter.PropUndecided, } } valuesFormated[i] = fmt.Sprintf("%+v", values[i].Interface()) } result := callCheck(values) for i, genResult := range genResults { result = result.AddArgs(gopter.NewPropArg(genResult, 0, values[i].Interface(), valuesFormated[i], values[i].Interface(), valuesFormated[i])) } return result }) } // ForAllNoShrink1 creates a property that requires the check condition to be true for all values // As the name suggests the generated values will not be shrunk if the condition falsiies func ForAllNoShrink1(gen gopter.Gen, check func(interface{}) (interface{}, error)) gopter.Prop { return gopter.SaveProp(func(genParams *gopter.GenParameters) *gopter.PropResult { genResult := gen(genParams) value, ok := genResult.Retrieve() if !ok { return &gopter.PropResult{ Status: gopter.PropUndecided, } } valueFormated := fmt.Sprintf("%+v", value) return convertResult(check(value)).AddArgs(gopter.NewPropArg(genResult, 0, value, valueFormated, value, valueFormated)) }) } gopter-0.2.11/prop/forall_no_shrink_test.go000066400000000000000000000026431460324054500210020ustar00rootroot00000000000000package prop_test import ( "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func TestForAllNoShrink(t *testing.T) { parameters := gopter.DefaultTestParameters() simpleForAll := prop.ForAllNoShrink1( gen.Const("const value"), func(value interface{}) (interface{}, error) { return value.(string) == "const value", nil }, ) simpleResult := simpleForAll.Check(parameters) if simpleResult.Status != gopter.TestPassed || simpleResult.Succeeded != parameters.MinSuccessfulTests { t.Errorf("Invalid simpleResult: %#v", simpleResult) } simpleForAllFail := prop.ForAllNoShrink1( gen.Const("const value"), func(value interface{}) (interface{}, error) { return value.(string) != "const value", nil }, ) simpleResultFail := simpleForAllFail.Check(parameters) if simpleResultFail.Status != gopter.TestFailed || simpleResultFail.Succeeded != 0 { t.Errorf("Invalid simpleResultFail: %#v", simpleResultFail) } fail := prop.ForAllNoShrink(0) result := fail(gopter.DefaultGenParameters()) if result.Status != gopter.PropError { t.Errorf("Invalid result: %#v", result) } undecided := prop.ForAllNoShrink(func(a int) bool { return true }, gen.Int().SuchThat(func(interface{}) bool { return false })) result = undecided(gopter.DefaultGenParameters()) if result.Status != gopter.PropUndecided { t.Errorf("Invalid result: %#v", result) } } gopter-0.2.11/prop/forall_test.go000066400000000000000000000027541460324054500167330ustar00rootroot00000000000000package prop_test import ( "math" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func TestSqrt(t *testing.T) { properties := gopter.NewProperties(nil) properties.Property("greater one of all greater one", prop.ForAll( func(v float64) bool { return math.Sqrt(v) >= 1 }, gen.Float64Range(1, math.MaxFloat64), )) properties.Property("greater one of all greater one alternative", prop.ForAll1( gen.Float64Range(1, math.MaxFloat64), func(v interface{}) (interface{}, error) { return math.Sqrt(v.(float64)) >= 1, nil }, )) properties.Property("squared is equal to value", prop.ForAll( func(v float64) bool { r := math.Sqrt(v) return math.Abs(r*r-v) < 1e-10*v }, gen.Float64Range(0, math.MaxFloat64), )) properties.Property("squared is equal to value alternative", prop.ForAll1( gen.Float64Range(0, math.MaxFloat64), func(v interface{}) (interface{}, error) { s := v.(float64) r := math.Sqrt(s) return math.Abs(r*r-s) < 1e-10*s, nil }, )) properties.TestingRun(t) fail := prop.ForAll(0) result := fail(gopter.DefaultGenParameters()) if result.Status != gopter.PropError { t.Errorf("Invalid result: %#v", result) } undecided := prop.ForAll(func(a int) bool { return true }, gen.Int().SuchThat(func(interface{}) bool { return false })) result = undecided(gopter.DefaultGenParameters()) if result.Status != gopter.PropUndecided { t.Errorf("Invalid result: %#v", result) } } gopter-0.2.11/prop_arg.go000066400000000000000000000016631460324054500152440ustar00rootroot00000000000000package gopter import ( "fmt" "strings" ) // PropArg contains information about the specific values for a certain property check. // This is mostly used for reporting when a property has falsified. type PropArg struct { Arg interface{} ArgFormatted string OrigArg interface{} OrigArgFormatted string Label string Shrinks int } func (p *PropArg) String() string { return fmt.Sprintf("%v", p.Arg) } // PropArgs is a list of PropArg. type PropArgs []*PropArg // NewPropArg creates a new PropArg. func NewPropArg(genResult *GenResult, shrinks int, value interface{}, valueFormated string, origValue interface{}, origValueFormated string) *PropArg { return &PropArg{ Label: strings.Join(genResult.Labels, ", "), Arg: value, ArgFormatted: valueFormated, OrigArg: origValue, OrigArgFormatted: origValueFormated, Shrinks: shrinks, } } gopter-0.2.11/prop_arg_test.go000066400000000000000000000007301460324054500162750ustar00rootroot00000000000000package gopter_test import ( "testing" "github.com/leanovate/gopter" ) func TestPropArg(t *testing.T) { gen := constGen("nothing").WithLabel("Label1").WithLabel("Label2") prop := gopter.NewPropArg(gen(gopter.DefaultGenParameters()), 1, "nothing", "nothing", "nothing", "nothing") if prop.Label != "Label1, Label2" { t.Errorf("Invalid prop.Label: %#v", prop.Label) } if prop.String() != "nothing" { t.Errorf("Invalid prop.Stirng(): %#v", prop.String()) } } gopter-0.2.11/prop_result.go000066400000000000000000000052521460324054500160070ustar00rootroot00000000000000package gopter type propStatus int const ( // PropProof THe property was proved (i.e. it is known to be correct and will be always true) PropProof propStatus = iota // PropTrue The property was true this time PropTrue // PropFalse The property was false this time PropFalse // PropUndecided The property has no clear outcome this time PropUndecided // PropError The property has generated an error PropError ) func (s propStatus) String() string { switch s { case PropProof: return "PROOF" case PropTrue: return "TRUE" case PropFalse: return "FALSE" case PropUndecided: return "UNDECIDED" case PropError: return "ERROR" } return "" } // PropResult contains the result of a property type PropResult struct { Status propStatus Error error ErrorStack []byte Args []*PropArg Labels []string } // NewPropResult create a PropResult with label func NewPropResult(success bool, label string) *PropResult { if success { return &PropResult{ Status: PropTrue, Labels: []string{label}, Args: make([]*PropArg, 0), } } return &PropResult{ Status: PropFalse, Labels: []string{label}, Args: make([]*PropArg, 0), } } // Success checks if the result was successful func (r *PropResult) Success() bool { return r.Status == PropTrue || r.Status == PropProof } // WithArgs sets argument descriptors to the PropResult for reporting func (r *PropResult) WithArgs(args []*PropArg) *PropResult { r.Args = args return r } // AddArgs add argument descriptors to the PropResult for reporting func (r *PropResult) AddArgs(args ...*PropArg) *PropResult { r.Args = append(r.Args, args...) return r } // And combines two PropResult by an and operation. // The resulting PropResult will be only true if both PropResults are true. func (r *PropResult) And(other *PropResult) *PropResult { switch { case r.Status == PropError: return r case other.Status == PropError: return other case r.Status == PropFalse: return r case other.Status == PropFalse: return other case r.Status == PropUndecided: return r case other.Status == PropUndecided: return other case r.Status == PropProof: return r.mergeWith(other, other.Status) case other.Status == PropProof: return r.mergeWith(other, r.Status) case r.Status == PropTrue && other.Status == PropTrue: return r.mergeWith(other, PropTrue) default: return r } } func (r *PropResult) mergeWith(other *PropResult, status propStatus) *PropResult { return &PropResult{ Status: status, Args: append(append(make([]*PropArg, 0, len(r.Args)+len(other.Args)), r.Args...), other.Args...), Labels: append(append(make([]string, 0, len(r.Labels)+len(other.Labels)), r.Labels...), other.Labels...), } } gopter-0.2.11/prop_result_test.go000066400000000000000000000050061460324054500170430ustar00rootroot00000000000000package gopter_test import ( "testing" "github.com/leanovate/gopter" ) func TestPropResult(t *testing.T) { result := &gopter.PropResult{Status: gopter.PropProof} if !result.Success() || result.Status.String() != "PROOF" { t.Errorf("Invalid status: %#v", result) } other := &gopter.PropResult{Status: gopter.PropTrue} if !result.And(other).Success() || result.And(other).Status.String() != "TRUE" { t.Errorf("Invalid combined state: %#v", result.And(other)) } if !other.And(result).Success() || other.And(result).Status.String() != "TRUE" { t.Errorf("Invalid combined state: %#v", other.And(result)) } result = &gopter.PropResult{Status: gopter.PropTrue} if !result.Success() || result.Status.String() != "TRUE" { t.Errorf("Invalid status: %#v", result) } if !result.And(other).Success() || result.And(other).Status.String() != "TRUE" { t.Errorf("Invalid combined state: %#v", result.And(other)) } if !other.And(result).Success() || other.And(result).Status.String() != "TRUE" { t.Errorf("Invalid combined state: %#v", other.And(result)) } result = &gopter.PropResult{Status: gopter.PropFalse} if result.Success() || result.Status.String() != "FALSE" { t.Errorf("Invalid status: %#v", result) } if result.And(other) != result { t.Errorf("Invalid combined state: %#v", result.And(other)) } if other.And(result) != result { t.Errorf("Invalid combined state: %#v", other.And(result)) } result = &gopter.PropResult{Status: gopter.PropUndecided} if result.Success() || result.Status.String() != "UNDECIDED" { t.Errorf("Invalid status: %#v", result) } if result.And(other) != result { t.Errorf("Invalid combined state: %#v", result.And(other)) } if other.And(result) != result { t.Errorf("Invalid combined state: %#v", other.And(result)) } result = &gopter.PropResult{Status: gopter.PropError} if result.Success() || result.Status.String() != "ERROR" { t.Errorf("Invalid status: %#v", result) } if result.And(other) != result { t.Errorf("Invalid combined state: %#v", result.And(other)) } if other.And(result) != result { t.Errorf("Invalid combined state: %#v", other.And(result)) } } func TestNewPropResult(t *testing.T) { trueResult := gopter.NewPropResult(true, "label") if trueResult.Status != gopter.PropTrue || trueResult.Labels[0] != "label" { t.Errorf("Invalid trueResult: %#v", trueResult) } falseResult := gopter.NewPropResult(false, "label") if falseResult.Status != gopter.PropFalse || falseResult.Labels[0] != "label" { t.Errorf("Invalid falseResult: %#v", falseResult) } } gopter-0.2.11/prop_test.go000066400000000000000000000075371460324054500154600ustar00rootroot00000000000000package gopter import ( "strings" "sync/atomic" "testing" ) func TestSaveProp(t *testing.T) { prop := SaveProp(func(*GenParameters) *PropResult { panic("Ouchy") }) parameters := DefaultTestParameters() result := prop.Check(parameters) if result.Status != TestError || result.Error == nil || !strings.HasPrefix(result.Error.Error(), "Check paniced: Ouchy") { t.Errorf("Invalid result: %#v", result) } } func TestPropUndecided(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) return &PropResult{ Status: PropUndecided, } }) parameters := DefaultTestParameters() result := prop.Check(parameters) if result.Status != TestExhausted || result.Succeeded != 0 { t.Errorf("Invalid result: %#v", result) } if called != int64(parameters.MinSuccessfulTests)+1 { t.Errorf("Invalid number of calls: %d", called) } } func TestPropMaxDiscardRatio(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) if genParams.MaxSize > 21 { return &PropResult{ Status: PropTrue, } } return &PropResult{ Status: PropUndecided, } }) parameters := DefaultTestParameters() parameters.MaxDiscardRatio = 0.2 result := prop.Check(parameters) if result.Status != TestExhausted || result.Succeeded != 100 { t.Errorf("Invalid result: %#v", result) } if called != int64(parameters.MinSuccessfulTests)+22 { t.Errorf("Invalid number of calls: %d", called) } } func TestPropPassed(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) return &PropResult{ Status: PropTrue, } }) parameters := DefaultTestParameters() result := prop.Check(parameters) if result.Status != TestPassed || result.Succeeded != parameters.MinSuccessfulTests { t.Errorf("Invalid result: %#v", result) } if called != int64(parameters.MinSuccessfulTests) { t.Errorf("Invalid number of calls: %d", called) } } func TestPropProof(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) return &PropResult{ Status: PropProof, } }) parameters := DefaultTestParameters() result := prop.Check(parameters) if result.Status != TestProved || result.Succeeded != 1 { t.Errorf("Invalid result: %#v", result) } if called != 1 { t.Errorf("Invalid number of calls: %d", called) } } func TestPropFalse(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) return &PropResult{ Status: PropFalse, } }) parameters := DefaultTestParameters() result := prop.Check(parameters) if result.Status != TestFailed || result.Succeeded != 0 { t.Errorf("Invalid result: %#v", result) } if called != 1 { t.Errorf("Invalid number of calls: %d", called) } } func TestPropError(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) return &PropResult{ Status: PropError, } }) parameters := DefaultTestParameters() result := prop.Check(parameters) if result.Status != TestError || result.Succeeded != 0 { t.Errorf("Invalid result: %#v", result) } if called != 1 { t.Errorf("Invalid number of calls: %d", called) } } func TestPropPassedMulti(t *testing.T) { var called int64 prop := Prop(func(genParams *GenParameters) *PropResult { atomic.AddInt64(&called, 1) return &PropResult{ Status: PropTrue, } }) parameters := DefaultTestParameters() parameters.Workers = 10 result := prop.Check(parameters) if result.Status != TestPassed || result.Succeeded != parameters.MinSuccessfulTests { t.Errorf("Invalid result: %#v", result) } if called != int64(parameters.MinSuccessfulTests) { t.Errorf("Invalid number of calls: %d", called) } } gopter-0.2.11/properties.go000066400000000000000000000030101460324054500156130ustar00rootroot00000000000000package gopter import "testing" // Properties is a collection of properties that should be checked in a test type Properties struct { parameters *TestParameters props map[string]Prop propNames []string } // NewProperties create new Properties with given test parameters. // If parameters is nil default test parameters will be used func NewProperties(parameters *TestParameters) *Properties { if parameters == nil { parameters = DefaultTestParameters() } return &Properties{ parameters: parameters, props: make(map[string]Prop, 0), propNames: make([]string, 0), } } // Property add/defines a property in a test. func (p *Properties) Property(name string, prop Prop) { p.propNames = append(p.propNames, name) p.props[name] = prop } // Run checks all definied propertiesand reports the result func (p *Properties) Run(reporter Reporter) bool { success := true for _, propName := range p.propNames { prop := p.props[propName] result := prop.Check(p.parameters) reporter.ReportTestResult(propName, result) if !result.Passed() { success = false } } return success } // TestingRun checks all definied properties with a testing.T context. // This the preferred wait to run property tests as part of a go unit test. func (p *Properties) TestingRun(t *testing.T, opts ...interface{}) { reporter := ConsoleReporter(true) for _, opt := range opts { if r, ok := opt.(Reporter); ok { reporter = r } } if !p.Run(reporter) { t.Errorf("failed with initial seed: %d", p.parameters.Seed()) } } gopter-0.2.11/properties_test.go000066400000000000000000000016511460324054500166630ustar00rootroot00000000000000package gopter_test import ( "os" "testing" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func TestProperties(t *testing.T) { parameters := gopter.DefaultTestParameters() properties := gopter.NewProperties(parameters) properties.Property("always fail", prop.ForAll( func(v int32) bool { return false }, gen.Int32(), )) fakeT := &testing.T{} properties.TestingRun(fakeT) if !fakeT.Failed() { t.Errorf("fakeT has not failed") } } func TestPropertiesCustomReporter(t *testing.T) { parameters := gopter.DefaultTestParameters() properties := gopter.NewProperties(parameters) properties.Property("always fail", prop.ForAll( func(v int32) bool { return false }, gen.Int32(), )) fakeT := &testing.T{} properties.TestingRun(fakeT, gopter.NewFormatedReporter(true, 160, os.Stdout)) if !fakeT.Failed() { t.Errorf("fakeT has not failed") } } gopter-0.2.11/reporter.go000066400000000000000000000003551460324054500152720ustar00rootroot00000000000000package gopter // Reporter is a simple interface to report/format the results of a property check. type Reporter interface { // ReportTestResult reports a single property result ReportTestResult(propName string, result *TestResult) } gopter-0.2.11/runner.go000066400000000000000000000032311460324054500147350ustar00rootroot00000000000000package gopter import ( "sync" "time" ) type shouldStop func() bool type worker func(int, shouldStop) *TestResult type runner struct { sync.RWMutex parameters *TestParameters worker worker } func (r *runner) mergeCheckResults(r1, r2 *TestResult) *TestResult { var result TestResult switch { case r1 == nil: return r2 case r1.Status != TestPassed && r1.Status != TestExhausted: result = *r1 case r2.Status != TestPassed && r2.Status != TestExhausted: result = *r2 default: result.Status = TestExhausted if r1.Succeeded+r2.Succeeded >= r.parameters.MinSuccessfulTests && float64(r1.Discarded+r2.Discarded) <= float64(r1.Succeeded+r2.Succeeded)*r.parameters.MaxDiscardRatio { result.Status = TestPassed } } result.Succeeded = r1.Succeeded + r2.Succeeded result.Discarded = r1.Discarded + r2.Discarded return &result } func (r *runner) runWorkers() *TestResult { var stopFlag Flag defer stopFlag.Set() start := time.Now() if r.parameters.Workers < 2 { result := r.worker(0, stopFlag.Get) result.Time = time.Since(start) return result } var waitGroup sync.WaitGroup waitGroup.Add(r.parameters.Workers) results := make(chan *TestResult, r.parameters.Workers) combinedResult := make(chan *TestResult) go func() { var combined *TestResult for result := range results { combined = r.mergeCheckResults(combined, result) } combinedResult <- combined }() for i := 0; i < r.parameters.Workers; i++ { go func(workerIdx int) { defer waitGroup.Done() results <- r.worker(workerIdx, stopFlag.Get) }(i) } waitGroup.Wait() close(results) result := <-combinedResult result.Time = time.Since(start) return result } gopter-0.2.11/runner_test.go000066400000000000000000000071401460324054500157770ustar00rootroot00000000000000package gopter import ( "errors" "reflect" "testing" "time" ) func TestRunnerSingleWorker(t *testing.T) { parameters := DefaultTestParameters() testRunner := &runner{ parameters: parameters, worker: func(num int, shouldStop shouldStop) *TestResult { return &TestResult{ Status: TestPassed, Succeeded: 1, Discarded: 0, } }, } result := testRunner.runWorkers() if result.Status != TestPassed || result.Succeeded != 1 || result.Discarded != 0 { t.Errorf("Invalid result: %#v", result) } } func TestRunnerParallelWorkers(t *testing.T) { parameters := DefaultTestParameters() specs := []struct { workers int res []TestResult exp *TestResult wait []int }{ // Test all pass { workers: 50, res: []TestResult{ { Status: TestPassed, Succeeded: 10, Discarded: 1, }, }, exp: &TestResult{ Status: TestPassed, Succeeded: 500, Discarded: 50, }, }, // Test exhausted { workers: 50, res: []TestResult{ { Status: TestExhausted, Succeeded: 1, Discarded: 10, }, }, exp: &TestResult{ Status: TestExhausted, Succeeded: 50, Discarded: 500, }, }, // Test all fail { workers: 50, res: []TestResult{ { Status: TestFailed, Succeeded: 0, Discarded: 0, Labels: []string{"some label"}, Error: errors.New("invalid result 0 != 1"), }, }, exp: &TestResult{ Status: TestFailed, Succeeded: 0, Discarded: 0, Labels: []string{"some label"}, Error: errors.New("invalid result 0 != 1"), }, }, // a pass and failure { workers: 2, res: []TestResult{ { Status: TestPassed, Succeeded: 94, Discarded: 1, }, { Status: TestFailed, Succeeded: 4, Discarded: 3, Labels: []string{"some label"}, Error: errors.New("invalid result 0 != 2"), }, }, exp: &TestResult{ Status: TestFailed, Succeeded: 98, Discarded: 4, Labels: []string{"some label"}, Error: errors.New("invalid result 0 != 2"), }, wait: []int{1, 0}, }, // a pass and multiple failures (first failure returned) { workers: 3, res: []TestResult{ { Status: TestPassed, Succeeded: 94, Discarded: 1, }, { Status: TestFailed, Succeeded: 3, Discarded: 2, Labels: []string{"worker 1"}, Error: errors.New("worker 1 error"), }, { Status: TestFailed, Succeeded: 1, Discarded: 1, Labels: []string{"worker 2"}, Error: errors.New("worker 2 error"), }, }, exp: &TestResult{ Status: TestFailed, Succeeded: 98, Discarded: 4, Labels: []string{"worker 1"}, Error: errors.New("worker 1 error"), }, wait: []int{0, 1, 2}, }, } for specIdx, spec := range specs { parameters.Workers = spec.workers testRunner := &runner{ parameters: parameters, worker: func(num int, shouldStop shouldStop) *TestResult { if num < len(spec.wait) { time.Sleep(time.Duration(spec.wait[num]) * time.Second) } if num < len(spec.res) { return &spec.res[num] } return &spec.res[0] }, } result := testRunner.runWorkers() if result.Time < 0 { t.Errorf("[%d] expected result time to be positive number but got %s", specIdx, result.Time) } // This is not deterministic and // have validated above the time result.Time = 0 if !reflect.DeepEqual(result, spec.exp) { t.Errorf("[%d] expected test result %#v but got %#v", specIdx, spec.exp, result, ) } } } gopter-0.2.11/shrink.go000066400000000000000000000112231460324054500147220ustar00rootroot00000000000000package gopter import ( "fmt" "reflect" ) // Shrink is a stream of shrunk down values. // Once the result of a shrink is false, it is considered to be exhausted. // Important notes for implementors: // - Ensure that the returned stream is finite, even though shrinking will // eventually be aborted, infinite streams may result in very slow running // test. // - Ensure that modifications to the returned value will not affect the // internal state of your Shrink. If in doubt return by value not by reference type Shrink func() (interface{}, bool) // Filter creates a shrink filtered by a condition func (s Shrink) Filter(condition func(interface{}) bool) Shrink { if condition == nil { return s } return func() (interface{}, bool) { value, ok := s() for ok && !condition(value) { value, ok = s() } return value, ok } } // Map creates a shrink by applying a converter to each element of a shrink. // f: has to be a function with one parameter (matching the generated value) and a single return. func (s Shrink) Map(f interface{}) Shrink { mapperVal := reflect.ValueOf(f) mapperType := mapperVal.Type() if mapperVal.Kind() != reflect.Func { panic(fmt.Sprintf("Param of Map has to be a func, but is %v", mapperType.Kind())) } if mapperType.NumIn() != 1 { panic(fmt.Sprintf("Param of Map has to be a func with one param, but is %v", mapperType.NumIn())) } if mapperType.NumOut() != 1 { panic(fmt.Sprintf("Param of Map has to be a func with one return value, but is %v", mapperType.NumOut())) } return func() (interface{}, bool) { value, ok := s() if ok { return mapperVal.Call([]reflect.Value{reflect.ValueOf(value)})[0].Interface(), ok } return nil, false } } // All collects all shrinks as a slice. Use with care as this might create // large results depending on the complexity of the shrink func (s Shrink) All() []interface{} { result := []interface{}{} value, ok := s() for ok { result = append(result, value) value, ok = s() } return result } type concatedShrink struct { index int shrinks []Shrink } func (c *concatedShrink) Next() (interface{}, bool) { for c.index < len(c.shrinks) { value, ok := c.shrinks[c.index]() if ok { return value, ok } c.index++ } return nil, false } // ConcatShrinks concats an array of shrinks to a single shrinks func ConcatShrinks(shrinks ...Shrink) Shrink { concated := &concatedShrink{ index: 0, shrinks: shrinks, } return concated.Next } type interleaved struct { first Shrink second Shrink firstExhausted bool secondExhaused bool state bool } func (i *interleaved) Next() (interface{}, bool) { for !i.firstExhausted || !i.secondExhaused { i.state = !i.state if i.state && !i.firstExhausted { value, ok := i.first() if ok { return value, true } i.firstExhausted = true } else if !i.state && !i.secondExhaused { value, ok := i.second() if ok { return value, true } i.secondExhaused = true } } return nil, false } // Interleave this shrink with another // Both shrinks are expected to produce the same result func (s Shrink) Interleave(other Shrink) Shrink { interleaved := &interleaved{ first: s, second: other, } return interleaved.Next } // Shrinker creates a shrink for a given value type Shrinker func(value interface{}) Shrink type elementShrink struct { original []interface{} index int elementShrink Shrink } func (e *elementShrink) Next() (interface{}, bool) { element, ok := e.elementShrink() if !ok { return nil, false } shrunk := make([]interface{}, len(e.original)) copy(shrunk, e.original) shrunk[e.index] = element return shrunk, true } // CombineShrinker create a shrinker by combining a list of shrinkers. // The resulting shrinker will shrink an []interface{} where each element will be shrunk by // the corresonding shrinker in 'shrinkers'. // This method is implicitly used by CombineGens. func CombineShrinker(shrinkers ...Shrinker) Shrinker { return func(v interface{}) Shrink { values := v.([]interface{}) shrinks := make([]Shrink, 0, len(values)) for i, shrinker := range shrinkers { if i >= len(values) { break } shrink := &elementShrink{ original: values, index: i, elementShrink: shrinker(values[i]), } shrinks = append(shrinks, shrink.Next) } return ConcatShrinks(shrinks...) } } // NoShrink is an empty shrink. var NoShrink = Shrink(func() (interface{}, bool) { return nil, false }) // NoShrinker is a shrinker for NoShrink, i.e. a Shrinker that will not shrink any values. // This is the default Shrinker if none is provided. var NoShrinker = Shrinker(func(value interface{}) Shrink { return NoShrink }) gopter-0.2.11/shrink_test.go000066400000000000000000000074671460324054500160000ustar00rootroot00000000000000package gopter_test import ( "reflect" "testing" "github.com/leanovate/gopter" ) type counterShrink struct { n int } func (c *counterShrink) Next() (interface{}, bool) { if c.n > 0 { v := c.n c.n-- return v, true } return 0, false } func TestShinkAll(t *testing.T) { counter := &counterShrink{n: 10} shrink := gopter.Shrink(counter.Next) all := shrink.All() if !reflect.DeepEqual(all, []interface{}{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}) { t.Errorf("Invalid all: %#v", all) } } func TestShrinkFilter(t *testing.T) { counter := &counterShrink{n: 20} shrink := gopter.Shrink(counter.Next) all := shrink.Filter(func(v interface{}) bool { return v.(int)%2 == 0 }).All() if !reflect.DeepEqual(all, []interface{}{20, 18, 16, 14, 12, 10, 8, 6, 4, 2}) { t.Errorf("Invalid all: %#v", all) } counter = &counterShrink{n: 5} shrink = gopter.Shrink(counter.Next) all = shrink.Filter(nil).All() if !reflect.DeepEqual(all, []interface{}{5, 4, 3, 2, 1}) { t.Errorf("Invalid all: %#v", all) } } func TestShrinkConcat(t *testing.T) { counterShrink1 := &counterShrink{n: 5} counterShrink2 := &counterShrink{n: 4} shrink1 := gopter.Shrink(counterShrink1.Next) shrink2 := gopter.Shrink(counterShrink2.Next) all := gopter.ConcatShrinks(shrink1, shrink2).All() if !reflect.DeepEqual(all, []interface{}{5, 4, 3, 2, 1, 4, 3, 2, 1}) { t.Errorf("Invalid all: %#v", all) } } func TestShrinkInterleave(t *testing.T) { counterShrink1 := &counterShrink{n: 5} counterShrink2 := &counterShrink{n: 7} shrink1 := gopter.Shrink(counterShrink1.Next) shrink2 := gopter.Shrink(counterShrink2.Next) all := shrink1.Interleave(shrink2).All() if !reflect.DeepEqual(all, []interface{}{5, 7, 4, 6, 3, 5, 2, 4, 1, 3, 2, 1}) { t.Errorf("Invalid all: %#v", all) } } func TestCombineShrinker(t *testing.T) { var shrinker1Arg, shrinker2Arg interface{} shrinker1 := func(v interface{}) gopter.Shrink { shrinker1Arg = v shrink := &counterShrink{n: 5} return shrink.Next } shrinker2 := func(v interface{}) gopter.Shrink { shrinker2Arg = v shrink := &counterShrink{n: 3} return shrink.Next } shrinker := gopter.CombineShrinker(shrinker1, shrinker2) all := shrinker([]interface{}{123, 456}).All() if shrinker1Arg != 123 { t.Errorf("Invalid shrinker1Arg: %#v", shrinker1Arg) } if shrinker2Arg != 456 { t.Errorf("Invalid shrinker1Arg: %#v", shrinker1Arg) } if !reflect.DeepEqual(all, []interface{}{ []interface{}{5, 456}, []interface{}{4, 456}, []interface{}{3, 456}, []interface{}{2, 456}, []interface{}{1, 456}, []interface{}{123, 3}, []interface{}{123, 2}, []interface{}{123, 1}, }) { t.Errorf("Invalid all: %#v", all) } } func TestShrinkMap(t *testing.T) { counter := &counterShrink{n: 10} shrink := gopter.Shrink(counter.Next).Map(func(v int) int { return 10 - v }) all := shrink.All() if !reflect.DeepEqual(all, []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) { t.Errorf("Invalid all: %#v", all) } } func TestShrinkMapNoFunc(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func, but is string") counter := &counterShrink{n: 10} gopter.Shrink(counter.Next).Map("not a function") } func TestShrinkMapTooManyParams(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func with one param, but is 2") counter := &counterShrink{n: 10} gopter.Shrink(counter.Next).Map(func(a, b string) string { return "" }) } func TestShrinkMapToManyReturns(t *testing.T) { defer expectPanic(t, "Param of Map has to be a func with one return value, but is 2") counter := &counterShrink{n: 10} gopter.Shrink(counter.Next).Map(func(a string) (string, bool) { return "", false }) } func TestNoShrinker(t *testing.T) { shrink := gopter.NoShrinker(123) if shrink == nil { t.Error("Shrink has to be != nil") } value, ok := shrink() if ok || value != nil { t.Errorf("Invalid shrink: %#v", value) } } gopter-0.2.11/test_parameters.go000066400000000000000000000023451460324054500166330ustar00rootroot00000000000000package gopter import ( "math/rand" "time" ) // TestParameters to run property tests type TestParameters struct { MinSuccessfulTests int // MinSize is an (inclusive) lower limit on the size of the parameters MinSize int // MaxSize is an (exclusive) upper limit on the size of the parameters MaxSize int MaxShrinkCount int seed int64 Rng *rand.Rand Workers int MaxDiscardRatio float64 } func (t *TestParameters) Seed() int64 { return t.seed } func (t *TestParameters) SetSeed(seed int64) { t.seed = seed t.Rng.Seed(seed) } // DefaultTestParameterWithSeeds creates reasonable default Parameters for most cases based on a fixed RNG-seed func DefaultTestParametersWithSeed(seed int64) *TestParameters { return &TestParameters{ MinSuccessfulTests: 100, MinSize: 0, MaxSize: 100, MaxShrinkCount: 1000, seed: seed, Rng: rand.New(NewLockedSource(seed)), Workers: 1, MaxDiscardRatio: 5, } } // DefaultTestParameterWithSeeds creates reasonable default Parameters for most cases with an undefined RNG-seed func DefaultTestParameters() *TestParameters { return DefaultTestParametersWithSeed(time.Now().UnixNano()) } gopter-0.2.11/test_result.go000066400000000000000000000022231460324054500160010ustar00rootroot00000000000000package gopter import "time" type testStatus int const ( // TestPassed indicates that the property check has passed. TestPassed testStatus = iota // TestProved indicates that the property has been proved. TestProved // TestFailed indicates that the property check has failed. TestFailed // TestExhausted indicates that the property check has exhausted, i.e. the generators have // generated too many empty results. TestExhausted // TestError indicates that the property check has finished with an error. TestError ) func (s testStatus) String() string { switch s { case TestPassed: return "PASSED" case TestProved: return "PROVED" case TestFailed: return "FAILED" case TestExhausted: return "EXHAUSTED" case TestError: return "ERROR" } return "" } // TestResult contains the result of a property property check. type TestResult struct { Status testStatus Succeeded int Discarded int Labels []string Error error ErrorStack []byte Args PropArgs Time time.Duration } // Passed checks if the check has passed func (r *TestResult) Passed() bool { return r.Status == TestPassed || r.Status == TestProved } gopter-0.2.11/test_result_test.go000066400000000000000000000022131460324054500170370ustar00rootroot00000000000000package gopter_test import ( "testing" "github.com/leanovate/gopter" ) func TestTestResult(t *testing.T) { result := &gopter.TestResult{Status: gopter.TestPassed} if !result.Passed() { t.Errorf("Test not passed: %#v", result) } if result.Status.String() != "PASSED" { t.Errorf("Invalid status: %#v", result) } result = &gopter.TestResult{Status: gopter.TestProved} if !result.Passed() { t.Errorf("Test not passed: %#v", result) } if result.Status.String() != "PROVED" { t.Errorf("Invalid status: %#v", result) } result = &gopter.TestResult{Status: gopter.TestFailed} if result.Passed() { t.Errorf("Test passed: %#v", result) } if result.Status.String() != "FAILED" { t.Errorf("Invalid status: %#v", result) } result = &gopter.TestResult{Status: gopter.TestExhausted} if result.Passed() { t.Errorf("Test passed: %#v", result) } if result.Status.String() != "EXHAUSTED" { t.Errorf("Invalid status: %#v", result) } result = &gopter.TestResult{Status: gopter.TestError} if result.Passed() { t.Errorf("Test passed: %#v", result) } if result.Status.String() != "ERROR" { t.Errorf("Invalid status: %#v", result) } }