github.com/leanovate/gopter@v0.2.9/gen/map_of.go (about)

     1  package gen
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/leanovate/gopter"
     7  )
     8  
     9  // MapOf generates an arbitrary map of generated kay values.
    10  // genParams.MaxSize sets an (exclusive) upper limit on the size of the map
    11  // genParams.MinSize sets an (inclusive) lower limit on the size of the map
    12  func MapOf(keyGen, elementGen gopter.Gen) gopter.Gen {
    13  	return func(genParams *gopter.GenParameters) *gopter.GenResult {
    14  		len := 0
    15  		if genParams.MaxSize > 0 || genParams.MinSize > 0 {
    16  			if genParams.MinSize > genParams.MaxSize {
    17  				panic("GenParameters.MinSize must be <= GenParameters.MaxSize")
    18  			}
    19  
    20  			if genParams.MaxSize == genParams.MinSize {
    21  				len = genParams.MaxSize
    22  			} else {
    23  				len = genParams.Rng.Intn(genParams.MaxSize-genParams.MinSize) + genParams.MinSize
    24  			}
    25  		}
    26  
    27  		result, keySieve, keyShrinker, elementSieve, elementShrinker := genMap(keyGen, elementGen, genParams, len)
    28  
    29  		genResult := gopter.NewGenResult(result.Interface(), MapShrinker(keyShrinker, elementShrinker))
    30  		if keySieve != nil || elementSieve != nil {
    31  			genResult.Sieve = forAllKeyValueSieve(keySieve, elementSieve)
    32  		}
    33  		return genResult
    34  	}
    35  }
    36  
    37  func genMap(keyGen, elementGen gopter.Gen, genParams *gopter.GenParameters, len int) (reflect.Value, func(interface{}) bool, gopter.Shrinker, func(interface{}) bool, gopter.Shrinker) {
    38  	element := elementGen(genParams)
    39  	elementSieve := element.Sieve
    40  	elementShrinker := element.Shrinker
    41  
    42  	key := keyGen(genParams)
    43  	keySieve := key.Sieve
    44  	keyShrinker := key.Shrinker
    45  
    46  	result := reflect.MakeMapWithSize(reflect.MapOf(key.ResultType, element.ResultType), len)
    47  
    48  	for i := 0; i < len; i++ {
    49  		keyValue, keyOk := key.Retrieve()
    50  		elementValue, elementOk := element.Retrieve()
    51  
    52  		if keyOk && elementOk {
    53  			if key == nil {
    54  				if elementValue == nil {
    55  					result.SetMapIndex(reflect.Zero(key.ResultType), reflect.Zero(element.ResultType))
    56  				} else {
    57  					result.SetMapIndex(reflect.Zero(key.ResultType), reflect.ValueOf(elementValue))
    58  				}
    59  			} else {
    60  				if elementValue == nil {
    61  					result.SetMapIndex(reflect.ValueOf(keyValue), reflect.Zero(element.ResultType))
    62  				} else {
    63  					result.SetMapIndex(reflect.ValueOf(keyValue), reflect.ValueOf(elementValue))
    64  				}
    65  			}
    66  		}
    67  		key = keyGen(genParams)
    68  		element = elementGen(genParams)
    69  	}
    70  
    71  	return result, keySieve, keyShrinker, elementSieve, elementShrinker
    72  }
    73  
    74  func forAllKeyValueSieve(keySieve, elementSieve func(interface{}) bool) func(interface{}) bool {
    75  	return func(v interface{}) bool {
    76  		rv := reflect.ValueOf(v)
    77  		for _, key := range rv.MapKeys() {
    78  			if keySieve != nil && !keySieve(key.Interface()) {
    79  				return false
    80  			}
    81  			if elementSieve != nil && !elementSieve(rv.MapIndex(key).Interface()) {
    82  				return false
    83  			}
    84  		}
    85  		return true
    86  	}
    87  }