@@ -54,6 +54,10 @@ type randomizeObjectCfg struct {
5454 ZeroesEveryN int
5555 // AllUintSizes will be equally likely to generate 8-bit, 16-bit, 32-bit, or 64-bit uints.
5656 AllUintSizes bool
57+ // MaxCollectionLen bounds randomized slice/map lengths when positive.
58+ MaxCollectionLen int
59+ // SilenceAllocWarnings suppresses allocbound warning prints.
60+ SilenceAllocWarnings bool
5761}
5862
5963// RandomizeObjectOption is an option for RandomizeObject
@@ -69,6 +73,20 @@ func RandomizeObjectWithAllUintSizes() RandomizeObjectOption {
6973 return func (cfg * randomizeObjectCfg ) { cfg .AllUintSizes = true }
7074}
7175
76+ // RandomizeObjectSilenceAllocWarnings silences allocbound warning prints.
77+ func RandomizeObjectSilenceAllocWarnings () RandomizeObjectOption {
78+ return func (cfg * randomizeObjectCfg ) { cfg .SilenceAllocWarnings = true }
79+ }
80+
81+ // RandomizeObjectWithMaxCollectionLen limits randomized slice/map lengths to n (when n>0).
82+ func RandomizeObjectWithMaxCollectionLen (n int ) RandomizeObjectOption {
83+ return func (cfg * randomizeObjectCfg ) {
84+ if n > 0 {
85+ cfg .MaxCollectionLen = n
86+ }
87+ }
88+ }
89+
7290// RandomizeObject returns a random object of the same type as template
7391func RandomizeObject (template interface {}, opts ... RandomizeObjectOption ) (interface {}, error ) {
7492 cfg := randomizeObjectCfg {}
@@ -185,7 +203,7 @@ func checkMsgpAllocBoundDirective(dataType reflect.Type) bool {
185203 return false
186204}
187205
188- func checkBoundsLimitingTag (val reflect.Value , datapath string , structTag string ) (hasAllocBound bool ) {
206+ func checkBoundsLimitingTag (val reflect.Value , datapath string , structTag string , cfg randomizeObjectCfg ) (hasAllocBound bool ) {
189207 var objType string
190208 if val .Kind () == reflect .Slice {
191209 objType = "slice"
@@ -199,7 +217,9 @@ func checkBoundsLimitingTag(val reflect.Value, datapath string, structTag string
199217 tagsMap := parseStructTags (structTag )
200218
201219 if tagsMap ["allocbound" ] == "-" {
202- printWarning (fmt .Sprintf ("%s %s have an unbounded allocbound defined" , objType , datapath ))
220+ if ! cfg .SilenceAllocWarnings {
221+ printWarning (fmt .Sprintf ("%s %s have an unbounded allocbound defined" , objType , datapath ))
222+ }
203223 return
204224 }
205225
@@ -234,7 +254,9 @@ func checkBoundsLimitingTag(val reflect.Value, datapath string, structTag string
234254 }
235255
236256 if val .Type ().Kind () == reflect .Slice || val .Type ().Kind () == reflect .Map || val .Type ().Kind () == reflect .Array {
237- printWarning (fmt .Sprintf ("%s %s does not have an allocbound defined for %s %s" , objType , datapath , val .Type ().String (), val .Type ().PkgPath ()))
257+ if ! cfg .SilenceAllocWarnings {
258+ printWarning (fmt .Sprintf ("%s %s does not have an allocbound defined for %s %s" , objType , datapath , val .Type ().String (), val .Type ().PkgPath ()))
259+ }
238260 }
239261 return
240262}
@@ -285,7 +307,7 @@ func randomizeValue(v reflect.Value, depth int, datapath string, tag string, rem
285307 v .SetInt (int64 (rand .Uint64 ()))
286308 * remainingChanges --
287309 case reflect .String :
288- hasAllocBound := checkBoundsLimitingTag (v , datapath , tag )
310+ hasAllocBound := checkBoundsLimitingTag (v , datapath , tag , cfg )
289311 var buf []byte
290312 var len int
291313 if strings .HasSuffix (v .Type ().PkgPath (), "go-algorand/agreement" ) && v .Type ().Name () == "serializableError" {
@@ -359,9 +381,13 @@ func randomizeValue(v reflect.Value, depth int, datapath string, tag string, rem
359381 case reflect .Slice :
360382 // we don't want to allocate a slice with size of 0. This is because decoding and encoding this slice
361383 // will result in nil and not slice of size 0
362- l := rand .Int ()% 31 + 1
384+ maxLen := 31
385+ if cfg .MaxCollectionLen > 0 {
386+ maxLen = min (maxLen , cfg .MaxCollectionLen )
387+ }
388+ l := rand .Intn (maxLen ) + 1
363389
364- hasAllocBound := checkBoundsLimitingTag (v , datapath , tag )
390+ hasAllocBound := checkBoundsLimitingTag (v , datapath , tag , cfg )
365391 if hasAllocBound {
366392 l = 1
367393 }
@@ -382,10 +408,15 @@ func randomizeValue(v reflect.Value, depth int, datapath string, tag string, rem
382408 v .SetBool (rand .Uint32 ()% 2 == 0 )
383409 * remainingChanges --
384410 case reflect .Map :
385- hasAllocBound := checkBoundsLimitingTag (v , datapath , tag )
411+ hasAllocBound := checkBoundsLimitingTag (v , datapath , tag , cfg )
386412 mt := v .Type ()
387413 v .Set (reflect .MakeMap (mt ))
388- l := rand .Int () % 32
414+ maxLen := 32
415+ if cfg .MaxCollectionLen > 0 {
416+ // preserve possibility of zero entries while capping positive lengths
417+ maxLen = min (maxLen , cfg .MaxCollectionLen + 1 )
418+ }
419+ l := rand .Intn (maxLen )
389420 if hasAllocBound {
390421 l = 1
391422 }
0 commit comments