github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/amino/binary_test.go (about)

     1  package amino_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	amino "github.com/gnolang/gno/tm2/pkg/amino"
    12  )
    13  
    14  func TestNilSliceEmptySlice(t *testing.T) {
    15  	t.Parallel()
    16  
    17  	cdc := amino.NewCodec()
    18  
    19  	type TestStruct struct {
    20  		A []byte
    21  		B []int
    22  		C [][]byte
    23  		D [][]int
    24  		E []*[]byte
    25  		F []*[]int
    26  	}
    27  	nnb, nni := []byte(nil), []int(nil)
    28  	eeb, eei := []byte{}, []int{}
    29  
    30  	a := TestStruct{
    31  		A: nnb,
    32  		B: nni,
    33  		C: [][]byte{nnb},
    34  		D: [][]int{nni},
    35  		E: []*[]byte{nil},
    36  		F: []*[]int{nil},
    37  	}
    38  	b := TestStruct{
    39  		A: eeb,
    40  		B: eei,
    41  		C: [][]byte{eeb},
    42  		D: [][]int{eei},
    43  		E: []*[]byte{&nnb},
    44  		F: []*[]int{&nni},
    45  	}
    46  	c := TestStruct{
    47  		A: eeb,
    48  		B: eei,
    49  		C: [][]byte{eeb},
    50  		D: [][]int{eei},
    51  		E: []*[]byte{&eeb},
    52  		F: []*[]int{&eei},
    53  	}
    54  
    55  	abz := cdc.MustMarshalSized(a)
    56  	bbz := cdc.MustMarshalSized(b)
    57  	cbz := cdc.MustMarshalSized(c)
    58  
    59  	assert.Equal(t, abz, bbz, "a != b")
    60  	assert.Equal(t, abz, cbz, "a != c")
    61  }
    62  
    63  func TestNewFieldBackwardsCompatibility(t *testing.T) {
    64  	t.Parallel()
    65  
    66  	type V1 struct {
    67  		String  string
    68  		String2 string
    69  	}
    70  
    71  	type V2 struct {
    72  		String  string
    73  		String2 string
    74  		// new fields in V2:
    75  		Time time.Time
    76  		Int  int
    77  	}
    78  
    79  	type SomeStruct struct {
    80  		Sth int
    81  	}
    82  
    83  	type V3 struct {
    84  		String string
    85  		// different from V1 starting here:
    86  		Int  int
    87  		Some SomeStruct
    88  	}
    89  
    90  	cdc := amino.NewCodec()
    91  	notNow, err := time.Parse("2006-01-02", "1934-11-09")
    92  	assert.NoError(t, err)
    93  	v2 := V2{String: "hi", String2: "cosmos", Time: notNow, Int: 4}
    94  	bz, err := cdc.Marshal(v2)
    95  	assert.Nil(t, err, "unexpected error while encoding V2: %v", err)
    96  
    97  	var v1 V1
    98  	err = cdc.Unmarshal(bz, &v1)
    99  	assert.Nil(t, err, "unexpected error %v", err)
   100  	assert.Equal(t, v1, V1{"hi", "cosmos"},
   101  		"backwards compatibility failed: didn't yield expected result ...")
   102  
   103  	v3 := V3{String: "tender", Int: 2014, Some: SomeStruct{Sth: 84}}
   104  	bz2, err := cdc.Marshal(v3)
   105  	assert.Nil(t, err, "unexpected error")
   106  
   107  	err = cdc.Unmarshal(bz2, &v1)
   108  	// this might change later but we include this case to document the current behaviour:
   109  	assert.NotNil(t, err, "expected an error here because of changed order of fields")
   110  
   111  	// we still expect that decoding worked to some extend (until above error occurred):
   112  	assert.Equal(t, v1, V1{"tender", "cosmos"})
   113  }
   114  
   115  func TestWriteEmpty(t *testing.T) {
   116  	t.Parallel()
   117  
   118  	type Inner struct {
   119  		Val int
   120  	}
   121  	type SomeStruct struct {
   122  		Inner Inner
   123  	}
   124  
   125  	cdc := amino.NewCodec()
   126  	b, err := cdc.Marshal(Inner{})
   127  	assert.NoError(t, err)
   128  	assert.Equal(t, b, []byte(nil), "empty struct should be encoded as empty bytes")
   129  	var inner Inner
   130  	err = cdc.Unmarshal(b, &inner)
   131  	require.NoError(t, err)
   132  	assert.Equal(t, Inner{}, inner, "")
   133  
   134  	b, err = cdc.Marshal(SomeStruct{})
   135  	assert.NoError(t, err)
   136  	assert.Equal(t, b, []byte(nil), "empty structs should be encoded as empty bytes")
   137  	var outer SomeStruct
   138  	err = cdc.Unmarshal(b, &outer)
   139  	require.NoError(t, err)
   140  
   141  	assert.Equal(t, SomeStruct{}, outer, "")
   142  }
   143  
   144  func TestForceWriteEmpty(t *testing.T) {
   145  	t.Parallel()
   146  
   147  	type InnerWriteEmpty struct {
   148  		// sth. that isn't zero-len if default, e.g. fixed32:
   149  		ValIn int32 `amino:"write_empty" binary:"fixed32"`
   150  	}
   151  
   152  	type OuterWriteEmpty struct {
   153  		In  InnerWriteEmpty `amino:"write_empty"`
   154  		Val int32           `amino:"write_empty" binary:"fixed32"`
   155  	}
   156  
   157  	cdc := amino.NewCodec()
   158  
   159  	b, err := cdc.Marshal(OuterWriteEmpty{})
   160  	assert.NoError(t, err)
   161  	assert.Equal(t, []byte{0xa, 0x5, 0xd, 0x0, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x0}, b)
   162  
   163  	b, err = cdc.Marshal(InnerWriteEmpty{})
   164  	assert.NoError(t, err)
   165  	assert.Equal(t, []byte{13, 0, 0, 0, 0}, b)
   166  }
   167  
   168  func TestStructSlice(t *testing.T) {
   169  	t.Parallel()
   170  
   171  	type Foo struct {
   172  		A uint
   173  		B uint
   174  	}
   175  
   176  	type Foos struct {
   177  		Fs []Foo
   178  	}
   179  
   180  	f := Foos{Fs: []Foo{{100, 101}, {102, 103}}}
   181  
   182  	cdc := amino.NewCodec()
   183  
   184  	bz, err := cdc.Marshal(f)
   185  	assert.NoError(t, err)
   186  	assert.Equal(t, "0A04086410650A0408661067", fmt.Sprintf("%X", bz))
   187  	t.Log(bz)
   188  	var f2 Foos
   189  	err = cdc.Unmarshal(bz, &f2)
   190  	require.NoError(t, err)
   191  	assert.Equal(t, f, f2)
   192  }
   193  
   194  func TestStructPointerSlice1(t *testing.T) {
   195  	t.Parallel()
   196  
   197  	cdc := amino.NewCodec()
   198  
   199  	type Foo struct {
   200  		A string
   201  		B int
   202  		C []*Foo `amino:"nil_elements"`
   203  		D string // exposed
   204  	}
   205  
   206  	f := Foo{
   207  		A: "k",
   208  		B: 2,
   209  		C: []*Foo{nil, nil, nil},
   210  		D: "j",
   211  	}
   212  	bz, err := cdc.MarshalSized(f)
   213  	assert.NoError(t, err)
   214  
   215  	var f2 Foo
   216  	err = cdc.UnmarshalSized(bz, &f2)
   217  	assert.Nil(t, err)
   218  
   219  	assert.Equal(t, f, f2)
   220  	assert.Nil(t, f2.C[0])
   221  
   222  	f3 := Foo{
   223  		A: "k",
   224  		B: 2,
   225  		C: []*Foo{{}, {}, {}},
   226  		D: "j",
   227  	}
   228  	bz2, err := cdc.MarshalSized(f3)
   229  	assert.NoError(t, err)
   230  	assert.Equal(t, bz, bz2, "empty slice elements should be encoded the same as nil")
   231  }
   232  
   233  // Like TestStructPointerSlice2, but without nil_elements field tag.
   234  func TestStructPointerSlice2(t *testing.T) {
   235  	t.Parallel()
   236  
   237  	cdc := amino.NewCodec()
   238  
   239  	type Foo struct {
   240  		A string
   241  		B int
   242  		C []*Foo
   243  		D string // exposed
   244  	}
   245  
   246  	f := Foo{
   247  		A: "k",
   248  		B: 2,
   249  		C: []*Foo{nil, nil, nil},
   250  		D: "j",
   251  	}
   252  	_, err := cdc.MarshalSized(f)
   253  	assert.Error(t, err, "nil elements of a slice/array not supported unless nil_elements field tag set.")
   254  
   255  	f.C = []*Foo{{}, {}, {}}
   256  	bz, err := cdc.MarshalSized(f)
   257  	assert.NoError(t, err)
   258  
   259  	var f2 Foo
   260  	err = cdc.UnmarshalSized(bz, &f2)
   261  	assert.Nil(t, err)
   262  
   263  	assert.Equal(t, f, f2)
   264  	assert.NotNil(t, f2.C[0])
   265  }
   266  
   267  func TestBasicTypes(t *testing.T) {
   268  	t.Parallel()
   269  
   270  	// we explicitly disallow type definitions like the following:
   271  	type byteAlias []byte
   272  
   273  	cdc := amino.NewCodec()
   274  	ba := byteAlias([]byte("this should work because it gets wrapped by a struct"))
   275  	bz, err := cdc.MarshalSized(ba)
   276  	assert.NotZero(t, bz)
   277  	require.NoError(t, err)
   278  
   279  	res := &byteAlias{}
   280  	err = cdc.UnmarshalSized(bz, res)
   281  
   282  	require.NoError(t, err)
   283  	assert.Equal(t, ba, *res)
   284  }
   285  
   286  func TestUnmarshalMapBinary(t *testing.T) {
   287  	t.Parallel()
   288  
   289  	obj := new(map[string]int)
   290  	cdc := amino.NewCodec()
   291  
   292  	// Binary doesn't support decoding to a map...
   293  	binBytes := []byte(`dontcare`)
   294  	assert.Panics(t, func() {
   295  		err := cdc.Unmarshal(binBytes, &obj)
   296  		assert.Fail(t, "should have panicked but got err: %v", err)
   297  	})
   298  
   299  	assert.Panics(t, func() {
   300  		err := cdc.Unmarshal(binBytes, obj)
   301  		require.Error(t, err)
   302  	})
   303  
   304  	// ... nor encoding it.
   305  	assert.Panics(t, func() {
   306  		bz, err := cdc.Marshal(obj)
   307  		assert.Fail(t, "should have panicked but got bz: %X err: %v", bz, err)
   308  	})
   309  }
   310  
   311  func TestUnmarshalFuncBinary(t *testing.T) {
   312  	t.Parallel()
   313  
   314  	obj := func() {}
   315  	cdc := amino.NewCodec()
   316  	// Binary doesn't support decoding to a func...
   317  	binBytes := []byte(`dontcare`)
   318  	err := cdc.UnmarshalSized(binBytes, &obj)
   319  	// on length prefixed we return an error:
   320  	assert.Error(t, err)
   321  
   322  	assert.Panics(t, func() {
   323  		err = cdc.Unmarshal(binBytes, &obj)
   324  		require.Error(t, err)
   325  	})
   326  
   327  	err = cdc.Unmarshal(binBytes, obj)
   328  	require.Error(t, err)
   329  	require.Equal(t, err, amino.ErrNoPointer)
   330  
   331  	// ... nor encoding it.
   332  	assert.Panics(t, func() {
   333  		bz, err := cdc.MarshalSized(obj)
   334  		assert.Fail(t, "should have panicked but got bz: %X err: %v", bz, err)
   335  	})
   336  }
   337  
   338  func TestDuration(t *testing.T) {
   339  	t.Parallel()
   340  
   341  	cdc := amino.NewCodec()
   342  	d0 := time.Duration(0)
   343  	bz := cdc.MustMarshal(d0)
   344  	assert.Equal(t, bz, []byte(nil))
   345  	var d time.Duration
   346  	var dPtr *time.Duration
   347  	var dZero time.Duration
   348  	err := cdc.Unmarshal(nil, &d)
   349  	assert.NoError(t, err)
   350  	assert.Equal(t, d, time.Duration(0))
   351  	err = cdc.Unmarshal(nil, &dPtr)
   352  	assert.NoError(t, err)
   353  	assert.Equal(t, dPtr, &dZero)
   354  }