|
20 | 20 | IsInstance, |
21 | 21 | LessThan, |
22 | 22 | MatchesRegex, |
| 23 | + Nearly, |
23 | 24 | NotEquals, |
24 | 25 | SameMembers, |
25 | 26 | StartsWith, |
26 | 27 | _BinaryMismatch, |
| 28 | + _NotNearlyEqual, |
27 | 29 | ) |
28 | 30 | from testtools.tests.helpers import FullStackRunTest |
29 | 31 | from testtools.tests.matchers.helpers import TestMatchersInterface |
@@ -443,6 +445,115 @@ class TestHasLength(TestCase, TestMatchersInterface): |
443 | 445 | ] |
444 | 446 |
|
445 | 447 |
|
| 448 | +class TestNearlyInterface(TestCase, TestMatchersInterface): |
| 449 | + matches_matcher: ClassVar = Nearly(4.0, delta=0.5) |
| 450 | + matches_matches: ClassVar = [4.0, 4.5, 3.5, 4.25, 3.75] |
| 451 | + matches_mismatches: ClassVar = [4.51, 3.49, 5.0, 2.0, "not a number"] |
| 452 | + |
| 453 | + str_examples: ClassVar = [ |
| 454 | + ("Nearly(4.0, delta=0.5)", Nearly(4.0, delta=0.5)), |
| 455 | + ("Nearly(1.5, delta=0.001)", Nearly(1.5, delta=0.001)), |
| 456 | + ("Nearly(10, delta=1)", Nearly(10, delta=1)), |
| 457 | + ] |
| 458 | + |
| 459 | + describe_examples: ClassVar = [ |
| 460 | + ( |
| 461 | + "5.0 is not nearly equal to 4.0: difference 1.0 exceeds tolerance 0.5", |
| 462 | + 5.0, |
| 463 | + Nearly(4.0, delta=0.5), |
| 464 | + ), |
| 465 | + ( |
| 466 | + "3.0 is not nearly equal to 4.0: difference 1.0 exceeds tolerance 0.5", |
| 467 | + 3.0, |
| 468 | + Nearly(4.0, delta=0.5), |
| 469 | + ), |
| 470 | + ] |
| 471 | + |
| 472 | + |
| 473 | +class TestNearlyMismatch(TestCase): |
| 474 | + """Tests for the _NotNearlyEqual mismatch class.""" |
| 475 | + |
| 476 | + def test_describe_with_numeric_values(self): |
| 477 | + """Test describe() with valid numeric values.""" |
| 478 | + mismatch = _NotNearlyEqual(5.0, 4.0, 0.5) |
| 479 | + self.assertEqual( |
| 480 | + "5.0 is not nearly equal to 4.0: difference 1.0 exceeds tolerance 0.5", |
| 481 | + mismatch.describe(), |
| 482 | + ) |
| 483 | + |
| 484 | + def test_describe_with_non_numeric_values(self): |
| 485 | + """Test describe() when subtraction is not supported.""" |
| 486 | + mismatch = _NotNearlyEqual("string", 4.0, 0.5) |
| 487 | + self.assertEqual( |
| 488 | + "'string' is not nearly equal to 4.0 within 0.5", mismatch.describe() |
| 489 | + ) |
| 490 | + |
| 491 | + |
| 492 | +class TestNearlyBehavior(TestCase): |
| 493 | + """Additional tests for Nearly matcher behavior.""" |
| 494 | + |
| 495 | + def test_integers_match(self): |
| 496 | + """Test that Nearly works with integers.""" |
| 497 | + matcher = Nearly(10, delta=2) |
| 498 | + self.assertIsNone(matcher.match(11)) |
| 499 | + self.assertIsNone(matcher.match(9)) |
| 500 | + self.assertIsNone(matcher.match(10)) |
| 501 | + |
| 502 | + def test_integers_mismatch(self): |
| 503 | + """Test that Nearly correctly fails with integers.""" |
| 504 | + matcher = Nearly(10, delta=2) |
| 505 | + mismatch = matcher.match(13) |
| 506 | + self.assertIsNotNone(mismatch) |
| 507 | + self.assertIn("13", mismatch.describe()) |
| 508 | + |
| 509 | + def test_exact_boundary_matches(self): |
| 510 | + """Test that values at exactly the boundary match.""" |
| 511 | + matcher = Nearly(1.0, delta=0.25) |
| 512 | + # Exactly at the boundary should match (<=) |
| 513 | + self.assertIsNone(matcher.match(1.25)) |
| 514 | + self.assertIsNone(matcher.match(0.75)) |
| 515 | + |
| 516 | + def test_just_outside_boundary_mismatches(self): |
| 517 | + """Test that values just outside the boundary don't match.""" |
| 518 | + matcher = Nearly(1.0, delta=0.1) |
| 519 | + # Just outside the boundary should not match |
| 520 | + self.assertIsNotNone(matcher.match(1.10001)) |
| 521 | + self.assertIsNotNone(matcher.match(0.89999)) |
| 522 | + |
| 523 | + def test_negative_numbers(self): |
| 524 | + """Test that Nearly works with negative numbers.""" |
| 525 | + matcher = Nearly(-5.0, delta=1.0) |
| 526 | + self.assertIsNone(matcher.match(-4.5)) |
| 527 | + self.assertIsNone(matcher.match(-5.5)) |
| 528 | + self.assertIsNotNone(matcher.match(-3.5)) |
| 529 | + |
| 530 | + def test_zero_delta(self): |
| 531 | + """Test Nearly with zero delta (exact match required).""" |
| 532 | + matcher = Nearly(1.0, delta=0.0) |
| 533 | + self.assertIsNone(matcher.match(1.0)) |
| 534 | + self.assertIsNotNone(matcher.match(1.0001)) |
| 535 | + |
| 536 | + def test_default_delta(self): |
| 537 | + """Test that default delta is 0.001.""" |
| 538 | + matcher = Nearly(1.0) |
| 539 | + self.assertEqual(0.001, matcher.delta) |
| 540 | + self.assertIsNone(matcher.match(1.0005)) |
| 541 | + self.assertIsNotNone(matcher.match(1.002)) |
| 542 | + |
| 543 | + def test_non_numeric_type_mismatch(self): |
| 544 | + """Test that non-numeric types result in a mismatch.""" |
| 545 | + matcher = Nearly(1.0, delta=0.1) |
| 546 | + mismatch = matcher.match("string") |
| 547 | + self.assertIsNotNone(mismatch) |
| 548 | + self.assertIn("string", mismatch.describe()) |
| 549 | + |
| 550 | + def test_none_type_mismatch(self): |
| 551 | + """Test that None results in a mismatch.""" |
| 552 | + matcher = Nearly(1.0, delta=0.1) |
| 553 | + mismatch = matcher.match(None) |
| 554 | + self.assertIsNotNone(mismatch) |
| 555 | + |
| 556 | + |
446 | 557 | def test_suite(): |
447 | 558 | from unittest import TestLoader |
448 | 559 |
|
|
0 commit comments