/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
1
# groupcompress, a bzr plugin providing new compression logic.
2
# Copyright (C) 2008 Canonical Limited.
3
# 
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License version 2 as published
6
# by the Free Software Foundation.
7
# 
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
# 
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
16
# 
17
18
"""Tests for group compression."""
19
20
import zlib
21
22
from bzrlib import tests
0.23.58 by John Arbash Meinel
fix up the failing tests.
23
from bzrlib.osutils import sha_string
0.17.31 by John Arbash Meinel
Bring in the 'rabin' experiment.
24
from bzrlib.plugins.groupcompress import errors, groupcompress
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
25
from bzrlib.tests import (
26
    TestCaseWithTransport,
27
    TestScenarioApplier,
28
    adapt_tests,
29
    )
30
from bzrlib.transport import get_transport
31
32
33
def load_tests(standard_tests, module, loader):
34
    from bzrlib.tests.test_versionedfile import TestVersionedFiles
35
    vf_interface_tests = loader.loadTestsFromTestCase(TestVersionedFiles)
36
    cleanup_pack_group = groupcompress.cleanup_pack_group
37
    make_pack_factory = groupcompress.make_pack_factory
0.23.9 by John Arbash Meinel
We now basically have full support for using diff-delta as the compressor.
38
    group_scenario = ('groupcompressrabin-nograph', {
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
39
            'cleanup':cleanup_pack_group,
40
            'factory':make_pack_factory(False, False, 1),
41
            'graph': False,
42
            'key_length':1,
0.20.21 by John Arbash Meinel
Merge the chk sorting code.
43
            'support_partial_insertion':False,
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
44
            }
45
        )
46
    applier = TestScenarioApplier()
47
    applier.scenarios = [group_scenario]
48
    adapt_tests(vf_interface_tests, applier, standard_tests)
49
    return standard_tests
50
51
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
52
class TestGroupCompressor(tests.TestCase):
0.17.2 by Robert Collins
Core proof of concept working.
53
    """Tests for GroupCompressor"""
54
55
    def test_empty_delta(self):
56
        compressor = groupcompress.GroupCompressor(True)
57
        self.assertEqual([], compressor.lines)
58
59
    def test_one_nosha_delta(self):
60
        # diff against NUKK
61
        compressor = groupcompress.GroupCompressor(True)
62
        sha1, end_point = compressor.compress(('label',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
63
            'strange\ncommon\n', None)
64
        self.assertEqual(sha_string('strange\ncommon\n'), sha1)
0.17.2 by Robert Collins
Core proof of concept working.
65
        expected_lines = [
0.23.27 by John Arbash Meinel
Fix up some failing tests.
66
            'strange\ncommon\n',
0.17.2 by Robert Collins
Core proof of concept working.
67
            ]
68
        self.assertEqual(expected_lines, compressor.lines)
69
        self.assertEqual(sum(map(len, expected_lines)), end_point)
70
0.23.58 by John Arbash Meinel
fix up the failing tests.
71
    def _chunks_to_repr_lines(self, chunks):
72
        return '\n'.join(map(repr, ''.join(chunks).split('\n')))
73
74
    def assertEqualDiffEncoded(self, expected, actual):
75
        """Compare the actual content to the expected content.
76
77
        :param expected: A group of chunks that we expect to see
78
        :param actual: The measured 'chunks'
79
80
        We will transform the chunks back into lines, and then run 'repr()'
81
        over them to handle non-ascii characters.
82
        """
83
        self.assertEqualDiff(self._chunks_to_repr_lines(expected),
84
                             self._chunks_to_repr_lines(actual))
85
0.17.2 by Robert Collins
Core proof of concept working.
86
    def test_two_nosha_delta(self):
87
        compressor = groupcompress.GroupCompressor(True)
88
        sha1_1, _ = compressor.compress(('label',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
89
            'strange\ncommon long line\nthat needs a 16 byte match\n', None)
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
90
        expected_lines = list(compressor.lines)
0.17.2 by Robert Collins
Core proof of concept working.
91
        sha1_2, end_point = compressor.compress(('newlabel',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
92
            'common long line\nthat needs a 16 byte match\ndifferent\n', None)
93
        self.assertEqual(sha_string('common long line\n'
94
                                    'that needs a 16 byte match\n'
95
                                    'different\n'), sha1_2)
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
96
        expected_lines.extend([
0.23.58 by John Arbash Meinel
fix up the failing tests.
97
            # source and target length
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
98
            '\x34\x36',
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
99
            # copy the line common
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
100
            '\x91\x08\x2c', #copy, offset 0x08, len 0x2c
0.20.17 by John Arbash Meinel
Fix the test suite now that we don't match short lines
101
            # add the line different, and the trailing newline
0.23.58 by John Arbash Meinel
fix up the failing tests.
102
            '\x0adifferent\n', # insert 10 bytes
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
103
            ])
0.23.58 by John Arbash Meinel
fix up the failing tests.
104
        self.assertEqualDiffEncoded(expected_lines, compressor.lines)
0.17.2 by Robert Collins
Core proof of concept working.
105
        self.assertEqual(sum(map(len, expected_lines)), end_point)
106
107
    def test_three_nosha_delta(self):
108
        # The first interesting test: make a change that should use lines from
109
        # both parents.
110
        compressor = groupcompress.GroupCompressor(True)
111
        sha1_1, end_point = compressor.compress(('label',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
112
            'strange\ncommon very very long line\nwith some extra text\n', None)
0.17.2 by Robert Collins
Core proof of concept working.
113
        sha1_2, _ = compressor.compress(('newlabel',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
114
            'different\nmoredifferent\nand then some more\n', None)
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
115
        expected_lines = list(compressor.lines)
0.17.2 by Robert Collins
Core proof of concept working.
116
        sha1_3, end_point = compressor.compress(('label3',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
117
            'new\ncommon very very long line\nwith some extra text\n'
118
            'different\nmoredifferent\nand then some more\n',
0.20.17 by John Arbash Meinel
Fix the test suite now that we don't match short lines
119
            None)
0.17.2 by Robert Collins
Core proof of concept working.
120
        self.assertEqual(
0.23.58 by John Arbash Meinel
fix up the failing tests.
121
            sha_string('new\ncommon very very long line\nwith some extra text\n'
122
                       'different\nmoredifferent\nand then some more\n'),
0.17.2 by Robert Collins
Core proof of concept working.
123
            sha1_3)
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
124
        expected_lines.extend([
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
125
            '\x63\x5f' # source and target length
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
126
            # insert new
0.23.58 by John Arbash Meinel
fix up the failing tests.
127
            '\x03new',
128
            # Copy of first parent 'common' range
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
129
            '\x91\x07\x31' # copy, offset 0x07, 0x31 bytes
0.23.58 by John Arbash Meinel
fix up the failing tests.
130
            # Copy of second parent 'different' range
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
131
            '\x91\x38\x2b' # copy, offset 0x38, 0x2b bytes
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
132
            ])
0.23.58 by John Arbash Meinel
fix up the failing tests.
133
        self.assertEqualDiffEncoded(expected_lines, compressor.lines)
0.17.2 by Robert Collins
Core proof of concept working.
134
        self.assertEqual(sum(map(len, expected_lines)), end_point)
135
136
    def test_stats(self):
137
        compressor = groupcompress.GroupCompressor(True)
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
138
        compressor.compress(('label',), 'strange\ncommon long line\n'
139
                                        'plus more text\n', None)
0.17.2 by Robert Collins
Core proof of concept working.
140
        compressor.compress(('newlabel',),
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
141
                            'common long line\nplus more text\n'
142
                            'different\nmoredifferent\n', None)
0.17.2 by Robert Collins
Core proof of concept working.
143
        compressor.compress(('label3',),
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
144
                            'new\ncommon long line\nplus more text\n'
145
                            '\ndifferent\nmoredifferent\n', None)
146
        self.assertAlmostEqual(1.4, compressor.ratio(), 1)
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
147
148
    def test_extract_from_compressor(self):
149
        # Knit fetching will try to reconstruct texts locally which results in
150
        # reading something that is in the compressor stream already.
151
        compressor = groupcompress.GroupCompressor(True)
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
152
        sha1_1, _ = compressor.compress(('label',),
153
            'strange\ncommon long line\nthat needs a 16 byte match\n', None)
154
        expected_lines = list(compressor.lines)
155
        sha1_2, end_point = compressor.compress(('newlabel',),
156
            'common long line\nthat needs a 16 byte match\ndifferent\n', None)
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
157
        # get the first out
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
158
        self.assertEqual(('strange\ncommon long line\n'
159
                          'that needs a 16 byte match\n', sha1_1),
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
160
            compressor.extract(('label',)))
161
        # and the second
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
162
        self.assertEqual(('common long line\nthat needs a 16 byte match\n'
163
                          'different\n', sha1_2),
164
                         compressor.extract(('newlabel',)))
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
165
166
0.25.3 by John Arbash Meinel
Add a encode/decode base128 functions.
167
class TestBase128Int(tests.TestCase):
168
169
    def assertEqualEncode(self, bytes, val):
170
        self.assertEqual(bytes, groupcompress.encode_base128_int(val))
171
172
    def assertEqualDecode(self, val, num_decode, bytes):
173
        self.assertEqual((val, num_decode),
174
                         groupcompress.decode_base128_int(bytes))
175
176
    def test_encode(self):
177
        self.assertEqualEncode('\x01', 1)
178
        self.assertEqualEncode('\x02', 2)
179
        self.assertEqualEncode('\x7f', 127)
180
        self.assertEqualEncode('\x80\x01', 128)
181
        self.assertEqualEncode('\xff\x01', 255)
182
        self.assertEqualEncode('\x80\x02', 256)
183
        self.assertEqualEncode('\xff\xff\xff\xff\x0f', 0xFFFFFFFF)
184
185
    def test_decode(self):
186
        self.assertEqualDecode(1, 1, '\x01')
187
        self.assertEqualDecode(2, 1, '\x02')
188
        self.assertEqualDecode(127, 1, '\x7f')
189
        self.assertEqualDecode(128, 2, '\x80\x01')
190
        self.assertEqualDecode(255, 2, '\xff\x01')
191
        self.assertEqualDecode(256, 2, '\x80\x02')
192
        self.assertEqualDecode(0xFFFFFFFF, 5, '\xff\xff\xff\xff\x0f')
193
194
    def test_decode_with_trailing_bytes(self):
195
        self.assertEqualDecode(1, 1, '\x01abcdef')
196
        self.assertEqualDecode(127, 1, '\x7f\x01')
197
        self.assertEqualDecode(128, 2, '\x80\x01abcdef')
198
        self.assertEqualDecode(255, 2, '\xff\x01\xff')
199
200
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
201
class TestGroupCompressBlock(tests.TestCase):
202
203
    def test_from_empty_bytes(self):
204
        self.assertRaises(errors.InvalidGroupCompressBlock,
205
                          groupcompress.GroupCompressBlock.from_bytes, '')
206
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
207
    def test_from_minimal_bytes(self):
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
208
        block = groupcompress.GroupCompressBlock.from_bytes('gcb1z\n0\n0\n')
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
209
        self.assertIsInstance(block, groupcompress.GroupCompressBlock)
210
        self.assertEqual({}, block._entries)
211
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
212
    def test_from_bytes(self):
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
213
        z_header_bytes = (
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
214
            'gcb1z\n' # group compress block v1 plain
215
            '76\n' # Length of zlib bytes
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
216
            '183\n' # Length of all meta-info
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
217
            + zlib.compress(
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
218
            'key:bing\n'
219
            'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
220
            'type:fulltext\n'
221
            'start:100\n'
222
            'length:100\n'
223
            '\n'
224
            'key:foo\x00bar\n'
225
            'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
226
            'type:fulltext\n'
227
            'start:0\n'
228
            'length:100\n'
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
229
            '\n'))
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
230
        block = groupcompress.GroupCompressBlock.from_bytes(
231
            z_header_bytes)
232
        self.assertIs(None, block._content)
233
        self.assertIsInstance(block, groupcompress.GroupCompressBlock)
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
234
        self.assertEqual([('bing',), ('foo', 'bar')], sorted(block._entries))
235
        bing = block._entries[('bing',)]
236
        self.assertEqual(('bing',), bing.key)
237
        self.assertEqual('fulltext', bing.type)
238
        self.assertEqual('abcd'*10, bing.sha1)
239
        self.assertEqual(100, bing.start)
240
        self.assertEqual(100, bing.length)
241
        foobar = block._entries[('foo', 'bar')]
242
        self.assertEqual(('foo', 'bar'), foobar.key)
243
        self.assertEqual('fulltext', foobar.type)
244
        self.assertEqual('abcd'*10, foobar.sha1)
245
        self.assertEqual(0, foobar.start)
246
        self.assertEqual(100, foobar.length)
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
247
248
    def test_add_entry(self):
249
        gcb = groupcompress.GroupCompressBlock()
250
        e = gcb.add_entry(('foo', 'bar'), 'fulltext', 'abcd'*10, 0, 100)
251
        self.assertIsInstance(e, groupcompress.GroupCompressBlockEntry)
252
        self.assertEqual(('foo', 'bar'), e.key)
253
        self.assertEqual('fulltext', e.type)
254
        self.assertEqual('abcd'*10, e.sha1)
255
        self.assertEqual(0, e.start)
256
        self.assertEqual(100, e.length)
257
258
    def test_to_bytes(self):
259
        gcb = groupcompress.GroupCompressBlock()
260
        gcb.add_entry(('foo', 'bar'), 'fulltext', 'abcd'*10, 0, 100)
261
        gcb.add_entry(('bing',), 'fulltext', 'abcd'*10, 100, 100)
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
262
        bytes = gcb.to_bytes()
263
        self.assertStartsWith(bytes,
264
                              'gcb1z\n' # group compress block v1 zlib
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
265
                              '77\n' # Length of compressed bytes
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
266
                              '183\n' # Length of all meta-info
267
                             )
268
        remaining_bytes = bytes[13:]
269
        raw_bytes = zlib.decompress(remaining_bytes)
270
        self.assertEqualDiff('key:bing\n'
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
271
                             'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
272
                             'type:fulltext\n'
273
                             'start:100\n'
274
                             'length:100\n'
275
                             '\n'
276
                             'key:foo\x00bar\n'
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
277
                             'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
278
                             'type:fulltext\n'
279
                             'start:0\n'
280
                             'length:100\n'
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
281
                             '\n', raw_bytes)