~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test__groupcompress_pyx.py

merge bzr.dev@4126 into brisbane-core

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008, 2009 Canonical Ltd
 
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 as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the pyrex extension of groupcompress"""
 
18
 
 
19
from bzrlib import tests
 
20
 
 
21
from bzrlib import groupcompress
 
22
 
 
23
 
 
24
class _CompiledGroupCompress(tests.Feature):
 
25
 
 
26
    def _probe(self):
 
27
        try:
 
28
            import bzrlib._groupcompress_pyx
 
29
        except ImportError:
 
30
            return False
 
31
        else:
 
32
            return True
 
33
 
 
34
    def feature_name(self):
 
35
        return 'bzrlib._groupcompress_pyx'
 
36
 
 
37
CompiledGroupCompress = _CompiledGroupCompress()
 
38
 
 
39
_text1 = """\
 
40
This is a bit
 
41
of source text
 
42
which is meant to be matched
 
43
against other text
 
44
"""
 
45
 
 
46
_text2 = """\
 
47
This is a bit
 
48
of source text
 
49
which is meant to differ from
 
50
against other text
 
51
"""
 
52
 
 
53
_text3 = """\
 
54
This is a bit
 
55
of source text
 
56
which is meant to be matched
 
57
against other text
 
58
except it also
 
59
has a lot more data
 
60
at the end of the file
 
61
"""
 
62
 
 
63
_first_text = """\
 
64
a bit of text, that
 
65
does not have much in
 
66
common with the next text
 
67
"""
 
68
 
 
69
_second_text = """\
 
70
some more bit of text, that
 
71
does not have much in
 
72
common with the previous text
 
73
and has some extra text
 
74
"""
 
75
 
 
76
 
 
77
_third_text = """\
 
78
a bit of text, that
 
79
has some in common with the previous text
 
80
and has some extra text
 
81
and not have much in
 
82
common with the next text
 
83
"""
 
84
 
 
85
_fourth_text = """\
 
86
123456789012345
 
87
same rabin hash
 
88
123456789012345
 
89
same rabin hash
 
90
123456789012345
 
91
same rabin hash
 
92
123456789012345
 
93
same rabin hash
 
94
"""
 
95
 
 
96
class Test_GroupCompress(tests.TestCase):
 
97
    """Direct tests for the compiled extension."""
 
98
 
 
99
    def setUp(self):
 
100
        super(Test_GroupCompress, self).setUp()
 
101
        self.requireFeature(CompiledGroupCompress)
 
102
        from bzrlib import _groupcompress_pyx
 
103
        self._gc_module = _groupcompress_pyx
 
104
 
 
105
 
 
106
class TestMakeAndApplyDelta(Test_GroupCompress):
 
107
 
 
108
    def setUp(self):
 
109
        super(TestMakeAndApplyDelta, self).setUp()
 
110
        self.make_delta = self._gc_module.make_delta
 
111
        self.apply_delta = self._gc_module.apply_delta
 
112
 
 
113
    def test_make_delta_is_typesafe(self):
 
114
        self.make_delta('a string', 'another string')
 
115
        self.assertRaises(TypeError,
 
116
            self.make_delta, 'a string', object())
 
117
        self.assertRaises(TypeError,
 
118
            self.make_delta, 'a string', u'not a string')
 
119
        self.assertRaises(TypeError,
 
120
            self.make_delta, object(), 'a string')
 
121
        self.assertRaises(TypeError,
 
122
            self.make_delta, u'not a string', 'a string')
 
123
 
 
124
    def test_make_noop_delta(self):
 
125
        ident_delta = self.make_delta(_text1, _text1)
 
126
        self.assertEqual('MM\x90M', ident_delta)
 
127
        ident_delta = self.make_delta(_text2, _text2)
 
128
        self.assertEqual('NN\x90N', ident_delta)
 
129
        ident_delta = self.make_delta(_text3, _text3)
 
130
        self.assertEqual('\x87\x01\x87\x01\x90\x87', ident_delta)
 
131
 
 
132
    def test_make_delta(self):
 
133
        delta = self.make_delta(_text1, _text2)
 
134
        self.assertEqual('MN\x90/\x1fdiffer from\nagainst other text\n', delta)
 
135
        delta = self.make_delta(_text2, _text1)
 
136
        self.assertEqual('NM\x90/\x1ebe matched\nagainst other text\n', delta)
 
137
        delta = self.make_delta(_text3, _text1)
 
138
        self.assertEqual('\x87\x01M\x90M', delta)
 
139
        delta = self.make_delta(_text3, _text2)
 
140
        self.assertEqual('\x87\x01N\x90/\x1fdiffer from\nagainst other text\n',
 
141
                         delta)
 
142
 
 
143
    def test_apply_delta_is_typesafe(self):
 
144
        self.apply_delta(_text1, 'MM\x90M')
 
145
        self.assertRaises(TypeError,
 
146
            self.apply_delta, object(), 'MM\x90M')
 
147
        self.assertRaises(TypeError,
 
148
            self.apply_delta, unicode(_text1), 'MM\x90M')
 
149
        self.assertRaises(TypeError,
 
150
            self.apply_delta, _text1, u'MM\x90M')
 
151
        self.assertRaises(TypeError,
 
152
            self.apply_delta, _text1, object())
 
153
 
 
154
    def test_apply_delta(self):
 
155
        target = self.apply_delta(_text1,
 
156
                    'MN\x90/\x1fdiffer from\nagainst other text\n')
 
157
        self.assertEqual(_text2, target)
 
158
        target = self.apply_delta(_text2,
 
159
                    'NM\x90/\x1ebe matched\nagainst other text\n')
 
160
        self.assertEqual(_text1, target)
 
161
 
 
162
 
 
163
class TestDeltaIndex(Test_GroupCompress):
 
164
 
 
165
    def test_repr(self):
 
166
        di = self._gc_module.DeltaIndex('test text\n')
 
167
        self.assertEqual('DeltaIndex(1, 10)', repr(di))
 
168
 
 
169
    def test_make_delta(self):
 
170
        di = self._gc_module.DeltaIndex(_text1)
 
171
        delta = di.make_delta(_text2)
 
172
        self.assertEqual('MN\x90/\x1fdiffer from\nagainst other text\n', delta)
 
173
 
 
174
    def test_delta_against_multiple_sources(self):
 
175
        di = self._gc_module.DeltaIndex()
 
176
        di.add_source(_first_text, 0)
 
177
        self.assertEqual(len(_first_text), di._source_offset)
 
178
        di.add_source(_second_text, 0)
 
179
        self.assertEqual(len(_first_text) + len(_second_text), di._source_offset)
 
180
        delta = di.make_delta(_third_text)
 
181
        result = self._gc_module.apply_delta(_first_text + _second_text, delta)
 
182
        self.assertEqualDiff(_third_text, result)
 
183
        self.assertEqual('\xac\x01\x85\x01\x90\x14\x0chas some in '
 
184
                         '\x91v6\x03and\x91d"\x91:\n', delta)
 
185
 
 
186
    def test_delta_with_offsets(self):
 
187
        di = self._gc_module.DeltaIndex()
 
188
        di.add_source(_first_text, 5)
 
189
        self.assertEqual(len(_first_text) + 5, di._source_offset)
 
190
        di.add_source(_second_text, 10)
 
191
        self.assertEqual(len(_first_text) + len(_second_text) + 15,
 
192
                         di._source_offset)
 
193
        delta = di.make_delta(_third_text)
 
194
        self.assertIsNot(None, delta)
 
195
        result = self._gc_module.apply_delta(
 
196
            '12345' + _first_text + '1234567890' + _second_text, delta)
 
197
        self.assertIsNot(None, result)
 
198
        self.assertEqualDiff(_third_text, result)
 
199
        self.assertEqual('\xbb\x01\x85\x01\x91\x05\x14\x0chas some in '
 
200
                         '\x91\x856\x03and\x91s"\x91?\n', delta)
 
201
 
 
202
    def test_delta_with_delta_bytes(self):
 
203
        di = self._gc_module.DeltaIndex()
 
204
        source = _first_text
 
205
        di.add_source(_first_text, 0)
 
206
        self.assertEqual(len(_first_text), di._source_offset)
 
207
        delta = di.make_delta(_second_text)
 
208
        self.assertEqual('Dh\tsome more\x91\x019'
 
209
                         '&previous text\nand has some extra text\n', delta)
 
210
        di.add_delta_source(delta, 0)
 
211
        source += delta
 
212
        self.assertEqual(len(_first_text) + len(delta), di._source_offset)
 
213
        second_delta = di.make_delta(_third_text)
 
214
        result = self._gc_module.apply_delta(source, second_delta)
 
215
        self.assertEqualDiff(_third_text, result)
 
216
        # We should be able to match against the 'previous text\nand has some...'
 
217
        # that was part of the delta bytes
 
218
        # Note that we don't match the 'common with the', because it isn't long
 
219
        # enough to match in the original text, and those bytes are not present
 
220
        # in the delta for the second text.
 
221
        self.assertEqual('z\x85\x01\x90\x14\x1chas some in common with the '
 
222
                         '\x91T&\x03and\x91\x18,', second_delta)
 
223
        # Add this delta, and create a new delta for the same text. We should
 
224
        # find the remaining text, and only insert the short 'and' text.
 
225
        di.add_delta_source(second_delta, 0)
 
226
        source += second_delta
 
227
        third_delta = di.make_delta(_third_text)
 
228
        result = self._gc_module.apply_delta(source, third_delta)
 
229
        self.assertEqualDiff(_third_text, result)
 
230
        self.assertEqual('\xa6\x01\x85\x01\x90\x14\x91\x80\x1c'
 
231
                         '\x91T&\x03and\x91\x18,', third_delta)
 
232
        # Now create a delta, which we know won't be able to be 'fit' into the
 
233
        # existing index
 
234
        fourth_delta = di.make_delta(_fourth_text)
 
235
        self.assertEqual(_fourth_text,
 
236
                         self._gc_module.apply_delta(source, fourth_delta))
 
237
        self.assertEqual('\xa6\x01\x80\x01'
 
238
                         '\x7f123456789012345\nsame rabin hash\n'
 
239
                         '123456789012345\nsame rabin hash\n'
 
240
                         '123456789012345\nsame rabin hash\n'
 
241
                         '123456789012345\nsame rabin hash'
 
242
                         '\x01\n', fourth_delta)
 
243
        di.add_delta_source(fourth_delta, 0)
 
244
        source += fourth_delta
 
245
        # With the next delta, everything should be found
 
246
        fifth_delta = di.make_delta(_fourth_text)
 
247
        self.assertEqual(_fourth_text,
 
248
                         self._gc_module.apply_delta(source, fifth_delta))
 
249
        self.assertEqual('\xac\x02\x80\x01\x91\xab\x7f\x01\n', fifth_delta)