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  }