test_hash.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. # test the invariant that
  2. # iff a==b then hash(a)==hash(b)
  3. #
  4. # Also test that hash implementations are inherited as expected
  5. import os
  6. import sys
  7. import struct
  8. import datetime
  9. import unittest
  10. import subprocess
  11. from test import test_support
  12. from collections import Hashable
  13. IS_64BIT = (struct.calcsize('l') == 8)
  14. class HashEqualityTestCase(unittest.TestCase):
  15. def same_hash(self, *objlist):
  16. # Hash each object given and fail if
  17. # the hash values are not all the same.
  18. hashed = map(hash, objlist)
  19. for h in hashed[1:]:
  20. if h != hashed[0]:
  21. self.fail("hashed values differ: %r" % (objlist,))
  22. def test_numeric_literals(self):
  23. self.same_hash(1, 1L, 1.0, 1.0+0.0j)
  24. self.same_hash(0, 0L, 0.0, 0.0+0.0j)
  25. self.same_hash(-1, -1L, -1.0, -1.0+0.0j)
  26. self.same_hash(-2, -2L, -2.0, -2.0+0.0j)
  27. def test_coerced_integers(self):
  28. self.same_hash(int(1), long(1), float(1), complex(1),
  29. int('1'), float('1.0'))
  30. self.same_hash(int(-2**31), long(-2**31), float(-2**31))
  31. self.same_hash(int(1-2**31), long(1-2**31), float(1-2**31))
  32. self.same_hash(int(2**31-1), long(2**31-1), float(2**31-1))
  33. # for 64-bit platforms
  34. self.same_hash(int(2**31), long(2**31), float(2**31))
  35. self.same_hash(int(-2**63), long(-2**63), float(-2**63))
  36. self.same_hash(int(1-2**63), long(1-2**63))
  37. self.same_hash(int(2**63-1), long(2**63-1))
  38. self.same_hash(long(2**63), float(2**63))
  39. def test_coerced_floats(self):
  40. self.same_hash(long(1.23e300), float(1.23e300))
  41. self.same_hash(float(0.5), complex(0.5, 0.0))
  42. _default_hash = object.__hash__
  43. class DefaultHash(object): pass
  44. _FIXED_HASH_VALUE = 42
  45. class FixedHash(object):
  46. def __hash__(self):
  47. return _FIXED_HASH_VALUE
  48. class OnlyEquality(object):
  49. def __eq__(self, other):
  50. return self is other
  51. # Trick to suppress Py3k warning in 2.x
  52. __hash__ = None
  53. del OnlyEquality.__hash__
  54. class OnlyInequality(object):
  55. def __ne__(self, other):
  56. return self is not other
  57. class OnlyCmp(object):
  58. def __cmp__(self, other):
  59. return cmp(id(self), id(other))
  60. # Trick to suppress Py3k warning in 2.x
  61. __hash__ = None
  62. del OnlyCmp.__hash__
  63. class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
  64. class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
  65. class InheritedHashWithCmp(FixedHash, OnlyCmp): pass
  66. class NoHash(object):
  67. __hash__ = None
  68. class HashInheritanceTestCase(unittest.TestCase):
  69. default_expected = [object(),
  70. DefaultHash(),
  71. OnlyEquality(),
  72. OnlyInequality(),
  73. OnlyCmp(),
  74. ]
  75. fixed_expected = [FixedHash(),
  76. InheritedHashWithEquality(),
  77. InheritedHashWithInequality(),
  78. InheritedHashWithCmp(),
  79. ]
  80. error_expected = [NoHash()]
  81. def test_default_hash(self):
  82. for obj in self.default_expected:
  83. self.assertEqual(hash(obj), _default_hash(obj))
  84. def test_fixed_hash(self):
  85. for obj in self.fixed_expected:
  86. self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
  87. def test_error_hash(self):
  88. for obj in self.error_expected:
  89. self.assertRaises(TypeError, hash, obj)
  90. def test_hashable(self):
  91. objects = (self.default_expected +
  92. self.fixed_expected)
  93. for obj in objects:
  94. self.assertIsInstance(obj, Hashable)
  95. def test_not_hashable(self):
  96. for obj in self.error_expected:
  97. self.assertNotIsInstance(obj, Hashable)
  98. # Issue #4701: Check that some builtin types are correctly hashable
  99. # (This test only used to fail in Python 3.0, but has been included
  100. # in 2.x along with the lazy call to PyType_Ready in PyObject_Hash)
  101. class DefaultIterSeq(object):
  102. seq = range(10)
  103. def __len__(self):
  104. return len(self.seq)
  105. def __getitem__(self, index):
  106. return self.seq[index]
  107. class HashBuiltinsTestCase(unittest.TestCase):
  108. hashes_to_check = [xrange(10),
  109. enumerate(xrange(10)),
  110. iter(DefaultIterSeq()),
  111. iter(lambda: 0, 0),
  112. ]
  113. def test_hashes(self):
  114. _default_hash = object.__hash__
  115. for obj in self.hashes_to_check:
  116. self.assertEqual(hash(obj), _default_hash(obj))
  117. class HashRandomizationTests(unittest.TestCase):
  118. # Each subclass should define a field "repr_", containing the repr() of
  119. # an object to be tested
  120. def get_hash_command(self, repr_):
  121. return 'print(hash(%s))' % repr_
  122. def get_hash(self, repr_, seed=None):
  123. env = os.environ.copy()
  124. if seed is not None:
  125. env['PYTHONHASHSEED'] = str(seed)
  126. else:
  127. env.pop('PYTHONHASHSEED', None)
  128. cmd_line = [sys.executable, '-c', self.get_hash_command(repr_)]
  129. p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
  130. stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
  131. env=env)
  132. out, err = p.communicate()
  133. out = test_support.strip_python_stderr(out)
  134. return int(out.strip())
  135. def test_randomized_hash(self):
  136. # two runs should return different hashes
  137. run1 = self.get_hash(self.repr_, seed='random')
  138. run2 = self.get_hash(self.repr_, seed='random')
  139. self.assertNotEqual(run1, run2)
  140. class StringlikeHashRandomizationTests(HashRandomizationTests):
  141. def test_null_hash(self):
  142. # PYTHONHASHSEED=0 disables the randomized hash
  143. if IS_64BIT:
  144. known_hash_of_obj = 1453079729188098211
  145. else:
  146. known_hash_of_obj = -1600925533
  147. # Randomization is disabled by default:
  148. self.assertEqual(self.get_hash(self.repr_), known_hash_of_obj)
  149. # It can also be disabled by setting the seed to 0:
  150. self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
  151. def test_fixed_hash(self):
  152. # test a fixed seed for the randomized hash
  153. # Note that all types share the same values:
  154. if IS_64BIT:
  155. if sys.byteorder == 'little':
  156. h = -4410911502303878509
  157. else:
  158. h = -3570150969479994130
  159. else:
  160. if sys.byteorder == 'little':
  161. h = -206076799
  162. else:
  163. h = -1024014457
  164. self.assertEqual(self.get_hash(self.repr_, seed=42), h)
  165. class StrHashRandomizationTests(StringlikeHashRandomizationTests):
  166. repr_ = repr('abc')
  167. def test_empty_string(self):
  168. self.assertEqual(hash(""), 0)
  169. class UnicodeHashRandomizationTests(StringlikeHashRandomizationTests):
  170. repr_ = repr(u'abc')
  171. def test_empty_string(self):
  172. self.assertEqual(hash(u""), 0)
  173. class BufferHashRandomizationTests(StringlikeHashRandomizationTests):
  174. repr_ = 'buffer("abc")'
  175. def test_empty_string(self):
  176. with test_support.check_py3k_warnings():
  177. self.assertEqual(hash(buffer("")), 0)
  178. class DatetimeTests(HashRandomizationTests):
  179. def get_hash_command(self, repr_):
  180. return 'import datetime; print(hash(%s))' % repr_
  181. class DatetimeDateTests(DatetimeTests):
  182. repr_ = repr(datetime.date(1066, 10, 14))
  183. class DatetimeDatetimeTests(DatetimeTests):
  184. repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
  185. class DatetimeTimeTests(DatetimeTests):
  186. repr_ = repr(datetime.time(0))
  187. def test_main():
  188. test_support.run_unittest(HashEqualityTestCase,
  189. HashInheritanceTestCase,
  190. HashBuiltinsTestCase,
  191. StrHashRandomizationTests,
  192. UnicodeHashRandomizationTests,
  193. BufferHashRandomizationTests,
  194. DatetimeDateTests,
  195. DatetimeDatetimeTests,
  196. DatetimeTimeTests)
  197. if __name__ == "__main__":
  198. test_main()