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  }