summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorEric V. Smith <ericvsmith@users.noreply.github.com>2018-02-23 18:01:31 (GMT)
committerGitHub <noreply@github.com>2018-02-23 18:01:31 (GMT)
commit718070db26b35da4aedc03088c58558a833ccf6e (patch)
tree2f1fbf3b621d33784abe36cd46a9a9ddb6dcb770 /Lib
parent98f42aac23f3863973cb6e9964c5212cfd3a1d98 (diff)
downloadcpython-718070db26b35da4aedc03088c58558a833ccf6e.zip
cpython-718070db26b35da4aedc03088c58558a833ccf6e.tar.gz
cpython-718070db26b35da4aedc03088c58558a833ccf6e.tar.bz2
Exhaustively test dataclass hashing when no hash= value is provided. This is in anticipation of changing how non-default hashing is handled. (#5834)
Diffstat (limited to 'Lib')
-rwxr-xr-xLib/test/test_dataclasses.py73
1 files changed, 73 insertions, 0 deletions
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index 736bc49..9752f55 100755
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -2393,6 +2393,79 @@ class TestHash(unittest.TestCase):
self.assertNotEqual(C(1), C(1))
self.assertEqual(hash(C(1)), hash(C(1.0)))
+ def test_hash_no_args(self):
+ # Test dataclasses with no hash= argument. This exists to
+ # make sure that when hash is changed, the default hashability
+ # keeps working.
+
+ class Base:
+ def __hash__(self):
+ return 301
+
+ # If frozen or eq is None, then use the default value (do not
+ # specify any value in the deecorator).
+ for frozen, eq, base, expected in [
+ (None, None, object, 'unhashable'),
+ (None, None, Base, 'unhashable'),
+ (None, False, object, 'object'),
+ (None, False, Base, 'base'),
+ (None, True, object, 'unhashable'),
+ (None, True, Base, 'unhashable'),
+ (False, None, object, 'unhashable'),
+ (False, None, Base, 'unhashable'),
+ (False, False, object, 'object'),
+ (False, False, Base, 'base'),
+ (False, True, object, 'unhashable'),
+ (False, True, Base, 'unhashable'),
+ (True, None, object, 'tuple'),
+ (True, None, Base, 'tuple'),
+ (True, False, object, 'object'),
+ (True, False, Base, 'base'),
+ (True, True, object, 'tuple'),
+ (True, True, Base, 'tuple'),
+ ]:
+
+ with self.subTest(frozen=frozen, eq=eq, base=base, expected=expected):
+ # First, create the class.
+ if frozen is None and eq is None:
+ @dataclass
+ class C(base):
+ i: int
+ elif frozen is None:
+ @dataclass(eq=eq)
+ class C(base):
+ i: int
+ elif eq is None:
+ @dataclass(frozen=frozen)
+ class C(base):
+ i: int
+ else:
+ @dataclass(frozen=frozen, eq=eq)
+ class C(base):
+ i: int
+
+ # Now, make sure it hashes as expected.
+ if expected == 'unhashable':
+ c = C(10)
+ with self.assertRaisesRegex(TypeError, 'unhashable type'):
+ hash(c)
+
+ elif expected == 'base':
+ self.assertEqual(hash(C(10)), 301)
+
+ elif expected == 'object':
+ # I'm not sure what test to use here. object's
+ # hash isn't based on id(), so calling hash()
+ # won't tell us much. So, just check the function
+ # used is object's.
+ self.assertIs(C.__hash__, object.__hash__)
+
+ elif expected == 'tuple':
+ self.assertEqual(hash(C(42)), hash((42,)))
+
+ else:
+ assert False, f'unknown value for expected={expected!r}'
+
if __name__ == '__main__':
unittest.main()