github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/common/hexutil/json_test.go (about)

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