blob: e3ab6e4385a9f9d14b7370c6f4654507678aaf3e [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
Georg Brandl2daf6ae2012-02-20 19:54:16 +010010from test.script_helper import assert_python_ok
Nick Coghland1abd252008-07-15 15:46:38 +000011from collections import Hashable
Fred Drake13634cf2000-06-29 19:17:04 +000012
Georg Brandl09a7c722012-02-20 21:31:46 +010013IS_64BIT = sys.maxsize > 2**32
Georg Brandl2daf6ae2012-02-20 19:54:16 +010014
Fred Drake13634cf2000-06-29 19:17:04 +000015
Fred Drake97656a12001-05-18 21:45:35 +000016class HashEqualityTestCase(unittest.TestCase):
17
18 def same_hash(self, *objlist):
Fred Drakeacb117e2001-05-18 21:50:02 +000019 # Hash each object given and fail if
20 # the hash values are not all the same.
Guido van Rossumc1f779c2007-07-03 08:25:58 +000021 hashed = list(map(hash, objlist))
Fred Drake97656a12001-05-18 21:45:35 +000022 for h in hashed[1:]:
23 if h != hashed[0]:
Walter Dörwald70a6b492004-02-12 17:35:32 +000024 self.fail("hashed values differ: %r" % (objlist,))
Fred Drake97656a12001-05-18 21:45:35 +000025
26 def test_numeric_literals(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +000027 self.same_hash(1, 1, 1.0, 1.0+0.0j)
Thomas Woutersce272b62007-09-19 21:19:28 +000028 self.same_hash(0, 0.0, 0.0+0.0j)
29 self.same_hash(-1, -1.0, -1.0+0.0j)
30 self.same_hash(-2, -2.0, -2.0+0.0j)
Fred Drake97656a12001-05-18 21:45:35 +000031
32 def test_coerced_integers(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +000033 self.same_hash(int(1), int(1), float(1), complex(1),
Fred Drake97656a12001-05-18 21:45:35 +000034 int('1'), float('1.0'))
Thomas Woutersce272b62007-09-19 21:19:28 +000035 self.same_hash(int(-2**31), float(-2**31))
36 self.same_hash(int(1-2**31), float(1-2**31))
37 self.same_hash(int(2**31-1), float(2**31-1))
38 # for 64-bit platforms
39 self.same_hash(int(2**31), float(2**31))
40 self.same_hash(int(-2**63), float(-2**63))
Guilherme Polo887b3f22009-02-07 00:45:10 +000041 self.same_hash(int(2**63), float(2**63))
Fred Drake97656a12001-05-18 21:45:35 +000042
43 def test_coerced_floats(self):
Guido van Rossume2a383d2007-01-15 16:59:06 +000044 self.same_hash(int(1.23e300), float(1.23e300))
Fred Drake97656a12001-05-18 21:45:35 +000045 self.same_hash(float(0.5), complex(0.5, 0.0))
Fred Drake13634cf2000-06-29 19:17:04 +000046
Antoine Pitrou37bfa4e2012-11-11 20:10:48 +010047 def test_unaligned_buffers(self):
48 # The hash function for bytes-like objects shouldn't have
49 # alignment-dependent results (example in issue #16427).
50 b = b"123456789abcdefghijklmnopqrstuvwxyz" * 128
51 for i in range(16):
52 for j in range(16):
53 aligned = b[i:128+j]
54 unaligned = memoryview(b)[i:128+j]
55 self.assertEqual(hash(aligned), hash(unaligned))
56
Fred Drake13634cf2000-06-29 19:17:04 +000057
Nick Coghland1abd252008-07-15 15:46:38 +000058_default_hash = object.__hash__
59class DefaultHash(object): pass
60
61_FIXED_HASH_VALUE = 42
62class FixedHash(object):
63 def __hash__(self):
64 return _FIXED_HASH_VALUE
65
66class OnlyEquality(object):
67 def __eq__(self, other):
68 return self is other
69
70class OnlyInequality(object):
71 def __ne__(self, other):
72 return self is not other
73
Nick Coghland1abd252008-07-15 15:46:38 +000074class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
75class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
Nick Coghland1abd252008-07-15 15:46:38 +000076
77class NoHash(object):
78 __hash__ = None
79
80class HashInheritanceTestCase(unittest.TestCase):
81 default_expected = [object(),
82 DefaultHash(),
83 OnlyInequality(),
84 ]
85 fixed_expected = [FixedHash(),
86 InheritedHashWithEquality(),
87 InheritedHashWithInequality(),
Nick Coghland1abd252008-07-15 15:46:38 +000088 ]
89 error_expected = [NoHash(),
90 OnlyEquality(),
Nick Coghland1abd252008-07-15 15:46:38 +000091 ]
92
93 def test_default_hash(self):
94 for obj in self.default_expected:
95 self.assertEqual(hash(obj), _default_hash(obj))
96
97 def test_fixed_hash(self):
98 for obj in self.fixed_expected:
99 self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
100
101 def test_error_hash(self):
102 for obj in self.error_expected:
103 self.assertRaises(TypeError, hash, obj)
104
105 def test_hashable(self):
106 objects = (self.default_expected +
107 self.fixed_expected)
108 for obj in objects:
Ezio Melottie9615932010-01-24 19:26:24 +0000109 self.assertIsInstance(obj, Hashable)
Nick Coghland1abd252008-07-15 15:46:38 +0000110
111 def test_not_hashable(self):
112 for obj in self.error_expected:
Ezio Melottie9615932010-01-24 19:26:24 +0000113 self.assertNotIsInstance(obj, Hashable)
Nick Coghland1abd252008-07-15 15:46:38 +0000114
115
Nick Coghlanf1f2f682008-12-30 07:29:12 +0000116# Issue #4701: Check that some builtin types are correctly hashable
117class DefaultIterSeq(object):
118 seq = range(10)
119 def __len__(self):
120 return len(self.seq)
121 def __getitem__(self, index):
122 return self.seq[index]
123
124class HashBuiltinsTestCase(unittest.TestCase):
Mark Dickinson36645682011-10-23 19:53:01 +0100125 hashes_to_check = [enumerate(range(10)),
Nick Coghlanf1f2f682008-12-30 07:29:12 +0000126 iter(DefaultIterSeq()),
127 iter(lambda: 0, 0),
128 ]
129
130 def test_hashes(self):
131 _default_hash = object.__hash__
132 for obj in self.hashes_to_check:
133 self.assertEqual(hash(obj), _default_hash(obj))
134
Ezio Melottie601fb02013-02-27 10:09:12 +0200135class HashRandomizationTests:
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100136
137 # Each subclass should define a field "repr_", containing the repr() of
138 # an object to be tested
139
140 def get_hash_command(self, repr_):
141 return 'print(hash(%s))' % repr_
142
143 def get_hash(self, repr_, seed=None):
144 env = os.environ.copy()
145 env['__cleanenv'] = True # signal to assert_python not to do a copy
146 # of os.environ on its own
147 if seed is not None:
148 env['PYTHONHASHSEED'] = str(seed)
149 else:
150 env.pop('PYTHONHASHSEED', None)
151 out = assert_python_ok(
152 '-c', self.get_hash_command(repr_),
153 **env)
154 stdout = out[1].strip()
155 return int(stdout)
156
157 def test_randomized_hash(self):
158 # two runs should return different hashes
159 run1 = self.get_hash(self.repr_, seed='random')
160 run2 = self.get_hash(self.repr_, seed='random')
161 self.assertNotEqual(run1, run2)
162
163class StringlikeHashRandomizationTests(HashRandomizationTests):
164 def test_null_hash(self):
165 # PYTHONHASHSEED=0 disables the randomized hash
166 if IS_64BIT:
167 known_hash_of_obj = 1453079729188098211
168 else:
169 known_hash_of_obj = -1600925533
170
Benjamin Petersonc9f54cf2012-02-21 16:08:05 -0500171 # Randomization is enabled by default:
172 self.assertNotEqual(self.get_hash(self.repr_), known_hash_of_obj)
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100173
174 # It can also be disabled by setting the seed to 0:
175 self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
176
177 def test_fixed_hash(self):
178 # test a fixed seed for the randomized hash
179 # Note that all types share the same values:
180 if IS_64BIT:
Antoine Pitrou679be992012-02-22 03:33:56 +0100181 if sys.byteorder == 'little':
182 h = -4410911502303878509
183 else:
184 h = -3570150969479994130
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100185 else:
Antoine Pitrou679be992012-02-22 03:33:56 +0100186 if sys.byteorder == 'little':
187 h = -206076799
188 else:
189 h = -1024014457
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100190 self.assertEqual(self.get_hash(self.repr_, seed=42), h)
191
Ezio Melottie601fb02013-02-27 10:09:12 +0200192class StrHashRandomizationTests(StringlikeHashRandomizationTests,
193 unittest.TestCase):
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100194 repr_ = repr('abc')
195
196 def test_empty_string(self):
197 self.assertEqual(hash(""), 0)
198
Ezio Melottie601fb02013-02-27 10:09:12 +0200199class BytesHashRandomizationTests(StringlikeHashRandomizationTests,
200 unittest.TestCase):
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100201 repr_ = repr(b'abc')
202
203 def test_empty_string(self):
204 self.assertEqual(hash(b""), 0)
205
Ezio Melottie601fb02013-02-27 10:09:12 +0200206class MemoryviewHashRandomizationTests(StringlikeHashRandomizationTests,
207 unittest.TestCase):
Antoine Pitrou07c65882012-02-21 19:14:26 +0100208 repr_ = "memoryview(b'abc')"
209
210 def test_empty_string(self):
211 self.assertEqual(hash(memoryview(b"")), 0)
212
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100213class DatetimeTests(HashRandomizationTests):
214 def get_hash_command(self, repr_):
215 return 'import datetime; print(hash(%s))' % repr_
216
Ezio Melottie601fb02013-02-27 10:09:12 +0200217class DatetimeDateTests(DatetimeTests, unittest.TestCase):
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100218 repr_ = repr(datetime.date(1066, 10, 14))
219
Ezio Melottie601fb02013-02-27 10:09:12 +0200220class DatetimeDatetimeTests(DatetimeTests, unittest.TestCase):
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100221 repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
222
Ezio Melottie601fb02013-02-27 10:09:12 +0200223class DatetimeTimeTests(DatetimeTests, unittest.TestCase):
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100224 repr_ = repr(datetime.time(0))
225
226
Fred Drake2e2be372001-09-20 21:33:42 +0000227if __name__ == "__main__":
Ezio Melottie601fb02013-02-27 10:09:12 +0200228 unittest.main()