aboutsummaryrefslogtreecommitdiff
path: root/tests/test_issue24.py
blob: 7d51e34f97afa63c4a288a7e2f417b3be8c276ef (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
145
146
147
148
149
150
151
152
153
154
155
156
import unittest

from immutables.map import Map as PyMap, map_bitcount


class CollisionKey:
    def __hash__(self):
        return 0


class Issue24Base:
    Map = None

    def test_issue24(self):
        keys = range(27)
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        self.assertTrue(17 in m)
        with m.mutate() as mm:
            for i in keys:
                del mm[i]
            self.assertEqual(len(mm), 0)

    def dump_check_node_kind(self, header, kind):
        header = header.strip()
        self.assertTrue(header.strip().startswith(kind))

    def dump_check_node_size(self, header, size):
        node_size = header.split('size=', 1)[1]
        node_size = int(node_size.split(maxsplit=1)[0])
        self.assertEqual(node_size, size)

    def dump_check_bitmap_count(self, header, count):
        header = header.split('bitmap=')[1]
        bitmap = int(header.split(maxsplit=1)[0], 0)
        self.assertEqual(map_bitcount(bitmap), count)

    def dump_check_bitmap_node_count(self, header, count):
        self.dump_check_node_kind(header, 'Bitmap')
        self.dump_check_node_size(header, count * 2)
        self.dump_check_bitmap_count(header, count)

    def dump_check_collision_node_count(self, header, count):
        self.dump_check_node_kind(header, 'Collision')
        self.dump_check_node_size(header, 2 * count)

    def test_bitmap_node_update_in_place_count(self):
        keys = range(7)
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        d = m.__dump__().splitlines()
        self.assertTrue(d)
        if d[0].startswith('HAMT'):
            header = d[1]  # skip _map.Map.__dump__() header
        else:
            header = d[0]
        self.dump_check_bitmap_node_count(header, 7)

    def test_bitmap_node_delete_in_place_count(self):
        keys = range(7)
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        with m.mutate() as mm:
            del mm[0], mm[2], mm[3]
            m2 = mm.finish()
        d = m2.__dump__().splitlines()
        self.assertTrue(d)
        if d[0].startswith('HAMT'):
            header = d[1]  # skip _map.Map.__dump__() header
        else:
            header = d[0]
        self.dump_check_bitmap_node_count(header, 4)

    def test_collision_node_update_in_place_count(self):
        keys = (CollisionKey() for i in range(7))
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        d = m.__dump__().splitlines()
        self.assertTrue(len(d) > 3)
        # get node headers
        if d[0].startswith('HAMT'):
            h1, h2 = d[1], d[3]  # skip _map.Map.__dump__() header
        else:
            h1, h2 = d[0], d[2]
        self.dump_check_node_kind(h1, 'Bitmap')
        self.dump_check_collision_node_count(h2, 7)

    def test_collision_node_delete_in_place_count(self):
        keys = [CollisionKey() for i in range(7)]
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        with m.mutate() as mm:
            del mm[keys[0]], mm[keys[2]], mm[keys[3]]
            m2 = mm.finish()
        d = m2.__dump__().splitlines()
        self.assertTrue(len(d) > 3)
        # get node headers
        if d[0].startswith('HAMT'):
            h1, h2 = d[1], d[3]  # skip _map.Map.__dump__() header
        else:
            h1, h2 = d[0], d[2]
        self.dump_check_node_kind(h1, 'Bitmap')
        self.dump_check_collision_node_count(h2, 4)


try:
    from immutables._map import Map as CMap
except ImportError:
    CMap = None


class Issue24PyTest(Issue24Base, unittest.TestCase):
    Map = PyMap


@unittest.skipIf(CMap is None, 'C Map is not available')
class Issue24CTest(Issue24Base, unittest.TestCase):
    Map = CMap

    def hamt_dump_check_first_return_second(self, m):
        d = m.__dump__().splitlines()
        self.assertTrue(len(d) > 2)
        self.assertTrue(d[0].startswith('HAMT'))
        return d[1]

    def test_array_node_update_in_place_count(self):
        keys = range(27)
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        header = self.hamt_dump_check_first_return_second(m)
        self.dump_check_node_kind(header, 'Array')
        for i in range(2, 18):
            m = m.delete(i)
        header = self.hamt_dump_check_first_return_second(m)
        self.dump_check_bitmap_node_count(header, 11)

    def test_array_node_delete_in_place_count(self):
        keys = range(27)
        new_entries = dict.fromkeys(keys, True)
        m = self.Map(new_entries)
        header = self.hamt_dump_check_first_return_second(m)
        self.dump_check_node_kind(header, 'Array')
        with m.mutate() as mm:
            for i in range(5):
                del mm[i]
            m2 = mm.finish()
        header = self.hamt_dump_check_first_return_second(m2)
        self.dump_check_node_kind(header, 'Array')
        for i in range(6, 17):
            m2 = m2.delete(i)
        header = self.hamt_dump_check_first_return_second(m2)
        self.dump_check_bitmap_node_count(header, 11)


if __name__ == '__main__':
    unittest.main()