--- a/Lib/test/test_hash.py Fri Jan 20 11:23:02 2012 +0000 +++ b/Lib/test/test_hash.py Sat Jan 28 00:03:46 2012 -0500 @@ -3,10 +3,14 @@ # # Also test that hash implementations are inherited as expected +import struct import unittest from test import support +from test.script_helper import assert_python_ok from collections import Hashable +IS_64BIT = (struct.calcsize('l') == 8) + class HashEqualityTestCase(unittest.TestCase): @@ -118,10 +122,65 @@ for obj in self.hashes_to_check: self.assertEqual(hash(obj), _default_hash(obj)) +class RandomizationTestCase(unittest.TestCase): + + # Examples of the various types having randomized hash: + test_reprs = [repr('abc'), repr(b'abc')] + + def get_hash(self, repr_, randomization=None, seed=None): + env = {} + if randomization is not None: + env['PYTHONHASHRANDOMIZATION'] = str(randomization) + if seed is not None: + env['PYTHONHASHSEED'] = str(seed) + out = assert_python_ok( + '-c', 'print(hash(%s))' % repr_, + **env) + stdout = out[1].strip() + return int(stdout) + + def test_empty_string(self): + self.assertEqual(hash(""), 0) + self.assertEqual(hash(b""), 0) + + def test_null_hash(self): + # PYTHONHASHSEED=0 disables the randomized hash + if IS_64BIT: + known_hash_of_obj = 1453079729188098211 + else: + known_hash_of_obj = -1600925533 + for repr_ in self.test_reprs: + # Randomization is disabled by default: + self.assertEqual(self.get_hash(repr_), known_hash_of_obj) + + # If enabled, it can still be disabled by setting the seed to 0: + self.assertEqual(self.get_hash(repr_, randomization=1, seed=0), + known_hash_of_obj) + + def test_fixed_hash(self): + # test a fixed seed for the randomized hash + # Note that all types share the same values: + if IS_64BIT: + h = -4410911502303878509 + else: + h = -206076799 + for repr_ in self.test_reprs: + self.assertEqual(self.get_hash(repr_, randomization=1, seed=42), + h) + + def test_randomized_hash(self): + # two runs should return different hashes + for repr_ in self.test_reprs: + run1 = self.get_hash(repr_, randomization=1) + run2 = self.get_hash(repr_, randomization=1) + self.assertNotEqual(run1, run2) + + def test_main(): support.run_unittest(HashEqualityTestCase, HashInheritanceTestCase, - HashBuiltinsTestCase) + HashBuiltinsTestCase, + RandomizationTestCase) if __name__ == "__main__":