github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/pkg/scale/codec_test.go (about) 1 // Copyright 2018 Jsgenesis 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package scale 16 17 import ( 18 "bytes" 19 "fmt" 20 "math" 21 "math/big" 22 "reflect" 23 "strings" 24 "testing" 25 26 "github.com/stretchr/testify/assert" 27 ) 28 29 func assertEqual(t *testing.T, a interface{}, b interface{}) { 30 if reflect.DeepEqual(a, b) { 31 return 32 } 33 t.Errorf("Received %v (type %v), expected %v (type %v)", a, reflect.TypeOf(a), b, reflect.TypeOf(b)) 34 } 35 36 func hexify(bytes []byte) string { 37 res := make([]string, len(bytes)) 38 for i, b := range bytes { 39 res[i] = fmt.Sprintf("%02x", b) 40 } 41 return strings.Join(res, " ") 42 } 43 44 func encodeToBytes(t *testing.T, value interface{}) []byte { 45 var buffer = bytes.Buffer{} 46 err := Encoder{writer: &buffer}.Encode(value) 47 assert.NoError(t, err) 48 return buffer.Bytes() 49 } 50 51 func assertRoundtrip(t *testing.T, value interface{}) { 52 var buffer = bytes.Buffer{} 53 err := Encoder{writer: &buffer}.Encode(value) 54 assert.NoError(t, err) 55 target := reflect.New(reflect.TypeOf(value)) 56 err = Decoder{reader: &buffer}.Decode(target.Interface()) 57 assert.NoError(t, err) 58 assertEqual(t, target.Elem().Interface(), value) 59 } 60 61 type CustomBool bool 62 63 func (c CustomBool) Encode(encoder Encoder) error { 64 var encoded byte 65 if c { 66 encoded = 0x05 67 } else { 68 encoded = 0x10 69 } 70 err := encoder.PushByte(encoded) 71 if err != nil { 72 return err 73 } 74 return nil 75 } 76 77 func (c *CustomBool) Decode(decoder Decoder) error { 78 b, _ := decoder.ReadOneByte() 79 switch b { 80 case 0x05: 81 *c = true 82 case 0x10: 83 *c = false 84 default: 85 return fmt.Errorf("unknown byte prefix for encoded CustomBool: %d", b) 86 } 87 return nil 88 } 89 90 func TestTypeImplementsEncodeableDecodeableEncodedAsExpected(t *testing.T) { 91 value := CustomBool(true) 92 assertRoundtrip(t, value) 93 94 var buffer = bytes.Buffer{} 95 err := Encoder{writer: &buffer}.Encode(value) 96 assert.NoError(t, err) 97 assert.Equal(t, []byte{0x05}, buffer.Bytes()) 98 99 var decoded CustomBool 100 err = Decoder{reader: &buffer}.Decode(&decoded) 101 assert.NoError(t, err) 102 assert.Equal(t, CustomBool(true), decoded) 103 } 104 105 type CustomBytes []byte 106 107 func (c CustomBytes) Encode(encoder Encoder) error { 108 for i := 0; i < len(c); i++ { 109 err := encoder.PushByte(^c[i]) 110 if err != nil { 111 return err 112 } 113 } 114 return nil 115 } 116 117 func (c *CustomBytes) Decode(decoder Decoder) error { 118 for i := 0; i < len(*c); i++ { 119 b, err := decoder.ReadOneByte() 120 if err != nil { 121 return err 122 } 123 (*c)[i] = ^b 124 } 125 return nil 126 } 127 128 func TestTypeImplementsEncodeableDecodeableSliceEncodedAsExpected(t *testing.T) { 129 value := CustomBytes([]byte{0x01, 0x23, 0xf2}) 130 // assertRoundtrip(t, value) 131 132 var buffer = bytes.Buffer{} 133 err := Encoder{writer: &buffer}.Encode(value) 134 assert.NoError(t, err) 135 assert.Equal(t, []byte{0xfe, 0xdc, 0xd}, buffer.Bytes()) 136 137 decoded := make(CustomBytes, len(value)) 138 err = Decoder{reader: &buffer}.Decode(&decoded) 139 assert.NoError(t, err) 140 assert.Equal(t, value, decoded) 141 } 142 143 func TestSliceOfBytesEncodedAsExpected(t *testing.T) { 144 value := []byte{0, 1, 1, 2, 3, 5, 8, 13, 21, 34} 145 assertRoundtrip(t, value) 146 assertEqual(t, hexify(encodeToBytes(t, value)), "28 00 01 01 02 03 05 08 0d 15 22") 147 } 148 149 func TestArrayOfBytesEncodedAsExpected(t *testing.T) { 150 value := [10]byte{0, 1, 1, 2, 3, 5, 8, 13, 21, 34} 151 assertRoundtrip(t, value) 152 assertEqual(t, hexify(encodeToBytes(t, value)), "00 01 01 02 03 05 08 0d 15 22") 153 } 154 155 func TestArrayCannotBeDecodedIntoIncompatible(t *testing.T) { 156 value := [3]byte{255, 254, 253} 157 value2 := [5]byte{1, 2, 3, 4, 5} 158 value3 := [1]byte{42} 159 160 var buffer = bytes.Buffer{} 161 err := Encoder{writer: &buffer}.Encode(value) 162 assert.NoError(t, err) 163 err = Decoder{reader: &buffer}.Decode(&value2) 164 assert.EqualError(t, err, "expected more bytes, but could not decode any more") 165 buffer.Reset() 166 err = Encoder{writer: &buffer}.Encode(value) 167 assert.NoError(t, err) 168 err = Decoder{reader: &buffer}.Decode(&value3) 169 assert.NoError(t, err) 170 assert.Equal(t, [1]byte{255}, value3) 171 buffer.Reset() 172 err = Encoder{writer: &buffer}.Encode(value) 173 assert.NoError(t, err) 174 err = Decoder{reader: &buffer}.Decode(&value) 175 assert.NoError(t, err) 176 } 177 178 func TestSliceOfInt16EncodedAsExpected(t *testing.T) { 179 value := []int16{0, 1, -1, 2, -2, 3, -3} 180 assertRoundtrip(t, value) 181 assertEqual(t, hexify(encodeToBytes(t, value)), "1c 00 00 01 00 ff ff 02 00 fe ff 03 00 fd ff") 182 } 183 184 func TestStructFieldByFieldEncoding(t *testing.T) { 185 value := struct { 186 A string 187 B int16 188 C bool 189 }{"my", 3, true} 190 assertRoundtrip(t, value) 191 } 192 193 // OptionInt8 is an example implementation of an "Option" type, mirroring Option<u8> in Rust version. 194 // Since Go does not support generics, one has to define such types manually. 195 // See below for ParityEncode / ParityDecode implementations. 196 type OptionInt8 struct { 197 hasValue bool 198 value int8 199 } 200 201 func (o OptionInt8) Encode(encoder Encoder) error { 202 return encoder.EncodeOption(o.hasValue, o.value) 203 } 204 205 func (o *OptionInt8) Decode(decoder Decoder) error { 206 return decoder.DecodeOption(&o.hasValue, &o.value) 207 } 208 209 func TestSliceOfOptionInt8EncodedAsExpected(t *testing.T) { 210 value := []OptionInt8{{true, 1}, {true, -1}, {false, 0}} 211 assertRoundtrip(t, value) 212 assertEqual(t, hexify(encodeToBytes(t, value)), "0c 01 01 01 ff 00") 213 } 214 215 func TestSliceOfOptionBoolEncodedAsExpected(t *testing.T) { 216 value := []OptionBool{NewOptionBool(true), NewOptionBool(false), NewOptionBoolEmpty()} 217 assertRoundtrip(t, value) 218 assertEqual(t, hexify(encodeToBytes(t, value)), "0c 01 02 00") 219 } 220 221 func TestSliceOfStringEncodedAsExpected(t *testing.T) { 222 value := []string{ 223 "Hamlet", 224 "Война и мир", 225 "三国演义", 226 "أَلْف لَيْلَة وَلَيْلَة"} 227 assertRoundtrip(t, value) 228 assertEqual(t, hexify(encodeToBytes(t, value)), "10 18 48 61 6d 6c 65 74 50 d0 92 d0 be d0 b9 d0 bd d0 b0 20 d0 "+ 229 "b8 20 d0 bc d0 b8 d1 80 30 e4 b8 89 e5 9b bd e6 bc 94 e4 b9 89 bc d8 a3 d9 8e d9 84 d9 92 "+ 230 "d9 81 20 d9 84 d9 8e d9 8a d9 92 d9 84 d9 8e d8 a9 20 d9 88 d9 8e d9 84 d9 8e d9 8a d9 92 "+ 231 "d9 84 d9 8e d8 a9 e2 80 8e") 232 } 233 234 func TestCompactIntegersEncodedAsExpected(t *testing.T) { 235 tests := map[uint64]string{ 236 0: "00", 237 63: "fc", 238 64: "01 01", 239 16383: "fd ff", 240 16384: "02 00 01 00", 241 1073741823: "fe ff ff ff", 242 1073741824: "03 00 00 00 40", 243 1<<32 - 1: "03 ff ff ff ff", 244 1 << 32: "07 00 00 00 00 01", 245 1 << 40: "0b 00 00 00 00 00 01", 246 1 << 48: "0f 00 00 00 00 00 00 01", 247 1<<56 - 1: "0f ff ff ff ff ff ff ff", 248 1 << 56: "13 00 00 00 00 00 00 00 01", 249 math.MaxUint64: "13 ff ff ff ff ff ff ff ff"} 250 for value, expectedHex := range tests { 251 var buffer = bytes.Buffer{} 252 valueBig := new(big.Int).SetUint64(value) 253 err := Encoder{writer: &buffer}.EncodeUintCompact(*valueBig) 254 assert.NoError(t, err) 255 assertEqual(t, hexify(buffer.Bytes()), expectedHex) 256 decoded, _ := Decoder{reader: &buffer}.DecodeUintCompact() 257 assertEqual(t, decoded, big.NewInt(0).SetUint64(value)) 258 } 259 }