github.com/ava-labs/avalanchego@v1.11.11/codec/codectest/codectest.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 // Package codectest provides a test suite for testing codec implementations. 5 package codectest 6 7 import ( 8 "math" 9 "testing" 10 11 "github.com/stretchr/testify/require" 12 13 codecpkg "github.com/ava-labs/avalanchego/codec" 14 ) 15 16 // A NamedTest couples a test in the suite with a human-readable name. 17 type NamedTest struct { 18 Name string 19 Test func(testing.TB, codecpkg.GeneralCodec) 20 } 21 22 // Run runs the test on the GeneralCodec. 23 func (tt *NamedTest) Run(t *testing.T, c codecpkg.GeneralCodec) { 24 t.Run(tt.Name, func(t *testing.T) { 25 tt.Test(t, c) 26 }) 27 } 28 29 // RunAll runs all [Tests], constructing a new GeneralCodec for each. 30 func RunAll(t *testing.T, ctor func() codecpkg.GeneralCodec) { 31 for _, tt := range Tests { 32 tt.Run(t, ctor()) 33 } 34 } 35 36 // RunAll runs all [MultipleTagsTests], constructing a new GeneralCodec for each. 37 func RunAllMultipleTags(t *testing.T, ctor func() codecpkg.GeneralCodec) { 38 for _, tt := range MultipleTagsTests { 39 tt.Run(t, ctor()) 40 } 41 } 42 43 var ( 44 Tests = []NamedTest{ 45 {"Struct", TestStruct}, 46 {"Register Struct Twice", TestRegisterStructTwice}, 47 {"UInt32", TestUInt32}, 48 {"UIntPtr", TestUIntPtr}, 49 {"Slice", TestSlice}, 50 {"Max-Size Slice", TestMaxSizeSlice}, 51 {"Bool", TestBool}, 52 {"Array", TestArray}, 53 {"Big Array", TestBigArray}, 54 {"Pointer To Struct", TestPointerToStruct}, 55 {"Slice Of Struct", TestSliceOfStruct}, 56 {"Interface", TestInterface}, 57 {"Slice Of Interface", TestSliceOfInterface}, 58 {"Array Of Interface", TestArrayOfInterface}, 59 {"Pointer To Interface", TestPointerToInterface}, 60 {"String", TestString}, 61 {"Nil Slice", TestNilSlice}, 62 {"Serialize Unexported Field", TestSerializeUnexportedField}, 63 {"Serialize Of NoSerialize Field", TestSerializeOfNoSerializeField}, 64 {"Nil Slice Serialization", TestNilSliceSerialization}, 65 {"Empty Slice Serialization", TestEmptySliceSerialization}, 66 {"Slice With Empty Serialization", TestSliceWithEmptySerialization}, 67 {"Slice With Empty Serialization Error", TestSliceWithEmptySerializationError}, 68 {"Map With Empty Serialization", TestMapWithEmptySerialization}, 69 {"Map With Empty Serialization Error", TestMapWithEmptySerializationError}, 70 {"Slice Too Large", TestSliceTooLarge}, 71 {"Negative Numbers", TestNegativeNumbers}, 72 {"Too Large Unmarshal", TestTooLargeUnmarshal}, 73 {"Unmarshal Invalid Interface", TestUnmarshalInvalidInterface}, 74 {"Extra Space", TestExtraSpace}, 75 {"Slice Length Overflow", TestSliceLengthOverflow}, 76 {"Map", TestMap}, 77 {"Can Marshal Large Slices", TestCanMarshalLargeSlices}, 78 } 79 80 MultipleTagsTests = []NamedTest{ 81 {"Multiple Tags", TestMultipleTags}, 82 } 83 ) 84 85 // The below structs and interfaces exist 86 // for the sake of testing 87 88 var ( 89 _ Foo = (*MyInnerStruct)(nil) 90 _ Foo = (*MyInnerStruct2)(nil) 91 ) 92 93 type Foo interface { 94 Foo() int 95 } 96 97 type MyInnerStruct struct { 98 Str string `serialize:"true"` 99 } 100 101 func (*MyInnerStruct) Foo() int { 102 return 1 103 } 104 105 type MyInnerStruct2 struct { 106 Bool bool `serialize:"true"` 107 } 108 109 func (*MyInnerStruct2) Foo() int { 110 return 2 111 } 112 113 // MyInnerStruct3 embeds Foo, an interface, 114 // so it has to implement TypeID and ConcreteInstance 115 type MyInnerStruct3 struct { 116 Str string `serialize:"true"` 117 M1 MyInnerStruct `serialize:"true"` 118 F Foo `serialize:"true"` 119 } 120 121 type myStruct struct { 122 InnerStruct MyInnerStruct `serialize:"true"` 123 InnerStruct2 *MyInnerStruct `serialize:"true"` 124 Member1 int64 `serialize:"true"` 125 Member2 uint16 `serialize:"true"` 126 MyArray2 [5]string `serialize:"true"` 127 MyArray3 [3]MyInnerStruct `serialize:"true"` 128 MyArray4 [2]*MyInnerStruct2 `serialize:"true"` 129 MySlice []byte `serialize:"true"` 130 MySlice2 []string `serialize:"true"` 131 MySlice3 []MyInnerStruct `serialize:"true"` 132 MySlice4 []*MyInnerStruct2 `serialize:"true"` 133 MyArray [4]byte `serialize:"true"` 134 MyInterface Foo `serialize:"true"` 135 MySlice5 []Foo `serialize:"true"` 136 InnerStruct3 MyInnerStruct3 `serialize:"true"` 137 MyPointer *Foo `serialize:"true"` 138 MyMap1 map[string]string `serialize:"true"` 139 MyMap2 map[int32][]MyInnerStruct3 `serialize:"true"` 140 MyMap3 map[MyInnerStruct2][]int32 `serialize:"true"` 141 MyMap4 map[int32]*int32 `serialize:"true"` 142 MyMap5 map[int32]int32 `serialize:"true"` 143 MyMap6 map[[5]int32]int32 `serialize:"true"` 144 MyMap7 map[interface{}]interface{} `serialize:"true"` 145 Uint8 uint8 `serialize:"true"` 146 Int8 int8 `serialize:"true"` 147 Uint16 uint16 `serialize:"true"` 148 Int16 int16 `serialize:"true"` 149 Uint32 uint32 `serialize:"true"` 150 Int32 int32 `serialize:"true"` 151 Uint64 uint64 `serialize:"true"` 152 Int64 int64 `serialize:"true"` 153 Bool bool `serialize:"true"` 154 String string `serialize:"true"` 155 } 156 157 // Test marshaling/unmarshaling a complicated struct 158 func TestStruct(t testing.TB, codec codecpkg.GeneralCodec) { 159 require := require.New(t) 160 161 temp := Foo(&MyInnerStruct{}) 162 myMap3 := make(map[MyInnerStruct2][]int32) 163 myMap3[MyInnerStruct2{false}] = []int32{991, 12} 164 myMap3[MyInnerStruct2{true}] = []int32{1911, 1921} 165 166 myMap4 := make(map[int32]*int32) 167 zero := int32(0) 168 one := int32(1) 169 myMap4[0] = &zero 170 myMap4[1] = &one 171 172 myMap6 := make(map[[5]int32]int32) 173 myMap6[[5]int32{0, 1, 2, 3, 4}] = 1 174 myMap6[[5]int32{1, 2, 3, 4, 5}] = 2 175 176 myMap7 := make(map[interface{}]interface{}) 177 myMap7["key"] = "value" 178 myMap7[int32(1)] = int32(2) 179 180 myStructInstance := myStruct{ 181 InnerStruct: MyInnerStruct{"hello"}, 182 InnerStruct2: &MyInnerStruct{"yello"}, 183 Member1: 1, 184 Member2: 2, 185 MySlice: []byte{1, 2, 3, 4}, 186 MySlice2: []string{"one", "two", "three"}, 187 MySlice3: []MyInnerStruct{{"abc"}, {"ab"}, {"c"}}, 188 MySlice4: []*MyInnerStruct2{{true}, {}}, 189 MySlice5: []Foo{&MyInnerStruct2{true}, &MyInnerStruct2{}}, 190 MyArray: [4]byte{5, 6, 7, 8}, 191 MyArray2: [5]string{"four", "five", "six", "seven"}, 192 MyArray3: [3]MyInnerStruct{{"d"}, {"e"}, {"f"}}, 193 MyArray4: [2]*MyInnerStruct2{{}, {true}}, 194 MyInterface: &MyInnerStruct{"yeet"}, 195 InnerStruct3: MyInnerStruct3{ 196 Str: "str", 197 M1: MyInnerStruct{ 198 Str: "other str", 199 }, 200 F: &MyInnerStruct2{}, 201 }, 202 MyPointer: &temp, 203 MyMap1: map[string]string{ 204 "test": "test", 205 }, 206 MyMap2: map[int32][]MyInnerStruct3{ 207 199921: { 208 { 209 Str: "str-1", 210 M1: MyInnerStruct{ 211 Str: "other str", 212 }, 213 F: &MyInnerStruct2{}, 214 }, 215 { 216 Str: "str-2", 217 M1: MyInnerStruct{ 218 Str: "other str", 219 }, 220 F: &MyInnerStruct2{}, 221 }, 222 }, 223 1921: { 224 { 225 Str: "str0", 226 M1: MyInnerStruct{ 227 Str: "other str", 228 }, 229 F: &MyInnerStruct2{}, 230 }, 231 { 232 Str: "str1", 233 M1: MyInnerStruct{ 234 Str: "other str", 235 }, 236 F: &MyInnerStruct2{}, 237 }, 238 }, 239 }, 240 MyMap3: myMap3, 241 MyMap4: myMap4, 242 MyMap6: myMap6, 243 MyMap7: myMap7, 244 } 245 246 manager := codecpkg.NewDefaultManager() 247 // Register the types that may be unmarshaled into interfaces 248 require.NoError(codec.RegisterType(&MyInnerStruct{})) 249 require.NoError(codec.RegisterType(&MyInnerStruct2{})) 250 require.NoError(codec.RegisterType("")) 251 require.NoError(codec.RegisterType(int32(0))) 252 require.NoError(manager.RegisterCodec(0, codec)) 253 254 myStructBytes, err := manager.Marshal(0, myStructInstance) 255 require.NoError(err) 256 257 bytesLen, err := manager.Size(0, myStructInstance) 258 require.NoError(err) 259 require.Len(myStructBytes, bytesLen) 260 261 myStructUnmarshaled := &myStruct{} 262 version, err := manager.Unmarshal(myStructBytes, myStructUnmarshaled) 263 require.NoError(err) 264 265 // In myStructInstance MyMap4 is nil and in myStructUnmarshaled MyMap4 is an 266 // empty map 267 require.Empty(myStructUnmarshaled.MyMap5) 268 myStructUnmarshaled.MyMap5 = nil 269 270 require.Zero(version) 271 require.Equal(myStructInstance, *myStructUnmarshaled) 272 } 273 274 func TestRegisterStructTwice(t testing.TB, codec codecpkg.GeneralCodec) { 275 require := require.New(t) 276 277 require.NoError(codec.RegisterType(&MyInnerStruct{})) 278 err := codec.RegisterType(&MyInnerStruct{}) 279 require.ErrorIs(err, codecpkg.ErrDuplicateType) 280 } 281 282 func TestUInt32(t testing.TB, codec codecpkg.GeneralCodec) { 283 require := require.New(t) 284 285 number := uint32(500) 286 287 manager := codecpkg.NewDefaultManager() 288 require.NoError(manager.RegisterCodec(0, codec)) 289 290 bytes, err := manager.Marshal(0, number) 291 require.NoError(err) 292 293 bytesLen, err := manager.Size(0, number) 294 require.NoError(err) 295 require.Len(bytes, bytesLen) 296 297 var numberUnmarshaled uint32 298 version, err := manager.Unmarshal(bytes, &numberUnmarshaled) 299 require.NoError(err) 300 require.Zero(version) 301 require.Equal(number, numberUnmarshaled) 302 } 303 304 func TestUIntPtr(t testing.TB, codec codecpkg.GeneralCodec) { 305 require := require.New(t) 306 307 manager := codecpkg.NewDefaultManager() 308 309 require.NoError(manager.RegisterCodec(0, codec)) 310 311 number := uintptr(500) 312 _, err := manager.Marshal(0, number) 313 require.ErrorIs(err, codecpkg.ErrUnsupportedType) 314 } 315 316 func TestSlice(t testing.TB, codec codecpkg.GeneralCodec) { 317 require := require.New(t) 318 319 mySlice := []bool{true, false, true, true} 320 manager := codecpkg.NewDefaultManager() 321 require.NoError(manager.RegisterCodec(0, codec)) 322 323 bytes, err := manager.Marshal(0, mySlice) 324 require.NoError(err) 325 326 bytesLen, err := manager.Size(0, mySlice) 327 require.NoError(err) 328 require.Len(bytes, bytesLen) 329 330 var sliceUnmarshaled []bool 331 version, err := manager.Unmarshal(bytes, &sliceUnmarshaled) 332 require.NoError(err) 333 require.Zero(version) 334 require.Equal(mySlice, sliceUnmarshaled) 335 } 336 337 // Test marshalling/unmarshalling largest possible slice 338 func TestMaxSizeSlice(t testing.TB, codec codecpkg.GeneralCodec) { 339 require := require.New(t) 340 341 mySlice := make([]string, math.MaxUint16) 342 mySlice[0] = "first!" 343 mySlice[math.MaxUint16-1] = "last!" 344 manager := codecpkg.NewDefaultManager() 345 require.NoError(manager.RegisterCodec(0, codec)) 346 347 bytes, err := manager.Marshal(0, mySlice) 348 require.NoError(err) 349 350 bytesLen, err := manager.Size(0, mySlice) 351 require.NoError(err) 352 require.Len(bytes, bytesLen) 353 354 var sliceUnmarshaled []string 355 version, err := manager.Unmarshal(bytes, &sliceUnmarshaled) 356 require.NoError(err) 357 require.Zero(version) 358 require.Equal(mySlice, sliceUnmarshaled) 359 } 360 361 // Test marshalling a bool 362 func TestBool(t testing.TB, codec codecpkg.GeneralCodec) { 363 require := require.New(t) 364 365 myBool := true 366 manager := codecpkg.NewDefaultManager() 367 require.NoError(manager.RegisterCodec(0, codec)) 368 369 bytes, err := manager.Marshal(0, myBool) 370 require.NoError(err) 371 372 bytesLen, err := manager.Size(0, myBool) 373 require.NoError(err) 374 require.Len(bytes, bytesLen) 375 376 var boolUnmarshaled bool 377 version, err := manager.Unmarshal(bytes, &boolUnmarshaled) 378 require.NoError(err) 379 require.Zero(version) 380 require.Equal(myBool, boolUnmarshaled) 381 } 382 383 // Test marshalling an array 384 func TestArray(t testing.TB, codec codecpkg.GeneralCodec) { 385 require := require.New(t) 386 387 myArr := [5]uint64{5, 6, 7, 8, 9} 388 manager := codecpkg.NewDefaultManager() 389 require.NoError(manager.RegisterCodec(0, codec)) 390 391 bytes, err := manager.Marshal(0, myArr) 392 require.NoError(err) 393 394 bytesLen, err := manager.Size(0, myArr) 395 require.NoError(err) 396 require.Len(bytes, bytesLen) 397 398 var myArrUnmarshaled [5]uint64 399 version, err := manager.Unmarshal(bytes, &myArrUnmarshaled) 400 require.NoError(err) 401 require.Zero(version) 402 require.Equal(myArr, myArrUnmarshaled) 403 } 404 405 // Test marshalling a really big array 406 func TestBigArray(t testing.TB, codec codecpkg.GeneralCodec) { 407 require := require.New(t) 408 409 myArr := [30000]uint64{5, 6, 7, 8, 9} 410 manager := codecpkg.NewDefaultManager() 411 require.NoError(manager.RegisterCodec(0, codec)) 412 413 bytes, err := manager.Marshal(0, myArr) 414 require.NoError(err) 415 416 bytesLen, err := manager.Size(0, myArr) 417 require.NoError(err) 418 require.Len(bytes, bytesLen) 419 420 var myArrUnmarshaled [30000]uint64 421 version, err := manager.Unmarshal(bytes, &myArrUnmarshaled) 422 require.NoError(err) 423 require.Zero(version) 424 require.Equal(myArr, myArrUnmarshaled) 425 } 426 427 // Test marshalling a pointer to a struct 428 func TestPointerToStruct(t testing.TB, codec codecpkg.GeneralCodec) { 429 require := require.New(t) 430 431 myPtr := &MyInnerStruct{Str: "Hello!"} 432 manager := codecpkg.NewDefaultManager() 433 require.NoError(manager.RegisterCodec(0, codec)) 434 435 bytes, err := manager.Marshal(0, myPtr) 436 require.NoError(err) 437 438 bytesLen, err := manager.Size(0, myPtr) 439 require.NoError(err) 440 require.Len(bytes, bytesLen) 441 442 var myPtrUnmarshaled *MyInnerStruct 443 version, err := manager.Unmarshal(bytes, &myPtrUnmarshaled) 444 require.NoError(err) 445 require.Zero(version) 446 require.Equal(myPtr, myPtrUnmarshaled) 447 } 448 449 // Test marshalling a slice of structs 450 func TestSliceOfStruct(t testing.TB, codec codecpkg.GeneralCodec) { 451 require := require.New(t) 452 mySlice := []MyInnerStruct3{ 453 { 454 Str: "One", 455 M1: MyInnerStruct{"Two"}, 456 F: &MyInnerStruct{"Three"}, 457 }, 458 { 459 Str: "Four", 460 M1: MyInnerStruct{"Five"}, 461 F: &MyInnerStruct{"Six"}, 462 }, 463 } 464 require.NoError(codec.RegisterType(&MyInnerStruct{})) 465 466 manager := codecpkg.NewDefaultManager() 467 require.NoError(manager.RegisterCodec(0, codec)) 468 469 bytes, err := manager.Marshal(0, mySlice) 470 require.NoError(err) 471 472 bytesLen, err := manager.Size(0, mySlice) 473 require.NoError(err) 474 require.Len(bytes, bytesLen) 475 476 var mySliceUnmarshaled []MyInnerStruct3 477 version, err := manager.Unmarshal(bytes, &mySliceUnmarshaled) 478 require.NoError(err) 479 require.Zero(version) 480 require.Equal(mySlice, mySliceUnmarshaled) 481 } 482 483 // Test marshalling an interface 484 func TestInterface(t testing.TB, codec codecpkg.GeneralCodec) { 485 require := require.New(t) 486 487 require.NoError(codec.RegisterType(&MyInnerStruct2{})) 488 489 manager := codecpkg.NewDefaultManager() 490 require.NoError(manager.RegisterCodec(0, codec)) 491 492 var f Foo = &MyInnerStruct2{true} 493 bytes, err := manager.Marshal(0, &f) 494 require.NoError(err) 495 496 bytesLen, err := manager.Size(0, &f) 497 require.NoError(err) 498 require.Len(bytes, bytesLen) 499 500 var unmarshaledFoo Foo 501 version, err := manager.Unmarshal(bytes, &unmarshaledFoo) 502 require.NoError(err) 503 require.Zero(version) 504 require.Equal(f, unmarshaledFoo) 505 } 506 507 // Test marshalling a slice of interfaces 508 func TestSliceOfInterface(t testing.TB, codec codecpkg.GeneralCodec) { 509 require := require.New(t) 510 511 mySlice := []Foo{ 512 &MyInnerStruct{ 513 Str: "Hello", 514 }, 515 &MyInnerStruct{ 516 Str: ", World!", 517 }, 518 } 519 require.NoError(codec.RegisterType(&MyInnerStruct{})) 520 521 manager := codecpkg.NewDefaultManager() 522 require.NoError(manager.RegisterCodec(0, codec)) 523 524 bytes, err := manager.Marshal(0, mySlice) 525 require.NoError(err) 526 527 bytesLen, err := manager.Size(0, mySlice) 528 require.NoError(err) 529 require.Len(bytes, bytesLen) 530 531 var mySliceUnmarshaled []Foo 532 version, err := manager.Unmarshal(bytes, &mySliceUnmarshaled) 533 require.NoError(err) 534 require.Zero(version) 535 require.Equal(mySlice, mySliceUnmarshaled) 536 } 537 538 // Test marshalling an array of interfaces 539 func TestArrayOfInterface(t testing.TB, codec codecpkg.GeneralCodec) { 540 require := require.New(t) 541 542 myArray := [2]Foo{ 543 &MyInnerStruct{ 544 Str: "Hello", 545 }, 546 &MyInnerStruct{ 547 Str: ", World!", 548 }, 549 } 550 require.NoError(codec.RegisterType(&MyInnerStruct{})) 551 552 manager := codecpkg.NewDefaultManager() 553 require.NoError(manager.RegisterCodec(0, codec)) 554 555 bytes, err := manager.Marshal(0, myArray) 556 require.NoError(err) 557 558 bytesLen, err := manager.Size(0, myArray) 559 require.NoError(err) 560 require.Len(bytes, bytesLen) 561 562 var myArrayUnmarshaled [2]Foo 563 version, err := manager.Unmarshal(bytes, &myArrayUnmarshaled) 564 require.NoError(err) 565 require.Zero(version) 566 require.Equal(myArray, myArrayUnmarshaled) 567 } 568 569 // Test marshalling a pointer to an interface 570 func TestPointerToInterface(t testing.TB, codec codecpkg.GeneralCodec) { 571 require := require.New(t) 572 573 var myinnerStruct Foo = &MyInnerStruct{Str: "Hello!"} 574 myPtr := &myinnerStruct 575 576 require.NoError(codec.RegisterType(&MyInnerStruct{})) 577 578 manager := codecpkg.NewDefaultManager() 579 require.NoError(manager.RegisterCodec(0, codec)) 580 581 bytes, err := manager.Marshal(0, &myPtr) 582 require.NoError(err) 583 584 bytesLen, err := manager.Size(0, &myPtr) 585 require.NoError(err) 586 require.Len(bytes, bytesLen) 587 588 var myPtrUnmarshaled *Foo 589 version, err := manager.Unmarshal(bytes, &myPtrUnmarshaled) 590 require.NoError(err) 591 require.Zero(version) 592 require.Equal(myPtr, myPtrUnmarshaled) 593 } 594 595 // Test marshalling a string 596 func TestString(t testing.TB, codec codecpkg.GeneralCodec) { 597 require := require.New(t) 598 599 myString := "Ayy" 600 manager := codecpkg.NewDefaultManager() 601 require.NoError(manager.RegisterCodec(0, codec)) 602 603 bytes, err := manager.Marshal(0, myString) 604 require.NoError(err) 605 606 bytesLen, err := manager.Size(0, myString) 607 require.NoError(err) 608 require.Len(bytes, bytesLen) 609 610 var stringUnmarshaled string 611 version, err := manager.Unmarshal(bytes, &stringUnmarshaled) 612 require.NoError(err) 613 require.Zero(version) 614 require.Equal(myString, stringUnmarshaled) 615 } 616 617 // Ensure a nil slice is unmarshaled to slice with length 0 618 func TestNilSlice(t testing.TB, codec codecpkg.GeneralCodec) { 619 require := require.New(t) 620 621 type structWithSlice struct { 622 Slice []byte `serialize:"true"` 623 } 624 625 myStruct := structWithSlice{Slice: nil} 626 manager := codecpkg.NewDefaultManager() 627 require.NoError(manager.RegisterCodec(0, codec)) 628 629 bytes, err := manager.Marshal(0, myStruct) 630 require.NoError(err) 631 632 bytesLen, err := manager.Size(0, myStruct) 633 require.NoError(err) 634 require.Len(bytes, bytesLen) 635 636 var structUnmarshaled structWithSlice 637 version, err := manager.Unmarshal(bytes, &structUnmarshaled) 638 require.NoError(err) 639 require.Zero(version) 640 require.Empty(structUnmarshaled.Slice) 641 } 642 643 // Ensure that trying to serialize a struct with an unexported member 644 // that has `serialize:"true"` returns error 645 func TestSerializeUnexportedField(t testing.TB, codec codecpkg.GeneralCodec) { 646 require := require.New(t) 647 648 type s struct { 649 ExportedField string `serialize:"true"` 650 unexportedField string `serialize:"true"` //nolint:revive 651 } 652 653 myS := s{ 654 ExportedField: "Hello, ", 655 unexportedField: "world!", 656 } 657 658 manager := codecpkg.NewDefaultManager() 659 require.NoError(manager.RegisterCodec(0, codec)) 660 661 _, err := manager.Marshal(0, myS) 662 require.ErrorIs(err, codecpkg.ErrUnexportedField) 663 664 _, err = manager.Size(0, myS) 665 require.ErrorIs(err, codecpkg.ErrUnexportedField) 666 } 667 668 func TestSerializeOfNoSerializeField(t testing.TB, codec codecpkg.GeneralCodec) { 669 require := require.New(t) 670 671 type s struct { 672 SerializedField string `serialize:"true"` 673 UnserializedField string `serialize:"false"` 674 UnmarkedField string 675 } 676 myS := s{ 677 SerializedField: "Serialize me", 678 UnserializedField: "Do not serialize me", 679 UnmarkedField: "No declared serialize", 680 } 681 manager := codecpkg.NewDefaultManager() 682 require.NoError(manager.RegisterCodec(0, codec)) 683 684 marshalled, err := manager.Marshal(0, myS) 685 require.NoError(err) 686 687 bytesLen, err := manager.Size(0, myS) 688 require.NoError(err) 689 require.Len(marshalled, bytesLen) 690 691 unmarshalled := s{} 692 version, err := manager.Unmarshal(marshalled, &unmarshalled) 693 require.NoError(err) 694 require.Zero(version) 695 696 expectedUnmarshalled := s{SerializedField: "Serialize me"} 697 require.Equal(expectedUnmarshalled, unmarshalled) 698 } 699 700 // Test marshalling of nil slice 701 func TestNilSliceSerialization(t testing.TB, codec codecpkg.GeneralCodec) { 702 require := require.New(t) 703 704 type simpleSliceStruct struct { 705 Arr []uint32 `serialize:"true"` 706 } 707 708 manager := codecpkg.NewDefaultManager() 709 require.NoError(manager.RegisterCodec(0, codec)) 710 711 val := &simpleSliceStruct{} 712 expected := []byte{0, 0, 0, 0, 0, 0} // 0 for codec version, then nil slice marshaled as 0 length slice 713 result, err := manager.Marshal(0, val) 714 require.NoError(err) 715 require.Equal(expected, result) 716 717 bytesLen, err := manager.Size(0, val) 718 require.NoError(err) 719 require.Len(result, bytesLen) 720 721 valUnmarshaled := &simpleSliceStruct{} 722 version, err := manager.Unmarshal(result, &valUnmarshaled) 723 require.NoError(err) 724 require.Zero(version) 725 require.Empty(valUnmarshaled.Arr) 726 } 727 728 // Test marshaling a slice that has 0 elements (but isn't nil) 729 func TestEmptySliceSerialization(t testing.TB, codec codecpkg.GeneralCodec) { 730 require := require.New(t) 731 732 type simpleSliceStruct struct { 733 Arr []uint32 `serialize:"true"` 734 } 735 736 manager := codecpkg.NewDefaultManager() 737 require.NoError(manager.RegisterCodec(0, codec)) 738 739 val := &simpleSliceStruct{Arr: make([]uint32, 0, 1)} 740 expected := []byte{0, 0, 0, 0, 0, 0} // 0 for codec version (uint16) and 0 for size (uint32) 741 result, err := manager.Marshal(0, val) 742 require.NoError(err) 743 require.Equal(expected, result) 744 745 bytesLen, err := manager.Size(0, val) 746 require.NoError(err) 747 require.Len(result, bytesLen) 748 749 valUnmarshaled := &simpleSliceStruct{} 750 version, err := manager.Unmarshal(result, &valUnmarshaled) 751 require.NoError(err) 752 require.Zero(version) 753 require.Equal(val, valUnmarshaled) 754 } 755 756 // Test marshaling empty slice of zero length structs 757 func TestSliceWithEmptySerialization(t testing.TB, codec codecpkg.GeneralCodec) { 758 require := require.New(t) 759 760 type emptyStruct struct{} 761 762 type nestedSliceStruct struct { 763 Arr []emptyStruct `serialize:"true"` 764 } 765 766 manager := codecpkg.NewDefaultManager() 767 require.NoError(manager.RegisterCodec(0, codec)) 768 769 val := &nestedSliceStruct{ 770 Arr: make([]emptyStruct, 0), 771 } 772 expected := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // codec version (0x00, 0x00) then (0x00, 0x00, 0x00, 0x00) for numElts 773 result, err := manager.Marshal(0, val) 774 require.NoError(err) 775 require.Equal(expected, result) 776 777 bytesLen, err := manager.Size(0, val) 778 require.NoError(err) 779 require.Len(result, bytesLen) 780 781 unmarshaled := nestedSliceStruct{} 782 version, err := manager.Unmarshal(expected, &unmarshaled) 783 require.NoError(err) 784 require.Zero(version) 785 require.Empty(unmarshaled.Arr) 786 } 787 788 func TestSliceWithEmptySerializationError(t testing.TB, codec codecpkg.GeneralCodec) { 789 require := require.New(t) 790 791 type emptyStruct struct{} 792 793 type nestedSliceStruct struct { 794 Arr []emptyStruct `serialize:"true"` 795 } 796 797 manager := codecpkg.NewDefaultManager() 798 require.NoError(manager.RegisterCodec(0, codec)) 799 800 val := &nestedSliceStruct{ 801 Arr: make([]emptyStruct, 1), 802 } 803 _, err := manager.Marshal(0, val) 804 require.ErrorIs(err, codecpkg.ErrMarshalZeroLength) 805 806 _, err = manager.Size(0, val) 807 require.ErrorIs(err, codecpkg.ErrMarshalZeroLength) 808 809 b := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01} // codec version (0x00, 0x00) then (0x00, 0x00, 0x00, 0x01) for numElts 810 811 unmarshaled := nestedSliceStruct{} 812 _, err = manager.Unmarshal(b, &unmarshaled) 813 require.ErrorIs(err, codecpkg.ErrUnmarshalZeroLength) 814 } 815 816 // Test marshaling empty map of zero length structs 817 func TestMapWithEmptySerialization(t testing.TB, codec codecpkg.GeneralCodec) { 818 require := require.New(t) 819 820 type emptyStruct struct{} 821 822 manager := codecpkg.NewDefaultManager() 823 require.NoError(manager.RegisterCodec(0, codec)) 824 825 val := make(map[emptyStruct]emptyStruct) 826 expected := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // codec version (0x00, 0x00) then (0x00, 0x00, 0x00, 0x00) for numElts 827 result, err := manager.Marshal(0, val) 828 require.NoError(err) 829 require.Equal(expected, result) 830 831 bytesLen, err := manager.Size(0, val) 832 require.NoError(err) 833 require.Len(result, bytesLen) 834 835 var unmarshaled map[emptyStruct]emptyStruct 836 version, err := manager.Unmarshal(expected, &unmarshaled) 837 require.NoError(err) 838 require.Zero(version) 839 require.Empty(unmarshaled) 840 } 841 842 func TestMapWithEmptySerializationError(t testing.TB, codec codecpkg.GeneralCodec) { 843 require := require.New(t) 844 845 type emptyStruct struct{} 846 847 manager := codecpkg.NewDefaultManager() 848 require.NoError(manager.RegisterCodec(0, codec)) 849 850 val := map[emptyStruct]emptyStruct{ 851 {}: {}, 852 } 853 _, err := manager.Marshal(0, val) 854 require.ErrorIs(err, codecpkg.ErrMarshalZeroLength) 855 856 _, err = manager.Size(0, val) 857 require.ErrorIs(err, codecpkg.ErrMarshalZeroLength) 858 859 b := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01} // codec version (0x00, 0x00) then (0x00, 0x00, 0x00, 0x01) for numElts 860 861 var unmarshaled map[emptyStruct]emptyStruct 862 _, err = manager.Unmarshal(b, &unmarshaled) 863 require.ErrorIs(err, codecpkg.ErrUnmarshalZeroLength) 864 } 865 866 func TestSliceTooLarge(t testing.TB, codec codecpkg.GeneralCodec) { 867 require := require.New(t) 868 869 manager := codecpkg.NewDefaultManager() 870 require.NoError(manager.RegisterCodec(0, codec)) 871 872 val := []struct{}{} 873 b := []byte{0x00, 0x00, 0xff, 0xff, 0xff, 0xff} 874 _, err := manager.Unmarshal(b, &val) 875 require.ErrorIs(err, codecpkg.ErrMaxSliceLenExceeded) 876 } 877 878 // Ensure serializing structs with negative number members works 879 func TestNegativeNumbers(t testing.TB, codec codecpkg.GeneralCodec) { 880 require := require.New(t) 881 882 type s struct { 883 MyInt8 int8 `serialize:"true"` 884 MyInt16 int16 `serialize:"true"` 885 MyInt32 int32 `serialize:"true"` 886 MyInt64 int64 `serialize:"true"` 887 } 888 889 manager := codecpkg.NewDefaultManager() 890 require.NoError(manager.RegisterCodec(0, codec)) 891 892 myS := s{-1, -2, -3, -4} 893 bytes, err := manager.Marshal(0, myS) 894 require.NoError(err) 895 896 bytesLen, err := manager.Size(0, myS) 897 require.NoError(err) 898 require.Len(bytes, bytesLen) 899 900 mySUnmarshaled := s{} 901 version, err := manager.Unmarshal(bytes, &mySUnmarshaled) 902 require.NoError(err) 903 require.Zero(version) 904 require.Equal(myS, mySUnmarshaled) 905 } 906 907 // Ensure deserializing structs with too many bytes errors correctly 908 func TestTooLargeUnmarshal(t testing.TB, codec codecpkg.GeneralCodec) { 909 require := require.New(t) 910 911 type inner struct { 912 B uint16 `serialize:"true"` 913 } 914 bytes := []byte{0, 0, 0, 0} 915 916 manager := codecpkg.NewManager(3) 917 require.NoError(manager.RegisterCodec(0, codec)) 918 919 s := inner{} 920 _, err := manager.Unmarshal(bytes, &s) 921 require.ErrorIs(err, codecpkg.ErrUnmarshalTooBig) 922 } 923 924 type outerInterface interface { 925 ToInt() int 926 } 927 928 type outer struct { 929 Interface outerInterface `serialize:"true"` 930 } 931 932 type innerInterface struct{} 933 934 func (*innerInterface) ToInt() int { 935 return 0 936 } 937 938 type innerNoInterface struct{} 939 940 // Ensure deserializing structs into the wrong interface errors gracefully 941 func TestUnmarshalInvalidInterface(t testing.TB, codec codecpkg.GeneralCodec) { 942 require := require.New(t) 943 944 manager := codecpkg.NewDefaultManager() 945 require.NoError(codec.RegisterType(&innerInterface{})) 946 require.NoError(codec.RegisterType(&innerNoInterface{})) 947 require.NoError(manager.RegisterCodec(0, codec)) 948 949 { 950 bytes := []byte{0, 0, 0, 0, 0, 0} 951 s := outer{} 952 version, err := manager.Unmarshal(bytes, &s) 953 require.NoError(err) 954 require.Zero(version) 955 } 956 { 957 bytes := []byte{0, 0, 0, 0, 0, 1} 958 s := outer{} 959 _, err := manager.Unmarshal(bytes, &s) 960 require.ErrorIs(err, codecpkg.ErrDoesNotImplementInterface) 961 } 962 } 963 964 // Test unmarshaling something with extra data 965 func TestExtraSpace(t testing.TB, codec codecpkg.GeneralCodec) { 966 require := require.New(t) 967 968 manager := codecpkg.NewDefaultManager() 969 require.NoError(manager.RegisterCodec(0, codec)) 970 971 // codec version 0x0000 then 0x01 for b then 0x02 as extra data. 972 byteSlice := []byte{0x00, 0x00, 0x01, 0x02} 973 var b byte 974 _, err := manager.Unmarshal(byteSlice, &b) 975 require.ErrorIs(err, codecpkg.ErrExtraSpace) 976 } 977 978 // Ensure deserializing slices whose lengths exceed MaxInt32 error correctly 979 func TestSliceLengthOverflow(t testing.TB, codec codecpkg.GeneralCodec) { 980 require := require.New(t) 981 982 type inner struct { 983 Vals []uint32 `serialize:"true"` 984 } 985 bytes := []byte{ 986 // Codec Version: 987 0x00, 0x00, 988 // Slice Length: 989 0xff, 0xff, 0xff, 0xff, 990 } 991 992 manager := codecpkg.NewDefaultManager() 993 require.NoError(manager.RegisterCodec(0, codec)) 994 995 s := inner{} 996 _, err := manager.Unmarshal(bytes, &s) 997 require.ErrorIs(err, codecpkg.ErrMaxSliceLenExceeded) 998 } 999 1000 type MultipleVersionsStruct struct { 1001 BothTags string `tag1:"true" tag2:"true"` 1002 SingleTag1 string `tag1:"true"` 1003 SingleTag2 string ` tag2:"true"` 1004 EitherTags1 string `tag1:"false" tag2:"true"` 1005 EitherTags2 string `tag1:"true" tag2:"false"` 1006 NoTags string `tag1:"false" tag2:"false"` 1007 } 1008 1009 func TestMultipleTags(t testing.TB, codec codecpkg.GeneralCodec) { 1010 // received codec is expected to have both v1 and v2 registered as tags 1011 inputs := MultipleVersionsStruct{ 1012 BothTags: "both Tags", 1013 SingleTag1: "Only Tag1", 1014 SingleTag2: "Only Tag2", 1015 EitherTags1: "Tag2 is false", 1016 EitherTags2: "Tag1 is false", 1017 NoTags: "Neither Tag", 1018 } 1019 1020 manager := codecpkg.NewDefaultManager() 1021 for _, codecVersion := range []uint16{0, 1, 2022} { 1022 require := require.New(t) 1023 1024 require.NoError(manager.RegisterCodec(codecVersion, codec)) 1025 1026 bytes, err := manager.Marshal(codecVersion, inputs) 1027 require.NoError(err) 1028 1029 output := MultipleVersionsStruct{} 1030 _, err = manager.Unmarshal(bytes, &output) 1031 require.NoError(err) 1032 1033 require.Equal(inputs.BothTags, output.BothTags) 1034 require.Equal(inputs.SingleTag1, output.SingleTag1) 1035 require.Equal(inputs.SingleTag2, output.SingleTag2) 1036 require.Equal(inputs.EitherTags1, output.EitherTags1) 1037 require.Equal(inputs.EitherTags2, output.EitherTags2) 1038 require.Empty(output.NoTags) 1039 } 1040 } 1041 1042 func TestMap(t testing.TB, codec codecpkg.GeneralCodec) { 1043 require := require.New(t) 1044 1045 data1 := map[string]MyInnerStruct2{ 1046 "test": {true}, 1047 "bar": {false}, 1048 } 1049 1050 data2 := map[string]MyInnerStruct2{ 1051 "bar": {false}, 1052 "test": {true}, 1053 } 1054 1055 data3 := map[string]MyInnerStruct2{ 1056 "bar": {false}, 1057 } 1058 1059 outerMap := make(map[int32]map[string]MyInnerStruct2) 1060 outerMap[3] = data1 1061 outerMap[19] = data2 1062 1063 outerArray := [3]map[string]MyInnerStruct2{ 1064 data1, 1065 data2, 1066 data3, 1067 } 1068 1069 manager := codecpkg.NewDefaultManager() 1070 require.NoError(manager.RegisterCodec(0, codec)) 1071 1072 data1Bytes, err := manager.Marshal(0, data1) 1073 require.NoError(err) 1074 1075 // data1 and data2 should have the same byte representation even though 1076 // their key-value pairs were defined in a different order. 1077 data2Bytes, err := manager.Marshal(0, data2) 1078 require.NoError(err) 1079 require.Equal(data1Bytes, data2Bytes) 1080 1081 // Make sure Size returns the correct size for the marshalled data 1082 data1Size, err := manager.Size(0, data1) 1083 require.NoError(err) 1084 require.Len(data1Bytes, data1Size) 1085 1086 var unmarshalledData1 map[string]MyInnerStruct2 1087 _, err = manager.Unmarshal(data1Bytes, &unmarshalledData1) 1088 require.NoError(err) 1089 require.Equal(data1, unmarshalledData1) 1090 1091 outerMapBytes, err := manager.Marshal(0, outerMap) 1092 require.NoError(err) 1093 1094 outerMapSize, err := manager.Size(0, outerMap) 1095 require.NoError(err) 1096 require.Len(outerMapBytes, outerMapSize) 1097 1098 var unmarshalledOuterMap map[int32]map[string]MyInnerStruct2 1099 _, err = manager.Unmarshal(outerMapBytes, &unmarshalledOuterMap) 1100 require.NoError(err) 1101 require.Equal(outerMap, unmarshalledOuterMap) 1102 1103 outerArrayBytes, err := manager.Marshal(0, outerArray) 1104 require.NoError(err) 1105 1106 outerArraySize, err := manager.Size(0, outerArray) 1107 require.NoError(err) 1108 require.Len(outerArrayBytes, outerArraySize) 1109 } 1110 1111 func TestCanMarshalLargeSlices(t testing.TB, codec codecpkg.GeneralCodec) { 1112 require := require.New(t) 1113 1114 data := make([]uint16, 1_000_000) 1115 1116 manager := codecpkg.NewManager(math.MaxInt) 1117 require.NoError(manager.RegisterCodec(0, codec)) 1118 1119 bytes, err := manager.Marshal(0, data) 1120 require.NoError(err) 1121 1122 var unmarshalledData []uint16 1123 _, err = manager.Unmarshal(bytes, &unmarshalledData) 1124 require.NoError(err) 1125 require.Equal(data, unmarshalledData) 1126 } 1127 1128 func FuzzStructUnmarshal(codec codecpkg.GeneralCodec, f *testing.F) { 1129 manager := codecpkg.NewDefaultManager() 1130 // Register the types that may be unmarshaled into interfaces 1131 require.NoError(f, codec.RegisterType(&MyInnerStruct{})) 1132 require.NoError(f, codec.RegisterType(&MyInnerStruct2{})) 1133 require.NoError(f, codec.RegisterType("")) 1134 require.NoError(f, codec.RegisterType(int32(0))) 1135 require.NoError(f, manager.RegisterCodec(0, codec)) 1136 1137 f.Fuzz(func(t *testing.T, bytes []byte) { 1138 require := require.New(t) 1139 1140 myParsedStruct := &myStruct{} 1141 version, err := manager.Unmarshal(bytes, myParsedStruct) 1142 if err != nil { 1143 return 1144 } 1145 require.Zero(version) 1146 1147 marshalled, err := manager.Marshal(version, myParsedStruct) 1148 require.NoError(err) 1149 require.Equal(bytes, marshalled) 1150 1151 size, err := manager.Size(version, myParsedStruct) 1152 require.NoError(err) 1153 require.Len(bytes, size) 1154 }) 1155 }