github.com/awesome-flow/flow@v0.0.3-0.20190918184116-508d75d68a2c/pkg/cast/converter_test.go (about) 1 package cast 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/awesome-flow/flow/pkg/types" 9 ) 10 11 func intptr(v int) *int { return &v } 12 func strptr(v string) *string { return &v } 13 func boolptr(v bool) *bool { return &v } 14 15 type convAct struct { 16 res types.Value 17 ok bool 18 } 19 20 type testConverter struct { 21 conv func(kv *types.KeyValue) (*types.KeyValue, bool) 22 } 23 24 var _ Converter = (*testConverter)(nil) 25 26 func newTestConverter(act convAct) *testConverter { 27 return &testConverter{ 28 conv: func(kv *types.KeyValue) (*types.KeyValue, bool) { 29 if act.ok { 30 return &types.KeyValue{Key: kv.Key, Value: act.res}, act.ok 31 } 32 return nil, false 33 }, 34 } 35 } 36 37 func (tc *testConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 38 return tc.conv(kv) 39 } 40 41 func TestIdentityConverter(t *testing.T) { 42 tests := []struct { 43 inVal interface{} 44 outVal interface{} 45 outFlag bool 46 }{ 47 {1, 1, true}, 48 {nil, nil, true}, 49 {'a', 'a', true}, 50 {"asdf", "asdf", true}, 51 {struct{}{}, struct{}{}, true}, 52 } 53 54 t.Parallel() 55 56 for ix, testCase := range tests { 57 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 58 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 59 out, ok := Identity.Convert(in) 60 if ok != testCase.outFlag { 61 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 62 } 63 if !ok { 64 return 65 } 66 if out == nil && testCase.outVal != nil { 67 t.Errorf("Expected a non-nil result, got nil") 68 } 69 if !reflect.DeepEqual(testCase.outVal, out.Value) { 70 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 71 } 72 }) 73 } 74 } 75 76 func TestIntToStrConverter(t *testing.T) { 77 tests := []struct { 78 inVal interface{} 79 outVal interface{} 80 outFlag bool 81 }{ 82 {1, "1", true}, 83 {-1, "-1", true}, 84 {nil, nil, false}, 85 {'a', nil, false}, 86 {"asdf", nil, false}, 87 {struct{}{}, nil, false}, 88 } 89 90 t.Parallel() 91 92 for ix, testCase := range tests { 93 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 94 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 95 out, ok := IntToStr.Convert(in) 96 if ok != testCase.outFlag { 97 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 98 } 99 if !ok { 100 return 101 } 102 if out == nil && testCase.outVal != nil { 103 t.Errorf("Expected a non-nil result, got nil") 104 } 105 if !reflect.DeepEqual(testCase.outVal, out.Value) { 106 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 107 } 108 }) 109 } 110 } 111 112 func TestIntPtrToIntConverter(t *testing.T) { 113 tests := []struct { 114 inVal interface{} 115 outVal interface{} 116 outFlag bool 117 }{ 118 {1, nil, false}, 119 {intptr(42), 42, true}, 120 {nil, nil, false}, 121 {'a', nil, false}, 122 {"asdf", nil, false}, 123 {struct{}{}, nil, false}, 124 } 125 126 t.Parallel() 127 128 for ix, testCase := range tests { 129 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 130 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 131 out, ok := IntPtrToInt.Convert(in) 132 if ok != testCase.outFlag { 133 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 134 } 135 if !ok { 136 return 137 } 138 if out == nil && testCase.outVal != nil { 139 t.Errorf("Expected a non-nil result, got nil") 140 } 141 if !reflect.DeepEqual(testCase.outVal, out.Value) { 142 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 143 } 144 }) 145 } 146 } 147 148 func TestStrPtrToStrConverter(t *testing.T) { 149 tests := []struct { 150 inVal interface{} 151 outVal interface{} 152 outFlag bool 153 }{ 154 {1, nil, false}, 155 {nil, nil, false}, 156 {'a', nil, false}, 157 {"asdf", nil, false}, 158 {strptr("asdf"), "asdf", true}, 159 {struct{}{}, nil, false}, 160 } 161 162 t.Parallel() 163 164 for ix, testCase := range tests { 165 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 166 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 167 out, ok := StrPtrToStr.Convert(in) 168 if ok != testCase.outFlag { 169 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 170 } 171 if !ok { 172 return 173 } 174 if out == nil && testCase.outVal != nil { 175 t.Errorf("Expected a non-nil result, got nil") 176 } 177 if !reflect.DeepEqual(testCase.outVal, out.Value) { 178 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 179 } 180 }) 181 } 182 } 183 184 func TestBoolPtrToBoolConverter(t *testing.T) { 185 tests := []struct { 186 inVal interface{} 187 outVal interface{} 188 outFlag bool 189 }{ 190 {true, nil, false}, 191 {boolptr(true), true, true}, 192 {boolptr(false), false, true}, 193 {nil, nil, false}, 194 } 195 196 t.Parallel() 197 198 for ix, testCase := range tests { 199 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 200 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 201 out, ok := BoolPtrToBool.Convert(in) 202 if ok != testCase.outFlag { 203 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 204 } 205 if !ok { 206 return 207 } 208 if out == nil && testCase.outVal != nil { 209 t.Errorf("Expected a non-nil result, got nil") 210 } 211 if !reflect.DeepEqual(testCase.outVal, out.Value) { 212 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 213 } 214 }) 215 } 216 } 217 218 func TestStrToIntConverter(t *testing.T) { 219 tests := []struct { 220 inVal interface{} 221 outVal interface{} 222 outFlag bool 223 }{ 224 {1, nil, false}, 225 {"1", 1, true}, 226 {"-1", -1, true}, 227 {"1234567890", 1234567890, true}, 228 {"asdf", nil, false}, 229 {'1', nil, false}, 230 } 231 232 t.Parallel() 233 234 for ix, testCase := range tests { 235 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 236 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 237 out, ok := StrToInt.Convert(in) 238 if ok != testCase.outFlag { 239 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 240 } 241 if !ok { 242 return 243 } 244 if out == nil && testCase.outVal != nil { 245 t.Errorf("Expected a non-nil result, got nil") 246 } 247 if !reflect.DeepEqual(testCase.outVal, out.Value) { 248 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 249 } 250 }) 251 } 252 } 253 254 func TestIfIntConverter(t *testing.T) { 255 tests := []struct { 256 inVal interface{} 257 outVal interface{} 258 outFlag bool 259 }{ 260 {1, 1, true}, 261 {-1, -1, true}, 262 {0, 0, true}, 263 {"asdf", nil, false}, 264 {intptr(1), nil, false}, 265 {"1", nil, false}, 266 {nil, nil, false}, 267 } 268 269 t.Parallel() 270 271 for ix, testCase := range tests { 272 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 273 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 274 out, ok := IfInt.Convert(in) 275 if ok != testCase.outFlag { 276 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 277 } 278 if !ok { 279 return 280 } 281 if out == nil && testCase.outVal != nil { 282 t.Errorf("Expected a non-nil result, got nil") 283 } 284 if !reflect.DeepEqual(testCase.outVal, out.Value) { 285 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 286 } 287 }) 288 } 289 } 290 291 func TestIfStrConverter(t *testing.T) { 292 tests := []struct { 293 inVal interface{} 294 outVal interface{} 295 outFlag bool 296 }{ 297 {1, nil, false}, 298 {"asdf", "asdf", true}, 299 {strptr("asdf"), nil, false}, 300 {'a', nil, false}, 301 {nil, nil, false}, 302 } 303 304 t.Parallel() 305 306 for ix, testCase := range tests { 307 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 308 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 309 out, ok := IfStr.Convert(in) 310 if ok != testCase.outFlag { 311 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 312 } 313 if !ok { 314 return 315 } 316 if out == nil && testCase.outVal != nil { 317 t.Errorf("Expected a non-nil result, got nil") 318 } 319 if !reflect.DeepEqual(testCase.outVal, out.Value) { 320 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 321 } 322 }) 323 } 324 } 325 326 func TestIfBoolConverter(t *testing.T) { 327 tests := []struct { 328 inVal interface{} 329 outVal interface{} 330 outFlag bool 331 }{ 332 {true, true, true}, 333 {false, false, true}, 334 {nil, nil, false}, 335 {"true", nil, false}, 336 {1, nil, false}, 337 {0, nil, false}, 338 } 339 340 t.Parallel() 341 342 for ix, testCase := range tests { 343 t.Run(fmt.Sprintf("Test #%d", ix), func(t *testing.T) { 344 in := &types.KeyValue{Key: nil, Value: testCase.inVal} 345 out, ok := IfBool.Convert(in) 346 if ok != testCase.outFlag { 347 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.outFlag, ok) 348 } 349 if !ok { 350 return 351 } 352 if out == nil && testCase.outVal != nil { 353 t.Errorf("Expected a non-nil result, got nil") 354 } 355 if !reflect.DeepEqual(testCase.outVal, out.Value) { 356 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.outVal, out.Value) 357 } 358 }) 359 } 360 } 361 362 func TestCompositeConverter_CompAnd(t *testing.T) { 363 tests := []struct { 364 name string 365 chain []convAct 366 expVal types.Value 367 expOk bool 368 }{ 369 { 370 "Empty chain", 371 []convAct{}, 372 nil, false, 373 }, 374 { 375 "1 positive", 376 []convAct{ 377 convAct{1, true}, 378 }, 379 1, true, 380 }, 381 { 382 "2 positive", 383 []convAct{ 384 convAct{1, true}, 385 convAct{2, true}, 386 }, 387 2, true, 388 }, 389 { 390 "1 negative", 391 []convAct{ 392 convAct{nil, false}, 393 }, 394 nil, false, 395 }, 396 { 397 "1 positive 1 negative", 398 []convAct{ 399 convAct{1, true}, 400 convAct{nil, false}, 401 }, 402 nil, false, 403 }, 404 { 405 "1 negative 1 positive", 406 []convAct{ 407 convAct{nil, false}, 408 convAct{1, true}, 409 }, 410 nil, false, 411 }, 412 } 413 414 t.Parallel() 415 416 for _, testCase := range tests { 417 t.Run(testCase.name, func(t *testing.T) { 418 convChain := make([]Converter, 0, len(testCase.chain)) 419 for _, act := range testCase.chain { 420 convChain = append(convChain, newTestConverter(act)) 421 } 422 423 comp := NewCompositeConverter(CompAnd, convChain...) 424 // None of the converters react to the input kv, so 425 // passing a nil value 426 got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil}) 427 if gotOk != testCase.expOk { 428 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk) 429 } 430 if !gotOk { 431 return 432 } 433 if !reflect.DeepEqual(testCase.expVal, got.Value) { 434 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value) 435 } 436 }) 437 } 438 } 439 440 func TestCompositeConverterCompOr(t *testing.T) { 441 tests := []struct { 442 name string 443 chain []convAct 444 expVal types.Value 445 expOk bool 446 }{ 447 { 448 "Empty chain", 449 []convAct{}, 450 nil, false, 451 }, 452 { 453 "1 positive", 454 []convAct{ 455 convAct{1, true}, 456 }, 457 1, true, 458 }, 459 { 460 "2 positive", 461 []convAct{ 462 convAct{1, true}, 463 convAct{2, true}, 464 }, 465 1, true, 466 }, 467 { 468 "1 negative", 469 []convAct{ 470 convAct{nil, false}, 471 }, 472 nil, false, 473 }, 474 { 475 "1 positive 1 negative", 476 []convAct{ 477 convAct{1, true}, 478 convAct{nil, false}, 479 }, 480 1, true, 481 }, 482 { 483 "1 negative 1 positive", 484 []convAct{ 485 convAct{nil, false}, 486 convAct{2, true}, 487 }, 488 2, true, 489 }, 490 { 491 "1 negative 2 positives", 492 []convAct{ 493 convAct{nil, false}, 494 convAct{1, true}, 495 convAct{2, true}, 496 }, 497 1, true, 498 }, 499 } 500 501 t.Parallel() 502 503 for _, testCase := range tests { 504 t.Run(testCase.name, func(t *testing.T) { 505 convChain := make([]Converter, 0, len(testCase.chain)) 506 for _, act := range testCase.chain { 507 convChain = append(convChain, newTestConverter(act)) 508 } 509 510 comp := NewCompositeConverter(CompOr, convChain...) 511 // None of the converters react to the input kv, so 512 // passing a nil value 513 got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil}) 514 if gotOk != testCase.expOk { 515 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk) 516 } 517 if !gotOk { 518 return 519 } 520 if !reflect.DeepEqual(testCase.expVal, got.Value) { 521 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value) 522 } 523 }) 524 } 525 } 526 527 func TestCompositeConverterCompFirst(t *testing.T) { 528 tests := []struct { 529 name string 530 chain []convAct 531 expVal types.Value 532 expOk bool 533 }{ 534 { 535 "Empty chain", 536 []convAct{}, 537 nil, false, 538 }, 539 { 540 "1 positive", 541 []convAct{ 542 convAct{1, true}, 543 }, 544 1, true, 545 }, 546 { 547 "2 positive", 548 []convAct{ 549 convAct{1, true}, 550 convAct{2, true}, 551 }, 552 1, true, 553 }, 554 { 555 "1 negative", 556 []convAct{ 557 convAct{nil, false}, 558 }, 559 nil, false, 560 }, 561 { 562 "1 positive 1 negative", 563 []convAct{ 564 convAct{1, true}, 565 convAct{nil, false}, 566 }, 567 1, true, 568 }, 569 { 570 "1 negative 1 positive", 571 []convAct{ 572 convAct{nil, false}, 573 convAct{2, true}, 574 }, 575 2, true, 576 }, 577 { 578 "1 negative 2 positives", 579 []convAct{ 580 convAct{nil, false}, 581 convAct{1, true}, 582 convAct{2, true}, 583 }, 584 1, true, 585 }, 586 } 587 588 t.Parallel() 589 590 for _, testCase := range tests { 591 t.Run(testCase.name, func(t *testing.T) { 592 convChain := make([]Converter, 0, len(testCase.chain)) 593 for _, act := range testCase.chain { 594 convChain = append(convChain, newTestConverter(act)) 595 } 596 597 comp := NewCompositeConverter(CompFirst, convChain...) 598 // None of the converters react to the input kv, so 599 // passing a nil value 600 got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil}) 601 if gotOk != testCase.expOk { 602 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk) 603 } 604 if !gotOk { 605 return 606 } 607 if !reflect.DeepEqual(testCase.expVal, got.Value) { 608 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value) 609 } 610 }) 611 } 612 } 613 614 func TestCompositeConverterCompLast(t *testing.T) { 615 tests := []struct { 616 name string 617 chain []convAct 618 expVal types.Value 619 expOk bool 620 }{ 621 { 622 "Empty chain", 623 []convAct{}, 624 nil, false, 625 }, 626 { 627 "1 positive", 628 []convAct{ 629 convAct{1, true}, 630 }, 631 1, true, 632 }, 633 { 634 "2 positive", 635 []convAct{ 636 convAct{1, true}, 637 convAct{2, true}, 638 }, 639 2, true, 640 }, 641 { 642 "1 negative", 643 []convAct{ 644 convAct{nil, false}, 645 }, 646 nil, false, 647 }, 648 { 649 "1 positive 1 negative", 650 []convAct{ 651 convAct{1, true}, 652 convAct{nil, false}, 653 }, 654 1, true, 655 }, 656 { 657 "1 negative 1 positive", 658 []convAct{ 659 convAct{nil, false}, 660 convAct{2, true}, 661 }, 662 2, true, 663 }, 664 { 665 "1 negative 2 positives", 666 []convAct{ 667 convAct{nil, false}, 668 convAct{1, true}, 669 convAct{2, true}, 670 }, 671 2, true, 672 }, 673 } 674 675 t.Parallel() 676 677 for _, testCase := range tests { 678 t.Run(testCase.name, func(t *testing.T) { 679 convChain := make([]Converter, 0, len(testCase.chain)) 680 for _, act := range testCase.chain { 681 convChain = append(convChain, newTestConverter(act)) 682 } 683 684 comp := NewCompositeConverter(CompLast, convChain...) 685 // None of the converters react to the input kv, so 686 // passing a nil value 687 got, gotOk := comp.Convert(&types.KeyValue{Key: nil, Value: nil}) 688 if gotOk != testCase.expOk { 689 t.Errorf("Unexpected Convert flag: want: %t, got: %t", testCase.expOk, gotOk) 690 } 691 if !gotOk { 692 return 693 } 694 if !reflect.DeepEqual(testCase.expVal, got.Value) { 695 t.Errorf("Unexpected Convert value: want: %#v, got: %#v", testCase.expVal, got.Value) 696 } 697 }) 698 } 699 }