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