/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
2
#
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
3
# This program is free software; you can redistribute it and/or modify
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
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
#
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
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.
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
12
#
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
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
3735.36.3 by John Arbash Meinel
Add the new address for FSF to the new files.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
16
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
17
"""Tests for the python and pyrex extensions of groupcompress"""
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
18
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
19
from bzrlib import (
20
    groupcompress,
21
    _groupcompress_py,
22
    tests,
23
    )
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
24
from bzrlib.tests.scenarios import (
25
    load_tests_apply_scenarios,
26
    multiply_scenarios,
27
    )
28
29
30
def module_scenarios():
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
31
    scenarios = [
32
        ('python', {'_gc_module': _groupcompress_py}),
33
        ]
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
34
    if compiled_groupcompress_feature.available():
35
        gc_module = compiled_groupcompress_feature.module
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
36
        scenarios.append(('C',
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
37
            {'_gc_module': gc_module}))
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
38
    return scenarios
39
40
41
def two_way_scenarios():
42
    scenarios = [
43
        ('PP', {'make_delta': _groupcompress_py.make_delta,
44
                'apply_delta': _groupcompress_py.apply_delta})
45
        ]
46
    if compiled_groupcompress_feature.available():
47
        gc_module = compiled_groupcompress_feature.module
48
        scenarios.extend([
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
49
            ('CC', {'make_delta': gc_module.make_delta,
50
                    'apply_delta': gc_module.apply_delta}),
3735.40.12 by John Arbash Meinel
Add tests that the deltas generated by one implementation are compatible
51
            ('PC', {'make_delta': _groupcompress_py.make_delta,
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
52
                    'apply_delta': gc_module.apply_delta}),
53
            ('CP', {'make_delta': gc_module.make_delta,
3735.40.12 by John Arbash Meinel
Add tests that the deltas generated by one implementation are compatible
54
                    'apply_delta': _groupcompress_py.apply_delta}),
55
            ])
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
56
    return scenarios
57
58
59
load_tests = load_tests_apply_scenarios
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
60
61
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
62
compiled_groupcompress_feature = tests.ModuleAvailableFeature(
63
                                    'bzrlib._groupcompress_pyx')
0.18.15 by John Arbash Meinel
Start writing tests directly for the compiled class
64
0.23.8 by John Arbash Meinel
Add another test text.
65
_text1 = """\
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
66
This is a bit
67
of source text
68
which is meant to be matched
69
against other text
70
"""
71
0.23.8 by John Arbash Meinel
Add another test text.
72
_text2 = """\
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
73
This is a bit
74
of source text
75
which is meant to differ from
76
against other text
77
"""
78
0.23.8 by John Arbash Meinel
Add another test text.
79
_text3 = """\
80
This is a bit
81
of source text
82
which is meant to be matched
83
against other text
84
except it also
85
has a lot more data
86
at the end of the file
87
"""
88
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
89
_first_text = """\
90
a bit of text, that
91
does not have much in
92
common with the next text
93
"""
94
95
_second_text = """\
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
96
some more bit of text, that
97
does not have much in
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
98
common with the previous text
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
99
and has some extra text
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
100
"""
101
102
103
_third_text = """\
104
a bit of text, that
105
has some in common with the previous text
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
106
and has some extra text
107
and not have much in
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
108
common with the next text
109
"""
110
3735.33.4 by John Arbash Meinel
The new layout is working.
111
_fourth_text = """\
112
123456789012345
113
same rabin hash
114
123456789012345
115
same rabin hash
116
123456789012345
117
same rabin hash
118
123456789012345
119
same rabin hash
120
"""
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
121
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
122
class TestMakeAndApplyDelta(tests.TestCase):
123
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
124
    scenarios = module_scenarios()
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
125
    _gc_module = None # Set by load_tests
0.23.14 by John Arbash Meinel
Implement a DeltaIndex wrapper.
126
127
    def setUp(self):
128
        super(TestMakeAndApplyDelta, self).setUp()
129
        self.make_delta = self._gc_module.make_delta
130
        self.apply_delta = self._gc_module.apply_delta
3735.40.19 by John Arbash Meinel
Implement apply_delta_to_source which doesn't have to malloc another string.
131
        self.apply_delta_to_source = self._gc_module.apply_delta_to_source
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
132
133
    def test_make_delta_is_typesafe(self):
134
        self.make_delta('a string', 'another string')
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
135
136
        def _check_make_delta(string1, string2):
137
            self.assertRaises(TypeError, self.make_delta, string1, string2)
138
139
        _check_make_delta('a string', object())
140
        _check_make_delta('a string', u'not a string')
141
        _check_make_delta(object(), 'a string')
142
        _check_make_delta(u'not a string', 'a string')
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
143
144
    def test_make_noop_delta(self):
0.23.8 by John Arbash Meinel
Add another test text.
145
        ident_delta = self.make_delta(_text1, _text1)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
146
        self.assertEqual('M\x90M', ident_delta)
0.23.8 by John Arbash Meinel
Add another test text.
147
        ident_delta = self.make_delta(_text2, _text2)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
148
        self.assertEqual('N\x90N', ident_delta)
0.23.8 by John Arbash Meinel
Add another test text.
149
        ident_delta = self.make_delta(_text3, _text3)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
150
        self.assertEqual('\x87\x01\x90\x87', ident_delta)
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
151
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
152
    def assertDeltaIn(self, delta1, delta2, delta):
153
        """Make sure that the delta bytes match one of the expectations."""
154
        # In general, the python delta matcher gives different results than the
155
        # pyrex delta matcher. Both should be valid deltas, though.
156
        if delta not in (delta1, delta2):
157
            self.fail("Delta bytes:\n"
158
                      "       %r\n"
159
                      "not in %r\n"
160
                      "    or %r"
161
                      % (delta, delta1, delta2))
162
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
163
    def test_make_delta(self):
0.23.8 by John Arbash Meinel
Add another test text.
164
        delta = self.make_delta(_text1, _text2)
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
165
        self.assertDeltaIn(
166
            'N\x90/\x1fdiffer from\nagainst other text\n',
167
            'N\x90\x1d\x1ewhich is meant to differ from\n\x91:\x13',
168
            delta)
0.23.8 by John Arbash Meinel
Add another test text.
169
        delta = self.make_delta(_text2, _text1)
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
170
        self.assertDeltaIn(
171
            'M\x90/\x1ebe matched\nagainst other text\n',
172
            'M\x90\x1d\x1dwhich is meant to be matched\n\x91;\x13',
173
            delta)
0.23.8 by John Arbash Meinel
Add another test text.
174
        delta = self.make_delta(_text3, _text1)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
175
        self.assertEqual('M\x90M', delta)
0.23.8 by John Arbash Meinel
Add another test text.
176
        delta = self.make_delta(_text3, _text2)
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
177
        self.assertDeltaIn(
178
            'N\x90/\x1fdiffer from\nagainst other text\n',
179
            'N\x90\x1d\x1ewhich is meant to differ from\n\x91:\x13',
180
            delta)
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
181
4300.2.1 by John Arbash Meinel
Fix bug #364900, properly remove the 64kB that was just encoded in the copy.
182
    def test_make_delta_with_large_copies(self):
183
        # We want to have a copy that is larger than 64kB, which forces us to
184
        # issue multiple copy instructions.
185
        big_text = _text3 * 1220
186
        delta = self.make_delta(big_text, big_text)
187
        self.assertDeltaIn(
188
            '\xdc\x86\x0a'      # Encoding the length of the uncompressed text
189
            '\x80'              # Copy 64kB, starting at byte 0
190
            '\x84\x01'          # and another 64kB starting at 64kB
191
            '\xb4\x02\x5c\x83', # And the bit of tail.
192
            None,   # Both implementations should be identical
193
            delta)
194
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
195
    def test_apply_delta_is_typesafe(self):
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
196
        self.apply_delta(_text1, 'M\x90M')
3735.40.10 by John Arbash Meinel
Merge in the new delta format code.
197
        self.assertRaises(TypeError, self.apply_delta, object(), 'M\x90M')
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
198
        self.assertRaises(TypeError, self.apply_delta,
3735.40.10 by John Arbash Meinel
Merge in the new delta format code.
199
                          unicode(_text1), 'M\x90M')
200
        self.assertRaises(TypeError, self.apply_delta, _text1, u'M\x90M')
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
201
        self.assertRaises(TypeError, self.apply_delta, _text1, object())
0.23.6 by John Arbash Meinel
Start stripping out the actual GroupCompressor
202
203
    def test_apply_delta(self):
0.23.8 by John Arbash Meinel
Add another test text.
204
        target = self.apply_delta(_text1,
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
205
                    'N\x90/\x1fdiffer from\nagainst other text\n')
0.23.8 by John Arbash Meinel
Add another test text.
206
        self.assertEqual(_text2, target)
207
        target = self.apply_delta(_text2,
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
208
                    'M\x90/\x1ebe matched\nagainst other text\n')
0.23.8 by John Arbash Meinel
Add another test text.
209
        self.assertEqual(_text1, target)
0.23.14 by John Arbash Meinel
Implement a DeltaIndex wrapper.
210
3735.40.19 by John Arbash Meinel
Implement apply_delta_to_source which doesn't have to malloc another string.
211
    def test_apply_delta_to_source_is_safe(self):
212
        self.assertRaises(TypeError,
213
            self.apply_delta_to_source, object(), 0, 1)
214
        self.assertRaises(TypeError,
215
            self.apply_delta_to_source, u'unicode str', 0, 1)
216
        # end > length
217
        self.assertRaises(ValueError,
218
            self.apply_delta_to_source, 'foo', 1, 4)
219
        # start > length
220
        self.assertRaises(ValueError,
221
            self.apply_delta_to_source, 'foo', 5, 3)
222
        # start > end
223
        self.assertRaises(ValueError,
224
            self.apply_delta_to_source, 'foo', 3, 2)
225
226
    def test_apply_delta_to_source(self):
227
        source_and_delta = (_text1
228
                            + 'N\x90/\x1fdiffer from\nagainst other text\n')
229
        self.assertEqual(_text2, self.apply_delta_to_source(source_and_delta,
230
                                    len(_text1), len(source_and_delta)))
231
0.23.14 by John Arbash Meinel
Implement a DeltaIndex wrapper.
232
3735.40.12 by John Arbash Meinel
Add tests that the deltas generated by one implementation are compatible
233
class TestMakeAndApplyCompatible(tests.TestCase):
234
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
235
    scenarios = two_way_scenarios()
236
3735.40.16 by John Arbash Meinel
Implement (de|en)code_base128_int in pyrex.
237
    make_delta = None # Set by load_tests
238
    apply_delta = None # Set by load_tests
3735.40.12 by John Arbash Meinel
Add tests that the deltas generated by one implementation are compatible
239
240
    def assertMakeAndApply(self, source, target):
241
        """Assert that generating a delta and applying gives success."""
242
        delta = self.make_delta(source, target)
243
        bytes = self.apply_delta(source, delta)
244
        self.assertEqualDiff(target, bytes)
245
246
    def test_direct(self):
247
        self.assertMakeAndApply(_text1, _text2)
248
        self.assertMakeAndApply(_text2, _text1)
249
        self.assertMakeAndApply(_text1, _text3)
250
        self.assertMakeAndApply(_text3, _text1)
251
        self.assertMakeAndApply(_text2, _text3)
252
        self.assertMakeAndApply(_text3, _text2)
253
254
3735.40.5 by John Arbash Meinel
Start adding permutation tests for _groupcompress_py and _groupcompress_pyx
255
class TestDeltaIndex(tests.TestCase):
256
257
    def setUp(self):
258
        super(TestDeltaIndex, self).setUp()
259
        # This test isn't multiplied, because we only have DeltaIndex for the
260
        # compiled form
261
        # We call this here, because _test_needs_features happens after setUp
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
262
        self.requireFeature(compiled_groupcompress_feature)
263
        self._gc_module = compiled_groupcompress_feature.module
0.23.14 by John Arbash Meinel
Implement a DeltaIndex wrapper.
264
265
    def test_repr(self):
266
        di = self._gc_module.DeltaIndex('test text\n')
0.23.43 by John Arbash Meinel
Change the internals to allow delta indexes to be expanded with new source data.
267
        self.assertEqual('DeltaIndex(1, 10)', repr(di))
0.23.14 by John Arbash Meinel
Implement a DeltaIndex wrapper.
268
4398.6.1 by John Arbash Meinel
Change groupcompress.DeltaIndex to be lazy about indexing the first source.
269
    def test_first_add_source_doesnt_index_until_make_delta(self):
270
        di = self._gc_module.DeltaIndex()
271
        self.assertFalse(di._has_index())
272
        di.add_source(_text1, 0)
273
        self.assertFalse(di._has_index())
274
        # However, asking to make a delta will trigger the index to be
275
        # generated, and will generate a proper delta
276
        delta = di.make_delta(_text2)
277
        self.assertTrue(di._has_index())
278
        self.assertEqual('N\x90/\x1fdiffer from\nagainst other text\n', delta)
279
280
    def test_second_add_source_triggers_make_index(self):
281
        di = self._gc_module.DeltaIndex()
282
        self.assertFalse(di._has_index())
283
        di.add_source(_text1, 0)
284
        self.assertFalse(di._has_index())
285
        di.add_source(_text2, 0)
286
        self.assertTrue(di._has_index())
287
0.23.14 by John Arbash Meinel
Implement a DeltaIndex wrapper.
288
    def test_make_delta(self):
289
        di = self._gc_module.DeltaIndex(_text1)
290
        delta = di.make_delta(_text2)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
291
        self.assertEqual('N\x90/\x1fdiffer from\nagainst other text\n', delta)
0.23.25 by John Arbash Meinel
We are now able to add multiple sources to the delta generator.
292
293
    def test_delta_against_multiple_sources(self):
294
        di = self._gc_module.DeltaIndex()
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
295
        di.add_source(_first_text, 0)
296
        self.assertEqual(len(_first_text), di._source_offset)
297
        di.add_source(_second_text, 0)
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
298
        self.assertEqual(len(_first_text) + len(_second_text),
299
                         di._source_offset)
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
300
        delta = di.make_delta(_third_text)
301
        result = self._gc_module.apply_delta(_first_text + _second_text, delta)
302
        self.assertEqualDiff(_third_text, result)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
303
        self.assertEqual('\x85\x01\x90\x14\x0chas some in '
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
304
                         '\x91v6\x03and\x91d"\x91:\n', delta)
0.23.25 by John Arbash Meinel
We are now able to add multiple sources to the delta generator.
305
0.23.26 by John Arbash Meinel
We now start to make use of the ability to extend the delta index
306
    def test_delta_with_offsets(self):
307
        di = self._gc_module.DeltaIndex()
308
        di.add_source(_first_text, 5)
309
        self.assertEqual(len(_first_text) + 5, di._source_offset)
310
        di.add_source(_second_text, 10)
311
        self.assertEqual(len(_first_text) + len(_second_text) + 15,
312
                         di._source_offset)
313
        delta = di.make_delta(_third_text)
314
        self.assertIsNot(None, delta)
315
        result = self._gc_module.apply_delta(
316
            '12345' + _first_text + '1234567890' + _second_text, delta)
317
        self.assertIsNot(None, result)
318
        self.assertEqualDiff(_third_text, result)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
319
        self.assertEqual('\x85\x01\x91\x05\x14\x0chas some in '
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
320
                         '\x91\x856\x03and\x91s"\x91?\n', delta)
321
322
    def test_delta_with_delta_bytes(self):
323
        di = self._gc_module.DeltaIndex()
3735.33.4 by John Arbash Meinel
The new layout is working.
324
        source = _first_text
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
325
        di.add_source(_first_text, 0)
326
        self.assertEqual(len(_first_text), di._source_offset)
327
        delta = di.make_delta(_second_text)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
328
        self.assertEqual('h\tsome more\x91\x019'
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
329
                         '&previous text\nand has some extra text\n', delta)
330
        di.add_delta_source(delta, 0)
3735.33.4 by John Arbash Meinel
The new layout is working.
331
        source += delta
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
332
        self.assertEqual(len(_first_text) + len(delta), di._source_offset)
3735.33.4 by John Arbash Meinel
The new layout is working.
333
        second_delta = di.make_delta(_third_text)
334
        result = self._gc_module.apply_delta(source, second_delta)
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
335
        self.assertEqualDiff(_third_text, result)
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
336
        # We should be able to match against the
337
        # 'previous text\nand has some...'  that was part of the delta bytes
0.23.45 by John Arbash Meinel
Add a function that updates the index for delta bytes.
338
        # Note that we don't match the 'common with the', because it isn't long
339
        # enough to match in the original text, and those bytes are not present
340
        # in the delta for the second text.
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
341
        self.assertEqual('\x85\x01\x90\x14\x1chas some in common with the '
342
                         '\x91S&\x03and\x91\x18,', second_delta)
3735.33.4 by John Arbash Meinel
The new layout is working.
343
        # Add this delta, and create a new delta for the same text. We should
344
        # find the remaining text, and only insert the short 'and' text.
345
        di.add_delta_source(second_delta, 0)
346
        source += second_delta
347
        third_delta = di.make_delta(_third_text)
348
        result = self._gc_module.apply_delta(source, third_delta)
349
        self.assertEqualDiff(_third_text, result)
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
350
        self.assertEqual('\x85\x01\x90\x14\x91\x7e\x1c'
351
                         '\x91S&\x03and\x91\x18,', third_delta)
3735.33.4 by John Arbash Meinel
The new layout is working.
352
        # Now create a delta, which we know won't be able to be 'fit' into the
353
        # existing index
354
        fourth_delta = di.make_delta(_fourth_text)
355
        self.assertEqual(_fourth_text,
356
                         self._gc_module.apply_delta(source, fourth_delta))
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
357
        self.assertEqual('\x80\x01'
3735.33.4 by John Arbash Meinel
The new layout is working.
358
                         '\x7f123456789012345\nsame rabin hash\n'
359
                         '123456789012345\nsame rabin hash\n'
360
                         '123456789012345\nsame rabin hash\n'
361
                         '123456789012345\nsame rabin hash'
362
                         '\x01\n', fourth_delta)
363
        di.add_delta_source(fourth_delta, 0)
364
        source += fourth_delta
365
        # With the next delta, everything should be found
366
        fifth_delta = di.make_delta(_fourth_text)
367
        self.assertEqual(_fourth_text,
368
                         self._gc_module.apply_delta(source, fifth_delta))
3735.38.1 by John Arbash Meinel
Change the delta byte stream to remove the 'source length' entry.
369
        self.assertEqual('\x80\x01\x91\xa7\x7f\x01\n', fifth_delta)
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
370
371
372
class TestCopyInstruction(tests.TestCase):
373
374
    def assertEncode(self, expected, offset, length):
375
        bytes = _groupcompress_py.encode_copy_instruction(offset, length)
376
        if expected != bytes:
377
            self.assertEqual([hex(ord(e)) for e in expected],
378
                             [hex(ord(b)) for b in bytes])
379
380
    def assertDecode(self, exp_offset, exp_length, exp_newpos, bytes, pos):
381
        cmd = ord(bytes[pos])
382
        pos += 1
383
        out = _groupcompress_py.decode_copy_instruction(bytes, cmd, pos)
384
        self.assertEqual((exp_offset, exp_length, exp_newpos), out)
385
386
    def test_encode_no_length(self):
4300.2.1 by John Arbash Meinel
Fix bug #364900, properly remove the 64kB that was just encoded in the copy.
387
        self.assertEncode('\x80', 0, 64*1024)
388
        self.assertEncode('\x81\x01', 1, 64*1024)
389
        self.assertEncode('\x81\x0a', 10, 64*1024)
390
        self.assertEncode('\x81\xff', 255, 64*1024)
391
        self.assertEncode('\x82\x01', 256, 64*1024)
392
        self.assertEncode('\x83\x01\x01', 257, 64*1024)
393
        self.assertEncode('\x8F\xff\xff\xff\xff', 0xFFFFFFFF, 64*1024)
394
        self.assertEncode('\x8E\xff\xff\xff', 0xFFFFFF00, 64*1024)
395
        self.assertEncode('\x8D\xff\xff\xff', 0xFFFF00FF, 64*1024)
396
        self.assertEncode('\x8B\xff\xff\xff', 0xFF00FFFF, 64*1024)
397
        self.assertEncode('\x87\xff\xff\xff', 0x00FFFFFF, 64*1024)
398
        self.assertEncode('\x8F\x04\x03\x02\x01', 0x01020304, 64*1024)
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
399
400
    def test_encode_no_offset(self):
401
        self.assertEncode('\x90\x01', 0, 1)
402
        self.assertEncode('\x90\x0a', 0, 10)
403
        self.assertEncode('\x90\xff', 0, 255)
404
        self.assertEncode('\xA0\x01', 0, 256)
405
        self.assertEncode('\xB0\x01\x01', 0, 257)
406
        self.assertEncode('\xB0\xff\xff', 0, 0xFFFF)
407
        # Special case, if copy == 64KiB, then we store exactly 0
408
        # Note that this puns with a copy of exactly 0 bytes, but we don't care
409
        # about that, as we would never actually copy 0 bytes
410
        self.assertEncode('\x80', 0, 64*1024)
411
412
    def test_encode(self):
413
        self.assertEncode('\x91\x01\x01', 1, 1)
414
        self.assertEncode('\x91\x09\x0a', 9, 10)
415
        self.assertEncode('\x91\xfe\xff', 254, 255)
416
        self.assertEncode('\xA2\x02\x01', 512, 256)
417
        self.assertEncode('\xB3\x02\x01\x01\x01', 258, 257)
418
        self.assertEncode('\xB0\x01\x01', 0, 257)
419
        # Special case, if copy == 64KiB, then we store exactly 0
420
        # Note that this puns with a copy of exactly 0 bytes, but we don't care
421
        # about that, as we would never actually copy 0 bytes
422
        self.assertEncode('\x81\x0a', 10, 64*1024)
423
424
    def test_decode_no_length(self):
425
        # If length is 0, it is interpreted as 64KiB
426
        # The shortest possible instruction is a copy of 64KiB from offset 0
427
        self.assertDecode(0, 65536, 1, '\x80', 0)
428
        self.assertDecode(1, 65536, 2, '\x81\x01', 0)
429
        self.assertDecode(10, 65536, 2, '\x81\x0a', 0)
430
        self.assertDecode(255, 65536, 2, '\x81\xff', 0)
431
        self.assertDecode(256, 65536, 2, '\x82\x01', 0)
432
        self.assertDecode(257, 65536, 3, '\x83\x01\x01', 0)
433
        self.assertDecode(0xFFFFFFFF, 65536, 5, '\x8F\xff\xff\xff\xff', 0)
434
        self.assertDecode(0xFFFFFF00, 65536, 4, '\x8E\xff\xff\xff', 0)
435
        self.assertDecode(0xFFFF00FF, 65536, 4, '\x8D\xff\xff\xff', 0)
436
        self.assertDecode(0xFF00FFFF, 65536, 4, '\x8B\xff\xff\xff', 0)
437
        self.assertDecode(0x00FFFFFF, 65536, 4, '\x87\xff\xff\xff', 0)
438
        self.assertDecode(0x01020304, 65536, 5, '\x8F\x04\x03\x02\x01', 0)
439
440
    def test_decode_no_offset(self):
441
        self.assertDecode(0, 1, 2, '\x90\x01', 0)
442
        self.assertDecode(0, 10, 2, '\x90\x0a', 0)
443
        self.assertDecode(0, 255, 2, '\x90\xff', 0)
444
        self.assertDecode(0, 256, 2, '\xA0\x01', 0)
445
        self.assertDecode(0, 257, 3, '\xB0\x01\x01', 0)
446
        self.assertDecode(0, 65535, 3, '\xB0\xff\xff', 0)
447
        # Special case, if copy == 64KiB, then we store exactly 0
448
        # Note that this puns with a copy of exactly 0 bytes, but we don't care
449
        # about that, as we would never actually copy 0 bytes
450
        self.assertDecode(0, 65536, 1, '\x80', 0)
451
452
    def test_decode(self):
453
        self.assertDecode(1, 1, 3, '\x91\x01\x01', 0)
454
        self.assertDecode(9, 10, 3, '\x91\x09\x0a', 0)
455
        self.assertDecode(254, 255, 3, '\x91\xfe\xff', 0)
456
        self.assertDecode(512, 256, 3, '\xA2\x02\x01', 0)
457
        self.assertDecode(258, 257, 5, '\xB3\x02\x01\x01\x01', 0)
458
        self.assertDecode(0, 257, 3, '\xB0\x01\x01', 0)
459
460
    def test_decode_not_start(self):
461
        self.assertDecode(1, 1, 6, 'abc\x91\x01\x01def', 3)
462
        self.assertDecode(9, 10, 5, 'ab\x91\x09\x0ade', 2)
463
        self.assertDecode(254, 255, 6, 'not\x91\xfe\xffcopy', 3)
464
465
466
class TestBase128Int(tests.TestCase):
467
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
468
    scenarios = module_scenarios()
469
3735.40.16 by John Arbash Meinel
Implement (de|en)code_base128_int in pyrex.
470
    _gc_module = None # Set by load_tests
471
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
472
    def assertEqualEncode(self, bytes, val):
3735.40.16 by John Arbash Meinel
Implement (de|en)code_base128_int in pyrex.
473
        self.assertEqual(bytes, self._gc_module.encode_base128_int(val))
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
474
475
    def assertEqualDecode(self, val, num_decode, bytes):
476
        self.assertEqual((val, num_decode),
3735.40.16 by John Arbash Meinel
Implement (de|en)code_base128_int in pyrex.
477
                         self._gc_module.decode_base128_int(bytes))
3735.40.11 by John Arbash Meinel
Implement make_delta and apply_delta.
478
479
    def test_encode(self):
480
        self.assertEqualEncode('\x01', 1)
481
        self.assertEqualEncode('\x02', 2)
482
        self.assertEqualEncode('\x7f', 127)
483
        self.assertEqualEncode('\x80\x01', 128)
484
        self.assertEqualEncode('\xff\x01', 255)
485
        self.assertEqualEncode('\x80\x02', 256)
486
        self.assertEqualEncode('\xff\xff\xff\xff\x0f', 0xFFFFFFFF)
487
488
    def test_decode(self):
489
        self.assertEqualDecode(1, 1, '\x01')
490
        self.assertEqualDecode(2, 1, '\x02')
491
        self.assertEqualDecode(127, 1, '\x7f')
492
        self.assertEqualDecode(128, 2, '\x80\x01')
493
        self.assertEqualDecode(255, 2, '\xff\x01')
494
        self.assertEqualDecode(256, 2, '\x80\x02')
495
        self.assertEqualDecode(0xFFFFFFFF, 5, '\xff\xff\xff\xff\x0f')
496
497
    def test_decode_with_trailing_bytes(self):
498
        self.assertEqualDecode(1, 1, '\x01abcdef')
499
        self.assertEqualDecode(127, 1, '\x7f\x01')
500
        self.assertEqualDecode(128, 2, '\x80\x01abcdef')
501
        self.assertEqualDecode(255, 2, '\xff\x01\xff')
502
503