Documentation
¶
Overview ¶
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.
Example (Arbitrary_structs) ¶
package main
import (
"fmt"
"time"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/arbitrary"
)
type MyStringType string
type MyInt8Type int8
type MyInt16Type int16
type MyInt32Type int32
type MyInt64Type int64
type MyUInt8Type uint8
type MyUInt16Type uint16
type MyUInt32Type uint32
type MyUInt64Type uint64
type Foo struct {
Name MyStringType
Id1 MyInt8Type
Id2 MyInt16Type
Id3 MyInt32Type
Id4 MyInt64Type
Id5 MyUInt8Type
Id6 MyUInt16Type
Id7 MyUInt32Type
Id8 MyUInt64Type
ATime time.Time
ATimePtr *time.Time
}
func (f Foo) ToString() string {
return fmt.Sprintf("For(%s, %d, %d, %d, %d, %d, %d, %d, %d, %v, %v)", f.Name, f.Id1, f.Id2, f.Id3, f.Id4, f.Id5, f.Id6, f.Id7, f.Id8, f.ATime, f.ATimePtr)
}
func main() {
time.Local = time.UTC
parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice
arbitraries := arbitrary.DefaultArbitraries()
properties := gopter.NewProperties(parameters)
properties.Property("MyInt64", arbitraries.ForAll(
func(id MyInt64Type) bool {
return id > -1000
}))
properties.Property("MyUInt32Type", arbitraries.ForAll(
func(id MyUInt32Type) bool {
return id < 2000
}))
properties.Property("Foo", arbitraries.ForAll(
func(foo *Foo) bool {
return foo.ATime.After(time.Unix(0, 0))
}))
properties.Property("Foo2", arbitraries.ForAll(
func(foo Foo) bool {
return foo.ATimePtr == nil || foo.ATimePtr.Before(time.Unix(20000, 0))
}))
properties.Run(gopter.ConsoleReporter(false))
}
Output: ! MyInt64: Falsified after 6 passed tests. ARG_0: -1000 ARG_0_ORIGINAL (54 shrinks): -1601066829744837253 ! MyUInt32Type: Falsified after 0 passed tests. ARG_0: 2000 ARG_0_ORIGINAL (23 shrinks): 2161922319 + Foo: OK, passed 100 tests. ! Foo2: Falsified after 1 passed tests. ARG_0: {Name: Id1:0 Id2:0 Id3:0 Id4:0 Id5:0 Id6:0 Id7:0 Id8:0 ATime:1970-01-01 00:00:00 +0000 UTC ATimePtr:1970-01-01 05:33:20 +0000 UTC} ARG_0_ORIGINAL (40 shrinks): {Name: Id1:-67 Id2:27301 Id3:-1350752892 Id4:7128486677722156226 Id5:208 Id6:28663 Id7:4178604448 Id8:16360504079646654692 ATime:2239-08-20 23:46:28.063412239 +0000 UTC ATimePtr:5468-08-19 13:09:39.171622464 +0000 UTC}
Example (Parseint) ¶
package main
import (
"fmt"
"strconv"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/arbitrary"
)
func main() {
parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice
arbitraries := arbitrary.DefaultArbitraries()
properties := gopter.NewProperties(parameters)
properties.Property("printed integers can be parsed", arbitraries.ForAll(
func(a int64) bool {
str := fmt.Sprintf("%d", a)
parsed, err := strconv.ParseInt(str, 10, 64)
return err == nil && parsed == a
}))
// When using testing.T you might just use: properties.TestingRun(t)
properties.Run(gopter.ConsoleReporter(false))
}
Output: + printed integers can be parsed: OK, passed 100 tests.
Example (Quadratic) ¶
package main
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 main() {
parameters := gopter.DefaultTestParametersWithSeed(1234) // Example should generate reproducible results, otherwise DefaultTestParameters() will suffice
arbitraries := arbitrary.DefaultArbitraries()
arbitraries.RegisterGen(gen.Complex128Box(-1e8-1e8i, 1e8+1e8i)) // Only use complex values within a range
properties := gopter.NewProperties(parameters)
properties.Property("Quadratic equations can be solved (as pointer)", arbitraries.ForAll(
func(quadratic *QudraticEquation) bool {
x1, x2, err := quadratic.Solve()
if err != nil {
return true
}
return cmplx.Abs(quadratic.Eval(x1)) < 1e-5 && cmplx.Abs(quadratic.Eval(x2)) < 1e-5
}))
properties.Property("Quadratic equations can be solved (as struct)", arbitraries.ForAll(
func(quadratic QudraticEquation) bool {
x1, x2, err := quadratic.Solve()
if err != nil {
return true
}
return cmplx.Abs(quadratic.Eval(x1)) < 1e-5 && cmplx.Abs(quadratic.Eval(x2)) < 1e-5
}))
properties.Property("Quadratic equations can be solved alternative", arbitraries.ForAll(
func(a, b, c complex128) bool {
quadratic := &QudraticEquation{
A: a,
B: b,
C: c,
}
x1, x2, err := quadratic.Solve()
if err != nil {
return true
}
return cmplx.Abs(quadratic.Eval(x1)) < 1e-5 && cmplx.Abs(quadratic.Eval(x2)) < 1e-5
}))
// When using testing.T you might just use: properties.TestingRun(t)
properties.Run(gopter.ConsoleReporter(false))
}
Output: + Quadratic equations can be solved (as pointer): OK, passed 100 tests. + Quadratic equations can be solved (as struct): OK, passed 100 tests. + Quadratic equations can be solved alternative: OK, passed 100 tests.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Arbitraries ¶
type Arbitraries struct {
// contains filtered or unexported fields
}
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.
func DefaultArbitraries ¶
func DefaultArbitraries() *Arbitraries
DefaultArbitraries creates a default arbitrary context with the widest possible ranges for all types.
func (*Arbitraries) ForAll ¶
func (a *Arbitraries) ForAll(condition interface{}) gopter.Prop
ForAll creates a property that requires the check condition to be true for all values, if the condition falsiies the generated values will be shrunk.
"condition" has to be a function with the any number of parameters that can generated in context of the Arbitraries. The function may return a simple bool, a *PropResult, a boolean with error or a *PropResult with error.
func (*Arbitraries) GenForType ¶
func (a *Arbitraries) GenForType(rt reflect.Type) gopter.Gen
GenForType gets a generator for a generator for a type
func (*Arbitraries) RegisterGen ¶
func (a *Arbitraries) RegisterGen(gen gopter.Gen)
RegisterGen registers a generator