github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/common/hexutil/json_test.go (about)

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