github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/common/hexutil/json_test.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package hexutil
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/hex"
    17  	"encoding/json"
    18  	"errors"
    19  	"math/big"
    20  	"testing"
    21  )
    22  
    23  func checkError(t *testing.T, input string, got, want error) bool {
    24  	if got == nil {
    25  		if want != nil {
    26  			t.Errorf("input %s: got no error, want %q", input, want)
    27  			return false
    28  		}
    29  		return true
    30  	}
    31  	if want == nil {
    32  		t.Errorf("input %s: unexpected error %q", input, got)
    33  	} else if got.Error() != want.Error() {
    34  		t.Errorf("input %s: got error %q, want %q", input, got, want)
    35  	}
    36  	return false
    37  }
    38  
    39  func referenceBig(s string) *big.Int {
    40  	b, ok := new(big.Int).SetString(s, 16)
    41  	if !ok {
    42  		panic("invalid")
    43  	}
    44  	return b
    45  }
    46  
    47  func referenceBytes(s string) []byte {
    48  	b, err := hex.DecodeString(s)
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  	return b
    53  }
    54  
    55  var errJSONEOF = errors.New("unexpected end of JSON input")
    56  
    57  var unmarshalBytesTests = []unmarshalTest{
    58  	// invalid encoding
    59  	{input: "", wantErr: errJSONEOF},
    60  	{input: "null", wantErr: errNonString(bytesT)},
    61  	{input: "10", wantErr: errNonString(bytesT)},
    62  	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, bytesT)},
    63  	{input: `"0x0"`, wantErr: wrapTypeError(ErrOddLength, bytesT)},
    64  	{input: `"0xxx"`, wantErr: wrapTypeError(ErrSyntax, bytesT)},
    65  	{input: `"0x01zz01"`, wantErr: wrapTypeError(ErrSyntax, bytesT)},
    66  
    67  	// valid encoding
    68  	{input: `""`, want: referenceBytes("")},
    69  	{input: `"0x"`, want: referenceBytes("")},
    70  	{input: `"0x02"`, want: referenceBytes("02")},
    71  	{input: `"0X02"`, want: referenceBytes("02")},
    72  	{input: `"0xffffffffff"`, want: referenceBytes("ffffffffff")},
    73  	{
    74  		input: `"0xffffffffffffffffffffffffffffffffffff"`,
    75  		want:  referenceBytes("ffffffffffffffffffffffffffffffffffff"),
    76  	},
    77  }
    78  
    79  func TestUnmarshalBytes(t *testing.T) {
    80  	for _, test := range unmarshalBytesTests {
    81  		var v Bytes
    82  		err := json.Unmarshal([]byte(test.input), &v)
    83  		if !checkError(t, test.input, err, test.wantErr) {
    84  			continue
    85  		}
    86  		if !bytes.Equal(test.want.([]byte), []byte(v)) {
    87  			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, &v, test.want)
    88  			continue
    89  		}
    90  	}
    91  }
    92  
    93  func BenchmarkUnmarshalBytes(b *testing.B) {
    94  	input := []byte(`"0x123456789abcdef123456789abcdef"`)
    95  	for i := 0; i < b.N; i++ {
    96  		var v Bytes
    97  		if err := v.UnmarshalJSON(input); err != nil {
    98  			b.Fatal(err)
    99  		}
   100  	}
   101  }
   102  
   103  func TestMarshalBytes(t *testing.T) {
   104  	for _, test := range encodeBytesTests {
   105  		in := test.input.([]byte)
   106  		out, err := json.Marshal(Bytes(in))
   107  		if err != nil {
   108  			t.Errorf("%x: %v", in, err)
   109  			continue
   110  		}
   111  		if want := `"` + test.want + `"`; string(out) != want {
   112  			t.Errorf("%x: MarshalJSON output mismatch: got %q, want %q", in, out, want)
   113  			continue
   114  		}
   115  		if out := Bytes(in).String(); out != test.want {
   116  			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
   117  			continue
   118  		}
   119  	}
   120  }
   121  
   122  var unmarshalBigTests = []unmarshalTest{
   123  	// invalid encoding
   124  	{input: "", wantErr: errJSONEOF},
   125  	{input: "null", wantErr: errNonString(bigT)},
   126  	{input: "10", wantErr: errNonString(bigT)},
   127  	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, bigT)},
   128  	{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, bigT)},
   129  	{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, bigT)},
   130  	{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, bigT)},
   131  	{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, bigT)},
   132  	{
   133  		input:   `"0x10000000000000000000000000000000000000000000000000000000000000000"`,
   134  		wantErr: wrapTypeError(ErrBig256Range, bigT),
   135  	},
   136  
   137  	// valid encoding
   138  	{input: `""`, want: big.NewInt(0)},
   139  	{input: `"0x0"`, want: big.NewInt(0)},
   140  	{input: `"0x2"`, want: big.NewInt(0x2)},
   141  	{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
   142  	{input: `"0X2F2"`, want: big.NewInt(0x2f2)},
   143  	{input: `"0x1122aaff"`, want: big.NewInt(0x1122aaff)},
   144  	{input: `"0xbBb"`, want: big.NewInt(0xbbb)},
   145  	{input: `"0xfffffffff"`, want: big.NewInt(0xfffffffff)},
   146  	{
   147  		input: `"0x112233445566778899aabbccddeeff"`,
   148  		want:  referenceBig("112233445566778899aabbccddeeff"),
   149  	},
   150  	{
   151  		input: `"0xffffffffffffffffffffffffffffffffffff"`,
   152  		want:  referenceBig("ffffffffffffffffffffffffffffffffffff"),
   153  	},
   154  	{
   155  		input: `"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"`,
   156  		want:  referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
   157  	},
   158  }
   159  
   160  func TestUnmarshalBig(t *testing.T) {
   161  	for _, test := range unmarshalBigTests {
   162  		var v Big
   163  		err := json.Unmarshal([]byte(test.input), &v)
   164  		if !checkError(t, test.input, err, test.wantErr) {
   165  			continue
   166  		}
   167  		if test.want != nil && test.want.(*big.Int).Cmp((*big.Int)(&v)) != 0 {
   168  			t.Errorf("input %s: value mismatch: got %x, want %x", test.input, (*big.Int)(&v), test.want)
   169  			continue
   170  		}
   171  	}
   172  }
   173  
   174  func BenchmarkUnmarshalBig(b *testing.B) {
   175  	input := []byte(`"0x123456789abcdef123456789abcdef"`)
   176  	for i := 0; i < b.N; i++ {
   177  		var v Big
   178  		if err := v.UnmarshalJSON(input); err != nil {
   179  			b.Fatal(err)
   180  		}
   181  	}
   182  }
   183  
   184  func TestMarshalBig(t *testing.T) {
   185  	for _, test := range encodeBigTests {
   186  		in := test.input.(*big.Int)
   187  		out, err := json.Marshal((*Big)(in))
   188  		if err != nil {
   189  			t.Errorf("%d: %v", in, err)
   190  			continue
   191  		}
   192  		if want := `"` + test.want + `"`; string(out) != want {
   193  			t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
   194  			continue
   195  		}
   196  		if out := (*Big)(in).String(); out != test.want {
   197  			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
   198  			continue
   199  		}
   200  	}
   201  }
   202  
   203  var unmarshalUint64Tests = []unmarshalTest{
   204  	// invalid encoding
   205  	{input: "", wantErr: errJSONEOF},
   206  	{input: "null", wantErr: errNonString(uint64T)},
   207  	{input: "10", wantErr: errNonString(uint64T)},
   208  	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, uint64T)},
   209  	{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, uint64T)},
   210  	{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, uint64T)},
   211  	{input: `"0xfffffffffffffffff"`, wantErr: wrapTypeError(ErrUint64Range, uint64T)},
   212  	{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, uint64T)},
   213  	{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, uint64T)},
   214  
   215  	// valid encoding
   216  	{input: `""`, want: uint64(0)},
   217  	{input: `"0x0"`, want: uint64(0)},
   218  	{input: `"0x2"`, want: uint64(0x2)},
   219  	{input: `"0x2F2"`, want: uint64(0x2f2)},
   220  	{input: `"0X2F2"`, want: uint64(0x2f2)},
   221  	{input: `"0x1122aaff"`, want: uint64(0x1122aaff)},
   222  	{input: `"0xbbb"`, want: uint64(0xbbb)},
   223  	{input: `"0xffffffffffffffff"`, want: uint64(0xffffffffffffffff)},
   224  }
   225  
   226  func TestUnmarshalUint64(t *testing.T) {
   227  	for _, test := range unmarshalUint64Tests {
   228  		var v Uint64
   229  		err := json.Unmarshal([]byte(test.input), &v)
   230  		if !checkError(t, test.input, err, test.wantErr) {
   231  			continue
   232  		}
   233  		if uint64(v) != test.want.(uint64) {
   234  			t.Errorf("input %s: value mismatch: got %d, want %d", test.input, v, test.want)
   235  			continue
   236  		}
   237  	}
   238  }
   239  
   240  func BenchmarkUnmarshalUint64(b *testing.B) {
   241  	input := []byte(`"0x123456789abcdf"`)
   242  	for i := 0; i < b.N; i++ {
   243  		var v Uint64
   244  		v.UnmarshalJSON(input)
   245  	}
   246  }
   247  
   248  func TestMarshalUint64(t *testing.T) {
   249  	for _, test := range encodeUint64Tests {
   250  		in := test.input.(uint64)
   251  		out, err := json.Marshal(Uint64(in))
   252  		if err != nil {
   253  			t.Errorf("%d: %v", in, err)
   254  			continue
   255  		}
   256  		if want := `"` + test.want + `"`; string(out) != want {
   257  			t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
   258  			continue
   259  		}
   260  		if out := (Uint64)(in).String(); out != test.want {
   261  			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
   262  			continue
   263  		}
   264  	}
   265  }
   266  
   267  func TestMarshalUint(t *testing.T) {
   268  	for _, test := range encodeUintTests {
   269  		in := test.input.(uint)
   270  		out, err := json.Marshal(Uint(in))
   271  		if err != nil {
   272  			t.Errorf("%d: %v", in, err)
   273  			continue
   274  		}
   275  		if want := `"` + test.want + `"`; string(out) != want {
   276  			t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
   277  			continue
   278  		}
   279  		if out := (Uint)(in).String(); out != test.want {
   280  			t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
   281  			continue
   282  		}
   283  	}
   284  }
   285  
   286  var (
   287  	// These are variables (not constants) to avoid constant overflow
   288  	// checks in the compiler on 32bit platforms.
   289  	maxUint33bits = uint64(^uint32(0)) + 1
   290  	maxUint64bits = ^uint64(0)
   291  )
   292  
   293  var unmarshalUintTests = []unmarshalTest{
   294  	// invalid encoding
   295  	{input: "", wantErr: errJSONEOF},
   296  	{input: "null", wantErr: errNonString(uintT)},
   297  	{input: "10", wantErr: errNonString(uintT)},
   298  	{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, uintT)},
   299  	{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, uintT)},
   300  	{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, uintT)},
   301  	{input: `"0x100000000"`, want: uint(maxUint33bits), wantErr32bit: wrapTypeError(ErrUintRange, uintT)},
   302  	{input: `"0xfffffffffffffffff"`, wantErr: wrapTypeError(ErrUintRange, uintT)},
   303  	{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, uintT)},
   304  	{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, uintT)},
   305  
   306  	// valid encoding
   307  	{input: `""`, want: uint(0)},
   308  	{input: `"0x0"`, want: uint(0)},
   309  	{input: `"0x2"`, want: uint(0x2)},
   310  	{input: `"0x2F2"`, want: uint(0x2f2)},
   311  	{input: `"0X2F2"`, want: uint(0x2f2)},
   312  	{input: `"0x1122aaff"`, want: uint(0x1122aaff)},
   313  	{input: `"0xbbb"`, want: uint(0xbbb)},
   314  	{input: `"0xffffffff"`, want: uint(0xffffffff)},
   315  	{input: `"0xffffffffffffffff"`, want: uint(maxUint64bits), wantErr32bit: wrapTypeError(ErrUintRange, uintT)},
   316  }
   317  
   318  func TestUnmarshalUint(t *testing.T) {
   319  	for _, test := range unmarshalUintTests {
   320  		var v Uint
   321  		err := json.Unmarshal([]byte(test.input), &v)
   322  		if uintBits == 32 && test.wantErr32bit != nil {
   323  			checkError(t, test.input, err, test.wantErr32bit)
   324  			continue
   325  		}
   326  		if !checkError(t, test.input, err, test.wantErr) {
   327  			continue
   328  		}
   329  		if uint(v) != test.want.(uint) {
   330  			t.Errorf("input %s: value mismatch: got %d, want %d", test.input, v, test.want)
   331  			continue
   332  		}
   333  	}
   334  }
   335  
   336  func TestUnmarshalFixedUnprefixedText(t *testing.T) {
   337  	tests := []struct {
   338  		input   string
   339  		want    []byte
   340  		wantErr error
   341  	}{
   342  		{input: "0x2", wantErr: ErrOddLength},
   343  		{input: "2", wantErr: ErrOddLength},
   344  		{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
   345  		{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
   346  		// check that output is not modified for partially correct input
   347  		{input: "444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
   348  		{input: "0x444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
   349  		// valid inputs
   350  		{input: "44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
   351  		{input: "0x44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
   352  	}
   353  
   354  	for _, test := range tests {
   355  		out := make([]byte, 4)
   356  		err := UnmarshalFixedUnprefixedText("x", []byte(test.input), out)
   357  		switch {
   358  		case err == nil && test.wantErr != nil:
   359  			t.Errorf("%q: got no error, expected %q", test.input, test.wantErr)
   360  		case err != nil && test.wantErr == nil:
   361  			t.Errorf("%q: unexpected error %q", test.input, err)
   362  		case err != nil && err.Error() != test.wantErr.Error():
   363  			t.Errorf("%q: error mismatch: got %q, want %q", test.input, err, test.wantErr)
   364  		}
   365  		if test.want != nil && !bytes.Equal(out, test.want) {
   366  			t.Errorf("%q: output mismatch: got %x, want %x", test.input, out, test.want)
   367  		}
   368  	}
   369  }