Add App,Trigger,Fn Equality and Clone Testing (#1159)

Creates a test that aims to assert that the Equals and Clone functions
for our three entity structs actually work.

The bulk of the code is spent creating gopter generators for the entities. See information of generative or property based testing for
explainations on that topic, but basically it's an object that is
capable of creating a stream of unique instances of the given struct.

With the generator we then make three assertions:
 1) Entities are always equal to themselves.
 2) A .Clone() of an entity is Equal to the original entity.
 3) A .Clone() of an entity that has a field modified is not equal to the
 orignal.

The third property is the worse for implementation, as it does not
generate the field to modify, it simply loops all fields for each generated
entity, and checks Equals always breaks.

Break testing shows that this would have caught earlier bugs in Equals
due to field addition. It will add to the work to add further fields,
generators have to be manually specified for each field, but that
seems a worthy cost.
This commit is contained in:
Tom Coupland
2018-08-22 11:00:04 +01:00
committed by GitHub
parent 9ca93edd76
commit 98880b5474
132 changed files with 9544 additions and 2 deletions

12
Gopkg.lock generated
View File

@@ -221,6 +221,16 @@
]
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
[[projects]]
name = "github.com/leanovate/gopter"
packages = [
".",
"gen",
"prop"
]
revision = "1f4d0ba27bd5df5390eb622bcb458f8f7ac2573c"
version = "v0.2.2"
[[projects]]
branch = "master"
name = "github.com/lib/pq"
@@ -494,6 +504,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "643d4a3862aeaa6f1115edc26fa3f1f3a6822bb17c01d60fcbdf9ce98bf183ac"
inputs-digest = "6c6cfaf48ee2f7f926ed2d063af6a65a505f927e7354fe4613ead8c8a6efb203"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -115,7 +115,7 @@ func (a *App) Clone() *App {
clone.Config[k] = v
}
}
clone.ID = a.ID
return clone
}

143
api/models/app_test.go Normal file
View File

@@ -0,0 +1,143 @@
package models
import (
"reflect"
"testing"
"time"
"github.com/fnproject/fn/api/common"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
)
var stringType = reflect.TypeOf("")
var intType = reflect.TypeOf(0)
func appReflectType() reflect.Type {
app := App{}
return reflect.TypeOf(app)
}
func configGenerator() gopter.Gen {
return gen.MapOf(gen.AlphaString(), gen.AlphaString())
}
func annotationGenerator() gopter.Gen {
annotation1, _ := EmptyAnnotations().With("anAnnotation1", "value1")
annotation2, _ := EmptyAnnotations().With("anAnnotation2", "value2")
return gen.OneConstOf(annotation1, annotation2)
}
func datetimeGenerator() gopter.Gen {
return gen.Time().Map(func(t time.Time) common.DateTime {
return common.DateTime(t)
})
}
func appFieldGenerators(t *testing.T) map[string]gopter.Gen {
fieldGens := make(map[string]gopter.Gen)
fieldGens["ID"] = gen.AlphaString()
fieldGens["Name"] = gen.AlphaString()
fieldGens["Config"] = configGenerator()
fieldGens["Annotations"] = annotationGenerator()
fieldGens["SyslogURL"] = gen.AlphaString().Map(func(s string) *string {
return &s
})
fieldGens["CreatedAt"] = datetimeGenerator()
fieldGens["UpdatedAt"] = datetimeGenerator()
appFieldCount := appReflectType().NumField()
if appFieldCount != len(fieldGens) {
t.Fatalf("App struct field count, %d, does not match app generator field count, %d", appFieldCount, len(fieldGens))
}
return fieldGens
}
func appGenerator(t *testing.T) gopter.Gen {
return gen.Struct(appReflectType(), appFieldGenerators(t))
}
func novelValue(t *testing.T, originalInstance reflect.Value, fieldName string, fieldGen gopter.Gen) (interface{}, reflect.Value) {
newValue, result := fieldGen.Sample()
if !result {
t.Fatalf("Error sampling field generator, %s, %v", fieldName, result)
}
field := originalInstance.FieldByName(fieldName)
currentValue := field.Interface()
for i := 0; i < 100; i++ {
if fieldName == "Annotations" {
if !newValue.(Annotations).Equals(currentValue.(Annotations)) {
break
}
} else {
if newValue != currentValue {
break
}
}
newValue, result = fieldGen.Sample()
if !result {
t.Fatalf("Error sampling field generator, %s, %v", fieldName, result)
}
if i == 99 {
t.Fatalf("Failed to generate a novel value for field, %s", fieldName)
}
}
return currentValue, reflect.ValueOf(newValue)
}
func TestAppEquality(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("An app should always equal itself", prop.ForAll(
func(app App) bool {
return app.Equals(&app)
},
appGenerator(t),
))
properties.Property("An app should always equal a clone of itself", prop.ForAll(
func(app App) bool {
clone := app.Clone()
return app.Equals(clone)
},
appGenerator(t),
))
appFieldGens := appFieldGenerators(t)
properties.Property("An app should never match a modified version of itself", prop.ForAll(
func(app App) bool {
for fieldName, fieldGen := range appFieldGens {
if fieldName == "CreatedAt" ||
fieldName == "UpdatedAt" {
continue
}
currentValue, newValue := novelValue(t, reflect.ValueOf(app), fieldName, fieldGen)
clone := app.Clone()
s := reflect.ValueOf(clone).Elem()
field := s.FieldByName(fieldName)
field.Set(newValue)
if app.Equals(clone) {
t.Errorf("Changed field, %s, from {%v} to {%v}, but still equal.", fieldName, currentValue, newValue)
return false
}
}
return true
},
appGenerator(t),
))
properties.TestingRun(t)
}

109
api/models/fn_test.go Normal file
View File

@@ -0,0 +1,109 @@
package models
import (
"reflect"
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
)
func fnReflectType() reflect.Type {
fn := Fn{}
return reflect.TypeOf(fn)
}
func resourceConfigGenerator(t *testing.T) gopter.Gen {
fieldGens := make(map[string]gopter.Gen)
fieldGens["Memory"] = gen.UInt64()
fieldGens["Timeout"] = gen.Int32()
fieldGens["IdleTimeout"] = gen.Int32()
resourceConfig := ResourceConfig{}
resourceConfigFieldCount := reflect.TypeOf(resourceConfig).NumField()
if resourceConfigFieldCount != len(fieldGens) {
t.Fatalf("Fn struct field count, %d, does not match fn generator field count, %d", resourceConfigFieldCount, len(fieldGens))
}
return gen.Struct(reflect.TypeOf(resourceConfig), fieldGens)
}
func fnFieldGenerators(t *testing.T) map[string]gopter.Gen {
fieldGens := make(map[string]gopter.Gen)
fieldGens["ID"] = gen.AlphaString()
fieldGens["Name"] = gen.AlphaString()
fieldGens["AppID"] = gen.AlphaString()
fieldGens["Image"] = gen.AlphaString()
fieldGens["Config"] = configGenerator()
fieldGens["ResourceConfig"] = resourceConfigGenerator(t)
fieldGens["Annotations"] = annotationGenerator()
fieldGens["CreatedAt"] = datetimeGenerator()
fieldGens["UpdatedAt"] = datetimeGenerator()
fieldGens["Format"] = gen.AlphaString()
fnFieldCount := fnReflectType().NumField()
if fnFieldCount != len(fieldGens) {
t.Fatalf("Fn struct field count, %d, does not match fn generator field count, %d", fnFieldCount, len(fieldGens))
}
return fieldGens
}
func fnGenerator(t *testing.T) gopter.Gen {
return gen.Struct(fnReflectType(), fnFieldGenerators(t))
}
func TestFnEquality(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("A fn should always equal itself", prop.ForAll(
func(fn Fn) bool {
return fn.Equals(&fn)
},
fnGenerator(t),
))
properties.Property("A fn should always equal a clone of itself", prop.ForAll(
func(fn Fn) bool {
clone := fn.Clone()
return fn.Equals(clone)
},
fnGenerator(t),
))
fnFieldGens := fnFieldGenerators(t)
properties.Property("A fn should never match a modified version of itself", prop.ForAll(
func(fn Fn) bool {
for fieldName, fieldGen := range fnFieldGens {
if fieldName == "CreatedAt" ||
fieldName == "UpdatedAt" {
continue
}
currentValue, newValue := novelValue(t, reflect.ValueOf(fn), fieldName, fieldGen)
clone := fn.Clone()
s := reflect.ValueOf(clone).Elem()
field := s.FieldByName(fieldName)
field.Set(newValue)
if fn.Equals(clone) {
t.Errorf("Changed field, %s, from {%v} to {%v}, but still equal.", fieldName, currentValue, newValue)
return false
}
}
return true
},
fnGenerator(t),
))
properties.TestingRun(t)
}

View File

@@ -2,7 +2,12 @@ package models
import (
"encoding/json"
"reflect"
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
)
var openEmptyJSON = `{"id":"","name":"","app_id":"","fn_id":"","created_at":"0001-01-01T00:00:00.000Z","updated_at":"0001-01-01T00:00:00.000Z","type":"","source":""`
@@ -62,3 +67,83 @@ func TestTriggerValidate(t *testing.T) {
}
}
}
func triggerReflectType() reflect.Type {
trigger := Trigger{}
return reflect.TypeOf(trigger)
}
func triggerFieldGenerators(t *testing.T) map[string]gopter.Gen {
fieldGens := make(map[string]gopter.Gen)
fieldGens["ID"] = gen.AlphaString()
fieldGens["Name"] = gen.AlphaString()
fieldGens["AppID"] = gen.AlphaString()
fieldGens["FnID"] = gen.AlphaString()
fieldGens["CreatedAt"] = datetimeGenerator()
fieldGens["UpdatedAt"] = datetimeGenerator()
fieldGens["Type"] = gen.AlphaString()
fieldGens["Source"] = gen.AlphaString()
fieldGens["Annotations"] = annotationGenerator()
triggerFieldCount := triggerReflectType().NumField()
if triggerFieldCount != len(fieldGens) {
t.Fatalf("Trigger struct field count, %d, does not match trigger generator field count, %d", triggerFieldCount, len(fieldGens))
}
return fieldGens
}
func triggerGenerator(t *testing.T) gopter.Gen {
return gen.Struct(triggerReflectType(), triggerFieldGenerators(t))
}
func TestTriggerEquality(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("A trigger should always equal itself", prop.ForAll(
func(trigger Trigger) bool {
return trigger.Equals(&trigger)
},
triggerGenerator(t),
))
properties.Property("A trigger should always equal a clone of itself", prop.ForAll(
func(trigger Trigger) bool {
clone := trigger.Clone()
return trigger.Equals(clone)
},
triggerGenerator(t),
))
triggerFieldGens := triggerFieldGenerators(t)
properties.Property("A trigger should never match a modified version of itself", prop.ForAll(
func(trigger Trigger) bool {
for fieldName, fieldGen := range triggerFieldGens {
if fieldName == "CreatedAt" ||
fieldName == "UpdatedAt" {
continue
}
currentValue, newValue := novelValue(t, reflect.ValueOf(trigger), fieldName, fieldGen)
clone := trigger.Clone()
s := reflect.ValueOf(clone).Elem()
field := s.FieldByName(fieldName)
field.Set(newValue)
if trigger.Equals(clone) {
t.Errorf("Changed field, %s, from {%v} to {%v}, but still equal.", fieldName, currentValue, newValue)
return false
}
}
return true
},
triggerGenerator(t),
))
properties.TestingRun(t)
}

30
vendor/github.com/leanovate/gopter/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,30 @@
# 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

12
vendor/github.com/leanovate/gopter/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,12 @@
sudo: 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=

65
vendor/github.com/leanovate/gopter/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,65 @@
# 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

21
vendor/github.com/leanovate/gopter/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The 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.

41
vendor/github.com/leanovate/gopter/Makefile generated vendored Normal file
View File

@@ -0,0 +1,41 @@
PACKAGES=$(shell go list ./...)
all: format
@go get github.com/smartystreets/goconvey
@go build -v ./...
format:
@echo "--> Running go fmt"
@go fmt ./...
test:
@echo "--> Running tests"
@go test -v ./...
@$(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 tool vet 2>/dev/null ; if [ $$? -eq 3 ]; then \
go get golang.org/x/tools/cmd/vet; \
fi
@echo "--> Running go tool vet $(VETARGS)"
@find . -name "*.go" | grep -v "./Godeps/" | xargs go tool 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

44
vendor/github.com/leanovate/gopter/README.md generated vendored Normal file
View File

@@ -0,0 +1,44 @@
# 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)
[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://www.scalacheck.org/files/scalacheck_2.11-1.14.0-api/index.html#org.scalacheck.Shrink) has become part of the generators. They can still be easily changed if necessary.
* There is no [Pretty](https://www.scalacheck.org/files/scalacheck_2.11-1.14.0-api/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)

View File

@@ -0,0 +1,41 @@
package 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.Now()): 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.DefaultGenParameters())
rt := result.ResultType
a.generators[rt] = gen
}

32
vendor/github.com/leanovate/gopter/arbitrary/doc.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
/*
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

View File

@@ -0,0 +1,64 @@
package arbitrary_test
import (
"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
}
func Example_arbitrary_structs() {
parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducable 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 true
}))
properties.Property("Foo2", arbitraries.ForAll(
func(foo Foo) bool {
return true
}))
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: OK, passed 100 tests.
}

View File

@@ -0,0 +1,28 @@
package arbitrary_test
import (
"fmt"
"strconv"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/arbitrary"
)
func Example_parseint() {
parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducable 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.
}

View File

@@ -0,0 +1,78 @@
package 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 reproducable 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.
}

33
vendor/github.com/leanovate/gopter/arbitrary/forall.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package 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 shrinked.
"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...)
}

View File

@@ -0,0 +1,333 @@
package 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.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)
}
return nil
}

View File

@@ -0,0 +1,30 @@
package 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)
}
}

View File

@@ -0,0 +1,52 @@
package 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)
}
}
}

View File

@@ -0,0 +1,135 @@
package 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
})
}

111
vendor/github.com/leanovate/gopter/bi_mapper.go generated vendored Normal file
View File

@@ -0,0 +1,111 @@
package 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
}

27
vendor/github.com/leanovate/gopter/bi_mapper_test.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
package 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)
}

140
vendor/github.com/leanovate/gopter/commands/actions.go generated vendored Normal file
View File

@@ -0,0 +1,140 @@
package commands
import (
"fmt"
"reflect"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
)
type shrinkableCommand struct {
command Command
shrinker gopter.Shrinker
}
func (s shrinkableCommand) shrink() gopter.Shrink {
return s.shrinker(s.command).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, error) {
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}, nil
}
result := shrinkableCommand.command.Run(systemUnderTest)
state = shrinkableCommand.command.NextState(state)
propResult = propResult.And(shrinkableCommand.command.PostCondition(state, result))
}
return propResult, nil
}
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,
shrinker: result.Shrinker,
}),
},
gopter.NoShrinker,
)
})
}, reflect.TypeOf(sizedCommands{}))
}
return sizedCommandsGen(genParams)
}
}

72
vendor/github.com/leanovate/gopter/commands/command.go generated vendored Normal file
View File

@@ -0,0 +1,72 @@
package 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
}

View File

@@ -0,0 +1,84 @@
package 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(<pointer to some mutable struct>)`.
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, error) {
systemUnderTest := commands.NewSystemUnderTest(actions.initialStateProvider())
defer commands.DestroySystemUnderTest(systemUnderTest)
return actions.run(systemUnderTest)
}, genActions(commands))
}

View File

@@ -0,0 +1,112 @@
package 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)
}
}

11
vendor/github.com/leanovate/gopter/commands/doc.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
/*
Package commands conains helpers to create stateful tests based on commands.
Tester 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 themself have to implement the Command interface, whereas
testers might choose to use ProtoCommand as prototype.
*/
package commands

View File

@@ -0,0 +1,256 @@
package 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 reproducable 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]
}

View File

@@ -0,0 +1,125 @@
package 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 occures 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
// commonds/function calls, and then shrinkted 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 reproducable 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]
}

5
vendor/github.com/leanovate/gopter/convey/doc.go generated vendored Normal file
View File

@@ -0,0 +1,5 @@
/*
Package convey contains special assertion that come handy when using groper
properties with goconvey.
*/
package convey

View File

@@ -0,0 +1,42 @@
package convey
import (
"bytes"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/arbitrary"
"github.com/leanovate/gopter/prop"
)
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 ""
}

View File

@@ -0,0 +1,80 @@
package 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 reproducable 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")
})
})
}

122
vendor/github.com/leanovate/gopter/derived_gen.go generated vendored Normal file
View File

@@ -0,0 +1,122 @@
package gopter
import (
"fmt"
"reflect"
)
type derivedGen struct {
biMapper *BiMapper
upGens []Gen
upSieves []func(interface{}) bool
upShrinker Shrinker
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: nil,
Labels: result.Labels,
ResultType: d.resultType,
Sieve: d.Sieve,
}
}
}
down := d.biMapper.ConvertDown(up)
if len(down) == 1 {
return &GenResult{
Shrinker: d.Shrinker,
Result: down[0],
Labels: labels,
ResultType: reflect.TypeOf(down[0]),
Sieve: d.Sieve,
}
}
return &GenResult{
Shrinker: d.Shrinker,
Result: down,
Labels: labels,
ResultType: reflect.TypeOf(down),
Sieve: d.Sieve,
}
}
func (d *derivedGen) Sieve(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 d.upSieves[i] != nil && !d.upSieves[i](up) {
return false
}
}
return true
}
func (d *derivedGen) Shrinker(down interface{}) Shrink {
downs, ok := down.([]interface{})
if !ok {
downs = []interface{}{down}
}
ups := d.biMapper.ConvertUp(downs)
upShrink := d.upShrinker(ups)
return upShrink.Map(func(shrinkedUps []interface{}) interface{} {
downs := d.biMapper.ConvertDown(shrinkedUps)
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]
}
sieves := make([]func(interface{}) bool, len(gens))
shrinkers := make([]Shrinker, len(gens))
for i, gen := range gens {
result := gen(DefaultGenParams)
sieves[i] = result.Sieve
shrinkers[i] = result.Shrinker
}
derived := &derivedGen{
biMapper: biMapper,
upGens: gens,
upSieves: sieves,
upShrinker: CombineShrinker(shrinkers...),
resultType: resultType,
}
return derived.Generate
}

186
vendor/github.com/leanovate/gopter/derived_gen_test.go generated vendored Normal file
View File

@@ -0,0 +1,186 @@
package 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})
shrinkedStructs := make([]*downStruct, 0)
value, next := shrink()
for next {
shrinkedStruct, ok := value.(*downStruct)
if !ok {
t.Errorf("Invalid shrinked value: %#v", value)
}
shrinkedStructs = append(shrinkedStructs, shrinkedStruct)
value, next = shrink()
}
expected := []*downStruct{
&downStruct{a: 0, b: "abcd", c: false},
&downStruct{a: 5, b: "abcd", c: false},
&downStruct{a: -5, b: "abcd", c: false},
&downStruct{a: 8, b: "abcd", c: false},
&downStruct{a: -8, b: "abcd", c: false},
&downStruct{a: 9, b: "abcd", c: false},
&downStruct{a: -9, b: "abcd", c: false},
&downStruct{a: 10, b: "cd", c: false},
&downStruct{a: 10, b: "ab", c: false},
&downStruct{a: 10, b: "bcd", c: false},
&downStruct{a: 10, b: "acd", c: false},
&downStruct{a: 10, b: "abd", c: false},
&downStruct{a: 10, b: "abc", c: false},
}
if !reflect.DeepEqual(shrinkedStructs, expected) {
t.Errorf("%v does not equal %v", shrinkedStructs, 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
for i := 0; i < 100; i++ {
result := gen(parameters)
_, ok := result.Retrieve()
if !ok {
hasNoValue = true
break
}
}
if !hasNoValue {
t.Error("Sieve is not applied")
}
sieve := gen(parameters).Sieve
if !sieve(&downStruct{a: 2, b: "something", c: false}) {
t.Error("Sieve did not pass even")
}
if sieve(&downStruct{a: 3, b: "something", c: false}) {
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()
shrinkedValues := make([][]interface{}, 0)
for next {
shrinked, ok := value.([]interface{})
if !ok || len(values) != 2 {
t.Errorf("%#v is not a slice of interface", sample)
}
shrinkedValues = append(shrinkedValues, shrinked)
value, next = shrink()
}
expected := [][]interface{}{
[]interface{}{&downStruct{a: 0, b: "abcd", c: false}, int64(10)},
[]interface{}{&downStruct{a: 5, b: "abcd", c: false}, int64(15)},
[]interface{}{&downStruct{a: -5, b: "abcd", c: false}, int64(5)},
[]interface{}{&downStruct{a: 8, b: "abcd", c: false}, int64(18)},
[]interface{}{&downStruct{a: -8, b: "abcd", c: false}, int64(2)},
[]interface{}{&downStruct{a: 9, b: "abcd", c: false}, int64(19)},
[]interface{}{&downStruct{a: -9, b: "abcd", c: false}, int64(1)},
[]interface{}{&downStruct{a: 10, b: "cd", c: false}, int64(20)},
[]interface{}{&downStruct{a: 10, b: "ab", c: false}, int64(20)},
[]interface{}{&downStruct{a: 10, b: "bcd", c: false}, int64(20)},
[]interface{}{&downStruct{a: 10, b: "acd", c: false}, int64(20)},
[]interface{}{&downStruct{a: 10, b: "abd", c: false}, int64(20)},
[]interface{}{&downStruct{a: 10, b: "abc", c: false}, int64(20)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(10)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(15)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(5)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(18)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(2)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(19)},
[]interface{}{&downStruct{a: 10, b: "abcd", c: false}, int64(1)},
}
if !reflect.DeepEqual(shrinkedValues, expected) {
t.Errorf("%v does not equal %v", shrinkedValues, expected)
}
}

35
vendor/github.com/leanovate/gopter/doc.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
/*
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

View File

@@ -0,0 +1,78 @@
package 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.
}

View File

@@ -0,0 +1,59 @@
package 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 reproducable 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
}

View File

@@ -0,0 +1,37 @@
package 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 reproducable 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.
}

23
vendor/github.com/leanovate/gopter/flag.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
package 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)
}

22
vendor/github.com/leanovate/gopter/flag_test.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
package 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)
}
}

140
vendor/github.com/leanovate/gopter/formated_reporter.go generated vendored Normal file
View File

@@ -0,0 +1,140 @@
package 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:
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: %v", label, propArg.Arg)
if propArg.Shrinks > 0 {
result += fmt.Sprintf("\n%s_ORIGINAL (%d shrinks): %v", label, propArg.Shrinks, propArg.OrigArg)
}
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
}

View File

@@ -0,0 +1,80 @@
package 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{&PropArg{
Arg: "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{&PropArg{
Arg: "0",
Label: "somehing",
OrigArg: "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{&PropArg{
Arg: "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()
}

251
vendor/github.com/leanovate/gopter/gen.go generated vendored Normal file
View File

@@ -0,0 +1,251 @@
package 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 reproducable 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()
)
// 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(DefaultGenParams).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 {
return checkVal.Call([]reflect.Value{reflect.ValueOf(v)})[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 generators 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.
// 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(DefaultGenParams).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
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)
}
return &GenResult{
Shrinker: NoShrinker,
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
},
}
}
}

10
vendor/github.com/leanovate/gopter/gen/bool.go generated vendored Normal file
View File

@@ -0,0 +1,10 @@
package 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)
}
}

14
vendor/github.com/leanovate/gopter/gen/bool_test.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
package 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
})
}

49
vendor/github.com/leanovate/gopter/gen/complex.go generated vendored Normal file
View File

@@ -0,0 +1,49 @@
package 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)
}

View File

@@ -0,0 +1,27 @@
package 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)
}

View File

@@ -0,0 +1,91 @@
package 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)
}
}

46
vendor/github.com/leanovate/gopter/gen/complex_test.go generated vendored Normal file
View File

@@ -0,0 +1,46 @@
package 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
complexs := gen.Complex128Box(complex(minReal, minImag), complex(maxReal, maxImag))
commonGeneratorTest(t, "complex 128 box", complexs, 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)
complexs := gen.Complex64Box(complex(minReal, minImag), complex(maxReal, maxImag))
commonGeneratorTest(t, "complex 64 box", complexs, 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
})
}

11
vendor/github.com/leanovate/gopter/gen/const.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
package 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)
}
}

14
vendor/github.com/leanovate/gopter/gen/const_test.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
package 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"
})
}

4
vendor/github.com/leanovate/gopter/gen/doc.go generated vendored Normal file
View File

@@ -0,0 +1,4 @@
/*
Package gen contains all commonly used generators and shrinkers.
*/
package gen

15
vendor/github.com/leanovate/gopter/gen/fail.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
package 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)
}
}

18
vendor/github.com/leanovate/gopter/gen/fail_test.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
package 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()
}
}

69
vendor/github.com/leanovate/gopter/gen/floats.go generated vendored Normal file
View File

@@ -0,0 +1,69 @@
package 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)
}

View File

@@ -0,0 +1,49 @@
package 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)
})
}

View File

@@ -0,0 +1,154 @@
package 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)
}
}

48
vendor/github.com/leanovate/gopter/gen/floats_test.go generated vendored Normal file
View File

@@ -0,0 +1,48 @@
package 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
})
}

33
vendor/github.com/leanovate/gopter/gen/frequency.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package 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
}
}

View File

@@ -0,0 +1,48 @@
package 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)
}
}
}

33
vendor/github.com/leanovate/gopter/gen/helper_test.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package 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)
}
}
}
}
}

225
vendor/github.com/leanovate/gopter/gen/integers.go generated vendored Normal file
View File

@@ -0,0 +1,225 @@
package 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)
}

View File

@@ -0,0 +1,95 @@
package 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)
}

View File

@@ -0,0 +1,127 @@
package 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)
}
}

130
vendor/github.com/leanovate/gopter/gen/integers_test.go generated vendored Normal file
View File

@@ -0,0 +1,130 @@
package 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)
}
}
}

87
vendor/github.com/leanovate/gopter/gen/map_of.go generated vendored Normal file
View File

@@ -0,0 +1,87 @@
package 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
}
}

96
vendor/github.com/leanovate/gopter/gen/map_of_test.go generated vendored Normal file
View File

@@ -0,0 +1,96 @@
package 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()
}

149
vendor/github.com/leanovate/gopter/gen/map_shrink.go generated vendored Normal file
View File

@@ -0,0 +1,149 @@
package 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
// shrinked 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 shrinked 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...)
}
}

View File

@@ -0,0 +1,57 @@
package 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)
}
}
}

29
vendor/github.com/leanovate/gopter/gen/one_of.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
package 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)
}
}

53
vendor/github.com/leanovate/gopter/gen/one_of_test.go generated vendored Normal file
View File

@@ -0,0 +1,53 @@
package 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) {
generated := make(map[string]bool, 0)
for i := 0; i < 100; i++ {
value, ok := gen.Sample()
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)
}
}

41
vendor/github.com/leanovate/gopter/gen/ptr_of.go generated vendored Normal file
View File

@@ -0,0 +1,41 @@
package gen
import (
"reflect"
"github.com/leanovate/gopter"
)
// PtrOf generates a pointer to a generated element
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
}
}

54
vendor/github.com/leanovate/gopter/gen/ptr_of_test.go generated vendored Normal file
View File

@@ -0,0 +1,54 @@
package 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)
})
}

41
vendor/github.com/leanovate/gopter/gen/ptr_shrink.go generated vendored Normal file
View File

@@ -0,0 +1,41 @@
package 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
}
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()
}),
)
}
}

View File

@@ -0,0 +1,17 @@
package 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)
}
}

78
vendor/github.com/leanovate/gopter/gen/regex.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
package 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)
}

36
vendor/github.com/leanovate/gopter/gen/regex_test.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package 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)
}
}

21
vendor/github.com/leanovate/gopter/gen/retry_until.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
package 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)
}
}

View File

@@ -0,0 +1,33 @@
package 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")
}
}

89
vendor/github.com/leanovate/gopter/gen/slice_of.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
package 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) 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, elementSieve, elementShrinker := genSlice(elementGen, genParams, len)
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(len int, elementGen gopter.Gen) gopter.Gen {
return func(genParams *gopter.GenParameters) *gopter.GenResult {
result, elementSieve, elementShrinker := genSlice(elementGen, genParams, len)
genResult := gopter.NewGenResult(result.Interface(), SliceShrinkerOne(elementShrinker))
if elementSieve != nil {
genResult.Sieve = func(v interface{}) bool {
rv := reflect.ValueOf(v)
return rv.Len() == len && forAllSieve(elementSieve)(v)
}
} else {
genResult.Sieve = func(v interface{}) bool {
return reflect.ValueOf(v).Len() == len
}
}
return genResult
}
}
func genSlice(elementGen gopter.Gen, genParams *gopter.GenParameters, len int) (reflect.Value, func(interface{}) bool, gopter.Shrinker) {
element := elementGen(genParams)
elementSieve := element.Sieve
elementShrinker := element.Shrinker
result := reflect.MakeSlice(reflect.SliceOf(element.ResultType), 0, len)
for i := 0; i < len; i++ {
value, ok := element.Retrieve()
if ok {
if value == nil {
result = reflect.Append(result, reflect.Zero(element.ResultType))
} 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
}
}

172
vendor/github.com/leanovate/gopter/gen/slice_of_test.go generated vendored Normal file
View File

@@ -0,0 +1,172 @@
package gen_test
import (
"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")
}
}

101
vendor/github.com/leanovate/gopter/gen/slice_shrink.go generated vendored Normal file
View File

@@ -0,0 +1,101 @@
package 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)
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 shrinked 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 shrinked 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...)
}
}

View File

@@ -0,0 +1,86 @@
package 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)
}
}

View File

@@ -0,0 +1,11 @@
package gen
import "github.com/leanovate/gopter"
var runeSliceShrinker = SliceShrinker(gopter.NoShrinker)
// StringShrinker is a shrinker for strings.
// It is very similiar to a sliace shrinker just that the elements themselves will not be shrinkeed.
func StringShrinker(v interface{}) gopter.Shrink {
return runeSliceShrinker([]rune(v.(string))).Map(runesToString)
}

158
vendor/github.com/leanovate/gopter/gen/strings.go generated vendored Normal file
View File

@@ -0,0 +1,158 @@
package 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)
}

161
vendor/github.com/leanovate/gopter/gen/strings_test.go generated vendored Normal file
View File

@@ -0,0 +1,161 @@
package 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
})
}
}

69
vendor/github.com/leanovate/gopter/gen/struct.go generated vendored Normal file
View File

@@ -0,0 +1,69 @@
package gen
import (
"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 correspoinding
// 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)
}
return func(genParams *gopter.GenParameters) *gopter.GenResult {
result := reflect.New(rt)
for name, gen := range gens {
field, ok := rt.FieldByName(name)
if !ok {
continue
}
value, ok := gen(genParams).Retrieve()
if !ok {
return gopter.NewEmptyResult(rt)
}
result.Elem().FieldByIndex(field.Index).Set(reflect.ValueOf(value))
}
return gopter.NewGenResult(reflect.Indirect(result).Interface(), gopter.NoShrinker)
}
}
// StructPtr generates pointers to a given struct type.
// Not that SturctPtr 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 correspoinding
// 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()
}
if rt.Kind() != reflect.Struct {
return Fail(rt)
}
return func(genParams *gopter.GenParameters) *gopter.GenResult {
result := reflect.New(rt)
for name, gen := range gens {
field, ok := rt.FieldByName(name)
if !ok {
continue
}
value, ok := gen(genParams).Retrieve()
if !ok {
return gopter.NewEmptyResult(rt)
}
result.Elem().FieldByIndex(field.Index).Set(reflect.ValueOf(value))
}
return gopter.NewGenResult(result.Interface(), gopter.NoShrinker)
}
}

96
vendor/github.com/leanovate/gopter/gen/struct_test.go generated vendored Normal file
View File

@@ -0,0 +1,96 @@
package 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
}
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(),
})
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 != "" {
t.Errorf("Invalid value: %#v", value)
}
}
}
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")
}
}

37
vendor/github.com/leanovate/gopter/gen/time.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package 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)
}
}

27
vendor/github.com/leanovate/gopter/gen/time_shrink.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
package 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))
}))
}

View File

@@ -0,0 +1,27 @@
package 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)
}
}

60
vendor/github.com/leanovate/gopter/gen/time_test.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
package 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)
}
}
}

44
vendor/github.com/leanovate/gopter/gen/weighted.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
package 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
}
}

View File

@@ -0,0 +1,41 @@
package gen_test
import (
"testing"
"github.com/leanovate/gopter/gen"
)
func TestWeighted(t *testing.T) {
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.Sample()
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)
}
}
}

View File

@@ -0,0 +1,63 @@
package 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")
}
}
}

68
vendor/github.com/leanovate/gopter/gen_parameters.go generated vendored Normal file
View File

@@ -0,0 +1,68 @@
package 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)),
}
}

55
vendor/github.com/leanovate/gopter/gen_result.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
package 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
}

26
vendor/github.com/leanovate/gopter/gen_result_test.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
package 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)
}
}

387
vendor/github.com/leanovate/gopter/gen_test.go generated vendored Normal file
View File

@@ -0,0 +1,387 @@
package 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)
}
}
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)
}
}

Some files were not shown because too many files have changed in this diff Show More