summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_hash.py
blob: d2571d0acde9c33bf587d07a32e1a9f33df5a569 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# test the invariant that
#   iff a==b then hash(a)==hash(b)
#
# Also test that hash implementations are inherited as expected

import unittest
from test import test_support
from collections import Hashable


class HashEqualityTestCase(unittest.TestCase):

    def same_hash(self, *objlist):
        # Hash each object given and fail if
        # the hash values are not all the same.
        hashed = map(hash, objlist)
        for h in hashed[1:]:
            if h != hashed[0]:
                self.fail("hashed values differ: %r" % (objlist,))

    def test_numeric_literals(self):
        self.same_hash(1, 1L, 1.0, 1.0+0.0j)
        self.same_hash(0, 0L, 0.0, 0.0+0.0j)
        self.same_hash(-1, -1L, -1.0, -1.0+0.0j)
        self.same_hash(-2, -2L, -2.0, -2.0+0.0j)

    def test_coerced_integers(self):
        self.same_hash(int(1), long(1), float(1), complex(1),
                       int('1'), float('1.0'))
        self.same_hash(int(-2**31), long(-2**31), float(-2**31))
        self.same_hash(int(1-2**31), long(1-2**31), float(1-2**31))
        self.same_hash(int(2**31-1), long(2**31-1), float(2**31-1))
        # for 64-bit platforms
        self.same_hash(int(2**31), long(2**31), float(2**31))
        self.same_hash(int(-2**63), long(-2**63), float(-2**63))
        self.same_hash(int(1-2**63), long(1-2**63))
        self.same_hash(int(2**63-1), long(2**63-1))
        self.same_hash(long(2**63), float(2**63))

    def test_coerced_floats(self):
        self.same_hash(long(1.23e300), float(1.23e300))
        self.same_hash(float(0.5), complex(0.5, 0.0))


_default_hash = object.__hash__
class DefaultHash(object): pass

_FIXED_HASH_VALUE = 42
class FixedHash(object):
    def __hash__(self):
        return _FIXED_HASH_VALUE

class OnlyEquality(object):
    def __eq__(self, other):
        return self is other
    # Trick to suppress Py3k warning in 2.x
    __hash__ = None
del OnlyEquality.__hash__

class OnlyInequality(object):
    def __ne__(self, other):
        return self is not other

class OnlyCmp(object):
    def __cmp__(self, other):
        return cmp(id(self), id(other))
    # Trick to suppress Py3k warning in 2.x
    __hash__ = None
del OnlyCmp.__hash__

class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
class InheritedHashWithCmp(FixedHash, OnlyCmp): pass

class NoHash(object):
    __hash__ = None

class HashInheritanceTestCase(unittest.TestCase):
    default_expected = [object(),
                        DefaultHash(),
                        OnlyEquality(),
                        OnlyInequality(),
                        OnlyCmp(),
                       ]
    fixed_expected = [FixedHash(),
                      InheritedHashWithEquality(),
                      InheritedHashWithInequality(),
                      InheritedHashWithCmp(),
                      ]
    error_expected = [NoHash()]

    def test_default_hash(self):
        for obj in self.default_expected:
            self.assertEqual(hash(obj), _default_hash(obj))

    def test_fixed_hash(self):
        for obj in self.fixed_expected:
            self.assertEqual(hash(obj), _FIXED_HASH_VALUE)

    def test_error_hash(self):
        for obj in self.error_expected:
            self.assertRaises(TypeError, hash, obj)

    def test_hashable(self):
        objects = (self.default_expected +
                   self.fixed_expected)
        for obj in objects:
            self.assertIsInstance(obj, Hashable)

    def test_not_hashable(self):
        for obj in self.error_expected:
            self.assertNotIsInstance(obj, Hashable)


# Issue #4701: Check that some builtin types are correctly hashable
#  (This test only used to fail in Python 3.0, but has been included
#   in 2.x along with the lazy call to PyType_Ready in PyObject_Hash)
class DefaultIterSeq(object):
    seq = range(10)
    def __len__(self):
        return len(self.seq)
    def __getitem__(self, index):
        return self.seq[index]

class HashBuiltinsTestCase(unittest.TestCase):
    hashes_to_check = [xrange(10),
                       enumerate(xrange(10)),
                       iter(DefaultIterSeq()),
                       iter(lambda: 0, 0),
                      ]

    def test_hashes(self):
        _default_hash = object.__hash__
        for obj in self.hashes_to_check:
            self.assertEqual(hash(obj), _default_hash(obj))

def test_main():
    test_support.run_unittest(HashEqualityTestCase,
                              HashInheritanceTestCase,
                              HashBuiltinsTestCase)


if __name__ == "__main__":
    test_main()