github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/btcjson/cmdparse_test.go (about)

     1  // Copyright (c) 2014 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package btcjson_test
     7  
     8  import (
     9  	"encoding/json"
    10  	"math"
    11  	"reflect"
    12  	"testing"
    13  
    14  	"github.com/dashpay/godash/btcjson"
    15  )
    16  
    17  // TestAssignField tests the assignField function handles supported combinations
    18  // properly.
    19  func TestAssignField(t *testing.T) {
    20  	t.Parallel()
    21  
    22  	tests := []struct {
    23  		name     string
    24  		dest     interface{}
    25  		src      interface{}
    26  		expected interface{}
    27  	}{
    28  		{
    29  			name:     "same types",
    30  			dest:     int8(0),
    31  			src:      int8(100),
    32  			expected: int8(100),
    33  		},
    34  		{
    35  			name: "same types - more source pointers",
    36  			dest: int8(0),
    37  			src: func() interface{} {
    38  				i := int8(100)
    39  				return &i
    40  			}(),
    41  			expected: int8(100),
    42  		},
    43  		{
    44  			name: "same types - more dest pointers",
    45  			dest: func() interface{} {
    46  				i := int8(0)
    47  				return &i
    48  			}(),
    49  			src:      int8(100),
    50  			expected: int8(100),
    51  		},
    52  		{
    53  			name: "convertible types - more source pointers",
    54  			dest: int16(0),
    55  			src: func() interface{} {
    56  				i := int8(100)
    57  				return &i
    58  			}(),
    59  			expected: int16(100),
    60  		},
    61  		{
    62  			name: "convertible types - both pointers",
    63  			dest: func() interface{} {
    64  				i := int8(0)
    65  				return &i
    66  			}(),
    67  			src: func() interface{} {
    68  				i := int16(100)
    69  				return &i
    70  			}(),
    71  			expected: int8(100),
    72  		},
    73  		{
    74  			name:     "convertible types - int16 -> int8",
    75  			dest:     int8(0),
    76  			src:      int16(100),
    77  			expected: int8(100),
    78  		},
    79  		{
    80  			name:     "convertible types - int16 -> uint8",
    81  			dest:     uint8(0),
    82  			src:      int16(100),
    83  			expected: uint8(100),
    84  		},
    85  		{
    86  			name:     "convertible types - uint16 -> int8",
    87  			dest:     int8(0),
    88  			src:      uint16(100),
    89  			expected: int8(100),
    90  		},
    91  		{
    92  			name:     "convertible types - uint16 -> uint8",
    93  			dest:     uint8(0),
    94  			src:      uint16(100),
    95  			expected: uint8(100),
    96  		},
    97  		{
    98  			name:     "convertible types - float32 -> float64",
    99  			dest:     float64(0),
   100  			src:      float32(1.5),
   101  			expected: float64(1.5),
   102  		},
   103  		{
   104  			name:     "convertible types - float64 -> float32",
   105  			dest:     float32(0),
   106  			src:      float64(1.5),
   107  			expected: float32(1.5),
   108  		},
   109  		{
   110  			name:     "convertible types - string -> bool",
   111  			dest:     false,
   112  			src:      "true",
   113  			expected: true,
   114  		},
   115  		{
   116  			name:     "convertible types - string -> int8",
   117  			dest:     int8(0),
   118  			src:      "100",
   119  			expected: int8(100),
   120  		},
   121  		{
   122  			name:     "convertible types - string -> uint8",
   123  			dest:     uint8(0),
   124  			src:      "100",
   125  			expected: uint8(100),
   126  		},
   127  		{
   128  			name:     "convertible types - string -> float32",
   129  			dest:     float32(0),
   130  			src:      "1.5",
   131  			expected: float32(1.5),
   132  		},
   133  		{
   134  			name: "convertible types - typecase string -> string",
   135  			dest: "",
   136  			src: func() interface{} {
   137  				type foo string
   138  				return foo("foo")
   139  			}(),
   140  			expected: "foo",
   141  		},
   142  		{
   143  			name:     "convertible types - string -> array",
   144  			dest:     [2]string{},
   145  			src:      `["test","test2"]`,
   146  			expected: [2]string{"test", "test2"},
   147  		},
   148  		{
   149  			name:     "convertible types - string -> slice",
   150  			dest:     []string{},
   151  			src:      `["test","test2"]`,
   152  			expected: []string{"test", "test2"},
   153  		},
   154  		{
   155  			name:     "convertible types - string -> struct",
   156  			dest:     struct{ A int }{},
   157  			src:      `{"A":100}`,
   158  			expected: struct{ A int }{100},
   159  		},
   160  		{
   161  			name:     "convertible types - string -> map",
   162  			dest:     map[string]float64{},
   163  			src:      `{"1Address":1.5}`,
   164  			expected: map[string]float64{"1Address": 1.5},
   165  		},
   166  	}
   167  
   168  	t.Logf("Running %d tests", len(tests))
   169  	for i, test := range tests {
   170  		dst := reflect.New(reflect.TypeOf(test.dest)).Elem()
   171  		src := reflect.ValueOf(test.src)
   172  		err := btcjson.TstAssignField(1, "testField", dst, src)
   173  		if err != nil {
   174  			t.Errorf("Test #%d (%s) unexpected error: %v", i,
   175  				test.name, err)
   176  			continue
   177  		}
   178  
   179  		// Inidirect through to the base types to ensure their values
   180  		// are the same.
   181  		for dst.Kind() == reflect.Ptr {
   182  			dst = dst.Elem()
   183  		}
   184  		if !reflect.DeepEqual(dst.Interface(), test.expected) {
   185  			t.Errorf("Test #%d (%s) unexpected value - got %v, "+
   186  				"want %v", i, test.name, dst.Interface(),
   187  				test.expected)
   188  			continue
   189  		}
   190  	}
   191  }
   192  
   193  // TestAssignFieldErrors tests the assignField function error paths.
   194  func TestAssignFieldErrors(t *testing.T) {
   195  	t.Parallel()
   196  
   197  	tests := []struct {
   198  		name string
   199  		dest interface{}
   200  		src  interface{}
   201  		err  btcjson.Error
   202  	}{
   203  		{
   204  			name: "general incompatible int -> string",
   205  			dest: string(0),
   206  			src:  int(0),
   207  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   208  		},
   209  		{
   210  			name: "overflow source int -> dest int",
   211  			dest: int8(0),
   212  			src:  int(128),
   213  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   214  		},
   215  		{
   216  			name: "overflow source int -> dest uint",
   217  			dest: uint8(0),
   218  			src:  int(256),
   219  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   220  		},
   221  		{
   222  			name: "int -> float",
   223  			dest: float32(0),
   224  			src:  int(256),
   225  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   226  		},
   227  		{
   228  			name: "overflow source uint64 -> dest int64",
   229  			dest: int64(0),
   230  			src:  uint64(1 << 63),
   231  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   232  		},
   233  		{
   234  			name: "overflow source uint -> dest int",
   235  			dest: int8(0),
   236  			src:  uint(128),
   237  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   238  		},
   239  		{
   240  			name: "overflow source uint -> dest uint",
   241  			dest: uint8(0),
   242  			src:  uint(256),
   243  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   244  		},
   245  		{
   246  			name: "uint -> float",
   247  			dest: float32(0),
   248  			src:  uint(256),
   249  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   250  		},
   251  		{
   252  			name: "float -> int",
   253  			dest: int(0),
   254  			src:  float32(1.0),
   255  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   256  		},
   257  		{
   258  			name: "overflow float64 -> float32",
   259  			dest: float32(0),
   260  			src:  float64(math.MaxFloat64),
   261  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   262  		},
   263  		{
   264  			name: "invalid string -> bool",
   265  			dest: true,
   266  			src:  "foo",
   267  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   268  		},
   269  		{
   270  			name: "invalid string -> int",
   271  			dest: int8(0),
   272  			src:  "foo",
   273  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   274  		},
   275  		{
   276  			name: "overflow string -> int",
   277  			dest: int8(0),
   278  			src:  "128",
   279  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   280  		},
   281  		{
   282  			name: "invalid string -> uint",
   283  			dest: uint8(0),
   284  			src:  "foo",
   285  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   286  		},
   287  		{
   288  			name: "overflow string -> uint",
   289  			dest: uint8(0),
   290  			src:  "256",
   291  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   292  		},
   293  		{
   294  			name: "invalid string -> float",
   295  			dest: float32(0),
   296  			src:  "foo",
   297  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   298  		},
   299  		{
   300  			name: "overflow string -> float",
   301  			dest: float32(0),
   302  			src:  "1.7976931348623157e+308",
   303  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   304  		},
   305  		{
   306  			name: "invalid string -> array",
   307  			dest: [3]int{},
   308  			src:  "foo",
   309  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   310  		},
   311  		{
   312  			name: "invalid string -> slice",
   313  			dest: []int{},
   314  			src:  "foo",
   315  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   316  		},
   317  		{
   318  			name: "invalid string -> struct",
   319  			dest: struct{ A int }{},
   320  			src:  "foo",
   321  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   322  		},
   323  		{
   324  			name: "invalid string -> map",
   325  			dest: map[string]int{},
   326  			src:  "foo",
   327  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   328  		},
   329  	}
   330  
   331  	t.Logf("Running %d tests", len(tests))
   332  	for i, test := range tests {
   333  		dst := reflect.New(reflect.TypeOf(test.dest)).Elem()
   334  		src := reflect.ValueOf(test.src)
   335  		err := btcjson.TstAssignField(1, "testField", dst, src)
   336  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
   337  			t.Errorf("Test #%d (%s) wrong error - got %T (%[3]v), "+
   338  				"want %T", i, test.name, err, test.err)
   339  			continue
   340  		}
   341  		gotErrorCode := err.(btcjson.Error).ErrorCode
   342  		if gotErrorCode != test.err.ErrorCode {
   343  			t.Errorf("Test #%d (%s) mismatched error code - got "+
   344  				"%v (%v), want %v", i, test.name, gotErrorCode,
   345  				err, test.err.ErrorCode)
   346  			continue
   347  		}
   348  	}
   349  }
   350  
   351  // TestNewCmdErrors ensures the error paths of NewCmd behave as expected.
   352  func TestNewCmdErrors(t *testing.T) {
   353  	t.Parallel()
   354  
   355  	tests := []struct {
   356  		name   string
   357  		method string
   358  		args   []interface{}
   359  		err    btcjson.Error
   360  	}{
   361  		{
   362  			name:   "unregistered command",
   363  			method: "boguscommand",
   364  			args:   []interface{}{},
   365  			err:    btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
   366  		},
   367  		{
   368  			name:   "too few parameters to command with required + optional",
   369  			method: "getblock",
   370  			args:   []interface{}{},
   371  			err:    btcjson.Error{ErrorCode: btcjson.ErrNumParams},
   372  		},
   373  		{
   374  			name:   "too many parameters to command with no optional",
   375  			method: "getblockcount",
   376  			args:   []interface{}{"123"},
   377  			err:    btcjson.Error{ErrorCode: btcjson.ErrNumParams},
   378  		},
   379  		{
   380  			name:   "incorrect parameter type",
   381  			method: "getblock",
   382  			args:   []interface{}{1},
   383  			err:    btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   384  		},
   385  	}
   386  
   387  	t.Logf("Running %d tests", len(tests))
   388  	for i, test := range tests {
   389  		_, err := btcjson.NewCmd(test.method, test.args...)
   390  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
   391  			t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+
   392  				"want %T", i, test.name, err, test.err)
   393  			continue
   394  		}
   395  		gotErrorCode := err.(btcjson.Error).ErrorCode
   396  		if gotErrorCode != test.err.ErrorCode {
   397  			t.Errorf("Test #%d (%s) mismatched error code - got "+
   398  				"%v (%v), want %v", i, test.name, gotErrorCode,
   399  				err, test.err.ErrorCode)
   400  			continue
   401  		}
   402  	}
   403  }
   404  
   405  // TestMarshalCmdErrors  tests the error paths of the MarshalCmd function.
   406  func TestMarshalCmdErrors(t *testing.T) {
   407  	t.Parallel()
   408  
   409  	tests := []struct {
   410  		name string
   411  		id   interface{}
   412  		cmd  interface{}
   413  		err  btcjson.Error
   414  	}{
   415  		{
   416  			name: "unregistered type",
   417  			id:   1,
   418  			cmd:  (*int)(nil),
   419  			err:  btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
   420  		},
   421  		{
   422  			name: "nil instance of registered type",
   423  			id:   1,
   424  			cmd:  (*btcjson.GetBlockCmd)(nil),
   425  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   426  		},
   427  		{
   428  			name: "nil instance of registered type",
   429  			id:   []int{0, 1},
   430  			cmd:  &btcjson.GetBlockCountCmd{},
   431  			err:  btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   432  		},
   433  	}
   434  
   435  	t.Logf("Running %d tests", len(tests))
   436  	for i, test := range tests {
   437  		_, err := btcjson.MarshalCmd(test.id, test.cmd)
   438  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
   439  			t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+
   440  				"want %T", i, test.name, err, test.err)
   441  			continue
   442  		}
   443  		gotErrorCode := err.(btcjson.Error).ErrorCode
   444  		if gotErrorCode != test.err.ErrorCode {
   445  			t.Errorf("Test #%d (%s) mismatched error code - got "+
   446  				"%v (%v), want %v", i, test.name, gotErrorCode,
   447  				err, test.err.ErrorCode)
   448  			continue
   449  		}
   450  	}
   451  }
   452  
   453  // TestUnmarshalCmdErrors  tests the error paths of the UnmarshalCmd function.
   454  func TestUnmarshalCmdErrors(t *testing.T) {
   455  	t.Parallel()
   456  
   457  	tests := []struct {
   458  		name    string
   459  		request btcjson.Request
   460  		err     btcjson.Error
   461  	}{
   462  		{
   463  			name: "unregistered type",
   464  			request: btcjson.Request{
   465  				Jsonrpc: "1.0",
   466  				Method:  "bogusmethod",
   467  				Params:  nil,
   468  				ID:      nil,
   469  			},
   470  			err: btcjson.Error{ErrorCode: btcjson.ErrUnregisteredMethod},
   471  		},
   472  		{
   473  			name: "incorrect number of params",
   474  			request: btcjson.Request{
   475  				Jsonrpc: "1.0",
   476  				Method:  "getblockcount",
   477  				Params:  []json.RawMessage{[]byte(`"bogusparam"`)},
   478  				ID:      nil,
   479  			},
   480  			err: btcjson.Error{ErrorCode: btcjson.ErrNumParams},
   481  		},
   482  		{
   483  			name: "invalid type for a parameter",
   484  			request: btcjson.Request{
   485  				Jsonrpc: "1.0",
   486  				Method:  "getblock",
   487  				Params:  []json.RawMessage{[]byte("1")},
   488  				ID:      nil,
   489  			},
   490  			err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   491  		},
   492  		{
   493  			name: "invalid JSON for a parameter",
   494  			request: btcjson.Request{
   495  				Jsonrpc: "1.0",
   496  				Method:  "getblock",
   497  				Params:  []json.RawMessage{[]byte(`"1`)},
   498  				ID:      nil,
   499  			},
   500  			err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
   501  		},
   502  	}
   503  
   504  	t.Logf("Running %d tests", len(tests))
   505  	for i, test := range tests {
   506  		_, err := btcjson.UnmarshalCmd(&test.request)
   507  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
   508  			t.Errorf("Test #%d (%s) wrong error - got %T (%[2]v), "+
   509  				"want %T", i, test.name, err, test.err)
   510  			continue
   511  		}
   512  		gotErrorCode := err.(btcjson.Error).ErrorCode
   513  		if gotErrorCode != test.err.ErrorCode {
   514  			t.Errorf("Test #%d (%s) mismatched error code - got "+
   515  				"%v (%v), want %v", i, test.name, gotErrorCode,
   516  				err, test.err.ErrorCode)
   517  			continue
   518  		}
   519  	}
   520  }