diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2019-08-04 09:38:46 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-04 09:38:46 (GMT) |
commit | 17e52649c0e7e9389f1cc2444a53f059e24e6bca (patch) | |
tree | 2cfdcdaefd375aaf93ef6973f507ffb768ee5472 /Lib/test | |
parent | 5c72badd06a962fe0018ceb9916f3ae66314ea8e (diff) | |
download | cpython-17e52649c0e7e9389f1cc2444a53f059e24e6bca.zip cpython-17e52649c0e7e9389f1cc2444a53f059e24e6bca.tar.gz cpython-17e52649c0e7e9389f1cc2444a53f059e24e6bca.tar.bz2 |
bpo-37685: Fixed comparisons of datetime.timedelta and datetime.timezone. (GH-14996)
There was a discrepancy between the Python and C implementations.
Add singletons ALWAYS_EQ, LARGEST and SMALLEST in test.support
to test mixed type comparison.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/datetimetester.py | 74 | ||||
-rw-r--r-- | Lib/test/support/__init__.py | 36 | ||||
-rw-r--r-- | Lib/test/test_ipaddress.py | 33 |
3 files changed, 75 insertions, 68 deletions
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 37ddd4b..99b620c 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -2,11 +2,8 @@ See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases """ -from test.support import is_resource_enabled - import itertools import bisect - import copy import decimal import sys @@ -22,6 +19,7 @@ from array import array from operator import lt, le, gt, ge, eq, ne, truediv, floordiv, mod from test import support +from test.support import is_resource_enabled, ALWAYS_EQ, LARGEST, SMALLEST import datetime as datetime_module from datetime import MINYEAR, MAXYEAR @@ -54,18 +52,6 @@ INF = float("inf") NAN = float("nan") -class ComparesEqualClass(object): - """ - A class that is always equal to whatever you compare it to. - """ - - def __eq__(self, other): - return True - - def __ne__(self, other): - return False - - ############################################################################# # module tests @@ -353,6 +339,18 @@ class TestTimeZone(unittest.TestCase): self.assertTrue(timezone(ZERO) != None) self.assertFalse(timezone(ZERO) == None) + tz = timezone(ZERO) + self.assertTrue(tz == ALWAYS_EQ) + self.assertFalse(tz != ALWAYS_EQ) + self.assertTrue(tz < LARGEST) + self.assertFalse(tz > LARGEST) + self.assertTrue(tz <= LARGEST) + self.assertFalse(tz >= LARGEST) + self.assertFalse(tz < SMALLEST) + self.assertTrue(tz > SMALLEST) + self.assertFalse(tz <= SMALLEST) + self.assertTrue(tz >= SMALLEST) + def test_aware_datetime(self): # test that timezone instances can be used by datetime t = datetime(1, 1, 1) @@ -414,10 +412,21 @@ class HarmlessMixedComparison: # Comparison to objects of unsupported types should return # NotImplemented which falls back to the right hand side's __eq__ - # method. In this case, ComparesEqualClass.__eq__ always returns True. - # ComparesEqualClass.__ne__ always returns False. - self.assertTrue(me == ComparesEqualClass()) - self.assertFalse(me != ComparesEqualClass()) + # method. In this case, ALWAYS_EQ.__eq__ always returns True. + # ALWAYS_EQ.__ne__ always returns False. + self.assertTrue(me == ALWAYS_EQ) + self.assertFalse(me != ALWAYS_EQ) + + # If the other class explicitly defines ordering + # relative to our class, it is allowed to do so + self.assertTrue(me < LARGEST) + self.assertFalse(me > LARGEST) + self.assertTrue(me <= LARGEST) + self.assertFalse(me >= LARGEST) + self.assertFalse(me < SMALLEST) + self.assertTrue(me > SMALLEST) + self.assertFalse(me <= SMALLEST) + self.assertTrue(me >= SMALLEST) def test_harmful_mixed_comparison(self): me = self.theclass(1, 1, 1) @@ -1582,29 +1591,6 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): self.assertRaises(TypeError, lambda: our < their) self.assertRaises(TypeError, lambda: their < our) - # However, if the other class explicitly defines ordering - # relative to our class, it is allowed to do so - - class LargerThanAnything: - def __lt__(self, other): - return False - def __le__(self, other): - return isinstance(other, LargerThanAnything) - def __eq__(self, other): - return isinstance(other, LargerThanAnything) - def __gt__(self, other): - return not isinstance(other, LargerThanAnything) - def __ge__(self, other): - return True - - their = LargerThanAnything() - self.assertEqual(our == their, False) - self.assertEqual(their == our, False) - self.assertEqual(our != their, True) - self.assertEqual(their != our, True) - self.assertEqual(our < their, True) - self.assertEqual(their < our, False) - def test_bool(self): # All dates are considered true. self.assertTrue(self.theclass.min) @@ -3781,8 +3767,8 @@ class TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase): self.assertRaises(ValueError, base.replace, microsecond=1000000) def test_mixed_compare(self): - t1 = time(1, 2, 3) - t2 = time(1, 2, 3) + t1 = self.theclass(1, 2, 3) + t2 = self.theclass(1, 2, 3) self.assertEqual(t1, t2) t2 = t2.replace(tzinfo=None) self.assertEqual(t1, t2) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index dbbbdb0..c82037e 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -113,6 +113,7 @@ __all__ = [ "run_with_locale", "swap_item", "swap_attr", "Matcher", "set_memlimit", "SuppressCrashReport", "sortdict", "run_with_tz", "PGO", "missing_compiler_executable", "fd_count", + "ALWAYS_EQ", "LARGEST", "SMALLEST" ] class Error(Exception): @@ -3103,6 +3104,41 @@ class FakePath: return self.path +class _ALWAYS_EQ: + """ + Object that is equal to anything. + """ + def __eq__(self, other): + return True + def __ne__(self, other): + return False + +ALWAYS_EQ = _ALWAYS_EQ() + +@functools.total_ordering +class _LARGEST: + """ + Object that is greater than anything (except itself). + """ + def __eq__(self, other): + return isinstance(other, _LARGEST) + def __lt__(self, other): + return False + +LARGEST = _LARGEST() + +@functools.total_ordering +class _SMALLEST: + """ + Object that is less than anything (except itself). + """ + def __eq__(self, other): + return isinstance(other, _SMALLEST) + def __gt__(self, other): + return False + +SMALLEST = _SMALLEST() + def maybe_get_event_loop_policy(): """Return the global event loop policy if one is set, else return None.""" return asyncio.events._event_loop_policy diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 9e17ea0..de77111 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -12,6 +12,7 @@ import operator import pickle import ipaddress import weakref +from test.support import LARGEST, SMALLEST class BaseTestCase(unittest.TestCase): @@ -673,20 +674,6 @@ class FactoryFunctionErrors(BaseTestCase): self.assertFactoryError(ipaddress.ip_network, "network") -@functools.total_ordering -class LargestObject: - def __eq__(self, other): - return isinstance(other, LargestObject) - def __lt__(self, other): - return False - -@functools.total_ordering -class SmallestObject: - def __eq__(self, other): - return isinstance(other, SmallestObject) - def __gt__(self, other): - return False - class ComparisonTests(unittest.TestCase): v4addr = ipaddress.IPv4Address(1) @@ -775,8 +762,6 @@ class ComparisonTests(unittest.TestCase): def test_foreign_type_ordering(self): other = object() - smallest = SmallestObject() - largest = LargestObject() for obj in self.objects: with self.assertRaises(TypeError): obj < other @@ -786,14 +771,14 @@ class ComparisonTests(unittest.TestCase): obj <= other with self.assertRaises(TypeError): obj >= other - self.assertTrue(obj < largest) - self.assertFalse(obj > largest) - self.assertTrue(obj <= largest) - self.assertFalse(obj >= largest) - self.assertFalse(obj < smallest) - self.assertTrue(obj > smallest) - self.assertFalse(obj <= smallest) - self.assertTrue(obj >= smallest) + self.assertTrue(obj < LARGEST) + self.assertFalse(obj > LARGEST) + self.assertTrue(obj <= LARGEST) + self.assertFalse(obj >= LARGEST) + self.assertFalse(obj < SMALLEST) + self.assertTrue(obj > SMALLEST) + self.assertFalse(obj <= SMALLEST) + self.assertTrue(obj >= SMALLEST) def test_mixed_type_key(self): # with get_mixed_type_key, you can sort addresses and network. |