github.com/klaytn/klaytn@v1.10.2/common/hexutil/json_test.go (about)

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