github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/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/BlockABC/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 }