/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test__groupcompress.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Tests for the python and pyrex extensions of groupcompress"""
18
18
 
19
 
import sys
20
 
 
21
 
from ... import (
 
19
from .. import (
22
20
    tests,
23
21
    )
24
 
from .. import (
 
22
from ..bzr import (
25
23
    _groupcompress_py,
26
24
    )
27
 
from ...tests.scenarios import (
 
25
from .scenarios import (
28
26
    load_tests_apply_scenarios,
29
27
    )
30
 
from ...tests import (
 
28
from . import (
31
29
    features,
32
30
    )
33
31
 
39
37
    if compiled_groupcompress_feature.available():
40
38
        gc_module = compiled_groupcompress_feature.module
41
39
        scenarios.append(('C',
42
 
                          {'_gc_module': gc_module}))
 
40
            {'_gc_module': gc_module}))
43
41
    return scenarios
44
42
 
45
43
 
67
65
compiled_groupcompress_feature = features.ModuleAvailableFeature(
68
66
    'breezy.bzr._groupcompress_pyx')
69
67
 
70
 
_text1 = b"""\
 
68
_text1 = """\
71
69
This is a bit
72
70
of source text
73
71
which is meant to be matched
74
72
against other text
75
73
"""
76
74
 
77
 
_text2 = b"""\
 
75
_text2 = """\
78
76
This is a bit
79
77
of source text
80
78
which is meant to differ from
81
79
against other text
82
80
"""
83
81
 
84
 
_text3 = b"""\
 
82
_text3 = """\
85
83
This is a bit
86
84
of source text
87
85
which is meant to be matched
91
89
at the end of the file
92
90
"""
93
91
 
94
 
_first_text = b"""\
 
92
_first_text = """\
95
93
a bit of text, that
96
94
does not have much in
97
95
common with the next text
98
96
"""
99
97
 
100
 
_second_text = b"""\
 
98
_second_text = """\
101
99
some more bit of text, that
102
100
does not have much in
103
101
common with the previous text
105
103
"""
106
104
 
107
105
 
108
 
_third_text = b"""\
 
106
_third_text = """\
109
107
a bit of text, that
110
108
has some in common with the previous text
111
109
and has some extra text
113
111
common with the next text
114
112
"""
115
113
 
116
 
_fourth_text = b"""\
 
114
_fourth_text = """\
117
115
123456789012345
118
116
same rabin hash
119
117
123456789012345
124
122
same rabin hash
125
123
"""
126
124
 
127
 
 
128
125
class TestMakeAndApplyDelta(tests.TestCase):
129
126
 
130
127
    scenarios = module_scenarios()
131
 
    _gc_module = None  # Set by load_tests
 
128
    _gc_module = None # Set by load_tests
132
129
 
133
130
    def setUp(self):
134
131
        super(TestMakeAndApplyDelta, self).setUp()
137
134
        self.apply_delta_to_source = self._gc_module.apply_delta_to_source
138
135
 
139
136
    def test_make_delta_is_typesafe(self):
140
 
        self.make_delta(b'a string', b'another string')
 
137
        self.make_delta('a string', 'another string')
141
138
 
142
139
        def _check_make_delta(string1, string2):
143
140
            self.assertRaises(TypeError, self.make_delta, string1, string2)
144
141
 
145
 
        _check_make_delta(b'a string', object())
146
 
        _check_make_delta(b'a string', u'not a string')
147
 
        _check_make_delta(object(), b'a string')
148
 
        _check_make_delta(u'not a string', b'a string')
 
142
        _check_make_delta('a string', object())
 
143
        _check_make_delta('a string', u'not a string')
 
144
        _check_make_delta(object(), 'a string')
 
145
        _check_make_delta(u'not a string', 'a string')
149
146
 
150
147
    def test_make_noop_delta(self):
151
148
        ident_delta = self.make_delta(_text1, _text1)
152
 
        self.assertEqual(b'M\x90M', ident_delta)
 
149
        self.assertEqual('M\x90M', ident_delta)
153
150
        ident_delta = self.make_delta(_text2, _text2)
154
 
        self.assertEqual(b'N\x90N', ident_delta)
 
151
        self.assertEqual('N\x90N', ident_delta)
155
152
        ident_delta = self.make_delta(_text3, _text3)
156
 
        self.assertEqual(b'\x87\x01\x90\x87', ident_delta)
 
153
        self.assertEqual('\x87\x01\x90\x87', ident_delta)
157
154
 
158
155
    def assertDeltaIn(self, delta1, delta2, delta):
159
156
        """Make sure that the delta bytes match one of the expectations."""
160
157
        # In general, the python delta matcher gives different results than the
161
158
        # pyrex delta matcher. Both should be valid deltas, though.
162
159
        if delta not in (delta1, delta2):
163
 
            self.fail(b"Delta bytes:\n"
164
 
                      b"       %r\n"
165
 
                      b"not in %r\n"
166
 
                      b"    or %r"
 
160
            self.fail("Delta bytes:\n"
 
161
                      "       %r\n"
 
162
                      "not in %r\n"
 
163
                      "    or %r"
167
164
                      % (delta, delta1, delta2))
168
165
 
169
166
    def test_make_delta(self):
170
167
        delta = self.make_delta(_text1, _text2)
171
168
        self.assertDeltaIn(
172
 
            b'N\x90/\x1fdiffer from\nagainst other text\n',
173
 
            b'N\x90\x1d\x1ewhich is meant to differ from\n\x91:\x13',
 
169
            'N\x90/\x1fdiffer from\nagainst other text\n',
 
170
            'N\x90\x1d\x1ewhich is meant to differ from\n\x91:\x13',
174
171
            delta)
175
172
        delta = self.make_delta(_text2, _text1)
176
173
        self.assertDeltaIn(
177
 
            b'M\x90/\x1ebe matched\nagainst other text\n',
178
 
            b'M\x90\x1d\x1dwhich is meant to be matched\n\x91;\x13',
 
174
            'M\x90/\x1ebe matched\nagainst other text\n',
 
175
            'M\x90\x1d\x1dwhich is meant to be matched\n\x91;\x13',
179
176
            delta)
180
177
        delta = self.make_delta(_text3, _text1)
181
 
        self.assertEqual(b'M\x90M', delta)
 
178
        self.assertEqual('M\x90M', delta)
182
179
        delta = self.make_delta(_text3, _text2)
183
180
        self.assertDeltaIn(
184
 
            b'N\x90/\x1fdiffer from\nagainst other text\n',
185
 
            b'N\x90\x1d\x1ewhich is meant to differ from\n\x91:\x13',
 
181
            'N\x90/\x1fdiffer from\nagainst other text\n',
 
182
            'N\x90\x1d\x1ewhich is meant to differ from\n\x91:\x13',
186
183
            delta)
187
184
 
188
185
    def test_make_delta_with_large_copies(self):
191
188
        big_text = _text3 * 1220
192
189
        delta = self.make_delta(big_text, big_text)
193
190
        self.assertDeltaIn(
194
 
            b'\xdc\x86\x0a'      # Encoding the length of the uncompressed text
195
 
            b'\x80'              # Copy 64kB, starting at byte 0
196
 
            b'\x84\x01'          # and another 64kB starting at 64kB
197
 
            b'\xb4\x02\x5c\x83',  # And the bit of tail.
 
191
            '\xdc\x86\x0a'      # Encoding the length of the uncompressed text
 
192
            '\x80'              # Copy 64kB, starting at byte 0
 
193
            '\x84\x01'          # and another 64kB starting at 64kB
 
194
            '\xb4\x02\x5c\x83', # And the bit of tail.
198
195
            None,   # Both implementations should be identical
199
196
            delta)
200
197
 
201
198
    def test_apply_delta_is_typesafe(self):
202
 
        self.apply_delta(_text1, b'M\x90M')
203
 
        self.assertRaises(TypeError, self.apply_delta, object(), b'M\x90M')
 
199
        self.apply_delta(_text1, 'M\x90M')
 
200
        self.assertRaises(TypeError, self.apply_delta, object(), 'M\x90M')
204
201
        self.assertRaises(TypeError, self.apply_delta,
205
 
                          _text1.decode('latin1'), b'M\x90M')
 
202
                          unicode(_text1), 'M\x90M')
206
203
        self.assertRaises(TypeError, self.apply_delta, _text1, u'M\x90M')
207
204
        self.assertRaises(TypeError, self.apply_delta, _text1, object())
208
205
 
209
206
    def test_apply_delta(self):
210
207
        target = self.apply_delta(_text1,
211
 
                                  b'N\x90/\x1fdiffer from\nagainst other text\n')
 
208
                    'N\x90/\x1fdiffer from\nagainst other text\n')
212
209
        self.assertEqual(_text2, target)
213
210
        target = self.apply_delta(_text2,
214
 
                                  b'M\x90/\x1ebe matched\nagainst other text\n')
 
211
                    'M\x90/\x1ebe matched\nagainst other text\n')
215
212
        self.assertEqual(_text1, target)
216
213
 
217
214
    def test_apply_delta_to_source_is_safe(self):
218
215
        self.assertRaises(TypeError,
219
 
                          self.apply_delta_to_source, object(), 0, 1)
 
216
            self.apply_delta_to_source, object(), 0, 1)
220
217
        self.assertRaises(TypeError,
221
 
                          self.apply_delta_to_source, u'unicode str', 0, 1)
 
218
            self.apply_delta_to_source, u'unicode str', 0, 1)
222
219
        # end > length
223
220
        self.assertRaises(ValueError,
224
 
                          self.apply_delta_to_source, b'foo', 1, 4)
 
221
            self.apply_delta_to_source, 'foo', 1, 4)
225
222
        # start > length
226
223
        self.assertRaises(ValueError,
227
 
                          self.apply_delta_to_source, b'foo', 5, 3)
 
224
            self.apply_delta_to_source, 'foo', 5, 3)
228
225
        # start > end
229
226
        self.assertRaises(ValueError,
230
 
                          self.apply_delta_to_source, b'foo', 3, 2)
 
227
            self.apply_delta_to_source, 'foo', 3, 2)
231
228
 
232
229
    def test_apply_delta_to_source(self):
233
230
        source_and_delta = (_text1
234
 
                            + b'N\x90/\x1fdiffer from\nagainst other text\n')
 
231
                            + 'N\x90/\x1fdiffer from\nagainst other text\n')
235
232
        self.assertEqual(_text2, self.apply_delta_to_source(source_and_delta,
236
 
                                                            len(_text1), len(source_and_delta)))
 
233
                                    len(_text1), len(source_and_delta)))
237
234
 
238
235
 
239
236
class TestMakeAndApplyCompatible(tests.TestCase):
240
237
 
241
238
    scenarios = two_way_scenarios()
242
239
 
243
 
    make_delta = None  # Set by load_tests
244
 
    apply_delta = None  # Set by load_tests
 
240
    make_delta = None # Set by load_tests
 
241
    apply_delta = None # Set by load_tests
245
242
 
246
243
    def assertMakeAndApply(self, source, target):
247
244
        """Assert that generating a delta and applying gives success."""
269
266
        self._gc_module = compiled_groupcompress_feature.module
270
267
 
271
268
    def test_repr(self):
272
 
        di = self._gc_module.DeltaIndex(b'test text\n')
 
269
        di = self._gc_module.DeltaIndex('test text\n')
273
270
        self.assertEqual('DeltaIndex(1, 10)', repr(di))
274
271
 
275
 
    def test_sizeof(self):
276
 
        di = self._gc_module.DeltaIndex()
277
 
        # Exact value will depend on platform but should include sources
278
 
        # source_info is a pointer and two longs so at least 12 bytes
279
 
        lower_bound = di._max_num_sources * 12
280
 
        self.assertGreater(sys.getsizeof(di), lower_bound)
281
 
 
282
272
    def test__dump_no_index(self):
283
273
        di = self._gc_module.DeltaIndex()
284
274
        self.assertEqual(None, di._dump_index())
295
285
        self.assertEqual(68, len(entry_list))
296
286
        just_entries = [(idx, text_offset, hash_val)
297
287
                        for idx, (text_offset, hash_val)
298
 
                        in enumerate(entry_list)
299
 
                        if text_offset != 0 or hash_val != 0]
 
288
                         in enumerate(entry_list)
 
289
                         if text_offset != 0 or hash_val != 0]
300
290
        rabin_hash = self._gc_module._rabin_hash
301
291
        self.assertEqual([(8, 16, rabin_hash(_text1[1:17])),
302
292
                          (25, 48, rabin_hash(_text1[33:49])),
303
293
                          (34, 32, rabin_hash(_text1[17:33])),
304
294
                          (47, 64, rabin_hash(_text1[49:65])),
305
 
                          ], just_entries)
 
295
                         ], just_entries)
306
296
        # This ensures that the hash map points to the location we expect it to
307
297
        for entry_idx, text_offset, hash_val in just_entries:
308
298
            self.assertEqual(entry_idx, hash_list[hash_val & 0xf])
318
308
        self.assertEqual(68, len(entry_list))
319
309
        just_entries = [(idx, text_offset, hash_val)
320
310
                        for idx, (text_offset, hash_val)
321
 
                        in enumerate(entry_list)
322
 
                        if text_offset != 0 or hash_val != 0]
 
311
                         in enumerate(entry_list)
 
312
                         if text_offset != 0 or hash_val != 0]
323
313
        rabin_hash = self._gc_module._rabin_hash
324
314
        self.assertEqual([(8, 16, rabin_hash(_text1[1:17])),
325
 
                          (9, start2 + 16, rabin_hash(_text2[1:17])),
 
315
                          (9, start2+16, rabin_hash(_text2[1:17])),
326
316
                          (25, 48, rabin_hash(_text1[33:49])),
327
 
                          (30, start2 + 64, rabin_hash(_text2[49:65])),
 
317
                          (30, start2+64, rabin_hash(_text2[49:65])),
328
318
                          (34, 32, rabin_hash(_text1[17:33])),
329
 
                          (35, start2 + 32, rabin_hash(_text2[17:33])),
330
 
                          (43, start2 + 48, rabin_hash(_text2[33:49])),
 
319
                          (35, start2+32, rabin_hash(_text2[17:33])),
 
320
                          (43, start2+48, rabin_hash(_text2[33:49])),
331
321
                          (47, 64, rabin_hash(_text1[49:65])),
332
 
                          ], just_entries)
 
322
                         ], just_entries)
333
323
        # Each entry should be in the appropriate hash bucket.
334
324
        for entry_idx, text_offset, hash_val in just_entries:
335
325
            hash_idx = hash_val & 0xf
336
326
            self.assertTrue(
337
 
                hash_list[hash_idx] <= entry_idx < hash_list[hash_idx + 1])
 
327
                hash_list[hash_idx] <= entry_idx < hash_list[hash_idx+1])
338
328
 
339
329
    def test_first_add_source_doesnt_index_until_make_delta(self):
340
330
        di = self._gc_module.DeltaIndex()
345
335
        # generated, and will generate a proper delta
346
336
        delta = di.make_delta(_text2)
347
337
        self.assertTrue(di._has_index())
348
 
        self.assertEqual(b'N\x90/\x1fdiffer from\nagainst other text\n', delta)
 
338
        self.assertEqual('N\x90/\x1fdiffer from\nagainst other text\n', delta)
349
339
 
350
340
    def test_add_source_max_bytes_to_index(self):
351
341
        di = self._gc_module.DeltaIndex()
352
 
        di._max_bytes_to_index = 3 * 16
353
 
        di.add_source(_text1, 0)  # (77 bytes -1) // 3 = 25 byte stride
354
 
        di.add_source(_text3, 3)  # (135 bytes -1) // 3 = 44 byte stride
 
342
        di._max_bytes_to_index = 3*16
 
343
        di.add_source(_text1, 0) # (77 bytes -1) // 3 = 25 byte stride
 
344
        di.add_source(_text3, 3) # (135 bytes -1) // 3 = 44 byte stride
355
345
        start2 = len(_text1) + 3
356
346
        hash_list, entry_list = di._dump_index()
357
347
        self.assertEqual(16, len(hash_list))
358
348
        self.assertEqual(67, len(entry_list))
359
349
        just_entries = sorted([(text_offset, hash_val)
360
350
                               for text_offset, hash_val in entry_list
361
 
                               if text_offset != 0 or hash_val != 0])
 
351
                                if text_offset != 0 or hash_val != 0])
362
352
        rabin_hash = self._gc_module._rabin_hash
363
353
        self.assertEqual([(25, rabin_hash(_text1[10:26])),
364
354
                          (50, rabin_hash(_text1[35:51])),
365
355
                          (75, rabin_hash(_text1[60:76])),
366
 
                          (start2 + 44, rabin_hash(_text3[29:45])),
367
 
                          (start2 + 88, rabin_hash(_text3[73:89])),
368
 
                          (start2 + 132, rabin_hash(_text3[117:133])),
369
 
                          ], just_entries)
 
356
                          (start2+44, rabin_hash(_text3[29:45])),
 
357
                          (start2+88, rabin_hash(_text3[73:89])),
 
358
                          (start2+132, rabin_hash(_text3[117:133])),
 
359
                         ], just_entries)
370
360
 
371
361
    def test_second_add_source_triggers_make_index(self):
372
362
        di = self._gc_module.DeltaIndex()
379
369
    def test_make_delta(self):
380
370
        di = self._gc_module.DeltaIndex(_text1)
381
371
        delta = di.make_delta(_text2)
382
 
        self.assertEqual(b'N\x90/\x1fdiffer from\nagainst other text\n', delta)
 
372
        self.assertEqual('N\x90/\x1fdiffer from\nagainst other text\n', delta)
383
373
 
384
374
    def test_delta_against_multiple_sources(self):
385
375
        di = self._gc_module.DeltaIndex()
391
381
        delta = di.make_delta(_third_text)
392
382
        result = self._gc_module.apply_delta(_first_text + _second_text, delta)
393
383
        self.assertEqualDiff(_third_text, result)
394
 
        self.assertEqual(b'\x85\x01\x90\x14\x0chas some in '
395
 
                         b'\x91v6\x03and\x91d"\x91:\n', delta)
 
384
        self.assertEqual('\x85\x01\x90\x14\x0chas some in '
 
385
                         '\x91v6\x03and\x91d"\x91:\n', delta)
396
386
 
397
387
    def test_delta_with_offsets(self):
398
388
        di = self._gc_module.DeltaIndex()
404
394
        delta = di.make_delta(_third_text)
405
395
        self.assertIsNot(None, delta)
406
396
        result = self._gc_module.apply_delta(
407
 
            b'12345' + _first_text + b'1234567890' + _second_text, delta)
 
397
            '12345' + _first_text + '1234567890' + _second_text, delta)
408
398
        self.assertIsNot(None, result)
409
399
        self.assertEqualDiff(_third_text, result)
410
 
        self.assertEqual(b'\x85\x01\x91\x05\x14\x0chas some in '
411
 
                         b'\x91\x856\x03and\x91s"\x91?\n', delta)
 
400
        self.assertEqual('\x85\x01\x91\x05\x14\x0chas some in '
 
401
                         '\x91\x856\x03and\x91s"\x91?\n', delta)
412
402
 
413
403
    def test_delta_with_delta_bytes(self):
414
404
        di = self._gc_module.DeltaIndex()
416
406
        di.add_source(_first_text, 0)
417
407
        self.assertEqual(len(_first_text), di._source_offset)
418
408
        delta = di.make_delta(_second_text)
419
 
        self.assertEqual(b'h\tsome more\x91\x019'
420
 
                         b'&previous text\nand has some extra text\n', delta)
 
409
        self.assertEqual('h\tsome more\x91\x019'
 
410
                         '&previous text\nand has some extra text\n', delta)
421
411
        di.add_delta_source(delta, 0)
422
412
        source += delta
423
413
        self.assertEqual(len(_first_text) + len(delta), di._source_offset)
429
419
        # Note that we don't match the 'common with the', because it isn't long
430
420
        # enough to match in the original text, and those bytes are not present
431
421
        # in the delta for the second text.
432
 
        self.assertEqual(b'\x85\x01\x90\x14\x1chas some in common with the '
433
 
                         b'\x91S&\x03and\x91\x18,', second_delta)
 
422
        self.assertEqual('\x85\x01\x90\x14\x1chas some in common with the '
 
423
                         '\x91S&\x03and\x91\x18,', second_delta)
434
424
        # Add this delta, and create a new delta for the same text. We should
435
425
        # find the remaining text, and only insert the short 'and' text.
436
426
        di.add_delta_source(second_delta, 0)
438
428
        third_delta = di.make_delta(_third_text)
439
429
        result = self._gc_module.apply_delta(source, third_delta)
440
430
        self.assertEqualDiff(_third_text, result)
441
 
        self.assertEqual(b'\x85\x01\x90\x14\x91\x7e\x1c'
442
 
                         b'\x91S&\x03and\x91\x18,', third_delta)
 
431
        self.assertEqual('\x85\x01\x90\x14\x91\x7e\x1c'
 
432
                         '\x91S&\x03and\x91\x18,', third_delta)
443
433
        # Now create a delta, which we know won't be able to be 'fit' into the
444
434
        # existing index
445
435
        fourth_delta = di.make_delta(_fourth_text)
446
436
        self.assertEqual(_fourth_text,
447
437
                         self._gc_module.apply_delta(source, fourth_delta))
448
 
        self.assertEqual(b'\x80\x01'
449
 
                         b'\x7f123456789012345\nsame rabin hash\n'
450
 
                         b'123456789012345\nsame rabin hash\n'
451
 
                         b'123456789012345\nsame rabin hash\n'
452
 
                         b'123456789012345\nsame rabin hash'
453
 
                         b'\x01\n', fourth_delta)
 
438
        self.assertEqual('\x80\x01'
 
439
                         '\x7f123456789012345\nsame rabin hash\n'
 
440
                         '123456789012345\nsame rabin hash\n'
 
441
                         '123456789012345\nsame rabin hash\n'
 
442
                         '123456789012345\nsame rabin hash'
 
443
                         '\x01\n', fourth_delta)
454
444
        di.add_delta_source(fourth_delta, 0)
455
445
        source += fourth_delta
456
446
        # With the next delta, everything should be found
457
447
        fifth_delta = di.make_delta(_fourth_text)
458
448
        self.assertEqual(_fourth_text,
459
449
                         self._gc_module.apply_delta(source, fifth_delta))
460
 
        self.assertEqual(b'\x80\x01\x91\xa7\x7f\x01\n', fifth_delta)
 
450
        self.assertEqual('\x80\x01\x91\xa7\x7f\x01\n', fifth_delta)
461
451
 
462
452
 
463
453
class TestCopyInstruction(tests.TestCase):
464
454
 
465
455
    def assertEncode(self, expected, offset, length):
466
 
        data = _groupcompress_py.encode_copy_instruction(offset, length)
467
 
        self.assertEqual(expected, data)
 
456
        bytes = _groupcompress_py.encode_copy_instruction(offset, length)
 
457
        if expected != bytes:
 
458
            self.assertEqual([hex(ord(e)) for e in expected],
 
459
                             [hex(ord(b)) for b in bytes])
468
460
 
469
 
    def assertDecode(self, exp_offset, exp_length, exp_newpos, data, pos):
470
 
        cmd = data[pos]
 
461
    def assertDecode(self, exp_offset, exp_length, exp_newpos, bytes, pos):
 
462
        cmd = ord(bytes[pos])
471
463
        pos += 1
472
 
        out = _groupcompress_py.decode_copy_instruction(data, cmd, pos)
 
464
        out = _groupcompress_py.decode_copy_instruction(bytes, cmd, pos)
473
465
        self.assertEqual((exp_offset, exp_length, exp_newpos), out)
474
466
 
475
467
    def test_encode_no_length(self):
476
 
        self.assertEncode(b'\x80', 0, 64 * 1024)
477
 
        self.assertEncode(b'\x81\x01', 1, 64 * 1024)
478
 
        self.assertEncode(b'\x81\x0a', 10, 64 * 1024)
479
 
        self.assertEncode(b'\x81\xff', 255, 64 * 1024)
480
 
        self.assertEncode(b'\x82\x01', 256, 64 * 1024)
481
 
        self.assertEncode(b'\x83\x01\x01', 257, 64 * 1024)
482
 
        self.assertEncode(b'\x8F\xff\xff\xff\xff', 0xFFFFFFFF, 64 * 1024)
483
 
        self.assertEncode(b'\x8E\xff\xff\xff', 0xFFFFFF00, 64 * 1024)
484
 
        self.assertEncode(b'\x8D\xff\xff\xff', 0xFFFF00FF, 64 * 1024)
485
 
        self.assertEncode(b'\x8B\xff\xff\xff', 0xFF00FFFF, 64 * 1024)
486
 
        self.assertEncode(b'\x87\xff\xff\xff', 0x00FFFFFF, 64 * 1024)
487
 
        self.assertEncode(b'\x8F\x04\x03\x02\x01', 0x01020304, 64 * 1024)
 
468
        self.assertEncode('\x80', 0, 64*1024)
 
469
        self.assertEncode('\x81\x01', 1, 64*1024)
 
470
        self.assertEncode('\x81\x0a', 10, 64*1024)
 
471
        self.assertEncode('\x81\xff', 255, 64*1024)
 
472
        self.assertEncode('\x82\x01', 256, 64*1024)
 
473
        self.assertEncode('\x83\x01\x01', 257, 64*1024)
 
474
        self.assertEncode('\x8F\xff\xff\xff\xff', 0xFFFFFFFF, 64*1024)
 
475
        self.assertEncode('\x8E\xff\xff\xff', 0xFFFFFF00, 64*1024)
 
476
        self.assertEncode('\x8D\xff\xff\xff', 0xFFFF00FF, 64*1024)
 
477
        self.assertEncode('\x8B\xff\xff\xff', 0xFF00FFFF, 64*1024)
 
478
        self.assertEncode('\x87\xff\xff\xff', 0x00FFFFFF, 64*1024)
 
479
        self.assertEncode('\x8F\x04\x03\x02\x01', 0x01020304, 64*1024)
488
480
 
489
481
    def test_encode_no_offset(self):
490
 
        self.assertEncode(b'\x90\x01', 0, 1)
491
 
        self.assertEncode(b'\x90\x0a', 0, 10)
492
 
        self.assertEncode(b'\x90\xff', 0, 255)
493
 
        self.assertEncode(b'\xA0\x01', 0, 256)
494
 
        self.assertEncode(b'\xB0\x01\x01', 0, 257)
495
 
        self.assertEncode(b'\xB0\xff\xff', 0, 0xFFFF)
 
482
        self.assertEncode('\x90\x01', 0, 1)
 
483
        self.assertEncode('\x90\x0a', 0, 10)
 
484
        self.assertEncode('\x90\xff', 0, 255)
 
485
        self.assertEncode('\xA0\x01', 0, 256)
 
486
        self.assertEncode('\xB0\x01\x01', 0, 257)
 
487
        self.assertEncode('\xB0\xff\xff', 0, 0xFFFF)
496
488
        # Special case, if copy == 64KiB, then we store exactly 0
497
489
        # Note that this puns with a copy of exactly 0 bytes, but we don't care
498
490
        # about that, as we would never actually copy 0 bytes
499
 
        self.assertEncode(b'\x80', 0, 64 * 1024)
 
491
        self.assertEncode('\x80', 0, 64*1024)
500
492
 
501
493
    def test_encode(self):
502
 
        self.assertEncode(b'\x91\x01\x01', 1, 1)
503
 
        self.assertEncode(b'\x91\x09\x0a', 9, 10)
504
 
        self.assertEncode(b'\x91\xfe\xff', 254, 255)
505
 
        self.assertEncode(b'\xA2\x02\x01', 512, 256)
506
 
        self.assertEncode(b'\xB3\x02\x01\x01\x01', 258, 257)
507
 
        self.assertEncode(b'\xB0\x01\x01', 0, 257)
 
494
        self.assertEncode('\x91\x01\x01', 1, 1)
 
495
        self.assertEncode('\x91\x09\x0a', 9, 10)
 
496
        self.assertEncode('\x91\xfe\xff', 254, 255)
 
497
        self.assertEncode('\xA2\x02\x01', 512, 256)
 
498
        self.assertEncode('\xB3\x02\x01\x01\x01', 258, 257)
 
499
        self.assertEncode('\xB0\x01\x01', 0, 257)
508
500
        # Special case, if copy == 64KiB, then we store exactly 0
509
501
        # Note that this puns with a copy of exactly 0 bytes, but we don't care
510
502
        # about that, as we would never actually copy 0 bytes
511
 
        self.assertEncode(b'\x81\x0a', 10, 64 * 1024)
 
503
        self.assertEncode('\x81\x0a', 10, 64*1024)
512
504
 
513
505
    def test_decode_no_length(self):
514
506
        # If length is 0, it is interpreted as 64KiB
515
507
        # The shortest possible instruction is a copy of 64KiB from offset 0
516
 
        self.assertDecode(0, 65536, 1, b'\x80', 0)
517
 
        self.assertDecode(1, 65536, 2, b'\x81\x01', 0)
518
 
        self.assertDecode(10, 65536, 2, b'\x81\x0a', 0)
519
 
        self.assertDecode(255, 65536, 2, b'\x81\xff', 0)
520
 
        self.assertDecode(256, 65536, 2, b'\x82\x01', 0)
521
 
        self.assertDecode(257, 65536, 3, b'\x83\x01\x01', 0)
522
 
        self.assertDecode(0xFFFFFFFF, 65536, 5, b'\x8F\xff\xff\xff\xff', 0)
523
 
        self.assertDecode(0xFFFFFF00, 65536, 4, b'\x8E\xff\xff\xff', 0)
524
 
        self.assertDecode(0xFFFF00FF, 65536, 4, b'\x8D\xff\xff\xff', 0)
525
 
        self.assertDecode(0xFF00FFFF, 65536, 4, b'\x8B\xff\xff\xff', 0)
526
 
        self.assertDecode(0x00FFFFFF, 65536, 4, b'\x87\xff\xff\xff', 0)
527
 
        self.assertDecode(0x01020304, 65536, 5, b'\x8F\x04\x03\x02\x01', 0)
 
508
        self.assertDecode(0, 65536, 1, '\x80', 0)
 
509
        self.assertDecode(1, 65536, 2, '\x81\x01', 0)
 
510
        self.assertDecode(10, 65536, 2, '\x81\x0a', 0)
 
511
        self.assertDecode(255, 65536, 2, '\x81\xff', 0)
 
512
        self.assertDecode(256, 65536, 2, '\x82\x01', 0)
 
513
        self.assertDecode(257, 65536, 3, '\x83\x01\x01', 0)
 
514
        self.assertDecode(0xFFFFFFFF, 65536, 5, '\x8F\xff\xff\xff\xff', 0)
 
515
        self.assertDecode(0xFFFFFF00, 65536, 4, '\x8E\xff\xff\xff', 0)
 
516
        self.assertDecode(0xFFFF00FF, 65536, 4, '\x8D\xff\xff\xff', 0)
 
517
        self.assertDecode(0xFF00FFFF, 65536, 4, '\x8B\xff\xff\xff', 0)
 
518
        self.assertDecode(0x00FFFFFF, 65536, 4, '\x87\xff\xff\xff', 0)
 
519
        self.assertDecode(0x01020304, 65536, 5, '\x8F\x04\x03\x02\x01', 0)
528
520
 
529
521
    def test_decode_no_offset(self):
530
 
        self.assertDecode(0, 1, 2, b'\x90\x01', 0)
531
 
        self.assertDecode(0, 10, 2, b'\x90\x0a', 0)
532
 
        self.assertDecode(0, 255, 2, b'\x90\xff', 0)
533
 
        self.assertDecode(0, 256, 2, b'\xA0\x01', 0)
534
 
        self.assertDecode(0, 257, 3, b'\xB0\x01\x01', 0)
535
 
        self.assertDecode(0, 65535, 3, b'\xB0\xff\xff', 0)
 
522
        self.assertDecode(0, 1, 2, '\x90\x01', 0)
 
523
        self.assertDecode(0, 10, 2, '\x90\x0a', 0)
 
524
        self.assertDecode(0, 255, 2, '\x90\xff', 0)
 
525
        self.assertDecode(0, 256, 2, '\xA0\x01', 0)
 
526
        self.assertDecode(0, 257, 3, '\xB0\x01\x01', 0)
 
527
        self.assertDecode(0, 65535, 3, '\xB0\xff\xff', 0)
536
528
        # Special case, if copy == 64KiB, then we store exactly 0
537
529
        # Note that this puns with a copy of exactly 0 bytes, but we don't care
538
530
        # about that, as we would never actually copy 0 bytes
539
 
        self.assertDecode(0, 65536, 1, b'\x80', 0)
 
531
        self.assertDecode(0, 65536, 1, '\x80', 0)
540
532
 
541
533
    def test_decode(self):
542
 
        self.assertDecode(1, 1, 3, b'\x91\x01\x01', 0)
543
 
        self.assertDecode(9, 10, 3, b'\x91\x09\x0a', 0)
544
 
        self.assertDecode(254, 255, 3, b'\x91\xfe\xff', 0)
545
 
        self.assertDecode(512, 256, 3, b'\xA2\x02\x01', 0)
546
 
        self.assertDecode(258, 257, 5, b'\xB3\x02\x01\x01\x01', 0)
547
 
        self.assertDecode(0, 257, 3, b'\xB0\x01\x01', 0)
 
534
        self.assertDecode(1, 1, 3, '\x91\x01\x01', 0)
 
535
        self.assertDecode(9, 10, 3, '\x91\x09\x0a', 0)
 
536
        self.assertDecode(254, 255, 3, '\x91\xfe\xff', 0)
 
537
        self.assertDecode(512, 256, 3, '\xA2\x02\x01', 0)
 
538
        self.assertDecode(258, 257, 5, '\xB3\x02\x01\x01\x01', 0)
 
539
        self.assertDecode(0, 257, 3, '\xB0\x01\x01', 0)
548
540
 
549
541
    def test_decode_not_start(self):
550
 
        self.assertDecode(1, 1, 6, b'abc\x91\x01\x01def', 3)
551
 
        self.assertDecode(9, 10, 5, b'ab\x91\x09\x0ade', 2)
552
 
        self.assertDecode(254, 255, 6, b'not\x91\xfe\xffcopy', 3)
 
542
        self.assertDecode(1, 1, 6, 'abc\x91\x01\x01def', 3)
 
543
        self.assertDecode(9, 10, 5, 'ab\x91\x09\x0ade', 2)
 
544
        self.assertDecode(254, 255, 6, 'not\x91\xfe\xffcopy', 3)
553
545
 
554
546
 
555
547
class TestBase128Int(tests.TestCase):
556
548
 
557
549
    scenarios = module_scenarios()
558
550
 
559
 
    _gc_module = None  # Set by load_tests
 
551
    _gc_module = None # Set by load_tests
560
552
 
561
553
    def assertEqualEncode(self, bytes, val):
562
554
        self.assertEqual(bytes, self._gc_module.encode_base128_int(val))
566
558
                         self._gc_module.decode_base128_int(bytes))
567
559
 
568
560
    def test_encode(self):
569
 
        self.assertEqualEncode(b'\x01', 1)
570
 
        self.assertEqualEncode(b'\x02', 2)
571
 
        self.assertEqualEncode(b'\x7f', 127)
572
 
        self.assertEqualEncode(b'\x80\x01', 128)
573
 
        self.assertEqualEncode(b'\xff\x01', 255)
574
 
        self.assertEqualEncode(b'\x80\x02', 256)
575
 
        self.assertEqualEncode(b'\xff\xff\xff\xff\x0f', 0xFFFFFFFF)
 
561
        self.assertEqualEncode('\x01', 1)
 
562
        self.assertEqualEncode('\x02', 2)
 
563
        self.assertEqualEncode('\x7f', 127)
 
564
        self.assertEqualEncode('\x80\x01', 128)
 
565
        self.assertEqualEncode('\xff\x01', 255)
 
566
        self.assertEqualEncode('\x80\x02', 256)
 
567
        self.assertEqualEncode('\xff\xff\xff\xff\x0f', 0xFFFFFFFF)
576
568
 
577
569
    def test_decode(self):
578
 
        self.assertEqualDecode(1, 1, b'\x01')
579
 
        self.assertEqualDecode(2, 1, b'\x02')
580
 
        self.assertEqualDecode(127, 1, b'\x7f')
581
 
        self.assertEqualDecode(128, 2, b'\x80\x01')
582
 
        self.assertEqualDecode(255, 2, b'\xff\x01')
583
 
        self.assertEqualDecode(256, 2, b'\x80\x02')
584
 
        self.assertEqualDecode(0xFFFFFFFF, 5, b'\xff\xff\xff\xff\x0f')
 
570
        self.assertEqualDecode(1, 1, '\x01')
 
571
        self.assertEqualDecode(2, 1, '\x02')
 
572
        self.assertEqualDecode(127, 1, '\x7f')
 
573
        self.assertEqualDecode(128, 2, '\x80\x01')
 
574
        self.assertEqualDecode(255, 2, '\xff\x01')
 
575
        self.assertEqualDecode(256, 2, '\x80\x02')
 
576
        self.assertEqualDecode(0xFFFFFFFF, 5, '\xff\xff\xff\xff\x0f')
585
577
 
586
578
    def test_decode_with_trailing_bytes(self):
587
 
        self.assertEqualDecode(1, 1, b'\x01abcdef')
588
 
        self.assertEqualDecode(127, 1, b'\x7f\x01')
589
 
        self.assertEqualDecode(128, 2, b'\x80\x01abcdef')
590
 
        self.assertEqualDecode(255, 2, b'\xff\x01\xff')
 
579
        self.assertEqualDecode(1, 1, '\x01abcdef')
 
580
        self.assertEqualDecode(127, 1, '\x7f\x01')
 
581
        self.assertEqualDecode(128, 2, '\x80\x01abcdef')
 
582
        self.assertEqualDecode(255, 2, '\xff\x01\xff')
 
583
 
 
584