/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
1
# Copyright (C) 2008, 2009 Canonical Ltd
2
#
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
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.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
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.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
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.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
16
17
"""Tests for group compression."""
18
19
import zlib
20
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
21
from bzrlib import (
22
    groupcompress,
23
    tests,
24
    )
0.23.58 by John Arbash Meinel
fix up the failing tests.
25
from bzrlib.osutils import sha_string
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
26
from bzrlib.tests import (
27
    TestCaseWithTransport,
0.17.42 by Robert Collins
Handle bzr.dev changes.
28
    multiply_tests,
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
29
    )
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
30
31
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
32
33
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
34
class TestGroupCompressor(tests.TestCase):
0.17.2 by Robert Collins
Core proof of concept working.
35
    """Tests for GroupCompressor"""
36
37
    def test_empty_delta(self):
38
        compressor = groupcompress.GroupCompressor(True)
39
        self.assertEqual([], compressor.lines)
40
41
    def test_one_nosha_delta(self):
42
        # diff against NUKK
43
        compressor = groupcompress.GroupCompressor(True)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
44
        sha1, end_point, _, _ = compressor.compress(('label',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
45
            'strange\ncommon\n', None)
46
        self.assertEqual(sha_string('strange\ncommon\n'), sha1)
0.17.2 by Robert Collins
Core proof of concept working.
47
        expected_lines = [
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
48
            'f', '\x0f', 'strange\ncommon\n',
0.17.2 by Robert Collins
Core proof of concept working.
49
            ]
50
        self.assertEqual(expected_lines, compressor.lines)
51
        self.assertEqual(sum(map(len, expected_lines)), end_point)
52
0.23.58 by John Arbash Meinel
fix up the failing tests.
53
    def _chunks_to_repr_lines(self, chunks):
54
        return '\n'.join(map(repr, ''.join(chunks).split('\n')))
55
56
    def assertEqualDiffEncoded(self, expected, actual):
57
        """Compare the actual content to the expected content.
58
59
        :param expected: A group of chunks that we expect to see
60
        :param actual: The measured 'chunks'
61
62
        We will transform the chunks back into lines, and then run 'repr()'
63
        over them to handle non-ascii characters.
64
        """
65
        self.assertEqualDiff(self._chunks_to_repr_lines(expected),
66
                             self._chunks_to_repr_lines(actual))
67
0.17.2 by Robert Collins
Core proof of concept working.
68
    def test_two_nosha_delta(self):
69
        compressor = groupcompress.GroupCompressor(True)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
70
        sha1_1, _, _, _ = compressor.compress(('label',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
71
            '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.
72
        expected_lines = list(compressor.lines)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
73
        sha1_2, end_point, _, _ = compressor.compress(('newlabel',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
74
            'common long line\nthat needs a 16 byte match\ndifferent\n', None)
75
        self.assertEqual(sha_string('common long line\n'
76
                                    'that needs a 16 byte match\n'
77
                                    'different\n'), sha1_2)
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
78
        expected_lines.extend([
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
79
            # 'delta', delta length
80
            'd\x10',
0.23.58 by John Arbash Meinel
fix up the failing tests.
81
            # source and target length
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
82
            '\x36\x36',
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
83
            # copy the line common
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
84
            '\x91\x0a\x2c', #copy, offset 0x0a, len 0x2c
0.20.17 by John Arbash Meinel
Fix the test suite now that we don't match short lines
85
            # add the line different, and the trailing newline
0.23.58 by John Arbash Meinel
fix up the failing tests.
86
            '\x0adifferent\n', # insert 10 bytes
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
87
            ])
0.23.58 by John Arbash Meinel
fix up the failing tests.
88
        self.assertEqualDiffEncoded(expected_lines, compressor.lines)
0.17.2 by Robert Collins
Core proof of concept working.
89
        self.assertEqual(sum(map(len, expected_lines)), end_point)
90
91
    def test_three_nosha_delta(self):
92
        # The first interesting test: make a change that should use lines from
93
        # both parents.
94
        compressor = groupcompress.GroupCompressor(True)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
95
        sha1_1, end_point, _, _ = compressor.compress(('label',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
96
            'strange\ncommon very very long line\nwith some extra text\n', None)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
97
        sha1_2, _, _, _ = compressor.compress(('newlabel',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
98
            '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.
99
        expected_lines = list(compressor.lines)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
100
        sha1_3, end_point, _, _ = compressor.compress(('label3',),
0.23.58 by John Arbash Meinel
fix up the failing tests.
101
            'new\ncommon very very long line\nwith some extra text\n'
102
            '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
103
            None)
0.17.2 by Robert Collins
Core proof of concept working.
104
        self.assertEqual(
0.23.58 by John Arbash Meinel
fix up the failing tests.
105
            sha_string('new\ncommon very very long line\nwith some extra text\n'
106
                       'different\nmoredifferent\nand then some more\n'),
0.17.2 by Robert Collins
Core proof of concept working.
107
            sha1_3)
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
108
        expected_lines.extend([
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
109
            # 'delta', delta length
110
            'd\x0c',
111
            # source and target length
112
            '\x67\x5f'
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
113
            # insert new
0.23.58 by John Arbash Meinel
fix up the failing tests.
114
            '\x03new',
115
            # Copy of first parent 'common' range
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
116
            '\x91\x09\x31' # copy, offset 0x09, 0x31 bytes
0.23.58 by John Arbash Meinel
fix up the failing tests.
117
            # Copy of second parent 'different' range
0.17.36 by John Arbash Meinel
Adding a mini-len to the delta/fulltext bytes
118
            '\x91\x3c\x2b' # copy, offset 0x3c, 0x2b bytes
0.17.3 by Robert Collins
new encoder, allows non monotonically increasing sequence matches for moar compression.
119
            ])
0.23.58 by John Arbash Meinel
fix up the failing tests.
120
        self.assertEqualDiffEncoded(expected_lines, compressor.lines)
0.17.2 by Robert Collins
Core proof of concept working.
121
        self.assertEqual(sum(map(len, expected_lines)), end_point)
122
123
    def test_stats(self):
124
        compressor = groupcompress.GroupCompressor(True)
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
125
        compressor.compress(('label',), 'strange\ncommon long line\n'
126
                                        'plus more text\n', None)
0.17.2 by Robert Collins
Core proof of concept working.
127
        compressor.compress(('newlabel',),
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
128
                            'common long line\nplus more text\n'
129
                            'different\nmoredifferent\n', None)
0.17.2 by Robert Collins
Core proof of concept working.
130
        compressor.compress(('label3',),
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
131
                            'new\ncommon long line\nplus more text\n'
132
                            '\ndifferent\nmoredifferent\n', None)
133
        self.assertAlmostEqual(1.4, compressor.ratio(), 1)
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
134
135
    def test_extract_from_compressor(self):
136
        # Knit fetching will try to reconstruct texts locally which results in
137
        # reading something that is in the compressor stream already.
138
        compressor = groupcompress.GroupCompressor(True)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
139
        sha1_1, _, _, _ = compressor.compress(('label',),
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
140
            'strange\ncommon long line\nthat needs a 16 byte match\n', None)
141
        expected_lines = list(compressor.lines)
0.25.10 by John Arbash Meinel
Play around with detecting compression breaks.
142
        sha1_2, end_point, _, _ = compressor.compress(('newlabel',),
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
143
            '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.
144
        # get the first out
0.25.8 by John Arbash Meinel
Fix up the tests. Mostly it was just changing things to
145
        self.assertEqual(('strange\ncommon long line\n'
146
                          '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.
147
            compressor.extract(('label',)))
148
        # and the second
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
149
        self.assertEqual(('common long line\nthat needs a 16 byte match\n'
150
                          'different\n', sha1_2),
151
                         compressor.extract(('newlabel',)))
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
152
153
0.25.3 by John Arbash Meinel
Add a encode/decode base128 functions.
154
class TestBase128Int(tests.TestCase):
155
156
    def assertEqualEncode(self, bytes, val):
157
        self.assertEqual(bytes, groupcompress.encode_base128_int(val))
158
159
    def assertEqualDecode(self, val, num_decode, bytes):
160
        self.assertEqual((val, num_decode),
161
                         groupcompress.decode_base128_int(bytes))
162
163
    def test_encode(self):
164
        self.assertEqualEncode('\x01', 1)
165
        self.assertEqualEncode('\x02', 2)
166
        self.assertEqualEncode('\x7f', 127)
167
        self.assertEqualEncode('\x80\x01', 128)
168
        self.assertEqualEncode('\xff\x01', 255)
169
        self.assertEqualEncode('\x80\x02', 256)
170
        self.assertEqualEncode('\xff\xff\xff\xff\x0f', 0xFFFFFFFF)
171
172
    def test_decode(self):
173
        self.assertEqualDecode(1, 1, '\x01')
174
        self.assertEqualDecode(2, 1, '\x02')
175
        self.assertEqualDecode(127, 1, '\x7f')
176
        self.assertEqualDecode(128, 2, '\x80\x01')
177
        self.assertEqualDecode(255, 2, '\xff\x01')
178
        self.assertEqualDecode(256, 2, '\x80\x02')
179
        self.assertEqualDecode(0xFFFFFFFF, 5, '\xff\xff\xff\xff\x0f')
180
181
    def test_decode_with_trailing_bytes(self):
182
        self.assertEqualDecode(1, 1, '\x01abcdef')
183
        self.assertEqualDecode(127, 1, '\x7f\x01')
184
        self.assertEqualDecode(128, 2, '\x80\x01abcdef')
185
        self.assertEqualDecode(255, 2, '\xff\x01\xff')
186
187
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
188
class TestGroupCompressBlock(tests.TestCase):
189
190
    def test_from_empty_bytes(self):
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
191
        self.assertRaises(ValueError,
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
192
                          groupcompress.GroupCompressBlock.from_bytes, '')
193
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
194
    def test_from_minimal_bytes(self):
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
195
        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.
196
        self.assertIsInstance(block, groupcompress.GroupCompressBlock)
197
        self.assertEqual({}, block._entries)
198
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
199
    def test_from_bytes(self):
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
200
        z_header_bytes = (
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
201
            'gcb1z\n' # group compress block v1 plain
202
            '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.
203
            '183\n' # Length of all meta-info
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
204
            + zlib.compress(
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
205
            'key:bing\n'
206
            'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
207
            'type:fulltext\n'
208
            'start:100\n'
209
            'length:100\n'
210
            '\n'
211
            'key:foo\x00bar\n'
212
            'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
213
            'type:fulltext\n'
214
            'start:0\n'
215
            'length:100\n'
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
216
            '\n'))
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
217
        block = groupcompress.GroupCompressBlock.from_bytes(
218
            z_header_bytes)
219
        self.assertIs(None, block._content)
220
        self.assertIsInstance(block, groupcompress.GroupCompressBlock)
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
221
        self.assertEqual([('bing',), ('foo', 'bar')], sorted(block._entries))
222
        bing = block._entries[('bing',)]
223
        self.assertEqual(('bing',), bing.key)
224
        self.assertEqual('fulltext', bing.type)
225
        self.assertEqual('abcd'*10, bing.sha1)
226
        self.assertEqual(100, bing.start)
227
        self.assertEqual(100, bing.length)
228
        foobar = block._entries[('foo', 'bar')]
229
        self.assertEqual(('foo', 'bar'), foobar.key)
230
        self.assertEqual('fulltext', foobar.type)
231
        self.assertEqual('abcd'*10, foobar.sha1)
232
        self.assertEqual(0, foobar.start)
233
        self.assertEqual(100, foobar.length)
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
234
235
    def test_add_entry(self):
236
        gcb = groupcompress.GroupCompressBlock()
237
        e = gcb.add_entry(('foo', 'bar'), 'fulltext', 'abcd'*10, 0, 100)
238
        self.assertIsInstance(e, groupcompress.GroupCompressBlockEntry)
239
        self.assertEqual(('foo', 'bar'), e.key)
240
        self.assertEqual('fulltext', e.type)
241
        self.assertEqual('abcd'*10, e.sha1)
242
        self.assertEqual(0, e.start)
243
        self.assertEqual(100, e.length)
244
245
    def test_to_bytes(self):
246
        gcb = groupcompress.GroupCompressBlock()
247
        gcb.add_entry(('foo', 'bar'), 'fulltext', 'abcd'*10, 0, 100)
248
        gcb.add_entry(('bing',), 'fulltext', 'abcd'*10, 100, 100)
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
249
        bytes = gcb.to_bytes()
250
        self.assertStartsWith(bytes,
251
                              'gcb1z\n' # group compress block v1 zlib
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
252
                              '76\n' # Length of compressed bytes
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
253
                              '183\n' # Length of all meta-info
254
                             )
255
        remaining_bytes = bytes[13:]
256
        raw_bytes = zlib.decompress(remaining_bytes)
257
        self.assertEqualDiff('key:bing\n'
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
258
                             'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
259
                             'type:fulltext\n'
260
                             'start:100\n'
261
                             'length:100\n'
262
                             '\n'
263
                             'key:foo\x00bar\n'
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
264
                             'sha1:abcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\n'
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
265
                             'type:fulltext\n'
266
                             'start:0\n'
267
                             'length:100\n'
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
268
                             '\n', raw_bytes)