/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
1
# Copyright (C) 2008 Canonical Limited.
2
# 
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License version 2 as published
5
# by the Free Software Foundation.
6
# 
7
# This program is distributed in the hope that it will be useful,
8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
# GNU General Public License for more details.
11
# 
12
# You should have received a copy of the GNU General Public License
13
# along with this program; if not, write to the Free Software
14
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
15
# 
16
17
"""Tests for the pyrex extension of groupcompress"""
18
19
from bzrlib import tests
20
21
22
class _CompiledGroupCompress(tests.Feature):
23
24
    def _probe(self):
25
        try:
26
            import bzrlib.plugins.groupcompress._groupcompress_c
27
        except ImportError:
28
            return False
29
        else:
30
            return True
31
32
    def feature_name(self):
33
        return 'bzrlib.plugins.groupcompress._groupcompress_c'
34
35
CompiledGroupCompress = _CompiledGroupCompress()
36
37
38
class TestCompiledEquivalenceTable(tests.TestCase):
39
    """Direct tests for the compiled Equivalence Table."""
40
41
    _tests_need_features = [CompiledGroupCompress]
42
0.18.18 by John Arbash Meinel
Start actually storing matches in the hash table, and testing the result.
43
    # These tests assume that hash(int) == int
44
    # If that ever changes, we can simply change this code to use a custom
45
    # class that has precomputed values returned from __hash__.
46
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
47
    def setUp(self):
48
        super(TestCompiledEquivalenceTable, self).setUp()
49
        from bzrlib.plugins.groupcompress import _groupcompress_c
50
        self._gc_module = _groupcompress_c
51
52
    def test_minimum_hash_size(self):
53
        eq = self._gc_module.EquivalenceTable([])
0.18.16 by John Arbash Meinel
Test the recommended versus minimum hash table sizes.
54
        # We request at least 33% free space in the hash (to make collisions
55
        # more bearable)
56
        self.assertEqual(1024, eq._py_compute_minimum_hash_size(683))
57
        self.assertEqual(2048, eq._py_compute_minimum_hash_size(684))
58
        self.assertEqual(2048, eq._py_compute_minimum_hash_size(1000))
59
        self.assertEqual(2048, eq._py_compute_minimum_hash_size(1024))
60
61
    def test_recommended_hash_size(self):
62
        eq = self._gc_module.EquivalenceTable([])
63
        # We always recommend a minimum of 8k
64
        self.assertEqual(8192, eq._py_compute_recommended_hash_size(10))
65
        self.assertEqual(8192, eq._py_compute_recommended_hash_size(1000))
66
        self.assertEqual(8192, eq._py_compute_recommended_hash_size(2000))
67
        self.assertEqual(8192, eq._py_compute_recommended_hash_size(4000))
68
69
        # And we recommend at least 50% free slots
70
        self.assertEqual(8192, eq._py_compute_recommended_hash_size(4096))
71
        self.assertEqual(16384, eq._py_compute_recommended_hash_size(4097))
0.18.17 by John Arbash Meinel
We now build the appropriate hash table entries.
72
73
    def test__raw_lines(self):
74
        eq = self._gc_module.EquivalenceTable([1, 2, 3])
0.18.18 by John Arbash Meinel
Start actually storing matches in the hash table, and testing the result.
75
        self.assertEqual([(1, 1, 1, -1), (2, 2, 2, -1), (3, 3, 3, -1)],
0.18.17 by John Arbash Meinel
We now build the appropriate hash table entries.
76
                         eq._inspect_left_lines())
77
78
    def test_build_hash(self):
79
        eq = self._gc_module.EquivalenceTable([1, 2, 3])
80
        # (size, [(offset, head_offset_in_lines, count)])
81
        self.assertEqual((8192, [(1, 0, 1), (2, 1, 1), (3, 2, 1)]),
82
                         eq._inspect_hash_table())
0.18.18 by John Arbash Meinel
Start actually storing matches in the hash table, and testing the result.
83
84
    def test_build_hash_with_duplicates(self):
85
        eq = self._gc_module.EquivalenceTable([1, 2, 4, 0, 1, 4, 2, 4])
86
        self.assertEqual([
87
            (1, 1, 1, 4),
88
            (2, 2, 2, 6),
89
            (4, 4, 4, 5),
90
            (0, 0, 0, -1),
91
            (1, 1, 1, -1),
92
            (4, 4, 4, 7),
93
            (2, 2, 2, -1),
94
            (4, 4, 4, -1),
95
            ], eq._inspect_left_lines())
96
        # (hash_offset, head_offset_in_lines, count)
97
        self.assertEqual((8192, [
98
            (0, 3, 1),
99
            (1, 0, 2),
100
            (2, 1, 2),
101
            (4, 2, 3),
102
            ]), eq._inspect_hash_table())
0.18.19 by John Arbash Meinel
Do some more testing about what happens when you get hash collisions, etc.
103
104
    def test_build_hash_table_with_wraparound(self):
105
        eq = self._gc_module.EquivalenceTable([1, 2+8192])
106
        self.assertEqual([
107
            (1, 1, 1, -1),
108
            (8194, 8194, 2, -1),
109
            ], eq._inspect_left_lines())
110
        self.assertEqual((8192, [
111
            (1, 0, 1),
112
            (2, 1, 1),
113
            ]), eq._inspect_hash_table())
114
115
    def test_build_hash_table_with_collisions(self):
116
        # We build up backwards, so # 2+8192 will wrap around to 2, and take
117
        # its spot because the 2 offset is taken, then the real '2' will get
118
        # bumped to 3, which will bump 3 into 4.  then when we have 5, it will
119
        # be fine, but the 8192+5 will get bumped to 6
120
        eq = self._gc_module.EquivalenceTable([1, 5+8192, 5, 3, 2, 2+8192])
121
        self.assertEqual([
122
            (1, 1, 1, -1),
123
            (8197, 8197, 6, -1),
124
            (5, 5, 5, -1),
125
            (3, 3, 4, -1),
126
            (2, 2, 3, -1),
127
            (8194, 8194, 2, -1),
128
            ], eq._inspect_left_lines())
129
        self.assertEqual((8192, [
130
            (1, 0, 1),
131
            (2, 5, 1),
132
            (3, 4, 1),
133
            (4, 3, 1),
134
            (5, 2, 1),
135
            (6, 1, 1),
136
            ]), eq._inspect_hash_table())
0.18.20 by John Arbash Meinel
Test the results with real strings rather than just integers
137
0.18.21 by John Arbash Meinel
Add support for not including certain lines in the hashtable.
138
    def test_build_hash_table_with_wrapped_collisions(self):
139
        eq = self._gc_module.EquivalenceTable([0, 8191+8192, 8191])
140
        self.assertEqual([
141
            (0, 0, 1, -1),
142
            (16383, 16383, 0, -1),
143
            (8191, 8191, 8191, -1),
144
            ], eq._inspect_left_lines())
145
        self.assertEqual((8192, [
146
            (0, 1, 1),
147
            (1, 0, 1),
148
            (8191, 2, 1),
149
            ]), eq._inspect_hash_table())
150
0.18.20 by John Arbash Meinel
Test the results with real strings rather than just integers
151
    def test_build_hash_table_with_strings(self):
152
        eq = self._gc_module.EquivalenceTable(['a', 'b', 'c', 'b'])
153
        self.assertEqual([
154
            ('a', hash('a'), hash('a') & 8191, -1),
155
            ('b', hash('b'), hash('b') & 8191, 3),
156
            ('c', hash('c'), hash('c') & 8191, -1),
157
            ('b', hash('b'), hash('b') & 8191, -1),
158
            ], eq._inspect_left_lines())
159
        self.assertEqual((8192, sorted([
160
            (hash('a') & 8191, 0, 1),
161
            (hash('b') & 8191, 1, 2),
162
            (hash('c') & 8191, 2, 1),
163
            ])), eq._inspect_hash_table())
0.18.21 by John Arbash Meinel
Add support for not including certain lines in the hashtable.
164
165
    def test_with_unhashable(self):
166
        self.assertRaises(TypeError, self._gc_module.EquivalenceTable,
167
                [['unhashable', 'list'], 'foo'])
168
        self.assertRaises(TypeError, self._gc_module.EquivalenceTable,
169
                ('foo', ['unhashable', 'list']))
170
171
    def test_extend_lines(self):
172
        eq = self._gc_module.EquivalenceTable([10, 20, 30, 20])
173
        eq.extend_lines([30, 20, 40], [True, True, True])
174
        self.assertEqual([
175
            (10, 10, 10, -1),
176
            (20, 20, 20, 3),
177
            (30, 30, 30, 4),
178
            (20, 20, 20, 5),
179
            (30, 30, 30, -1),
180
            (20, 20, 20, -1),
181
            (40, 40, 40, -1),
182
            ], eq._inspect_left_lines())
183
        # (hash_offset, head_offset_in_lines, count)
184
        self.assertEqual((8192, [
185
            (10, 0, 1),
186
            (20, 1, 3),
187
            (30, 2, 2),
188
            (40, 6, 1),
189
            ]), eq._inspect_hash_table())
190
191
    def test_extend_lines_ignored(self):
192
        eq = self._gc_module.EquivalenceTable([10, 20, 30, 20])
193
        eq.extend_lines([30, 20, 40], [True, False, False])
194
        self.assertEqual([
195
            (10, 10, 10, -1),
196
            (20, 20, 20, 3),
197
            (30, 30, 30, 4),
198
            (20, 20, 20, -1),
199
            (30, 30, 30, -1),
200
            (20, 20, -1, -1),
201
            (40, 40, -1, -1),
202
            ], eq._inspect_left_lines())
203
        # (hash_offset, head_offset_in_lines, count)
204
        self.assertEqual((8192, [
205
            (10, 0, 1),
206
            (20, 1, 2),
207
            (30, 2, 2),
208
            ]), eq._inspect_hash_table())