github.com/mithrandie/csvq@v1.18.1/lib/value/comparison_test.go (about) 1 package value 2 3 import ( 4 "math" 5 "testing" 6 "time" 7 8 "github.com/mithrandie/ternary" 9 ) 10 11 func TestComparisonResult_String(t *testing.T) { 12 if IsEqual.String() != "IsEqual" { 13 t.Errorf("string = %s, want %s for %s.String()", IsEqual.String(), "IsEqual", IsEqual) 14 } 15 } 16 17 var location, _ = time.LoadLocation("UTC") 18 19 var compareCombinedlyTests = []struct { 20 LHS Primary 21 RHS Primary 22 Result ComparisonResult 23 }{ 24 { 25 LHS: NewInteger(1), 26 RHS: NewNull(), 27 Result: IsIncommensurable, 28 }, 29 { 30 LHS: NewInteger(1), 31 RHS: NewInteger(2), 32 Result: IsLess, 33 }, 34 { 35 LHS: NewInteger(2), 36 RHS: NewInteger(1), 37 Result: IsGreater, 38 }, 39 { 40 LHS: NewInteger(2), 41 RHS: NewInteger(2), 42 Result: IsEqual, 43 }, 44 { 45 LHS: NewFloat(1.5), 46 RHS: NewFloat(2.0), 47 Result: IsLess, 48 }, 49 { 50 LHS: NewFloat(1.5), 51 RHS: NewFloat(1.0), 52 Result: IsGreater, 53 }, 54 { 55 LHS: NewFloat(1.5), 56 RHS: NewFloat(1.5), 57 Result: IsEqual, 58 }, 59 { 60 LHS: NewString("1"), 61 RHS: NewInteger(2), 62 Result: IsLess, 63 }, 64 { 65 LHS: NewString("2"), 66 RHS: NewInteger(1), 67 Result: IsGreater, 68 }, 69 { 70 LHS: NewString("2"), 71 RHS: NewInteger(2), 72 Result: IsEqual, 73 }, 74 { 75 LHS: NewString("1.0"), 76 RHS: NewFloat(1.5), 77 Result: IsLess, 78 }, 79 { 80 LHS: NewString("2.0"), 81 RHS: NewFloat(1.5), 82 Result: IsGreater, 83 }, 84 { 85 LHS: NewString("1.5"), 86 RHS: NewFloat(1.5), 87 Result: IsEqual, 88 }, 89 { 90 LHS: NewInteger(1), 91 RHS: NewFloat(1.5), 92 Result: IsLess, 93 }, 94 { 95 LHS: NewString("1"), 96 RHS: NewString("1.5"), 97 Result: IsLess, 98 }, 99 { 100 LHS: NewDatetimeFromString("2006-01-02T15:04:05-07:00", nil, location), 101 RHS: NewDatetimeFromString("2006-01-02T15:04:05-07:00", nil, location), 102 Result: IsEqual, 103 }, 104 { 105 LHS: NewDatetimeFromString("2006-01-02T15:04:05-07:00", nil, location), 106 RHS: NewDatetimeFromString("2006-02-02T15:04:05-07:00", nil, location), 107 Result: IsLess, 108 }, 109 { 110 LHS: NewDatetimeFromString("2006-02-02T15:04:05-07:00", nil, location), 111 RHS: NewDatetimeFromString("2006-01-02T15:04:05-07:00", nil, location), 112 Result: IsGreater, 113 }, 114 { 115 LHS: NewDatetimeFromString("2006-02-02T15:04:05-07:00", nil, location), 116 RHS: NewString("abc"), 117 Result: IsIncommensurable, 118 }, 119 { 120 LHS: NewBoolean(true), 121 RHS: NewBoolean(true), 122 Result: IsBoolEqual, 123 }, 124 { 125 LHS: NewBoolean(true), 126 RHS: NewBoolean(false), 127 Result: IsNotEqual, 128 }, 129 { 130 LHS: NewString(" A "), 131 RHS: NewString("a"), 132 Result: IsEqual, 133 }, 134 { 135 LHS: NewString("A"), 136 RHS: NewString("B"), 137 Result: IsLess, 138 }, 139 { 140 LHS: NewString("B"), 141 RHS: NewString("A"), 142 Result: IsGreater, 143 }, 144 { 145 LHS: NewString("B"), 146 RHS: NewTernaryFromString("true"), 147 Result: IsIncommensurable, 148 }, 149 { 150 LHS: NewString("1"), 151 RHS: NewString("A"), 152 Result: IsLess, 153 }, 154 { 155 LHS: NewFloat(math.Inf(1)), 156 RHS: NewFloat(math.Inf(1)), 157 Result: IsEqual, 158 }, 159 { 160 LHS: NewFloat(math.Inf(1)), 161 RHS: NewFloat(math.Inf(-1)), 162 Result: IsGreater, 163 }, 164 { 165 LHS: NewFloat(math.NaN()), 166 RHS: NewFloat(math.NaN()), 167 Result: IsNotEqual, 168 }, 169 { 170 LHS: NewFloat(math.Inf(1)), 171 RHS: NewFloat(math.NaN()), 172 Result: IsNotEqual, 173 }, 174 } 175 176 func TestCompareCombinedly(t *testing.T) { 177 for _, v := range compareCombinedlyTests { 178 r := CompareCombinedly(v.LHS, v.RHS, nil, location) 179 if r != v.Result { 180 t.Errorf("result = %s, want %s for comparison with %s and %s", r, v.Result, v.LHS, v.RHS) 181 } 182 } 183 } 184 185 var identicalTests = []struct { 186 LHS Primary 187 RHS Primary 188 Result ternary.Value 189 }{ 190 { 191 LHS: NewNull(), 192 RHS: NewString("R"), 193 Result: ternary.UNKNOWN, 194 }, 195 { 196 LHS: NewTernary(ternary.UNKNOWN), 197 RHS: NewString("R"), 198 Result: ternary.UNKNOWN, 199 }, 200 { 201 LHS: NewString("L"), 202 RHS: NewNull(), 203 Result: ternary.UNKNOWN, 204 }, 205 { 206 LHS: NewString("L"), 207 RHS: NewTernary(ternary.UNKNOWN), 208 Result: ternary.UNKNOWN, 209 }, 210 { 211 LHS: NewInteger(1), 212 RHS: NewInteger(1), 213 Result: ternary.TRUE, 214 }, 215 { 216 LHS: NewFloat(1), 217 RHS: NewFloat(1), 218 Result: ternary.TRUE, 219 }, 220 { 221 LHS: NewDatetimeFromString("2006-02-02T15:04:05-07:00", nil, location), 222 RHS: NewDatetimeFromString("2006-02-02T22:04:05", nil, location), 223 Result: ternary.TRUE, 224 }, 225 { 226 LHS: NewBoolean(true), 227 RHS: NewBoolean(true), 228 Result: ternary.TRUE, 229 }, 230 { 231 LHS: NewTernary(ternary.TRUE), 232 RHS: NewTernary(ternary.TRUE), 233 Result: ternary.TRUE, 234 }, 235 { 236 LHS: NewString("L"), 237 RHS: NewString("R"), 238 Result: ternary.FALSE, 239 }, 240 { 241 LHS: NewString("A"), 242 RHS: NewString("A"), 243 Result: ternary.TRUE, 244 }, 245 { 246 LHS: NewInteger(1), 247 RHS: NewFloat(1), 248 Result: ternary.FALSE, 249 }, 250 } 251 252 func TestIdentical(t *testing.T) { 253 for _, v := range identicalTests { 254 r := Identical(v.LHS, v.RHS) 255 if r != v.Result { 256 t.Errorf("result = %s, want %s for comparison with %s and %s", r, v.Result, v.LHS, v.RHS) 257 } 258 } 259 } 260 261 var compareTests = []struct { 262 LHS Primary 263 RHS Primary 264 Op string 265 Result ternary.Value 266 }{ 267 { 268 LHS: NewInteger(1), 269 RHS: NewInteger(2), 270 Op: "=", 271 Result: ternary.FALSE, 272 }, 273 { 274 LHS: NewInteger(1), 275 RHS: NewInteger(1), 276 Op: "=", 277 Result: ternary.TRUE, 278 }, 279 { 280 LHS: NewInteger(1), 281 RHS: NewNull(), 282 Op: "=", 283 Result: ternary.UNKNOWN, 284 }, 285 { 286 LHS: NewString("0001"), 287 RHS: NewInteger(1), 288 Op: "=", 289 Result: ternary.TRUE, 290 }, 291 { 292 LHS: NewString("0001"), 293 RHS: NewInteger(1), 294 Op: "==", 295 Result: ternary.FALSE, 296 }, 297 { 298 LHS: NewInteger(1), 299 RHS: NewInteger(2), 300 Op: ">", 301 Result: ternary.FALSE, 302 }, 303 { 304 LHS: NewInteger(2), 305 RHS: NewInteger(1), 306 Op: ">", 307 Result: ternary.TRUE, 308 }, 309 { 310 LHS: NewInteger(1), 311 RHS: NewNull(), 312 Op: ">", 313 Result: ternary.UNKNOWN, 314 }, 315 { 316 LHS: NewInteger(2), 317 RHS: NewInteger(1), 318 Op: "<", 319 Result: ternary.FALSE, 320 }, 321 { 322 LHS: NewInteger(1), 323 RHS: NewInteger(2), 324 Op: "<", 325 Result: ternary.TRUE, 326 }, 327 { 328 LHS: NewInteger(1), 329 RHS: NewNull(), 330 Op: "<", 331 Result: ternary.UNKNOWN, 332 }, 333 { 334 LHS: NewInteger(1), 335 RHS: NewInteger(2), 336 Op: ">=", 337 Result: ternary.FALSE, 338 }, 339 { 340 LHS: NewInteger(2), 341 RHS: NewInteger(2), 342 Op: ">=", 343 Result: ternary.TRUE, 344 }, 345 { 346 LHS: NewInteger(1), 347 RHS: NewNull(), 348 Op: ">=", 349 Result: ternary.UNKNOWN, 350 }, 351 { 352 LHS: NewInteger(2), 353 RHS: NewInteger(1), 354 Op: "<=", 355 Result: ternary.FALSE, 356 }, 357 { 358 LHS: NewInteger(2), 359 RHS: NewInteger(2), 360 Op: "<=", 361 Result: ternary.TRUE, 362 }, 363 { 364 LHS: NewInteger(1), 365 RHS: NewNull(), 366 Op: "<=", 367 Result: ternary.UNKNOWN, 368 }, 369 { 370 LHS: NewInteger(2), 371 RHS: NewInteger(2), 372 Op: "<>", 373 Result: ternary.FALSE, 374 }, 375 { 376 LHS: NewInteger(2), 377 RHS: NewInteger(1), 378 Op: "<>", 379 Result: ternary.TRUE, 380 }, 381 { 382 LHS: NewInteger(1), 383 RHS: NewNull(), 384 Op: "<>", 385 Result: ternary.UNKNOWN, 386 }, 387 { 388 LHS: NewFloat(math.Inf(1)), 389 RHS: NewFloat(math.Inf(1)), 390 Op: "=", 391 Result: ternary.TRUE, 392 }, 393 { 394 LHS: NewFloat(math.Inf(1)), 395 RHS: NewFloat(math.Inf(-1)), 396 Op: ">", 397 Result: ternary.TRUE, 398 }, 399 { 400 LHS: NewFloat(math.Inf(1)), 401 RHS: NewFloat(math.NaN()), 402 Op: "<", 403 Result: ternary.UNKNOWN, 404 }, 405 { 406 LHS: NewFloat(math.NaN()), 407 RHS: NewFloat(math.NaN()), 408 Op: "=", 409 Result: ternary.FALSE, 410 }, 411 { 412 LHS: NewFloat(math.NaN()), 413 RHS: NewFloat(math.NaN()), 414 Op: "==", 415 Result: ternary.FALSE, 416 }, 417 { 418 LHS: NewFloat(math.NaN()), 419 RHS: NewFloat(math.NaN()), 420 Op: "<>", 421 Result: ternary.TRUE, 422 }, 423 { 424 LHS: NewFloat(math.NaN()), 425 RHS: NewFloat(math.Inf(1)), 426 Op: "<>", 427 Result: ternary.TRUE, 428 }, 429 } 430 431 func TestCompare(t *testing.T) { 432 for _, v := range compareTests { 433 r := Compare(v.LHS, v.RHS, v.Op, nil, location) 434 if r != v.Result { 435 t.Errorf("result = %s, want %s for (%s %s %s)", r, v.Result, v.LHS, v.Op, v.RHS) 436 } 437 } 438 } 439 440 var compareRowValuesTests = []struct { 441 LHS RowValue 442 RHS RowValue 443 Op string 444 Result ternary.Value 445 Error string 446 }{ 447 { 448 LHS: RowValue{ 449 NewInteger(1), 450 NewInteger(2), 451 NewInteger(3), 452 }, 453 RHS: RowValue{ 454 NewInteger(1), 455 NewInteger(2), 456 NewInteger(3), 457 }, 458 Op: "=", 459 Result: ternary.TRUE, 460 }, 461 { 462 LHS: RowValue{ 463 NewInteger(1), 464 NewInteger(2), 465 NewInteger(3), 466 }, 467 RHS: RowValue{ 468 NewInteger(1), 469 NewNull(), 470 NewInteger(3), 471 }, 472 Op: "=", 473 Result: ternary.UNKNOWN, 474 }, 475 { 476 LHS: RowValue{ 477 NewInteger(1), 478 NewInteger(2), 479 NewInteger(3), 480 }, 481 RHS: RowValue{ 482 NewInteger(1), 483 NewNull(), 484 NewInteger(2), 485 }, 486 Op: "=", 487 Result: ternary.FALSE, 488 }, 489 { 490 LHS: RowValue{ 491 NewInteger(1), 492 NewInteger(2), 493 NewInteger(3), 494 }, 495 RHS: RowValue{ 496 NewInteger(1), 497 NewInteger(2), 498 NewNull(), 499 }, 500 Op: "=", 501 Result: ternary.UNKNOWN, 502 }, 503 { 504 LHS: RowValue{ 505 NewInteger(1), 506 NewInteger(2), 507 NewInteger(3), 508 }, 509 RHS: RowValue{ 510 NewInteger(1), 511 NewInteger(9), 512 NewInteger(3), 513 }, 514 Op: "=", 515 Result: ternary.FALSE, 516 }, 517 { 518 LHS: RowValue{ 519 NewInteger(1), 520 NewInteger(2), 521 NewInteger(3), 522 }, 523 RHS: RowValue{ 524 NewInteger(1), 525 NewInteger(2), 526 NewInteger(3), 527 }, 528 Op: "==", 529 Result: ternary.TRUE, 530 }, 531 { 532 LHS: RowValue{ 533 NewInteger(1), 534 NewInteger(2), 535 NewInteger(3), 536 }, 537 RHS: RowValue{ 538 NewInteger(1), 539 NewNull(), 540 NewInteger(2), 541 }, 542 Op: "==", 543 Result: ternary.FALSE, 544 }, 545 { 546 LHS: RowValue{ 547 NewInteger(1), 548 NewInteger(2), 549 NewInteger(3), 550 }, 551 RHS: RowValue{ 552 NewInteger(1), 553 NewNull(), 554 NewInteger(3), 555 }, 556 Op: "==", 557 Result: ternary.UNKNOWN, 558 }, 559 { 560 LHS: RowValue{ 561 NewInteger(1), 562 NewInteger(2), 563 NewInteger(3), 564 }, 565 RHS: RowValue{ 566 NewInteger(1), 567 NewInteger(0), 568 NewInteger(3), 569 }, 570 Op: "<>", 571 Result: ternary.TRUE, 572 }, 573 { 574 LHS: RowValue{ 575 NewInteger(1), 576 NewInteger(2), 577 NewInteger(3), 578 }, 579 RHS: RowValue{ 580 NewInteger(1), 581 NewNull(), 582 NewInteger(2), 583 }, 584 Op: "<>", 585 Result: ternary.TRUE, 586 }, 587 { 588 LHS: RowValue{ 589 NewInteger(1), 590 NewInteger(2), 591 NewInteger(3), 592 }, 593 RHS: RowValue{ 594 NewInteger(1), 595 NewNull(), 596 NewInteger(3), 597 }, 598 Op: "<>", 599 Result: ternary.UNKNOWN, 600 }, 601 { 602 LHS: RowValue{ 603 NewInteger(1), 604 NewInteger(2), 605 NewInteger(3), 606 }, 607 RHS: RowValue{ 608 NewInteger(1), 609 NewInteger(2), 610 NewInteger(3), 611 }, 612 Op: "!=", 613 Result: ternary.FALSE, 614 }, 615 { 616 LHS: RowValue{ 617 NewInteger(1), 618 NewInteger(2), 619 NewInteger(3), 620 }, 621 RHS: RowValue{ 622 NewInteger(1), 623 NewInteger(2), 624 NewInteger(2), 625 }, 626 Op: ">", 627 Result: ternary.TRUE, 628 }, 629 { 630 LHS: RowValue{ 631 NewInteger(1), 632 NewInteger(2), 633 NewInteger(3), 634 }, 635 RHS: RowValue{ 636 NewInteger(1), 637 NewInteger(2), 638 NewInteger(4), 639 }, 640 Op: ">", 641 Result: ternary.FALSE, 642 }, 643 { 644 LHS: RowValue{ 645 NewInteger(1), 646 NewInteger(2), 647 NewInteger(3), 648 }, 649 RHS: RowValue{ 650 NewInteger(1), 651 NewInteger(2), 652 NewInteger(3), 653 }, 654 Op: ">", 655 Result: ternary.FALSE, 656 }, 657 { 658 LHS: RowValue{ 659 NewInteger(1), 660 NewInteger(2), 661 NewInteger(3), 662 }, 663 RHS: RowValue{ 664 NewInteger(1), 665 NewInteger(2), 666 NewInteger(3), 667 }, 668 Op: ">=", 669 Result: ternary.TRUE, 670 }, 671 { 672 LHS: RowValue{ 673 NewInteger(1), 674 NewBoolean(true), 675 NewInteger(3), 676 }, 677 RHS: RowValue{ 678 NewInteger(1), 679 NewBoolean(false), 680 NewInteger(2), 681 }, 682 Op: ">", 683 Result: ternary.UNKNOWN, 684 }, 685 { 686 LHS: RowValue{ 687 NewInteger(1), 688 NewInteger(2), 689 NewInteger(3), 690 }, 691 RHS: RowValue{ 692 NewInteger(1), 693 NewInteger(2), 694 NewInteger(4), 695 }, 696 Op: "<", 697 Result: ternary.TRUE, 698 }, 699 { 700 LHS: RowValue{ 701 NewInteger(1), 702 NewInteger(2), 703 NewInteger(3), 704 }, 705 RHS: RowValue{ 706 NewInteger(1), 707 NewInteger(2), 708 NewInteger(2), 709 }, 710 Op: "<", 711 Result: ternary.FALSE, 712 }, 713 { 714 LHS: RowValue{ 715 NewInteger(1), 716 NewInteger(2), 717 NewInteger(3), 718 }, 719 RHS: RowValue{ 720 NewInteger(1), 721 NewInteger(2), 722 NewInteger(3), 723 }, 724 Op: "<", 725 Result: ternary.FALSE, 726 }, 727 { 728 LHS: RowValue{ 729 NewInteger(1), 730 NewInteger(2), 731 NewInteger(3), 732 }, 733 RHS: RowValue{ 734 NewInteger(1), 735 NewInteger(2), 736 NewInteger(3), 737 }, 738 Op: "<=", 739 Result: ternary.TRUE, 740 }, 741 { 742 LHS: RowValue{ 743 NewInteger(1), 744 NewInteger(2), 745 NewInteger(3), 746 }, 747 RHS: RowValue(nil), 748 Op: "=", 749 Result: ternary.UNKNOWN, 750 }, 751 { 752 LHS: RowValue{ 753 NewInteger(1), 754 NewInteger(2), 755 NewInteger(3), 756 }, 757 RHS: RowValue{ 758 NewInteger(1), 759 NewInteger(3), 760 }, 761 Op: "=", 762 Error: "row value length does not match", 763 }, 764 } 765 766 func TestCompareRowValues(t *testing.T) { 767 for _, v := range compareRowValuesTests { 768 r, err := CompareRowValues(v.LHS, v.RHS, v.Op, nil, location) 769 if err != nil { 770 if len(v.Error) < 1 { 771 t.Errorf("unexpected error %q for (%s %s %s)", err, v.LHS, v.Op, v.RHS) 772 } else if err.Error() != v.Error { 773 t.Errorf("error %q, want error %q for (%s %s %s)", err.Error(), v.Error, v.LHS, v.Op, v.RHS) 774 } 775 continue 776 } 777 if 0 < len(v.Error) { 778 t.Errorf("no error, want error %q for (%s %s %s)", v.Error, v.LHS, v.Op, v.RHS) 779 continue 780 } 781 if r != v.Result { 782 t.Errorf("result = %s, want %s for (%s %s %s)", r, v.Result, v.LHS, v.Op, v.RHS) 783 } 784 } 785 } 786 787 var equivalentToTests = []struct { 788 LHS Primary 789 RHS Primary 790 Result ternary.Value 791 }{ 792 { 793 LHS: NewNull(), 794 RHS: NewNull(), 795 Result: ternary.TRUE, 796 }, 797 { 798 LHS: NewInteger(1), 799 RHS: NewNull(), 800 Result: ternary.UNKNOWN, 801 }, 802 } 803 804 func TestEquivalentTo(t *testing.T) { 805 for _, v := range equivalentToTests { 806 r := Equivalent(v.LHS, v.RHS, nil, location) 807 if r != v.Result { 808 t.Errorf("result = %s, want %s for (%s is equivalent to %s)", r, v.Result, v.LHS, v.RHS) 809 } 810 } 811 }