arbitrary

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 16, 2018 License: MIT Imports: 6 Imported by: 0

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 (
	"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 main() {
	parameters := gopter.DefaultTestParameters()
	parameters.Rng.Seed(1234)

	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.
Example (Parseint)
package main

import (
	"fmt"
	"strconv"

	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/arbitrary"
)

func main() {
	parameters := gopter.DefaultTestParameters()
	parameters.Rng.Seed(1234) // Just for this example to generate reproducable results

	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.DefaultTestParameters()
	parameters.Rng.Seed(1234) // Just for this example to generate reproducable results

	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 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 (*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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL