1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
package gopter
import (
"fmt"
"reflect"
)
type derivedGen struct {
biMapper *BiMapper
upGens []Gen
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.Shrinker),
Result: nil,
Labels: result.Labels,
ResultType: d.resultType,
Sieve: d.Sieve(sieves...),
}
}
}
down := d.biMapper.ConvertDown(up)
if len(down) == 1 {
return &GenResult{
Shrinker: d.Shrinker(CombineShrinker(shrinkers...)),
Result: down[0],
Labels: labels,
ResultType: reflect.TypeOf(down[0]),
Sieve: d.Sieve(sieves...),
}
}
return &GenResult{
Shrinker: d.Shrinker(CombineShrinker(shrinkers...)),
Result: down,
Labels: labels,
ResultType: reflect.TypeOf(down),
Sieve: d.Sieve(sieves...),
}
}
func (d *derivedGen) Sieve(baseSieve ...func(interface{}) bool) func(interface{}) bool {
return func(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 baseSieve[i] != nil && !baseSieve[i](up) {
return false
}
}
return true
}
}
func (d *derivedGen) Shrinker(baseShrinker Shrinker) func(down interface{}) Shrink {
return func(down interface{}) Shrink {
downs, ok := down.([]interface{})
if !ok {
downs = []interface{}{down}
}
ups := d.biMapper.ConvertUp(downs)
upShrink := baseShrinker(ups)
return upShrink.Map(func(shrunkUps []interface{}) interface{} {
downs := d.biMapper.ConvertDown(shrunkUps)
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]
}
derived := &derivedGen{
biMapper: biMapper,
upGens: gens,
resultType: resultType,
}
return derived.Generate
}
|