blob: d1ddc7698473e1b3ee92f07759f7f3d8fa97797b [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
Antoine Pitrou37bfa4e2012-11-11 20:10:48 +010048 def test_unaligned_buffers(self):
49 # The hash function for bytes-like objects shouldn't have
50 # alignment-dependent results (example in issue #16427).
51 b = b"123456789abcdefghijklmnopqrstuvwxyz" * 128
52 for i in range(16):
53 for j in range(16):
54 aligned = b[i:128+j]
55 unaligned = memoryview(b)[i:128+j]
56 self.assertEqual(hash(aligned), hash(unaligned))
57
Fred Drake13634cf2000-06-29 19:17:04 +000058
Nick Coghland1abd252008-07-15 15:46:38 +000059_default_hash = object.__hash__
60class DefaultHash(object): pass
61
62_FIXED_HASH_VALUE = 42
63class FixedHash(object):
64 def __hash__(self):
65 return _FIXED_HASH_VALUE
66
67class OnlyEquality(object):
68 def __eq__(self, other):
69 return self is other
70
71class OnlyInequality(object):
72 def __ne__(self, other):
73 return self is not other
74
Nick Coghland1abd252008-07-15 15:46:38 +000075class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
76class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
Nick Coghland1abd252008-07-15 15:46:38 +000077
78class NoHash(object):
79 __hash__ = None
80
81class HashInheritanceTestCase(unittest.TestCase):
82 default_expected = [object(),
83 DefaultHash(),
84 OnlyInequality(),
85 ]
86 fixed_expected = [FixedHash(),
87 InheritedHashWithEquality(),
88 InheritedHashWithInequality(),
Nick Coghland1abd252008-07-15 15:46:38 +000089 ]
90 error_expected = [NoHash(),
91 OnlyEquality(),
Nick Coghland1abd252008-07-15 15:46:38 +000092 ]
93
94 def test_default_hash(self):
95 for obj in self.default_expected:
96 self.assertEqual(hash(obj), _default_hash(obj))
97
98 def test_fixed_hash(self):
99 for obj in self.fixed_expected:
100 self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
101
102 def test_error_hash(self):
103 for obj in self.error_expected:
104 self.assertRaises(TypeError, hash, obj)
105
106 def test_hashable(self):
107 objects = (self.default_expected +
108 self.fixed_expected)
109 for obj in objects:
Ezio Melottie9615932010-01-24 19:26:24 +0000110 self.assertIsInstance(obj, Hashable)
Nick Coghland1abd252008-07-15 15:46:38 +0000111
112 def test_not_hashable(self):
113 for obj in self.error_expected:
Ezio Melottie9615932010-01-24 19:26:24 +0000114 self.assertNotIsInstance(obj, Hashable)
Nick Coghland1abd252008-07-15 15:46:38 +0000115
116
Nick Coghlanf1f2f682008-12-30 07:29:12 +0000117# Issue #4701: Check that some builtin types are correctly hashable
118class DefaultIterSeq(object):
119 seq = range(10)
120 def __len__(self):
121 return len(self.seq)
122 def __getitem__(self, index):
123 return self.seq[index]
124
125class HashBuiltinsTestCase(unittest.TestCase):
Mark Dickinson36645682011-10-23 19:53:01 +0100126 hashes_to_check = [enumerate(range(10)),
Nick Coghlanf1f2f682008-12-30 07:29:12 +0000127 iter(DefaultIterSeq()),
128 iter(lambda: 0, 0),
129 ]
130
131 def test_hashes(self):
132 _default_hash = object.__hash__
133 for obj in self.hashes_to_check:
134 self.assertEqual(hash(obj), _default_hash(obj))
135
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100136class HashRandomizationTests(unittest.TestCase):
137
138 # Each subclass should define a field "repr_", containing the repr() of
139 # an object to be tested
140
141 def get_hash_command(self, repr_):
142 return 'print(hash(%s))' % repr_
143
144 def get_hash(self, repr_, seed=None):
145 env = os.environ.copy()
146 env['__cleanenv'] = True # signal to assert_python not to do a copy
147 # of os.environ on its own
148 if seed is not None:
149 env['PYTHONHASHSEED'] = str(seed)
150 else:
151 env.pop('PYTHONHASHSEED', None)
152 out = assert_python_ok(
153 '-c', self.get_hash_command(repr_),
154 **env)
155 stdout = out[1].strip()
156 return int(stdout)
157
158 def test_randomized_hash(self):
159 # two runs should return different hashes
160 run1 = self.get_hash(self.repr_, seed='random')
161 run2 = self.get_hash(self.repr_, seed='random')
162 self.assertNotEqual(run1, run2)
163
164class StringlikeHashRandomizationTests(HashRandomizationTests):
165 def test_null_hash(self):
166 # PYTHONHASHSEED=0 disables the randomized hash
167 if IS_64BIT:
168 known_hash_of_obj = 1453079729188098211
169 else:
170 known_hash_of_obj = -1600925533
171
Benjamin Petersonc9f54cf2012-02-21 16:08:05 -0500172 # Randomization is enabled by default:
173 self.assertNotEqual(self.get_hash(self.repr_), known_hash_of_obj)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100174
175 # It can also be disabled by setting the seed to 0:
176 self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
177
178 def test_fixed_hash(self):
179 # test a fixed seed for the randomized hash
180 # Note that all types share the same values:
181 if IS_64BIT:
Antoine Pitrou679be992012-02-22 03:33:56 +0100182 if sys.byteorder == 'little':
183 h = -4410911502303878509
184 else:
185 h = -3570150969479994130
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100186 else:
Antoine Pitrou679be992012-02-22 03:33:56 +0100187 if sys.byteorder == 'little':
188 h = -206076799
189 else:
190 h = -1024014457
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100191 self.assertEqual(self.get_hash(self.repr_, seed=42), h)
192
193class StrHashRandomizationTests(StringlikeHashRandomizationTests):
194 repr_ = repr('abc')
195
196 def test_empty_string(self):
197 self.assertEqual(hash(""), 0)
198
199class BytesHashRandomizationTests(StringlikeHashRandomizationTests):
200 repr_ = repr(b'abc')
201
202 def test_empty_string(self):
203 self.assertEqual(hash(b""), 0)
204
Antoine Pitrou07c65882012-02-21 19:14:26 +0100205class MemoryviewHashRandomizationTests(StringlikeHashRandomizationTests):
206 repr_ = "memoryview(b'abc')"
207
208 def test_empty_string(self):
209 self.assertEqual(hash(memoryview(b"")), 0)
210
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100211class DatetimeTests(HashRandomizationTests):
212 def get_hash_command(self, repr_):
213 return 'import datetime; print(hash(%s))' % repr_
214
215class DatetimeDateTests(DatetimeTests):
216 repr_ = repr(datetime.date(1066, 10, 14))
217
218class DatetimeDatetimeTests(DatetimeTests):
219 repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
220
221class DatetimeTimeTests(DatetimeTests):
222 repr_ = repr(datetime.time(0))
223
224
Fred Drake2e2be372001-09-20 21:33:42 +0000225def test_main():
Nick Coghland1abd252008-07-15 15:46:38 +0000226 support.run_unittest(HashEqualityTestCase,
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100227 HashInheritanceTestCase,
228 HashBuiltinsTestCase,
229 StrHashRandomizationTests,
230 BytesHashRandomizationTests,
Antoine Pitroubc499d22012-02-21 19:18:10 +0100231 MemoryviewHashRandomizationTests,
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100232 DatetimeDateTests,
233 DatetimeDatetimeTests,
234 DatetimeTimeTests)
Fred Drake2e2be372001-09-20 21:33:42 +0000235
236
237if __name__ == "__main__":
238 test_main()