blob: c4f7c66ad16e13e70823e90abd365c112f4c176b [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 Coghlan53663a62008-07-15 14:27:37 +00004# Also test that hash implementations are inherited as expected
Fred Drake13634cf2000-06-29 19:17:04 +00005
Barry Warsaw1e13eb02012-02-20 20:42:21 -05006import os
7import sys
8import struct
9import datetime
Fred Drake97656a12001-05-18 21:45:35 +000010import unittest
Barry Warsaw1e13eb02012-02-20 20:42:21 -050011import subprocess
12
Barry Warsaw04f357c2002-07-23 19:04:11 +000013from test import test_support
Nick Coghlan53663a62008-07-15 14:27:37 +000014from collections import Hashable
Fred Drake13634cf2000-06-29 19:17:04 +000015
Barry Warsaw1e13eb02012-02-20 20:42:21 -050016IS_64BIT = (struct.calcsize('l') == 8)
17
Fred Drake13634cf2000-06-29 19:17:04 +000018
Fred Drake97656a12001-05-18 21:45:35 +000019class HashEqualityTestCase(unittest.TestCase):
20
21 def same_hash(self, *objlist):
Fred Drakeacb117e2001-05-18 21:50:02 +000022 # Hash each object given and fail if
23 # the hash values are not all the same.
Fred Drake97656a12001-05-18 21:45:35 +000024 hashed = map(hash, objlist)
25 for h in hashed[1:]:
26 if h != hashed[0]:
Walter Dörwald70a6b492004-02-12 17:35:32 +000027 self.fail("hashed values differ: %r" % (objlist,))
Fred Drake97656a12001-05-18 21:45:35 +000028
29 def test_numeric_literals(self):
30 self.same_hash(1, 1L, 1.0, 1.0+0.0j)
Facundo Batistad544df72007-09-19 15:10:06 +000031 self.same_hash(0, 0L, 0.0, 0.0+0.0j)
32 self.same_hash(-1, -1L, -1.0, -1.0+0.0j)
33 self.same_hash(-2, -2L, -2.0, -2.0+0.0j)
Fred Drake97656a12001-05-18 21:45:35 +000034
35 def test_coerced_integers(self):
36 self.same_hash(int(1), long(1), float(1), complex(1),
37 int('1'), float('1.0'))
Facundo Batistad544df72007-09-19 15:10:06 +000038 self.same_hash(int(-2**31), long(-2**31), float(-2**31))
39 self.same_hash(int(1-2**31), long(1-2**31), float(1-2**31))
40 self.same_hash(int(2**31-1), long(2**31-1), float(2**31-1))
41 # for 64-bit platforms
42 self.same_hash(int(2**31), long(2**31), float(2**31))
43 self.same_hash(int(-2**63), long(-2**63), float(-2**63))
44 self.same_hash(int(1-2**63), long(1-2**63))
45 self.same_hash(int(2**63-1), long(2**63-1))
Mark Dickinsonf709ab82009-01-31 16:44:04 +000046 self.same_hash(long(2**63), float(2**63))
Fred Drake97656a12001-05-18 21:45:35 +000047
48 def test_coerced_floats(self):
49 self.same_hash(long(1.23e300), float(1.23e300))
50 self.same_hash(float(0.5), complex(0.5, 0.0))
Fred Drake13634cf2000-06-29 19:17:04 +000051
52
Nick Coghlan53663a62008-07-15 14:27:37 +000053_default_hash = object.__hash__
54class DefaultHash(object): pass
55
56_FIXED_HASH_VALUE = 42
57class FixedHash(object):
58 def __hash__(self):
59 return _FIXED_HASH_VALUE
60
61class OnlyEquality(object):
62 def __eq__(self, other):
63 return self is other
Nick Coghlan48361f52008-08-11 15:45:58 +000064 # Trick to suppress Py3k warning in 2.x
65 __hash__ = None
66del OnlyEquality.__hash__
Nick Coghlan53663a62008-07-15 14:27:37 +000067
68class OnlyInequality(object):
69 def __ne__(self, other):
70 return self is not other
71
72class OnlyCmp(object):
73 def __cmp__(self, other):
74 return cmp(id(self), id(other))
Nick Coghlan48361f52008-08-11 15:45:58 +000075 # Trick to suppress Py3k warning in 2.x
76 __hash__ = None
77del OnlyCmp.__hash__
Nick Coghlan53663a62008-07-15 14:27:37 +000078
79class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
80class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
81class InheritedHashWithCmp(FixedHash, OnlyCmp): pass
82
83class NoHash(object):
84 __hash__ = None
85
86class HashInheritanceTestCase(unittest.TestCase):
87 default_expected = [object(),
88 DefaultHash(),
Nick Coghlan48361f52008-08-11 15:45:58 +000089 OnlyEquality(),
90 OnlyInequality(),
91 OnlyCmp(),
Nick Coghlan53663a62008-07-15 14:27:37 +000092 ]
93 fixed_expected = [FixedHash(),
94 InheritedHashWithEquality(),
95 InheritedHashWithInequality(),
96 InheritedHashWithCmp(),
97 ]
Nick Coghlan53663a62008-07-15 14:27:37 +000098 error_expected = [NoHash()]
99
100 def test_default_hash(self):
101 for obj in self.default_expected:
102 self.assertEqual(hash(obj), _default_hash(obj))
103
104 def test_fixed_hash(self):
105 for obj in self.fixed_expected:
106 self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
107
Nick Coghlan53663a62008-07-15 14:27:37 +0000108 def test_error_hash(self):
109 for obj in self.error_expected:
110 self.assertRaises(TypeError, hash, obj)
111
112 def test_hashable(self):
113 objects = (self.default_expected +
Nick Coghlan48361f52008-08-11 15:45:58 +0000114 self.fixed_expected)
Nick Coghlan53663a62008-07-15 14:27:37 +0000115 for obj in objects:
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000116 self.assertIsInstance(obj, Hashable)
Nick Coghlan53663a62008-07-15 14:27:37 +0000117
118 def test_not_hashable(self):
119 for obj in self.error_expected:
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000120 self.assertNotIsInstance(obj, Hashable)
Nick Coghlan53663a62008-07-15 14:27:37 +0000121
122
Nick Coghlan180e4002008-12-30 01:18:48 +0000123# Issue #4701: Check that some builtin types are correctly hashable
124# (This test only used to fail in Python 3.0, but has been included
125# in 2.x along with the lazy call to PyType_Ready in PyObject_Hash)
126class DefaultIterSeq(object):
127 seq = range(10)
128 def __len__(self):
129 return len(self.seq)
130 def __getitem__(self, index):
131 return self.seq[index]
132
133class HashBuiltinsTestCase(unittest.TestCase):
134 hashes_to_check = [xrange(10),
135 enumerate(xrange(10)),
136 iter(DefaultIterSeq()),
137 iter(lambda: 0, 0),
138 ]
139
140 def test_hashes(self):
141 _default_hash = object.__hash__
142 for obj in self.hashes_to_check:
143 self.assertEqual(hash(obj), _default_hash(obj))
144
Barry Warsaw1e13eb02012-02-20 20:42:21 -0500145class HashRandomizationTests(unittest.TestCase):
146
147 # Each subclass should define a field "repr_", containing the repr() of
148 # an object to be tested
149
150 def get_hash_command(self, repr_):
151 return 'print(hash(%s))' % repr_
152
153 def get_hash(self, repr_, seed=None):
154 env = os.environ.copy()
155 if seed is not None:
156 env['PYTHONHASHSEED'] = str(seed)
157 else:
158 env.pop('PYTHONHASHSEED', None)
159 cmd_line = [sys.executable, '-c', self.get_hash_command(repr_)]
160 p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
161 stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
162 env=env)
163 out, err = p.communicate()
164 out = test_support.strip_python_stderr(out)
165 return int(out.strip())
166
167 def test_randomized_hash(self):
168 # two runs should return different hashes
169 run1 = self.get_hash(self.repr_, seed='random')
170 run2 = self.get_hash(self.repr_, seed='random')
171 self.assertNotEqual(run1, run2)
172
173class StringlikeHashRandomizationTests(HashRandomizationTests):
174 def test_null_hash(self):
175 # PYTHONHASHSEED=0 disables the randomized hash
176 if IS_64BIT:
177 known_hash_of_obj = 1453079729188098211
178 else:
179 known_hash_of_obj = -1600925533
180
181 # Randomization is disabled by default:
182 self.assertEqual(self.get_hash(self.repr_), known_hash_of_obj)
183
184 # It can also be disabled by setting the seed to 0:
185 self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
186
187 def test_fixed_hash(self):
188 # test a fixed seed for the randomized hash
189 # Note that all types share the same values:
190 if IS_64BIT:
Antoine Pitrou4b670f52012-02-22 03:33:56 +0100191 if sys.byteorder == 'little':
192 h = -4410911502303878509
193 else:
194 h = -3570150969479994130
Barry Warsaw1e13eb02012-02-20 20:42:21 -0500195 else:
Antoine Pitrou4b670f52012-02-22 03:33:56 +0100196 if sys.byteorder == 'little':
197 h = -206076799
198 else:
199 h = -1024014457
Barry Warsaw1e13eb02012-02-20 20:42:21 -0500200 self.assertEqual(self.get_hash(self.repr_, seed=42), h)
201
202class StrHashRandomizationTests(StringlikeHashRandomizationTests):
203 repr_ = repr('abc')
204
205 def test_empty_string(self):
206 self.assertEqual(hash(""), 0)
207
208class UnicodeHashRandomizationTests(StringlikeHashRandomizationTests):
209 repr_ = repr(u'abc')
210
211 def test_empty_string(self):
212 self.assertEqual(hash(u""), 0)
213
214class BufferHashRandomizationTests(StringlikeHashRandomizationTests):
215 repr_ = 'buffer("abc")'
216
217 def test_empty_string(self):
Victor Stinnera3acea32014-09-05 21:05:05 +0200218 with test_support.check_py3k_warnings():
219 self.assertEqual(hash(buffer("")), 0)
Barry Warsaw1e13eb02012-02-20 20:42:21 -0500220
221class DatetimeTests(HashRandomizationTests):
222 def get_hash_command(self, repr_):
223 return 'import datetime; print(hash(%s))' % repr_
224
225class DatetimeDateTests(DatetimeTests):
226 repr_ = repr(datetime.date(1066, 10, 14))
227
228class DatetimeDatetimeTests(DatetimeTests):
229 repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
230
231class DatetimeTimeTests(DatetimeTests):
232 repr_ = repr(datetime.time(0))
233
234
Fred Drake2e2be372001-09-20 21:33:42 +0000235def test_main():
Nick Coghlan53663a62008-07-15 14:27:37 +0000236 test_support.run_unittest(HashEqualityTestCase,
Nick Coghlan180e4002008-12-30 01:18:48 +0000237 HashInheritanceTestCase,
Barry Warsaw1e13eb02012-02-20 20:42:21 -0500238 HashBuiltinsTestCase,
239 StrHashRandomizationTests,
240 UnicodeHashRandomizationTests,
241 BufferHashRandomizationTests,
242 DatetimeDateTests,
243 DatetimeDatetimeTests,
244 DatetimeTimeTests)
Barry Warsawb19fb242012-02-20 20:44:15 -0500245
Fred Drake2e2be372001-09-20 21:33:42 +0000246
247
248if __name__ == "__main__":
249 test_main()