blob: 077677983696ea11f40a2671c118dcfe8f624126 [file] [log] [blame]
Fred Drake13634cf2000-06-29 19:17:04 +00001# test the invariant that
2# iff a==b then hash(a)==hash(b)
3#
Nick Coghland1abd252008-07-15 15:46:38 +00004# Also test that hash implementations are inherited as expected
Fred Drake13634cf2000-06-29 19:17:04 +00005
Georg Brandl2daf6ae2012-02-20 19:54:16 +01006import datetime
7import os
Georg Brandl09a7c722012-02-20 21:31:46 +01008import sys
Fred Drake97656a12001-05-18 21:45:35 +00009import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +000010from test import support
Georg Brandl2daf6ae2012-02-20 19:54:16 +010011from test.script_helper import assert_python_ok
Nick Coghland1abd252008-07-15 15:46:38 +000012from collections import Hashable
Fred Drake13634cf2000-06-29 19:17:04 +000013
Georg Brandl09a7c722012-02-20 21:31:46 +010014IS_64BIT = sys.maxsize > 2**32
Georg Brandl2daf6ae2012-02-20 19:54:16 +010015
Fred Drake13634cf2000-06-29 19:17:04 +000016
Fred Drake97656a12001-05-18 21:45:35 +000017class HashEqualityTestCase(unittest.TestCase):
18
19 def same_hash(self, *objlist):
Fred Drakeacb117e2001-05-18 21:50:02 +000020 # Hash each object given and fail if
21 # the hash values are not all the same.
Guido van Rossumc1f779c2007-07-03 08:25:58 +000022 hashed = list(map(hash, objlist))
Fred Drake97656a12001-05-18 21:45:35 +000023 for h in hashed[1:]:
24 if h != hashed[0]:
Walter Dörwald70a6b492004-02-12 17:35:32 +000025 self.fail("hashed values differ: %r" % (objlist,))
Fred Drake97656a12001-05-18 21:45:35 +000026
27 def test_numeric_literals(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +000028 self.same_hash(1, 1, 1.0, 1.0+0.0j)
Thomas Woutersce272b62007-09-19 21:19:28 +000029 self.same_hash(0, 0.0, 0.0+0.0j)
30 self.same_hash(-1, -1.0, -1.0+0.0j)
31 self.same_hash(-2, -2.0, -2.0+0.0j)
Fred Drake97656a12001-05-18 21:45:35 +000032
33 def test_coerced_integers(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +000034 self.same_hash(int(1), int(1), float(1), complex(1),
Fred Drake97656a12001-05-18 21:45:35 +000035 int('1'), float('1.0'))
Thomas Woutersce272b62007-09-19 21:19:28 +000036 self.same_hash(int(-2**31), float(-2**31))
37 self.same_hash(int(1-2**31), float(1-2**31))
38 self.same_hash(int(2**31-1), float(2**31-1))
39 # for 64-bit platforms
40 self.same_hash(int(2**31), float(2**31))
41 self.same_hash(int(-2**63), float(-2**63))
Guilherme Polo887b3f22009-02-07 00:45:10 +000042 self.same_hash(int(2**63), float(2**63))
Fred Drake97656a12001-05-18 21:45:35 +000043
44 def test_coerced_floats(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +000045 self.same_hash(int(1.23e300), float(1.23e300))
Fred Drake97656a12001-05-18 21:45:35 +000046 self.same_hash(float(0.5), complex(0.5, 0.0))
Fred Drake13634cf2000-06-29 19:17:04 +000047
48
Nick Coghland1abd252008-07-15 15:46:38 +000049_default_hash = object.__hash__
50class DefaultHash(object): pass
51
52_FIXED_HASH_VALUE = 42
53class FixedHash(object):
54 def __hash__(self):
55 return _FIXED_HASH_VALUE
56
57class OnlyEquality(object):
58 def __eq__(self, other):
59 return self is other
60
61class OnlyInequality(object):
62 def __ne__(self, other):
63 return self is not other
64
Nick Coghland1abd252008-07-15 15:46:38 +000065class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
66class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
Nick Coghland1abd252008-07-15 15:46:38 +000067
68class NoHash(object):
69 __hash__ = None
70
71class HashInheritanceTestCase(unittest.TestCase):
72 default_expected = [object(),
73 DefaultHash(),
74 OnlyInequality(),
75 ]
76 fixed_expected = [FixedHash(),
77 InheritedHashWithEquality(),
78 InheritedHashWithInequality(),
Nick Coghland1abd252008-07-15 15:46:38 +000079 ]
80 error_expected = [NoHash(),
81 OnlyEquality(),
Nick Coghland1abd252008-07-15 15:46:38 +000082 ]
83
84 def test_default_hash(self):
85 for obj in self.default_expected:
86 self.assertEqual(hash(obj), _default_hash(obj))
87
88 def test_fixed_hash(self):
89 for obj in self.fixed_expected:
90 self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
91
92 def test_error_hash(self):
93 for obj in self.error_expected:
94 self.assertRaises(TypeError, hash, obj)
95
96 def test_hashable(self):
97 objects = (self.default_expected +
98 self.fixed_expected)
99 for obj in objects:
Ezio Melottie9615932010-01-24 19:26:24 +0000100 self.assertIsInstance(obj, Hashable)
Nick Coghland1abd252008-07-15 15:46:38 +0000101
102 def test_not_hashable(self):
103 for obj in self.error_expected:
Ezio Melottie9615932010-01-24 19:26:24 +0000104 self.assertNotIsInstance(obj, Hashable)
Nick Coghland1abd252008-07-15 15:46:38 +0000105
106
Nick Coghlanf1f2f682008-12-30 07:29:12 +0000107# Issue #4701: Check that some builtin types are correctly hashable
108class DefaultIterSeq(object):
109 seq = range(10)
110 def __len__(self):
111 return len(self.seq)
112 def __getitem__(self, index):
113 return self.seq[index]
114
115class HashBuiltinsTestCase(unittest.TestCase):
Mark Dickinson36645682011-10-23 19:53:01 +0100116 hashes_to_check = [enumerate(range(10)),
Nick Coghlanf1f2f682008-12-30 07:29:12 +0000117 iter(DefaultIterSeq()),
118 iter(lambda: 0, 0),
119 ]
120
121 def test_hashes(self):
122 _default_hash = object.__hash__
123 for obj in self.hashes_to_check:
124 self.assertEqual(hash(obj), _default_hash(obj))
125
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100126class HashRandomizationTests(unittest.TestCase):
127
128 # Each subclass should define a field "repr_", containing the repr() of
129 # an object to be tested
130
131 def get_hash_command(self, repr_):
132 return 'print(hash(%s))' % repr_
133
134 def get_hash(self, repr_, seed=None):
135 env = os.environ.copy()
136 env['__cleanenv'] = True # signal to assert_python not to do a copy
137 # of os.environ on its own
138 if seed is not None:
139 env['PYTHONHASHSEED'] = str(seed)
140 else:
141 env.pop('PYTHONHASHSEED', None)
142 out = assert_python_ok(
143 '-c', self.get_hash_command(repr_),
144 **env)
145 stdout = out[1].strip()
146 return int(stdout)
147
148 def test_randomized_hash(self):
149 # two runs should return different hashes
150 run1 = self.get_hash(self.repr_, seed='random')
151 run2 = self.get_hash(self.repr_, seed='random')
152 self.assertNotEqual(run1, run2)
153
154class StringlikeHashRandomizationTests(HashRandomizationTests):
155 def test_null_hash(self):
156 # PYTHONHASHSEED=0 disables the randomized hash
157 if IS_64BIT:
158 known_hash_of_obj = 1453079729188098211
159 else:
160 known_hash_of_obj = -1600925533
161
Benjamin Petersonc9f54cf2012-02-21 16:08:05 -0500162 # Randomization is enabled by default:
163 self.assertNotEqual(self.get_hash(self.repr_), known_hash_of_obj)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100164
165 # It can also be disabled by setting the seed to 0:
166 self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
167
168 def test_fixed_hash(self):
169 # test a fixed seed for the randomized hash
170 # Note that all types share the same values:
171 if IS_64BIT:
Antoine Pitrou679be992012-02-22 03:33:56 +0100172 if sys.byteorder == 'little':
173 h = -4410911502303878509
174 else:
175 h = -3570150969479994130
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100176 else:
Antoine Pitrou679be992012-02-22 03:33:56 +0100177 if sys.byteorder == 'little':
178 h = -206076799
179 else:
180 h = -1024014457
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100181 self.assertEqual(self.get_hash(self.repr_, seed=42), h)
182
183class StrHashRandomizationTests(StringlikeHashRandomizationTests):
184 repr_ = repr('abc')
185
186 def test_empty_string(self):
187 self.assertEqual(hash(""), 0)
188
189class BytesHashRandomizationTests(StringlikeHashRandomizationTests):
190 repr_ = repr(b'abc')
191
192 def test_empty_string(self):
193 self.assertEqual(hash(b""), 0)
194
Antoine Pitrou07c65882012-02-21 19:14:26 +0100195class MemoryviewHashRandomizationTests(StringlikeHashRandomizationTests):
196 repr_ = "memoryview(b'abc')"
197
198 def test_empty_string(self):
199 self.assertEqual(hash(memoryview(b"")), 0)
200
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100201class DatetimeTests(HashRandomizationTests):
202 def get_hash_command(self, repr_):
203 return 'import datetime; print(hash(%s))' % repr_
204
205class DatetimeDateTests(DatetimeTests):
206 repr_ = repr(datetime.date(1066, 10, 14))
207
208class DatetimeDatetimeTests(DatetimeTests):
209 repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
210
211class DatetimeTimeTests(DatetimeTests):
212 repr_ = repr(datetime.time(0))
213
214
Fred Drake2e2be372001-09-20 21:33:42 +0000215def test_main():
Nick Coghland1abd252008-07-15 15:46:38 +0000216 support.run_unittest(HashEqualityTestCase,
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100217 HashInheritanceTestCase,
218 HashBuiltinsTestCase,
219 StrHashRandomizationTests,
220 BytesHashRandomizationTests,
Antoine Pitroubc499d22012-02-21 19:18:10 +0100221 MemoryviewHashRandomizationTests,
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100222 DatetimeDateTests,
223 DatetimeDatetimeTests,
224 DatetimeTimeTests)
Fred Drake2e2be372001-09-20 21:33:42 +0000225
226
227if __name__ == "__main__":
228 test_main()