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

     1  package gen
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/leanovate/gopter"
     7  )
     8  
     9  // SliceOf generates an arbitrary slice of generated elements
    10  // genParams.MaxSize sets an (exclusive) upper limit on the size of the slice
    11  // genParams.MinSize sets an (inclusive) lower limit on the size of the slice
    12  func SliceOf(elementGen gopter.Gen, typeOverrides ...reflect.Type) gopter.Gen {
    13  	var typeOverride reflect.Type
    14  	if len(typeOverrides) > 1 {
    15  		panic("too many type overrides specified, at most 1 may be provided.")
    16  	} else if len(typeOverrides) == 1 {
    17  		typeOverride = typeOverrides[0]
    18  	}
    19  	return func(genParams *gopter.GenParameters) *gopter.GenResult {
    20  		len := 0
    21  		if genParams.MaxSize > 0 || genParams.MinSize > 0 {
    22  			if genParams.MinSize > genParams.MaxSize {
    23  				panic("GenParameters.MinSize must be <= GenParameters.MaxSize")
    24  			}
    25  
    26  			if genParams.MaxSize == genParams.MinSize {
    27  				len = genParams.MaxSize
    28  			} else {
    29  				len = genParams.Rng.Intn(genParams.MaxSize-genParams.MinSize) + genParams.MinSize
    30  			}
    31  		}
    32  		result, elementSieve, elementShrinker := genSlice(elementGen, genParams, len, typeOverride)
    33  
    34  		genResult := gopter.NewGenResult(result.Interface(), SliceShrinker(elementShrinker))
    35  		if elementSieve != nil {
    36  			genResult.Sieve = forAllSieve(elementSieve)
    37  		}
    38  		return genResult
    39  	}
    40  }
    41  
    42  // SliceOfN generates a slice of generated elements with definied length
    43  func SliceOfN(desiredlen int, elementGen gopter.Gen, typeOverrides ...reflect.Type) gopter.Gen {
    44  	var typeOverride reflect.Type
    45  	if len(typeOverrides) > 1 {
    46  		panic("too many type overrides specified, at most 1 may be provided.")
    47  	} else if len(typeOverrides) == 1 {
    48  		typeOverride = typeOverrides[0]
    49  	}
    50  	return func(genParams *gopter.GenParameters) *gopter.GenResult {
    51  		result, elementSieve, elementShrinker := genSlice(elementGen, genParams, desiredlen, typeOverride)
    52  
    53  		genResult := gopter.NewGenResult(result.Interface(), SliceShrinkerOne(elementShrinker))
    54  		if elementSieve != nil {
    55  			genResult.Sieve = func(v interface{}) bool {
    56  				rv := reflect.ValueOf(v)
    57  				return rv.Len() == desiredlen && forAllSieve(elementSieve)(v)
    58  			}
    59  		} else {
    60  			genResult.Sieve = func(v interface{}) bool {
    61  				return reflect.ValueOf(v).Len() == desiredlen
    62  			}
    63  		}
    64  		return genResult
    65  	}
    66  }
    67  
    68  func genSlice(elementGen gopter.Gen, genParams *gopter.GenParameters, desiredlen int, typeOverride reflect.Type) (reflect.Value, func(interface{}) bool, gopter.Shrinker) {
    69  	element := elementGen(genParams)
    70  	elementSieve := element.Sieve
    71  	elementShrinker := element.Shrinker
    72  
    73  	sliceType := typeOverride
    74  	if sliceType == nil {
    75  		sliceType = element.ResultType
    76  	}
    77  
    78  	result := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, desiredlen)
    79  
    80  	for i := 0; i < desiredlen; i++ {
    81  		value, ok := element.Retrieve()
    82  
    83  		if ok {
    84  			if value == nil {
    85  				result = reflect.Append(result, reflect.Zero(sliceType))
    86  			} else {
    87  				result = reflect.Append(result, reflect.ValueOf(value))
    88  			}
    89  		}
    90  		element = elementGen(genParams)
    91  	}
    92  
    93  	return result, elementSieve, elementShrinker
    94  }
    95  
    96  func forAllSieve(elementSieve func(interface{}) bool) func(interface{}) bool {
    97  	return func(v interface{}) bool {
    98  		rv := reflect.ValueOf(v)
    99  		for i := rv.Len() - 1; i >= 0; i-- {
   100  			if !elementSieve(rv.Index(i).Interface()) {
   101  				return false
   102  			}
   103  		}
   104  		return true
   105  	}
   106  }