// Copyright 2019 Gregory Petrosyan <gregory.petrosyan@gmail.com>//// This Source Code Form is subject to the terms of the Mozilla Public// License, v. 2.0. If a copy of the MPL was not distributed with this// file, You can obtain one at https://mozilla.org/MPL/2.0/. package rapid_test import ( "context" "errors" "fmt" "strconv" "testing" . "pgregory.net/rapid") type testStruct struct { x int y int} func genBool(t *T) bool { return Bool().Draw(t, "")} func genInterface(t *T) any { if Bool().Draw(t, "coinflip") { return Int8().Draw(t, "") } else { return Float64().Draw(t, "") }} func genSlice(t *T) []uint64 { return []uint64{ Uint64().Draw(t, ""), Uint64().Draw(t, ""), }} func genStruct(t *T) testStruct { return testStruct{ x: Int().Draw(t, "x"), y: Int().Draw(t, "y"), }} func TestCustom(t *testing.T) { t.Parallel() gens := []*Generator[any]{ Custom(genBool).AsAny(), Custom(genInterface).AsAny(), Custom(genSlice).AsAny(), Custom(genStruct).AsAny(), } for _, g := range gens { t.Run(g.String(), MakeCheck(func(t *T) { g.Draw(t, "") })) }} func TestCustomContext(t *testing.T) { t.Parallel() type key struct{} gen := Custom(func(t *T) context.Context { ctx := t.Context() // Inside the custom generator, the context must be valid. if err := ctx.Err(); err != nil { t.Fatalf("context must be valid: %v", err) } x := Int().Draw(t, "x") return context.WithValue(ctx, key{}, x) }) Check(t, func(t *T) { ctx := gen.Draw(t, "value") if _, ok := ctx.Value(key{}).(int); !ok { t.Fatalf("context must contain an int") } // Outside the custom generator, // the context from inside the generator // must no longer be valid. if err := ctx.Err(); err == nil || !errors.Is(err, context.Canceled) { t.Fatalf("context must be canceled: %v", err) } })} func TestCustomCleanup(t *testing.T) { t.Parallel() var open bool gen := Custom(func(t *T) int { t.Cleanup(func() { open = false }) return Int().Draw(t, "") }) // Cleanup functions registered during a Custom generator // are run after generation, not after the Check. Check(t, func(t *T) { open = true _ = gen.Draw(t, "value") // Cleanup must run after each run of the custom generator. if open { t.Fatalf("cleanup must be run") } })} func TestFilter(t *testing.T) { t.Parallel() g := Int().Filter(func(i int) bool { return i >= 0 }) Check(t, func(t *T) { v := g.Draw(t, "v") if v < 0 { t.Fatalf("got negative %v", v) } })} func TestMap(t *testing.T) { t.Parallel() g := Map(Int(), strconv.Itoa) Check(t, func(t *T) { s := g.Draw(t, "s") _, err := strconv.Atoi(s) if err != nil { t.Fatalf("Atoi() error %v", err) } })} func TestSampledFrom(t *testing.T) { t.Parallel() gens := []*Generator[int]{ Just(3), SampledFrom([]int{3, 5, 7}), } for _, g := range gens { t.Run(g.String(), MakeCheck(func(t *T) { n := g.Draw(t, "n") if n != 3 && n != 5 && n != 7 { t.Fatalf("got impossible %v", n) } })) }} func TestOneOf_SameType(t *testing.T) { t.Parallel() pos := Int().Filter(func(v int) bool { return v >= 10 }) neg := Int().Filter(func(v int) bool { return v <= -10 }) g := OneOf(pos, neg) Check(t, func(t *T) { n := g.Draw(t, "n") if n > -10 && n < 10 { t.Fatalf("got impossible %v", n) } })} func TestOneOf_DifferentTypes(t *testing.T) { t.Parallel() g := OneOf(Int().AsAny(), Int8().AsAny(), Int16().AsAny(), Int32().AsAny(), Int64().AsAny()) Check(t, func(t *T) { n := g.Draw(t, "n") _ = rv(n).Int() })} func TestPtr(t *testing.T) { t.Parallel() for _, allowNil := range []bool{false, true} { t.Run(fmt.Sprintf("allowNil=%v", allowNil), MakeCheck(func(t *T) { i := Ptr(Int(), allowNil).Draw(t, "i") if i == nil && !allowNil { t.Fatalf("got nil pointer") } })) }}
// Copyright 2019 Gregory Petrosyan <gregory.petrosyan@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
package rapid_test
import (
"context"
"errors"
"fmt"
"strconv"
"testing"
. "pgregory.net/rapid"
)
type testStruct struct {
x int
y int
}
func genBool(t *T) bool {
return Bool().Draw(t, "")
}
func genInterface(t *T) any {
if Bool().Draw(t, "coinflip") {
return Int8().Draw(t, "")
} else {
return Float64().Draw(t, "")
}
}
func genSlice(t *T) []uint64 {
return []uint64{
Uint64().Draw(t, ""),
Uint64().Draw(t, ""),
}
}
func genStruct(t *T) testStruct {
return testStruct{
x: Int().Draw(t, "x"),
y: Int().Draw(t, "y"),
}
}
func TestCustom(t *testing.T) {
t.Parallel()
gens := []*Generator[any]{
Custom(genBool).AsAny(),
Custom(genInterface).AsAny(),
Custom(genSlice).AsAny(),
Custom(genStruct).AsAny(),
}
for _, g := range gens {
t.Run(g.String(), MakeCheck(func(t *T) { g.Draw(t, "") }))
}
}
func TestCustomContext(t *testing.T) {
t.Parallel()
type key struct{}
gen := Custom(func(t *T) context.Context {
ctx := t.Context()
// Inside the custom generator, the context must be valid.
if err := ctx.Err(); err != nil {
t.Fatalf("context must be valid: %v", err)
}
x := Int().Draw(t, "x")
return context.WithValue(ctx, key{}, x)
})
Check(t, func(t *T) {
ctx := gen.Draw(t, "value")
if _, ok := ctx.Value(key{}).(int); !ok {
t.Fatalf("context must contain an int")
}
// Outside the custom generator,
// the context from inside the generator
// must no longer be valid.
if err := ctx.Err(); err == nil || !errors.Is(err, context.Canceled) {
t.Fatalf("context must be canceled: %v", err)
}
})
}
func TestCustomCleanup(t *testing.T) {
t.Parallel()
var open bool
gen := Custom(func(t *T) int {
t.Cleanup(func() { open = false })
return Int().Draw(t, "")
})
// Cleanup functions registered during a Custom generator
// are run after generation, not after the Check.
Check(t, func(t *T) {
open = true
_ = gen.Draw(t, "value")
// Cleanup must run after each run of the custom generator.
if open {
t.Fatalf("cleanup must be run")
}
})
}
func TestFilter(t *testing.T) {
t.Parallel()
g := Int().Filter(func(i int) bool { return i >= 0 })
Check(t, func(t *T) {
v := g.Draw(t, "v")
if v < 0 {
t.Fatalf("got negative %v", v)
}
})
}
func TestMap(t *testing.T) {
t.Parallel()
g := Map(Int(), strconv.Itoa)
Check(t, func(t *T) {
s := g.Draw(t, "s")
_, err := strconv.Atoi(s)
if err != nil {
t.Fatalf("Atoi() error %v", err)
}
})
}
func TestSampledFrom(t *testing.T) {
t.Parallel()
gens := []*Generator[int]{
Just(3),
SampledFrom([]int{3, 5, 7}),
}
for _, g := range gens {
t.Run(g.String(), MakeCheck(func(t *T) {
n := g.Draw(t, "n")
if n != 3 && n != 5 && n != 7 {
t.Fatalf("got impossible %v", n)
}
}))
}
}
func TestOneOf_SameType(t *testing.T) {
t.Parallel()
pos := Int().Filter(func(v int) bool { return v >= 10 })
neg := Int().Filter(func(v int) bool { return v <= -10 })
g := OneOf(pos, neg)
Check(t, func(t *T) {
n := g.Draw(t, "n")
if n > -10 && n < 10 {
t.Fatalf("got impossible %v", n)
}
})
}
func TestOneOf_DifferentTypes(t *testing.T) {
t.Parallel()
g := OneOf(Int().AsAny(), Int8().AsAny(), Int16().AsAny(), Int32().AsAny(), Int64().AsAny())
Check(t, func(t *T) {
n := g.Draw(t, "n")
_ = rv(n).Int()
})
}
func TestPtr(t *testing.T) {
t.Parallel()
for _, allowNil := range []bool{false, true} {
t.Run(fmt.Sprintf("allowNil=%v", allowNil), MakeCheck(func(t *T) {
i := Ptr(Int(), allowNil).Draw(t, "i")
if i == nil && !allowNil {
t.Fatalf("got nil pointer")
}
}))
}
}