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 }