github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/amino/reflect_test.go (about) 1 package amino_test 2 3 import ( 4 "fmt" 5 "math/rand" 6 "reflect" 7 "runtime/debug" 8 "testing" 9 "time" 10 11 "github.com/davecgh/go-spew/spew" 12 fuzz "github.com/google/gofuzz" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 proto "google.golang.org/protobuf/proto" 16 17 "github.com/gnolang/gno/tm2/pkg/amino" 18 "github.com/gnolang/gno/tm2/pkg/amino/tests" 19 ) 20 21 // ------------------------------------- 22 // Non-interface Google fuzz tests 23 24 func TestCodecStruct(t *testing.T) { 25 t.Parallel() 26 27 for _, ptr := range tests.StructTypes { 28 t.Logf("case %v", reflect.TypeOf(ptr)) 29 rt := getTypeFromPointer(ptr) 30 name := rt.Name() 31 t.Run(name+":binary", func(t *testing.T) { 32 t.Parallel() 33 _testCodec(t, rt, "binary") 34 }) 35 t.Run(name+":json", func(t *testing.T) { 36 t.Parallel() 37 _testCodec(t, rt, "json") 38 }) 39 } 40 } 41 42 func TestCodecDef(t *testing.T) { 43 t.Parallel() 44 45 for _, ptr := range tests.DefTypes { 46 t.Logf("case %v", reflect.TypeOf(ptr)) 47 rt := getTypeFromPointer(ptr) 48 name := rt.Name() 49 t.Run(name+":binary", func(t *testing.T) { 50 t.Parallel() 51 _testCodec(t, rt, "binary") 52 }) 53 t.Run(name+":json", func(t *testing.T) { 54 t.Parallel() 55 _testCodec(t, rt, "json") 56 }) 57 } 58 } 59 60 func TestDeepCopyStruct(t *testing.T) { 61 t.Parallel() 62 63 for _, ptr := range tests.StructTypes { 64 t.Logf("case %v", reflect.TypeOf(ptr)) 65 rt := getTypeFromPointer(ptr) 66 name := rt.Name() 67 t.Run(name+":deepcopy", func(t *testing.T) { 68 t.Parallel() 69 _testDeepCopy(t, rt) 70 }) 71 } 72 } 73 74 func TestDeepCopyDef(t *testing.T) { 75 t.Parallel() 76 77 for _, ptr := range tests.DefTypes { 78 t.Logf("case %v", reflect.TypeOf(ptr)) 79 rt := getTypeFromPointer(ptr) 80 name := rt.Name() 81 t.Run(name+":deepcopy", func(t *testing.T) { 82 t.Parallel() 83 _testDeepCopy(t, rt) 84 }) 85 } 86 } 87 88 func _testCodec(t *testing.T, rt reflect.Type, codecType string) { 89 t.Helper() 90 91 err := error(nil) 92 bz := []byte{} 93 cdc := amino.NewCodec() 94 f := fuzz.New() 95 rv := reflect.New(rt) 96 rv2 := reflect.New(rt) 97 ptr := rv.Interface() 98 ptr2 := rv2.Interface() 99 rnd := rand.New(rand.NewSource(10)) 100 f.RandSource(rnd) 101 f.Funcs(fuzzFuncs...) 102 103 defer func() { 104 if r := recover(); r != nil { 105 t.Fatalf("panic'd:\nreason: %v\n%s\nerr: %v\nbz: %X\nrv: %#v\nrv2: %#v\nptr: %v\nptr2: %v\n", 106 r, debug.Stack(), err, bz, rv, rv2, spw(ptr), spw(ptr2), 107 ) 108 } 109 }() 110 111 for i := 0; i < 1e4; i++ { 112 f.Fuzz(ptr) 113 114 // Reset, which makes debugging decoding easier. 115 rv2 = reflect.New(rt) 116 ptr2 = rv2.Interface() 117 118 // Encode to bz. 119 switch codecType { 120 case "binary": 121 bz, err = cdc.Marshal(ptr) 122 case "json": 123 bz, err = cdc.MarshalJSON(ptr) 124 default: 125 panic("should not happen") 126 } 127 require.Nil(t, err, 128 "failed to marshal %v to bytes: %v\n", 129 spw(ptr), err) 130 131 // Decode from bz. 132 switch codecType { 133 case "binary": 134 err = cdc.Unmarshal(bz, ptr2) 135 case "json": 136 err = cdc.UnmarshalJSON(bz, ptr2) 137 default: 138 panic("should not happen") 139 } 140 require.NoError(t, err, 141 "failed to unmarshal bytes %X (%s): %v\nptr: %v\n", 142 bz, bz, err, spw(ptr)) 143 require.Equal(t, ptr, ptr2, 144 "end to end failed.\nstart: %v\nend: %v\nbytes: %X\nstring(bytes): %s\n", 145 spw(ptr), spw(ptr2), bz, bz) 146 147 if codecType == "binary" { 148 // Get pbo from rv. (go -> p3go) 149 pbm, ok := rv.Interface().(amino.PBMessager) 150 if !ok { 151 // typedefs that are not structs, for example, 152 // are not pbMessanger. 153 continue 154 } 155 pbo, err := pbm.ToPBMessage(cdc) 156 require.NoError(t, err) 157 158 // Get back to go from pbo, and ensure equality. (go -> p3go -> go vs go) 159 rv3 := reflect.New(rt) 160 ptr3 := rv3.Interface() 161 err = ptr3.(amino.PBMessager).FromPBMessage(cdc, pbo) 162 require.NoError(t, err) 163 require.Equal(t, ptr, ptr3, 164 "end to end through pbo failed.\nstart(goo): %v\nend(goo): %v\nmid(pbo): %v\n", 165 spw(ptr), spw(ptr3), spw(pbo)) 166 167 // Marshal pbo and check for equality of bz and b3. (go -> p3go -> bz vs go -> bz) 168 bz3, err := proto.Marshal(pbo) 169 require.NoError(t, err) 170 require.Equal(t, bz, bz3, 171 "pbo serialization check failed.\nbz(go): %X\nbz(pb-go): %X\nstart(goo): %v\nend(pbo): %v\n", 172 bz, bz3, spw(ptr), spw(pbo)) 173 174 // Decode from bz and check for equality (go -> bz -> p3go -> go vs go) 175 pbo2 := pbm.EmptyPBMessage(cdc) 176 err = proto.Unmarshal(bz, pbo2) 177 require.NoError(t, err) 178 rv4 := reflect.New(rt) 179 ptr4 := rv4.Interface() 180 err = ptr4.(amino.PBMessager).FromPBMessage(cdc, pbo2) 181 require.NoError(t, err) 182 require.Equal(t, ptr, ptr4, 183 "end to end through bytes and pbo failed.\nbz(go): %X\nstart(goo): %v\nend(goo): %v\nmid(pbo): %v\n", 184 bz, spw(ptr), spw(ptr3), spw(pbo)) 185 } 186 } 187 } 188 189 func _testDeepCopy(t *testing.T, rt reflect.Type) { 190 t.Helper() 191 192 err := error(nil) 193 f := fuzz.New() 194 rv := reflect.New(rt) 195 ptr := rv.Interface() 196 rnd := rand.New(rand.NewSource(10)) 197 f.RandSource(rnd) 198 f.Funcs(fuzzFuncs...) 199 200 defer func() { 201 if r := recover(); r != nil { 202 t.Fatalf("panic'd:\nreason: %v\n%s\nerr: %v\nrv: %#v\nptr: %v\n", 203 r, debug.Stack(), err, rv, spw(ptr), 204 ) 205 } 206 }() 207 208 for i := 0; i < 1e4; i++ { 209 f.Fuzz(ptr) 210 211 ptr2 := amino.DeepCopy(ptr) 212 213 require.Equal(t, ptr, ptr2, 214 "end to end failed.\nstart: %v\nend: %v\nbytes: %X\nstring(bytes): %s\n", 215 spw(ptr), spw(ptr2)) 216 } 217 } 218 219 // ---------------------------------------- 220 // Register/interface tests 221 222 func TestCodecMashalFailsOnUnregisteredConcrete(t *testing.T) { 223 t.Parallel() 224 225 cdc := amino.NewCodec() 226 227 bz, err := cdc.Marshal(struct{ tests.Interface1 }{tests.Concrete1{}}) 228 assert.Error(t, err, "concrete type not registered") 229 assert.Empty(t, bz) 230 } 231 232 func TestCodecMarshalPassesOnRegistered(t *testing.T) { 233 t.Parallel() 234 235 cdc := amino.NewCodec() 236 cdc.RegisterTypeFrom(reflect.TypeOf(tests.Concrete1{}), tests.Package) 237 238 bz, err := cdc.Marshal(struct{ tests.Interface1 }{tests.Concrete1{}}) 239 assert.NoError(t, err, "correctly registered") 240 assert.Equal(t, 241 // 0x0a --> field #1 Typ3ByteLength (anonymous struct) 242 // 0x12 --> length prefix (18 bytes) 243 // 0x0a --> field #1 Typ3ByteLength (Any) 244 // 0x10 --> length prefix (12 bytes) 245 // 0x2f, ... 0x31 --> "/tests.Concrete1" 246 []byte{0x0a, 0x12, 0x0a, 0x10, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x31}, 247 bz, 248 "bytes did not match") 249 } 250 251 func TestCodecRegisterAndMarshalMultipleConcrete(t *testing.T) { 252 t.Parallel() 253 254 cdc := amino.NewCodec() 255 cdc.RegisterTypeFrom(reflect.TypeOf(tests.Concrete1{}), tests.Package) 256 cdc.RegisterTypeFrom(reflect.TypeOf(tests.Concrete2{}), tests.Package) 257 258 { // test tests.Concrete1, no conflict. 259 bz, err := cdc.Marshal(struct{ tests.Interface1 }{tests.Concrete1{}}) 260 assert.NoError(t, err, "correctly registered") 261 assert.Equal(t, 262 // 0x0a --> field #1 Typ3ByteLength (anonymous struct) 263 // 0x12 --> length prefix (18 bytes) 264 // 0x0a --> field #1 Typ3ByteLength (Any) 265 // 0x10 --> length prefix (12 bytes) 266 // 0x2f, ... 0x31 --> "/tests.Concrete1" 267 []byte{0x0a, 0x12, 0x0a, 0x10, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x31}, 268 bz, 269 "bytes did not match") 270 } 271 272 { // test tests.Concrete2, no conflict 273 bz, err := cdc.Marshal(struct{ tests.Interface1 }{tests.Concrete2{}}) 274 assert.NoError(t, err, "correctly registered") 275 assert.Equal(t, 276 // 0x0a --> field #1 Typ3ByteLength (anonymous struct) 277 // 0x12 --> length prefix (18 bytes) 278 // 0x0a --> field #1 Typ3ByteLength (Any TypeURL) 279 // 0x10 --> length prefix (12 bytes) 280 // 0x2f, ... 0x31 --> "/tests.Concrete2" 281 []byte{0x0a, 0x12, 0x0a, 0x10, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x32}, 282 bz, 283 "bytes did not match") 284 } 285 } 286 287 // Serialize and deserialize a registered typedef. 288 func TestCodecRoundtripNonNilRegisteredTypeDef(t *testing.T) { 289 t.Parallel() 290 291 cdc := amino.NewCodec() 292 cdc.RegisterTypeFrom(reflect.TypeOf(tests.ConcreteTypeDef{}), tests.Package) 293 294 c3 := tests.ConcreteTypeDef{} 295 copy(c3[:], []byte("0123")) 296 297 bz, err := cdc.Marshal(struct{ tests.Interface1 }{c3}) 298 assert.Nil(t, err) 299 assert.Equal(t, 300 // 0x0a --> field #1 Typ3ByteLength (anonymous struct) 301 // 0x20 --> length prefix (32 bytes) 302 // 0x0a --> field #1 Typ3ByteLength (Any TypeURL) 303 // 0x16 --> length prefix (18 bytes) 304 // 0x2f, ... 0x31 --> "/tests.ConcreteTypeDef" 305 []byte{ 306 0x0a, 0x20, 0x0a, 0x16, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x44, 0x65, 0x66, 307 // 0x12 --> field #2 Typ3ByteLength (Any Value) 308 // 0x06 --> length prefix (6 bytes) 309 // 0x0a --> field #1, one and only, of implicit struct. 310 // 0x04 --> length prefix (4 bytes) 311 /**/ 0x12, 0x06, 0x0a, 0x04, 0x30, 0x31, 0x32, 0x33, 312 }, 313 bz, 314 "ConcreteTypeDef incorrectly serialized") 315 316 var i1 tests.Interface1 317 err = cdc.Unmarshal(bz, &i1) 318 assert.Error(t, err) // This fails, because the interface was wrapped in an anonymous struct. 319 320 // try wrapping it in an Any struct 321 // without changing the existing behavior. 322 type anyType struct { 323 TypeURL string 324 Value []byte 325 } 326 anyc3 := anyType{ 327 TypeURL: "/tests.ConcreteTypeDef", 328 Value: []byte{0x0a, 0x04, 0x30, 0x31, 0x32, 0x33}, // An implicit struct, the first field which is the length-prefixed 4 bytes. 329 } 330 331 // var i1c3 tests.Interface1 = c3 332 // bz, err = cdc.Marshal(&i1c3) 333 bz, err = cdc.Marshal(anyc3) 334 assert.Nil(t, err) 335 assert.Equal(t, 336 // 0x0a --> field #1 Typ3ByteLength (Any TypeURL) 337 // 0x16 --> length prefix (22 bytes) 338 // 0x2f, ... 0x33 --> "/tests.ConcreteTypeDef" 339 []byte{ 340 0x0a, 0x16, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x44, 0x65, 0x66, 341 // 0x12 --> field #2 Typ3ByteLength (Any Value) 342 // 0x06 --> length prefix (6 bytes) 343 // 0x0a --> field #1, one and only, of implicit struct. 344 // 0x04 --> length prefix (4 bytes) 345 /**/ 0x12, 0x06, 0x0a, 0x04, 0x30, 0x31, 0x32, 0x33, 346 }, 347 bz, 348 "ConcreteTypeDef incorrectly serialized") 349 350 // This time it should work. 351 err = cdc.Unmarshal(bz, &i1) 352 assert.NoError(t, err) 353 assert.Equal(t, c3, i1) 354 355 // The easiest way is this: 356 bz2, err := cdc.MarshalAny(c3) 357 assert.Nil(t, err) 358 assert.Equal(t, bz, bz2) 359 } 360 361 // Exactly like TestCodecRoundtripNonNilRegisteredTypeDef but with struct 362 // around the value instead of a type def. 363 func TestCodecRoundtripNonNilRegisteredWrappedValue(t *testing.T) { 364 t.Parallel() 365 366 cdc := amino.NewCodec() 367 cdc.RegisterTypeFrom(reflect.TypeOf(tests.ConcreteWrappedBytes{}), tests.Package) 368 369 c3 := tests.ConcreteWrappedBytes{Value: []byte("0123")} 370 371 bz, err := cdc.MarshalAny(c3) 372 assert.Nil(t, err) 373 assert.Equal(t, 374 // 0x0a --> field #1 Typ3ByteLength (Any TypeURL) 375 // 0x1b --> length prefix (27 bytes) 376 // 0x2f, ... 0x33 --> "/tests.ConcreteWrappedBytes" 377 []byte{ 378 0x0a, 0x1b, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 379 // 0x12 --> field #2 Typ3ByteLength (Any Value) 380 // 0x06 --> length prefix (6 bytes) 381 // 0x0a --> field #1, one and only, of implicit struct. 382 // 0x04 --> length prefix (4 bytes) 383 /**/ 0x12, 0x06, 0x0a, 0x04, 0x30, 0x31, 0x32, 0x33, 384 }, 385 bz, 386 "ConcreteWrappedBytes incorrectly serialized") 387 388 var i1 tests.Interface1 389 err = cdc.Unmarshal(bz, &i1) 390 assert.NoError(t, err) 391 assert.Equal(t, c3, i1) 392 } 393 394 // MarshalAny(msg) and Marshal(&msg) are the same. 395 func TestCodecMarshalAny(t *testing.T) { 396 t.Parallel() 397 398 cdc := amino.NewCodec() 399 cdc.RegisterTypeFrom(reflect.TypeOf(tests.ConcreteWrappedBytes{}), tests.Package) 400 401 obj := tests.ConcreteWrappedBytes{Value: []byte("0123")} 402 ifc := (interface{})(obj) 403 404 bz1, err := cdc.MarshalAny(obj) 405 assert.Nil(t, err) 406 407 bz2, err := cdc.Marshal(&ifc) 408 assert.Nil(t, err) 409 410 assert.Equal(t, bz1, bz2, "Marshal(*interface) or MarshalAny(concrete) incorrectly serialized\nMarshalAny(concrete): %X\nMarshal(*interface): %X", bz1, bz2) 411 } 412 413 // Like TestCodecRoundtripNonNilRegisteredTypeDef, but JSON. 414 func TestCodecJSONRoundtripNonNilRegisteredTypeDef(t *testing.T) { 415 t.Parallel() 416 417 cdc := amino.NewCodec() 418 cdc.RegisterTypeFrom(reflect.TypeOf(tests.ConcreteTypeDef{}), tests.Package) 419 420 var c3 tests.ConcreteTypeDef 421 copy(c3[:], []byte("0123")) 422 423 bz, err := cdc.MarshalJSONAny(c3) 424 assert.Nil(t, err) 425 assert.Equal(t, 426 `{"@type":"/tests.ConcreteTypeDef","value":"MDEyMw=="}`, string(bz), 427 "ConcreteTypeDef incorrectly serialized") 428 429 var i1 tests.Interface1 430 err = cdc.UnmarshalJSON(bz, &i1) 431 assert.Nil(t, err) 432 assert.Equal(t, c3, i1) 433 } 434 435 // Like TestCodecRoundtripNonNilRegisteredTypeDef, but serialize the concrete value directly. 436 func TestCodecRoundtripMarshalOnConcreteNonNilRegisteredTypeDef(t *testing.T) { 437 t.Parallel() 438 439 cdc := amino.NewCodec() 440 cdc.RegisterTypeFrom(reflect.TypeOf(tests.ConcreteTypeDef{}), tests.Package) 441 442 var c3 tests.ConcreteTypeDef 443 copy(c3[:], []byte("0123")) 444 445 bz, err := cdc.MarshalAny(c3) 446 assert.Nil(t, err) 447 assert.Equal(t, 448 // 0x0a --> field #1 Typ3ByteLength (Any TypeURL) 449 // 0x16 --> length prefix (18 bytes) 450 // 0x2f, ... 0x31 --> "/tests.ConcreteTypeDef" 451 []byte{ 452 0x0a, 0x16, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x44, 0x65, 0x66, 453 // 0x12 --> field #2 Typ3ByteLength (Any Value) 454 // 0x06 --> length prefix (6 bytes) 455 // 0x0a --> field #1, one and only, of implicit struct. 456 // 0x04 --> length prefix (4 bytes) 457 /**/ 0x12, 0x06, 0x0a, 0x04, 0x30, 0x31, 0x32, 0x33, 458 }, 459 bz, 460 "ConcreteTypeDef incorrectly serialized") 461 462 var i1 tests.Interface1 463 err = cdc.Unmarshal(bz, &i1) 464 assert.NoError(t, err) 465 assert.Equal(t, c3, i1) 466 } 467 468 // Like TestCodecRoundtripNonNilRegisteredTypeDef but read into concrete var. 469 func TestCodecRoundtripUnmarshalOnConcreteNonNilRegisteredTypeDef(t *testing.T) { 470 t.Parallel() 471 472 cdc := amino.NewCodec() 473 cdc.RegisterTypeFrom(reflect.TypeOf(tests.ConcreteTypeDef{}), tests.Package) 474 475 var c3a tests.ConcreteTypeDef 476 copy(c3a[:], []byte("0123")) 477 478 bz, err := cdc.Marshal(c3a) 479 assert.Nil(t, err) 480 assert.Equal(t, 481 []byte{0xa, 0x4, 0x30, 0x31, 0x32, 0x33}, bz, 482 "ConcreteTypeDef incorrectly serialized") 483 484 var c3b tests.ConcreteTypeDef 485 err = cdc.Unmarshal(bz, &c3b) 486 assert.Nil(t, err) 487 assert.Equal(t, c3a, c3b) 488 } 489 490 func TestCodecBinaryStructFieldNilInterface(t *testing.T) { 491 t.Parallel() 492 493 cdc := amino.NewCodec() 494 cdc.RegisterTypeFrom(reflect.TypeOf(tests.InterfaceFieldsStruct{}), tests.Package) 495 496 i1 := &tests.InterfaceFieldsStruct{F1: new(tests.InterfaceFieldsStruct), F2: nil} 497 bz, err := cdc.MarshalSized(i1) 498 assert.NoError(t, err) 499 500 i2 := new(tests.InterfaceFieldsStruct) 501 err = cdc.UnmarshalSized(bz, i2) 502 503 assert.NoError(t, err) 504 require.Equal(t, i1, i2, "i1 and i2 should be the same after decoding") 505 } 506 507 // ---------------------------------------- 508 // Misc. 509 510 func spw(o interface{}) string { 511 return spew.Sprintf("%#v", o) 512 } 513 514 var fuzzFuncs = []interface{}{ 515 func(ptr **int8, c fuzz.Continue) { 516 var i int8 517 c.Fuzz(&i) 518 *ptr = &i 519 }, 520 func(ptr **int16, c fuzz.Continue) { 521 var i int16 522 c.Fuzz(&i) 523 *ptr = &i 524 }, 525 func(ptr **int32, c fuzz.Continue) { 526 var i int32 527 c.Fuzz(&i) 528 *ptr = &i 529 }, 530 func(ptr **int64, c fuzz.Continue) { 531 var i int64 532 c.Fuzz(&i) 533 *ptr = &i 534 }, 535 func(ptr **int, c fuzz.Continue) { 536 var i int 537 c.Fuzz(&i) 538 *ptr = &i 539 }, 540 func(ptr **uint8, c fuzz.Continue) { 541 var ui uint8 542 c.Fuzz(&ui) 543 *ptr = &ui 544 }, 545 /* go-amino 1.2 removed nested pointer support 546 func(ptr ***uint8, c fuzz.Continue) { 547 var ui uint8 548 c.Fuzz(&ui) 549 *ptr = new(*uint8) 550 **ptr = new(uint8) 551 ***ptr = ui 552 }, 553 func(ptr ****uint8, c fuzz.Continue) { 554 var ui uint8 555 c.Fuzz(&ui) 556 *ptr = new(**uint8) 557 **ptr = new(*uint8) 558 ***ptr = new(uint8) 559 ****ptr = ui 560 }, 561 */ 562 func(ptr **uint16, c fuzz.Continue) { 563 var ui uint16 564 c.Fuzz(&ui) 565 *ptr = &ui 566 }, 567 func(ptr **uint32, c fuzz.Continue) { 568 var ui uint32 569 c.Fuzz(&ui) 570 *ptr = &ui 571 }, 572 func(ptr **uint64, c fuzz.Continue) { 573 var ui uint64 574 c.Fuzz(&ui) 575 *ptr = &ui 576 }, 577 func(ptr **uint, c fuzz.Continue) { 578 var ui uint 579 c.Fuzz(&ui) 580 *ptr = &ui 581 }, 582 func(ptr **string, c fuzz.Continue) { 583 // Prefer nil instead of zero, for deep equality. 584 // (go-amino decoder will always prefer nil). 585 s := randString(c) 586 if len(s) == 0 { 587 *ptr = nil 588 } else { 589 *ptr = &s 590 } 591 }, 592 func(bz **[]byte, c fuzz.Continue) { 593 // Prefer nil instead of zero, for deep equality. 594 // (go-amino decoder will always prefer nil). 595 var by []byte 596 c.Fuzz(&by) 597 *bz = &by 598 }, 599 func(tyme *time.Time, c fuzz.Continue) { 600 // Set time.Unix(_,_) to wipe .wal 601 switch c.Intn(4) { 602 case 0: 603 ns := c.Int63n(10) 604 *tyme = time.Unix(0, ns) 605 case 1: 606 ns := c.Int63n(1e10) 607 *tyme = time.Unix(0, ns) 608 case 2: 609 const maxSeconds = 4611686018 // (1<<63 - 1) / 1e9 610 s := c.Int63n(maxSeconds) 611 ns := c.Int63n(1e10) 612 *tyme = time.Unix(s, ns) 613 case 3: 614 s := c.Int63n(10) 615 ns := c.Int63n(1e10) 616 *tyme = time.Unix(s, ns) 617 } 618 // Strip timezone and monotonic for deep equality. 619 // Also set to UTC. 620 *tyme = tyme.Truncate(0).UTC() 621 }, 622 func(ptr **time.Duration, c fuzz.Continue) { 623 // Zero should decode to ptr to zero duration, 624 // rather than a nil duration pointer. 625 switch c.Intn(4) { 626 case 0: 627 ns := c.Int63n(20) - 10 628 dur := time.Duration(ns) 629 *ptr = &dur 630 case 1: 631 ns := c.Int63n(2e10) - 1e10 632 dur := time.Duration(ns) 633 *ptr = &dur 634 case 2: // NOTE: not max p3 duration 635 ns := 1<<63 - 1 636 dur := time.Duration(ns) 637 *ptr = &dur 638 case 3: // NOTE: not min p3 duration 639 ns := -1<<63 + 1 640 dur := time.Duration(ns) 641 *ptr = &dur 642 } 643 }, 644 func(esz *[]*tests.EmptyStruct, c fuzz.Continue) { 645 n := c.Intn(4) 646 switch n { 647 case 0: 648 // Prefer nil over empty slice. 649 *esz = nil 650 default: 651 // Empty slice elements should be non-nil, 652 // since we don't set amino:"nil_elements". 653 *esz = make([]*tests.EmptyStruct, n) 654 for i := 0; i < n; i++ { 655 (*esz)[i] = &tests.EmptyStruct{} 656 } 657 } 658 }, 659 } 660 661 func getTypeFromPointer(ptr interface{}) reflect.Type { 662 rt := reflect.TypeOf(ptr) 663 if rt.Kind() != reflect.Ptr { 664 panic(fmt.Sprintf("expected pointer, got %v", rt)) 665 } 666 return rt.Elem() 667 } 668 669 // ---------------------------------------- 670 // From https://github.com/google/gofuzz/blob/master/fuzz.go 671 // (Apache2.0 License) 672 673 type charRange struct { 674 first, last rune 675 } 676 677 // choose returns a random unicode character from the given range, using the 678 // given randomness source. 679 func (r *charRange) choose(rand fuzz.Continue) rune { 680 count := int64(r.last - r.first) 681 return r.first + rune(rand.Int63n(count)) 682 } 683 684 var unicodeRanges = []charRange{ 685 {' ', '~'}, // ASCII characters 686 {'\u00a0', '\u02af'}, // Multi-byte encoded characters 687 {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) 688 } 689 690 // randString makes a random string up to 20 characters long. The returned string 691 // may include a variety of (valid) UTF-8 encodings. 692 func randString(r fuzz.Continue) string { 693 n := r.Intn(19) + 1 694 runes := make([]rune, n) 695 for i := range runes { 696 runes[i] = unicodeRanges[r.Intn(len(unicodeRanges))].choose(r) 697 } 698 return string(runes) 699 }