blob: c0dd34dc7ffc5b95d0e9be05db9882d8b2083b42 [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):
116 hashes_to_check = [range(10),
117 enumerate(range(10)),
118 iter(DefaultIterSeq()),
119 iter(lambda: 0, 0),
120 ]
121
122 def test_hashes(self):
123 _default_hash = object.__hash__
124 for obj in self.hashes_to_check:
125 self.assertEqual(hash(obj), _default_hash(obj))
126
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100127class HashRandomizationTests(unittest.TestCase):
128
129 # Each subclass should define a field "repr_", containing the repr() of
130 # an object to be tested
131
132 def get_hash_command(self, repr_):
133 return 'print(hash(%s))' % repr_
134
135 def get_hash(self, repr_, seed=None):
136 env = os.environ.copy()
137 env['__cleanenv'] = True # signal to assert_python not to do a copy
138 # of os.environ on its own
139 if seed is not None:
140 env['PYTHONHASHSEED'] = str(seed)
141 else:
142 env.pop('PYTHONHASHSEED', None)
143 out = assert_python_ok(
144 '-c', self.get_hash_command(repr_),
145 **env)
146 stdout = out[1].strip()
147 return int(stdout)
148
149 def test_randomized_hash(self):
150 # two runs should return different hashes
151 run1 = self.get_hash(self.repr_, seed='random')
152 run2 = self.get_hash(self.repr_, seed='random')
153 self.assertNotEqual(run1, run2)
154
155class StringlikeHashRandomizationTests(HashRandomizationTests):
156 def test_null_hash(self):
157 # PYTHONHASHSEED=0 disables the randomized hash
158 if IS_64BIT:
159 known_hash_of_obj = 1453079729188098211
160 else:
161 known_hash_of_obj = -1600925533
162
163 # Randomization is disabled by default:
164 self.assertEqual(self.get_hash(self.repr_), known_hash_of_obj)
165
166 # It can also be disabled by setting the seed to 0:
167 self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
168
169 def test_fixed_hash(self):
170 # test a fixed seed for the randomized hash
171 # Note that all types share the same values:
172 if IS_64BIT:
Antoine Pitrouc0942422012-02-22 03:33:56 +0100173 if sys.byteorder == 'little':
174 h = -4410911502303878509
175 else:
176 h = -3570150969479994130
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100177 else:
Antoine Pitrouc0942422012-02-22 03:33:56 +0100178 if sys.byteorder == 'little':
179 h = -206076799
180 else:
181 h = -1024014457
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100182 self.assertEqual(self.get_hash(self.repr_, seed=42), h)
183
184class StrHashRandomizationTests(StringlikeHashRandomizationTests):
185 repr_ = repr('abc')
186
187 def test_empty_string(self):
188 self.assertEqual(hash(""), 0)
189
190class BytesHashRandomizationTests(StringlikeHashRandomizationTests):
191 repr_ = repr(b'abc')
192
193 def test_empty_string(self):
194 self.assertEqual(hash(b""), 0)
195
196class DatetimeTests(HashRandomizationTests):
197 def get_hash_command(self, repr_):
198 return 'import datetime; print(hash(%s))' % repr_
199
200class DatetimeDateTests(DatetimeTests):
201 repr_ = repr(datetime.date(1066, 10, 14))
202
203class DatetimeDatetimeTests(DatetimeTests):
204 repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
205
206class DatetimeTimeTests(DatetimeTests):
207 repr_ = repr(datetime.time(0))
208
209
Fred Drake2e2be372001-09-20 21:33:42 +0000210def test_main():
Nick Coghland1abd252008-07-15 15:46:38 +0000211 support.run_unittest(HashEqualityTestCase,
Georg Brandl2daf6ae2012-02-20 19:54:16 +0100212 HashInheritanceTestCase,
213 HashBuiltinsTestCase,
214 StrHashRandomizationTests,
215 BytesHashRandomizationTests,
216 DatetimeDateTests,
217 DatetimeDatetimeTests,
218 DatetimeTimeTests)
Fred Drake2e2be372001-09-20 21:33:42 +0000219
220
221if __name__ == "__main__":
222 test_main()