github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/common/hexutil/json_test.go (about)

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