Documentation ¶
Overview ¶
Package rapid implements utilities for property-based testing.
Check verifies that properties you define hold for a large number of automatically generated test cases. If a failure is found, rapid fails the current test and presents an automatically minimized version of the failing test case.
T.Repeat is used to construct state machine (sometimes called "stateful" or "model-based") tests.
Generators ¶
Primitives:
- Bool
- Rune, RuneFrom
- Byte, ByteMin, ByteMax, ByteRange
- Int, IntMin, IntMax, IntRange
- Int8, Int8Min, Int8Max, Int8Range
- Int16, Int16Min, Int16Max, Int16Range
- Int32, Int32Min, Int32Max, Int32Range
- Int64, Int64Min, Int64Max, Int64Range
- Uint, UintMin, UintMax, UintRange
- Uint8, Uint8Min, Uint8Max, Uint8Range
- Uint16, Uint16Min, Uint16Max, Uint16Range
- Uint32, Uint32Min, Uint32Max, Uint32Range
- Uint64, Uint64Min, Uint64Max, Uint64Range
- Uintptr, UintptrMin, UintptrMax, UintptrRange
- Float32, Float32Min, Float32Max, Float32Range
- Float64, Float64Min, Float64Max, Float64Range
Collections:
- String, StringMatching, StringOf, StringOfN, StringN
- SliceOfBytesMatching
- SliceOf, SliceOfN, SliceOfDistinct, SliceOfNDistinct
- Permutation
- MapOf, MapOfN, MapOfValues, MapOfNValues
User-defined types:
Other:
Index ¶
- func Check(t TB, prop func(*T))
- func ID[V any](v V) V
- func MakeCheck(prop func(*T)) func(*testing.T)
- func MakeFuzz(prop func(*T)) func(*testing.T, []byte)
- func StateMachineActions(sm StateMachine) map[string]func(*T)
- type Generator
- func Bool() *Generator[bool]
- func Byte() *Generator[byte]
- func ByteMax(max byte) *Generator[byte]
- func ByteMin(min byte) *Generator[byte]
- func ByteRange(min byte, max byte) *Generator[byte]
- func Custom[V any](fn func(*T) V) *Generator[V]
- func Deferred[V any](fn func() *Generator[V]) *Generator[V]
- func Float32() *Generator[float32]
- func Float32Max(max float32) *Generator[float32]
- func Float32Min(min float32) *Generator[float32]
- func Float32Range(min float32, max float32) *Generator[float32]
- func Float64() *Generator[float64]
- func Float64Max(max float64) *Generator[float64]
- func Float64Min(min float64) *Generator[float64]
- func Float64Range(min float64, max float64) *Generator[float64]
- func Int() *Generator[int]
- func Int16() *Generator[int16]
- func Int16Max(max int16) *Generator[int16]
- func Int16Min(min int16) *Generator[int16]
- func Int16Range(min int16, max int16) *Generator[int16]
- func Int32() *Generator[int32]
- func Int32Max(max int32) *Generator[int32]
- func Int32Min(min int32) *Generator[int32]
- func Int32Range(min int32, max int32) *Generator[int32]
- func Int64() *Generator[int64]
- func Int64Max(max int64) *Generator[int64]
- func Int64Min(min int64) *Generator[int64]
- func Int64Range(min int64, max int64) *Generator[int64]
- func Int8() *Generator[int8]
- func Int8Max(max int8) *Generator[int8]
- func Int8Min(min int8) *Generator[int8]
- func Int8Range(min int8, max int8) *Generator[int8]
- func IntMax(max int) *Generator[int]
- func IntMin(min int) *Generator[int]
- func IntRange(min int, max int) *Generator[int]
- func Just[V any](val V) *Generator[V]
- func Make[V any]() *Generator[V]
- func Map[U any, V any](g *Generator[U], fn func(U) V) *Generator[V]
- func MapOf[K comparable, V any](key *Generator[K], val *Generator[V]) *Generator[map[K]V]
- func MapOfN[K comparable, V any](key *Generator[K], val *Generator[V], minLen int, maxLen int) *Generator[map[K]V]
- func MapOfNValues[K comparable, V any](val *Generator[V], minLen int, maxLen int, keyFn func(V) K) *Generator[map[K]V]
- func MapOfValues[K comparable, V any](val *Generator[V], keyFn func(V) K) *Generator[map[K]V]
- func OneOf[V any](gens ...*Generator[V]) *Generator[V]
- func Permutation[S ~[]E, E any](slice S) *Generator[S]
- func Ptr[E any](elem *Generator[E], allowNil bool) *Generator[*E]
- func Rune() *Generator[rune]
- func RuneFrom(runes []rune, tables ...*unicode.RangeTable) *Generator[rune]
- func SampledFrom[S ~[]E, E any](slice S) *Generator[E]
- func SliceOf[E any](elem *Generator[E]) *Generator[[]E]
- func SliceOfBytesMatching(expr string) *Generator[[]byte]
- func SliceOfDistinct[E any, K comparable](elem *Generator[E], keyFn func(E) K) *Generator[[]E]
- func SliceOfN[E any](elem *Generator[E], minLen int, maxLen int) *Generator[[]E]
- func SliceOfNDistinct[E any, K comparable](elem *Generator[E], minLen int, maxLen int, keyFn func(E) K) *Generator[[]E]
- func String() *Generator[string]
- func StringMatching(expr string) *Generator[string]
- func StringN(minRunes int, maxRunes int, maxLen int) *Generator[string]
- func StringOf(elem *Generator[rune]) *Generator[string]
- func StringOfN(elem *Generator[rune], minRunes int, maxRunes int, maxLen int) *Generator[string]
- func Uint() *Generator[uint]
- func Uint16() *Generator[uint16]
- func Uint16Max(max uint16) *Generator[uint16]
- func Uint16Min(min uint16) *Generator[uint16]
- func Uint16Range(min uint16, max uint16) *Generator[uint16]
- func Uint32() *Generator[uint32]
- func Uint32Max(max uint32) *Generator[uint32]
- func Uint32Min(min uint32) *Generator[uint32]
- func Uint32Range(min uint32, max uint32) *Generator[uint32]
- func Uint64() *Generator[uint64]
- func Uint64Max(max uint64) *Generator[uint64]
- func Uint64Min(min uint64) *Generator[uint64]
- func Uint64Range(min uint64, max uint64) *Generator[uint64]
- func Uint8() *Generator[uint8]
- func Uint8Max(max uint8) *Generator[uint8]
- func Uint8Min(min uint8) *Generator[uint8]
- func Uint8Range(min uint8, max uint8) *Generator[uint8]
- func UintMax(max uint) *Generator[uint]
- func UintMin(min uint) *Generator[uint]
- func UintRange(min uint, max uint) *Generator[uint]
- func Uintptr() *Generator[uintptr]
- func UintptrMax(max uintptr) *Generator[uintptr]
- func UintptrMin(min uintptr) *Generator[uintptr]
- func UintptrRange(min uintptr, max uintptr) *Generator[uintptr]
- type StateMachine
- type T
- func (t *T) Error(args ...any)
- func (t *T) Errorf(format string, args ...any)
- func (t *T) Fail()
- func (t *T) FailNow()
- func (t *T) Failed() bool
- func (t *T) Fatal(args ...any)
- func (t *T) Fatalf(format string, args ...any)
- func (t *T) Log(args ...any)
- func (t *T) Logf(format string, args ...any)
- func (t *T) Repeat(actions map[string]func(*T))
- func (t *T) Skip(args ...any)
- func (t *T) SkipNow()
- func (t *T) Skipf(format string, args ...any)
- type TB
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Check ¶
Check fails the current test if rapid can find a test case which falsifies prop.
Property is falsified in case of a panic or a call to *T.Fatalf, *T.Fatal, *T.Errorf, *T.Error, *T.FailNow or *T.Fail.
Example (ParseDate) ¶
Rename to TestParseDate(t *testing.T) to make an actual (failing) test.
package main import ( "fmt" "strconv" "testing" "pgregory.net/rapid" ) // ParseDate parses dates in the YYYY-MM-DD format. func ParseDate(s string) (int, int, int, error) { if len(s) != 10 { return 0, 0, 0, fmt.Errorf("%q has wrong length: %v instead of 10", s, len(s)) } if s[4] != '-' || s[7] != '-' { return 0, 0, 0, fmt.Errorf("'-' separators expected in %q", s) } y, err := strconv.Atoi(s[0:4]) if err != nil { return 0, 0, 0, fmt.Errorf("failed to parse year: %v", err) } m, err := strconv.Atoi(s[6:7]) if err != nil { return 0, 0, 0, fmt.Errorf("failed to parse month: %v", err) } d, err := strconv.Atoi(s[8:10]) if err != nil { return 0, 0, 0, fmt.Errorf("failed to parse day: %v", err) } return y, m, d, nil } func testParseDate(t *rapid.T) { y := rapid.IntRange(0, 9999).Draw(t, "y") m := rapid.IntRange(1, 12).Draw(t, "m") d := rapid.IntRange(1, 31).Draw(t, "d") s := fmt.Sprintf("%04d-%02d-%02d", y, m, d) y_, m_, d_, err := ParseDate(s) if err != nil { t.Fatalf("failed to parse date %q: %v", s, err) } if y_ != y || m_ != m || d_ != d { t.Fatalf("got back wrong date: (%d, %d, %d)", y_, m_, d_) } } // Rename to TestParseDate(t *testing.T) to make an actual (failing) test. func main() { var t *testing.T rapid.Check(t, testParseDate) }
Output:
func ID ¶ added in v0.5.0
func ID[V any](v V) V
ID returns its argument as is. ID is a helper for use with SliceOfDistinct and similar functions.
func MakeCheck ¶
MakeCheck is a convenience function for defining subtests suitable for *testing.T.Run. It allows you to write this:
t.Run("subtest name", rapid.MakeCheck(func(t *rapid.T) { // test code }))
instead of this:
t.Run("subtest name", func(t *testing.T) { rapid.Check(t, func(t *rapid.T) { // test code }) })
func MakeFuzz ¶ added in v0.5.2
MakeFuzz creates a fuzz target for *testing.F.Fuzz:
func FuzzFoo(f *testing.F) { f.Fuzz(rapid.MakeFuzz(func(t *rapid.T) { // test code })) }
func StateMachineActions ¶ added in v0.6.0
func StateMachineActions(sm StateMachine) map[string]func(*T)
StateMachineActions creates an actions map for *T.Repeat from methods of a StateMachine type instance using reflection.
Types ¶
type Generator ¶
type Generator[V any] struct { // contains filtered or unexported fields }
Generator describes a generator of values of type V.
func Custom ¶
Custom creates a generator which produces results of calling fn. In fn, values should be generated by calling other generators; it is invalid to return a value from fn without using any other generator. Custom is a primary way of creating user-defined generators.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { type point struct { x int y int } gen := rapid.Custom(func(t *rapid.T) point { return point{ x: rapid.IntRange(-100, 100).Draw(t, "x"), y: rapid.IntRange(-100, 100).Draw(t, "y"), } }) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: {-1 23} {-3 -50} {0 94} {-2 -50} {11 -57}
func Deferred ¶ added in v0.5.0
Deferred creates a generator which defers calling fn until attempting to produce a value. This allows to define recursive generators.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func recursive() *rapid.Generator[any] { return rapid.OneOf( rapid.Bool().AsAny(), rapid.SliceOfN(rapid.Deferred(recursive), 1, 2).AsAny(), ) } func main() { gen := recursive() for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: [[[[false] false]]] false [[true [[[true]]]]] true true
func Float32 ¶
Float32 is a shorthand for Float32Range(-math.MaxFloat32, math.MaxFloat32).
func Float32Max ¶
Float32Max is a shorthand for Float32Range(-math.MaxFloat32, max).
func Float32Min ¶
Float32Min is a shorthand for Float32Range(min, math.MaxFloat32).
func Float32Range ¶
Float32Range creates a generator of 32-bit floating-point numbers in range [min, max]. Both min and max can be infinite.
func Float64 ¶
Float64 is a shorthand for Float64Range(-math.MaxFloat64, math.MaxFloat64).
func Float64Max ¶
Float64Max is a shorthand for Float64Range(-math.MaxFloat64, max).
func Float64Min ¶
Float64Min is a shorthand for Float64Range(min, math.MaxFloat64).
func Float64Range ¶
Float64Range creates a generator of 64-bit floating-point numbers in range [min, max]. Both min and max can be infinite.
func Just ¶
Just creates a generator which always produces the given value. Just(val) is a shorthand for SampledFrom([]V{val}).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.Just(42) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: 42 42 42 42 42
func Make ¶ added in v0.5.0
Make creates a generator of values of type V, using reflection to infer the required structure.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.Make[map[int]bool]() for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: map[-433:true -261:false -53:false -23:false 1:true 184:false] map[-3:true 0:true] map[4:true] map[-359:true -154:true -71:true -17:false -1:false 590:false 22973756520:true] map[]
Example (Tree) ¶
package main import ( "fmt" "pgregory.net/rapid" ) type nodeValue int type tree struct { Value nodeValue Left, Right *tree } func (t *tree) String() string { if t == nil { return "nil" } return fmt.Sprintf("(%s %v %s)", t.Left.String(), t.Value, t.Right.String()) } func main() { gen := rapid.Make[*tree]() for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: (nil 1 (nil 184 nil)) (((nil -1 (((((nil -485 ((nil -2 ((((nil -5 nil) -9898554875447 nil) -34709387 ((nil 50440 nil) 113 (((((nil -442 nil) -66090341586 nil) 179745 nil) 494 (((nil -2 nil) 543360606020 nil) 15261837 nil)) -1778 nil))) -21034573818 nil)) -5 nil)) 15606609 nil) 882666 (nil 3 nil)) -12 (nil -2 ((nil 1 nil) -2 (((nil 11 nil) -187307 ((nil -198 (nil -6895 nil)) 12027 (nil -539313 nil))) 1532 (nil 6 nil))))) 1745354 nil)) -2 nil) -3 nil) nil (((nil -15 (nil 6598 nil)) -131 (nil 317121006373596 ((nil 14 ((nil -9223372036854775808 nil) 1 nil)) 14668 nil))) 590 nil) nil
func Map ¶ added in v0.5.4
Map creates a generator producing fn(u) for each u produced by g.
Example ¶
package main import ( "fmt" "strconv" "pgregory.net/rapid" ) func main() { gen := rapid.Map(rapid.Int(), strconv.Itoa) for i := 0; i < 5; i++ { fmt.Printf("%#v\n", gen.Example(i)) } }
Output: "-3" "-186981" "4" "-2" "43"
func MapOf ¶
func MapOf[K comparable, V any](key *Generator[K], val *Generator[V]) *Generator[map[K]V]
MapOf is a shorthand for MapOfN(key, val, -1, -1).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.MapOf(rapid.Int(), rapid.StringMatching(`[a-z]+`)) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: map[1:nhlgqwasbggbaociac 561860:r] map[-3752:pizpv -3:bacuabp 0:bi] map[-33086515648293:gewf -264276:b -1313:a -258:v -4:b -2:fdhbzcz 4:ubfsdbowrja 1775:tcozav 8334:lvcprss 376914:braigey] map[-350:h 590:coaaamcasnapgaad] map[]
func MapOfN ¶
func MapOfN[K comparable, V any](key *Generator[K], val *Generator[V], minLen int, maxLen int) *Generator[map[K]V]
MapOfN creates a map[K]V generator. If minLen >= 0, generated maps have minimum length of minLen. If maxLen >= 0, generated maps have maximum length of maxLen. MapOfN panics if maxLen >= 0 and minLen > maxLen.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.MapOfN(rapid.Int(), rapid.StringMatching(`[a-z]+`), 5, 5) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: map[-130450326583:bd -2983:bbdbcs 1:nhlgqwasbggbaociac 31:kmdnpmcbuagzr 561860:r] map[-82024404:d -3752:pizpv -3:bacuabp 0:bi 179745:rzkneb] map[-33086515648293:gewf -258:v 4:ubfsdbowrja 1775:tcozav 8334:lvcprss] map[-4280678227:j -25651:aafmd -3308:o -350:h 590:coaaamcasnapgaad] map[-9614404661322:gsb -378:y 2:paai 4629136912:otg 1476419818092:qign]
func MapOfNValues ¶
func MapOfNValues[K comparable, V any](val *Generator[V], minLen int, maxLen int, keyFn func(V) K) *Generator[map[K]V]
MapOfNValues creates a map[K]V generator, where keys are generated by applying keyFn to values. If minLen >= 0, generated maps have minimum length of minLen. If maxLen >= 0, generated maps have maximum length of maxLen. MapOfNValues panics if maxLen >= 0 and minLen > maxLen.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.MapOfNValues(rapid.StringMatching(`[a-z]+`), 5, 5, func(s string) int { return len(s) }) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: map[1:s 2:dr 3:anc 7:xguehfc 11:sbggbaociac] map[1:b 2:bp 4:ydag 5:jarxz 6:ebzkwa] map[1:j 3:gjl 5:eeeqa 7:stcozav 9:fxmcadagf] map[2:ub 8:waraafmd 10:bfiqcaxazu 16:rjgqimcasnapgaad 17:gckfbljafcedhcvfc] map[1:k 2:ay 3:wzb 4:dign 7:faabhcb]
func MapOfValues ¶
func MapOfValues[K comparable, V any](val *Generator[V], keyFn func(V) K) *Generator[map[K]V]
MapOfValues is a shorthand for MapOfNValues(val, -1, -1, keyFn).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.MapOfValues(rapid.StringMatching(`[a-z]+`), func(s string) int { return len(s) }) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: map[2:dr 7:xguehfc 11:sbggbaociac] map[2:bp 5:jarxz 6:ebzkwa] map[1:j 2:aj 3:gjl 4:vayt 5:eeeqa 6:riacaa 7:stcozav 8:mfdhbzcz 9:fxmcadagf 10:bgsbraigey 15:gxongygnxqlovib] map[2:ub 8:waraafmd 10:bfiqcaxazu 16:rjgqimcasnapgaad 17:gckfbljafcedhcvfc] map[]
func OneOf ¶
OneOf creates a generator which produces each value by selecting one of gens and producing a value from it. OneOf panics if gens is empty.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.OneOf(rapid.Int32Range(1, 10).AsAny(), rapid.Float32Range(100, 1000).AsAny()) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: 997.0737 10 475.3125 2 9
func Permutation ¶ added in v0.5.3
Permutation creates a generator which produces permutations of the given slice.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.Permutation([]int{1, 2, 3}) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: [2 3 1] [3 2 1] [2 1 3] [3 2 1] [1 2 3]
func Ptr ¶
Ptr creates a *E generator. If allowNil is true, Ptr can return nil pointers.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.Ptr(rapid.Int(), true) for i := 0; i < 5; i++ { v := gen.Example(i) if v == nil { fmt.Println("<nil>") } else { fmt.Println("(*int)", *v) } } }
Output: (*int) 1 (*int) -3 <nil> (*int) 590 <nil>
func Rune ¶
Rune creates a rune generator. Rune is equivalent to RuneFrom with default set of runes and tables.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.Rune() for i := 0; i < 25; i++ { if i%5 == 0 { fmt.Println() } else { fmt.Print(" ") } fmt.Printf("%q", gen.Example(i)) } }
Output: '\n' '\x1b' 'A' 'a' '*' '0' '@' '?' '\'' '\ue05d' '<' '%' '!' '\u0604' 'A' '%' '╷' '~' '!' '/' '\u00ad' '𝪪' '@' '҈' ' '
func RuneFrom ¶
func RuneFrom(runes []rune, tables ...*unicode.RangeTable) *Generator[rune]
RuneFrom creates a rune generator from provided runes and tables. RuneFrom panics if both runes and tables are empty. RuneFrom panics if tables contain an empty table.
Example ¶
package main import ( "fmt" "unicode" "pgregory.net/rapid" ) func main() { gens := []*rapid.Generator[rune]{ rapid.RuneFrom([]rune{'A', 'B', 'C'}), rapid.RuneFrom(nil, unicode.Cyrillic, unicode.Greek), rapid.RuneFrom([]rune{'⌘'}, &unicode.RangeTable{ R32: []unicode.Range32{{0x1F600, 0x1F64F, 1}}, }), } for _, gen := range gens { for i := 0; i < 5; i++ { if i > 0 { fmt.Print(" ") } fmt.Printf("%q", gen.Example(i)) } fmt.Println() } }
Output: 'A' 'A' 'A' 'B' 'A' 'Ͱ' 'Ѥ' 'Ͱ' 'ͱ' 'Ϳ' '😀' '⌘' '😀' '😁' '😋'
func SampledFrom ¶
SampledFrom creates a generator which produces values from the given slice. SampledFrom panics if slice is empty.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.SampledFrom([]int{1, 2, 3}) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: 2 3 2 3 1
func SliceOf ¶
SliceOf is a shorthand for SliceOfN(elem, -1, -1).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.SliceOf(rapid.Int()) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: [1 -1902 7 -236 14 -433 -1572631 -1 4219826 -50 1414 -3890044391133 -9223372036854775808 5755498240 -10 680558 10 -80458281 0 -27] [-3 -2 -1 -3 -2172865589 -5 -2 -2503553836720] [4 308 -2 21 -5843 3 1 78 6129321692 -59] [590 -131 -15 -769 16 -1 14668 14 -1 -58784] []
func SliceOfBytesMatching ¶
SliceOfBytesMatching creates a UTF-8 byte slice generator matching the provided syntax.Perl regular expression.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.SliceOfBytesMatching(`[CAGT]+`) for i := 0; i < 5; i++ { fmt.Printf("%q\n", gen.Example(i)) } }
Output: "CCTTGAGAGCGATACGGAAG" "GCAGAACT" "AACCGTCGAG" "GGGAAAAGAT" "AGTG"
func SliceOfDistinct ¶
func SliceOfDistinct[E any, K comparable](elem *Generator[E], keyFn func(E) K) *Generator[[]E]
SliceOfDistinct is a shorthand for SliceOfNDistinct(elem, -1, -1, keyFn).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.SliceOfDistinct(rapid.IntMin(0), func(i int) int { return i % 2 }) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: [1] [2 1] [4 1] [590] []
func SliceOfN ¶
SliceOfN creates a []E generator. If minLen >= 0, generated slices have minimum length of minLen. If maxLen >= 0, generated slices have maximum length of maxLen. SliceOfN panics if maxLen >= 0 and minLen > maxLen.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.SliceOfN(rapid.Int(), 5, 5) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: [1 -1902 7 -236 14] [-3 -2 -1 -3 -2172865589] [4 308 -2 21 -5843] [590 -131 -15 -769 16] [4629136912 270 141395 -129322425838843911 -7]
func SliceOfNDistinct ¶
func SliceOfNDistinct[E any, K comparable](elem *Generator[E], minLen int, maxLen int, keyFn func(E) K) *Generator[[]E]
SliceOfNDistinct creates a []E generator. Elements of each generated slice are distinct according to keyFn. If minLen >= 0, generated slices have minimum length of minLen. If maxLen >= 0, generated slices have maximum length of maxLen. SliceOfNDistinct panics if maxLen >= 0 and minLen > maxLen. ID helper can be used as keyFn to generate slices of distinct comparable elements.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.SliceOfNDistinct(rapid.IntMin(0), 2, 2, func(i int) int { return i % 2 }) for i := 0; i < 5; i++ { fmt.Println(gen.Example(i)) } }
Output: [4219826 49] [2 1] [4 1] [0 58783] [4629136912 141395]
func String ¶
String is a shorthand for StringOf(Rune()).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.String() for i := 0; i < 5; i++ { fmt.Printf("%q\n", gen.Example(i)) } }
Output: "\n߾⃝?\rA�֍" "\u2006𑰼" "A¢\u0603ᾢ" "+^#.[#৲" ""
func StringMatching ¶
StringMatching creates a UTF-8 string generator matching the provided syntax.Perl regular expression.
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.StringMatching(`\(?([0-9]{3})\)?([ .-]?)([0-9]{3})([ .-]?)([0-9]{4})`) for i := 0; i < 5; i++ { fmt.Printf("%q\n", gen.Example(i)) } }
Output: "(532) 649-9610" "901)-5783983" "914.444.1575" "(316 696.3584" "816)0861080"
func StringN ¶
StringN is a shorthand for StringOfN(Rune(), minRunes, maxRunes, maxLen).
Example ¶
package main import ( "fmt" "pgregory.net/rapid" ) func main() { gen := rapid.StringN(5, 5, -1) for i := 0; i < 5; i++ { fmt.Printf("%q\n", gen.Example(i)) } }
Output: "\n߾⃝?\r" "\u2006𑰼#`\x1b" "A¢\u0603ᾢÉ" "+^#.[" ".A<a¤"
func StringOf ¶
StringOf is a shorthand for StringOfN(elem, -1, -1, -1).
Example ¶
package main import ( "fmt" "unicode" "pgregory.net/rapid" ) func main() { gen := rapid.StringOf(rapid.RuneFrom(nil, unicode.Tibetan)) for i := 0; i < 5; i++ { fmt.Printf("%q\n", gen.Example(i)) } }
Output: "༁༭༇ཬ༆༐༖ༀྸ༁༆༎ༀ༁ཱི༂༨ༀ༂" "༂༁ༀ༂༴ༀ༁ྵ" "ༀ༴༁༅ན༃༁༎ྼ༄༽" "༎༂༎ༀༀༀཌྷ༂ༀྥ" ""
func StringOfN ¶
StringOfN creates a UTF-8 string generator. If minRunes >= 0, generated strings have minimum minRunes runes. If maxRunes >= 0, generated strings have maximum maxRunes runes. If maxLen >= 0, generates strings have maximum length of maxLen. StringOfN panics if maxRunes >= 0 and minRunes > maxRunes. StringOfN panics if maxLen >= 0 and maxLen < maxRunes.
Example ¶
package main import ( "fmt" "unicode" "pgregory.net/rapid" ) func main() { gen := rapid.StringOfN(rapid.RuneFrom(nil, unicode.ASCII_Hex_Digit), 6, 6, -1) for i := 0; i < 5; i++ { fmt.Printf("%q\n", gen.Example(i)) } }
Output: "1D7B6a" "2102e0" "0e15c3" "E2E000" "aEd623"
func UintptrMax ¶
func UintptrMin ¶
func (*Generator[V]) AsAny ¶ added in v0.5.0
AsAny creates a generator producing values from g converted to any.
func (*Generator[V]) Example ¶
Example produces an example value from the generator. If seed is provided, value is produced deterministically based on seed. Example should only be used for examples; always use *Generator.Draw in property-based tests.
type StateMachine ¶
type StateMachine interface { // Check is ran after every action and should contain invariant checks. // // All other public methods should have a form ActionName(t *rapid.T) // and are used as possible actions. At least one action has to be specified. Check(*T) }
type T ¶
type T struct {
// contains filtered or unexported fields
}
T is similar to testing.T, but with extra bookkeeping for property-based tests.
For tests to be reproducible, they should generally run in a single goroutine. If concurrency is unavoidable, methods on *T, such as *testing.T.Helper and *T.Errorf, are safe for concurrent calls, but *Generator.Draw from a given *T is not.
func (*T) Repeat ¶ added in v0.7.0
Repeat executes a random sequence of actions (often called a "state machine" test). actions[""], if set, is executed before/after every other action invocation and should only contain invariant checking code.
For complex state machines, it can be more convenient to specify actions as methods of a special state machine type. In this case, StateMachineActions can be used to create an actions map from state machine methods using reflection.
Example (Queue) ¶
Rename to TestQueue(t *testing.T) to make an actual (failing) test.
package main import ( "testing" "pgregory.net/rapid" ) // Queue implements integer queue with a fixed maximum size. type Queue struct { buf []int in int out int } func NewQueue(n int) *Queue { return &Queue{ buf: make([]int, n+1), } } // Precondition: Size() > 0. func (q *Queue) Get() int { i := q.buf[q.out] q.out = (q.out + 1) % len(q.buf) return i } // Precondition: Size() < n. func (q *Queue) Put(i int) { q.buf[q.in] = i q.in = (q.in + 1) % len(q.buf) } func (q *Queue) Size() int { return (q.in - q.out) % len(q.buf) } func testQueue(t *rapid.T) { n := rapid.IntRange(1, 1000).Draw(t, "n") // maximum queue size q := NewQueue(n) // queue being tested var state []int // model of the queue t.Repeat(map[string]func(*rapid.T){ "get": func(t *rapid.T) { if q.Size() == 0 { t.Skip("queue empty") } i := q.Get() if i != state[0] { t.Fatalf("got invalid value: %v vs expected %v", i, state[0]) } state = state[1:] }, "put": func(t *rapid.T) { if q.Size() == n { t.Skip("queue full") } i := rapid.Int().Draw(t, "i") q.Put(i) state = append(state, i) }, "": func(t *rapid.T) { if q.Size() != len(state) { t.Fatalf("queue size mismatch: %v vs expected %v", q.Size(), len(state)) } }, }) } // Rename to TestQueue(t *testing.T) to make an actual (failing) test. func main() { var t *testing.T rapid.Check(t, testQueue) }
Output:
func (*T) SkipNow ¶
func (t *T) SkipNow()
SkipNow marks the current test case as invalid (except in T.Repeat actions, where it marks current action as non-applicable instead). If too many test cases are skipped, rapid will mark the test as failing due to inability to generate enough valid test cases.
Prefer *Generator.Filter to SkipNow, and prefer generators that always produce valid test cases to Filter.
type TB ¶ added in v0.4.8
type TB interface { Helper() Name() string Logf(format string, args ...any) Log(args ...any) Skipf(format string, args ...any) Skip(args ...any) SkipNow() Errorf(format string, args ...any) Error(args ...any) Fatalf(format string, args ...any) Fatal(args ...any) FailNow() Fail() Failed() bool }
TB is a common interface between *testing.T, *testing.B and *T.