/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: 2018-07-08 14:45:27 UTC
  • mto: This revision was merged to the branch mainline in revision 7036.
  • Revision ID: jelmer@jelmer.uk-20180708144527-codhlvdcdg9y0nji
Fix a bunch of merge tests.

Show diffs side-by-side

added added

removed removed

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