// SliceShrinker creates a slice shrinker from a shrinker for the elements of the slice. // The length of the slice will be shrinked as well func SliceShrinker(elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Slice { panic(fmt.Sprintf("%#v is not a slice", v)) } sliceShrink := &sliceShrink{ original: rv, offset: 0, length: rv.Len(), chunkLength: rv.Len() >> 1, } shrinks := make([]gopter.Shrink, 0, rv.Len()+1) shrinks = append(shrinks, sliceShrink.Next) for i := 0; i < rv.Len(); i++ { sliceShrinkOne := &sliceShrinkOne{ original: rv, index: i, elementShrink: elementShrinker(rv.Index(i).Interface()), } shrinks = append(shrinks, sliceShrinkOne.Next) } return gopter.ConcatShrinks(shrinks...) } }
// PtrShrinker convert a value shrinker to a pointer to value shrinker func PtrShrinker(elementShrinker gopter.Shrinker) gopter.Shrinker { return func(v interface{}) gopter.Shrink { if v == nil { return gopter.NoShrink } rt := reflect.TypeOf(v) elementShink := elementShrinker(reflect.ValueOf(v).Elem().Interface()) nilShrink := &nilShrink{} return gopter.ConcatShrinks( nilShrink.Next, elementShink.Map(func(elem interface{}) interface{} { slice := reflect.MakeSlice(reflect.SliceOf(rt.Elem()), 0, 1) slice = reflect.Append(slice, reflect.ValueOf(elem)) return slice.Index(0).Addr().Interface() }), ) } }