/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_pack.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007 Canonical Ltd
 
1
# Copyright (C) 2007, 2009, 2011, 2012, 2016 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
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
"""Tests for bzrlib.pack."""
18
 
 
19
 
 
20
 
from cStringIO import StringIO
21
 
 
22
 
from bzrlib import pack, errors, tests
 
17
"""Tests for breezy.pack."""
 
18
 
 
19
from .. import errors, tests
 
20
from ..bzr import (
 
21
    pack,
 
22
    )
 
23
from ..sixish import (
 
24
    BytesIO,
 
25
    )
23
26
 
24
27
 
25
28
class TestContainerSerialiser(tests.TestCase):
31
34
 
32
35
    def test_begin(self):
33
36
        serialiser = pack.ContainerSerialiser()
34
 
        self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\n',
 
37
        self.assertEqual(b'Bazaar pack format 1 (introduced in 0.18)\n',
35
38
                         serialiser.begin())
36
39
 
37
40
    def test_end(self):
38
41
        serialiser = pack.ContainerSerialiser()
39
 
        self.assertEqual('E', serialiser.end())
 
42
        self.assertEqual(b'E', serialiser.end())
40
43
 
41
44
    def test_bytes_record_no_name(self):
42
45
        serialiser = pack.ContainerSerialiser()
43
 
        record = serialiser.bytes_record('bytes', [])
44
 
        self.assertEqual('B5\n\nbytes', record)
 
46
        record = serialiser.bytes_record(b'bytes', [])
 
47
        self.assertEqual(b'B5\n\nbytes', record)
45
48
 
46
49
    def test_bytes_record_one_name_with_one_part(self):
47
50
        serialiser = pack.ContainerSerialiser()
48
 
        record = serialiser.bytes_record('bytes', [('name',)])
49
 
        self.assertEqual('B5\nname\n\nbytes', record)
 
51
        record = serialiser.bytes_record(b'bytes', [(b'name',)])
 
52
        self.assertEqual(b'B5\nname\n\nbytes', record)
50
53
 
51
54
    def test_bytes_record_one_name_with_two_parts(self):
52
55
        serialiser = pack.ContainerSerialiser()
53
 
        record = serialiser.bytes_record('bytes', [('part1', 'part2')])
54
 
        self.assertEqual('B5\npart1\x00part2\n\nbytes', record)
 
56
        record = serialiser.bytes_record(b'bytes', [(b'part1', b'part2')])
 
57
        self.assertEqual(b'B5\npart1\x00part2\n\nbytes', record)
55
58
 
56
59
    def test_bytes_record_two_names(self):
57
60
        serialiser = pack.ContainerSerialiser()
58
 
        record = serialiser.bytes_record('bytes', [('name1',), ('name2',)])
59
 
        self.assertEqual('B5\nname1\nname2\n\nbytes', record)
 
61
        record = serialiser.bytes_record(b'bytes', [(b'name1',), (b'name2',)])
 
62
        self.assertEqual(b'B5\nname1\nname2\n\nbytes', record)
60
63
 
61
64
    def test_bytes_record_whitespace_in_name_part(self):
62
65
        serialiser = pack.ContainerSerialiser()
63
66
        self.assertRaises(
64
67
            errors.InvalidRecordError,
65
 
            serialiser.bytes_record, 'bytes', [('bad name',)])
 
68
            serialiser.bytes_record, b'bytes', [(b'bad name',)])
 
69
 
 
70
    def test_bytes_record_header(self):
 
71
        serialiser = pack.ContainerSerialiser()
 
72
        record = serialiser.bytes_header(32, [(b'name1',), (b'name2',)])
 
73
        self.assertEqual(b'B32\nname1\nname2\n\n', record)
66
74
 
67
75
 
68
76
class TestContainerWriter(tests.TestCase):
69
77
 
70
78
    def setUp(self):
71
 
        tests.TestCase.setUp(self)
72
 
        self.output = StringIO()
 
79
        super(TestContainerWriter, self).setUp()
 
80
        self.output = BytesIO()
73
81
        self.writer = pack.ContainerWriter(self.output.write)
74
82
 
75
83
    def assertOutput(self, expected_output):
84
92
        This uses None as the output stream to show that the constructor
85
93
        doesn't try to use the output stream.
86
94
        """
87
 
        writer = pack.ContainerWriter(None)
 
95
        pack.ContainerWriter(None)
88
96
 
89
97
    def test_begin(self):
90
98
        """The begin() method writes the container format marker line."""
91
99
        self.writer.begin()
92
 
        self.assertOutput('Bazaar pack format 1 (introduced in 0.18)\n')
 
100
        self.assertOutput(b'Bazaar pack format 1 (introduced in 0.18)\n')
93
101
 
94
102
    def test_zero_records_written_after_begin(self):
95
103
        """After begin is written, 0 records have been written."""
100
108
        """The end() method writes an End Marker record."""
101
109
        self.writer.begin()
102
110
        self.writer.end()
103
 
        self.assertOutput('Bazaar pack format 1 (introduced in 0.18)\nE')
 
111
        self.assertOutput(b'Bazaar pack format 1 (introduced in 0.18)\nE')
104
112
 
105
113
    def test_empty_end_does_not_add_a_record_to_records_written(self):
106
114
        """The end() method does not count towards the records written."""
111
119
    def test_non_empty_end_does_not_add_a_record_to_records_written(self):
112
120
        """The end() method does not count towards the records written."""
113
121
        self.writer.begin()
114
 
        self.writer.add_bytes_record('foo', names=[])
 
122
        self.writer.add_bytes_record([b'foo'], len(b'foo'), names=[])
115
123
        self.writer.end()
116
124
        self.assertEqual(1, self.writer.records_written)
117
125
 
118
126
    def test_add_bytes_record_no_name(self):
119
127
        """Add a bytes record with no name."""
120
128
        self.writer.begin()
121
 
        offset, length = self.writer.add_bytes_record('abc', names=[])
 
129
        offset, length = self.writer.add_bytes_record([b'abc'], len(b'abc'), names=[])
122
130
        self.assertEqual((42, 7), (offset, length))
123
131
        self.assertOutput(
124
 
            'Bazaar pack format 1 (introduced in 0.18)\nB3\n\nabc')
 
132
            b'Bazaar pack format 1 (introduced in 0.18)\nB3\n\nabc')
125
133
 
126
134
    def test_add_bytes_record_one_name(self):
127
135
        """Add a bytes record with one name."""
128
136
        self.writer.begin()
 
137
 
129
138
        offset, length = self.writer.add_bytes_record(
130
 
            'abc', names=[('name1', )])
 
139
            [b'abc'], len(b'abc'), names=[(b'name1', )])
131
140
        self.assertEqual((42, 13), (offset, length))
132
141
        self.assertOutput(
133
 
            'Bazaar pack format 1 (introduced in 0.18)\n'
134
 
            'B3\nname1\n\nabc')
135
 
 
136
 
    def test_add_bytes_record_two_names(self):
137
 
        """Add a bytes record with two names."""
138
 
        self.writer.begin()
139
 
        offset, length = self.writer.add_bytes_record(
140
 
            'abc', names=[('name1', ), ('name2', )])
141
 
        self.assertEqual((42, 19), (offset, length))
142
 
        self.assertOutput(
143
 
            'Bazaar pack format 1 (introduced in 0.18)\n'
144
 
            'B3\nname1\nname2\n\nabc')
145
 
 
146
 
    def test_add_bytes_record_two_names(self):
147
 
        """Add a bytes record with two names."""
148
 
        self.writer.begin()
149
 
        offset, length = self.writer.add_bytes_record(
150
 
            'abc', names=[('name1', ), ('name2', )])
151
 
        self.assertEqual((42, 19), (offset, length))
152
 
        self.assertOutput(
153
 
            'Bazaar pack format 1 (introduced in 0.18)\n'
154
 
            'B3\nname1\nname2\n\nabc')
 
142
            b'Bazaar pack format 1 (introduced in 0.18)\n'
 
143
            b'B3\nname1\n\nabc')
 
144
 
 
145
    def test_add_bytes_record_split_writes(self):
 
146
        """Write a large record which does multiple IOs"""
 
147
 
 
148
        writes = []
 
149
        real_write = self.writer.write_func
 
150
 
 
151
        def record_writes(data):
 
152
            writes.append(data)
 
153
            return real_write(data)
 
154
 
 
155
        self.writer.write_func = record_writes
 
156
        self.writer._JOIN_WRITES_THRESHOLD = 2
 
157
 
 
158
        self.writer.begin()
 
159
        offset, length = self.writer.add_bytes_record(
 
160
            [b'abcabc'], len(b'abcabc'), names=[(b'name1', )])
 
161
        self.assertEqual((42, 16), (offset, length))
 
162
        self.assertOutput(
 
163
            b'Bazaar pack format 1 (introduced in 0.18)\n'
 
164
            b'B6\nname1\n\nabcabc')
 
165
 
 
166
        self.assertEqual([
 
167
            b'Bazaar pack format 1 (introduced in 0.18)\n',
 
168
            b'B6\nname1\n\n',
 
169
            b'abcabc'],
 
170
            writes)
 
171
 
 
172
    def test_add_bytes_record_two_names(self):
 
173
        """Add a bytes record with two names."""
 
174
        self.writer.begin()
 
175
        offset, length = self.writer.add_bytes_record(
 
176
            [b'abc'], len(b'abc'), names=[(b'name1', ), (b'name2', )])
 
177
        self.assertEqual((42, 19), (offset, length))
 
178
        self.assertOutput(
 
179
            b'Bazaar pack format 1 (introduced in 0.18)\n'
 
180
            b'B3\nname1\nname2\n\nabc')
 
181
 
 
182
    def test_add_bytes_record_two_names(self):
 
183
        """Add a bytes record with two names."""
 
184
        self.writer.begin()
 
185
        offset, length = self.writer.add_bytes_record(
 
186
            [b'abc'], len(b'abc'), names=[(b'name1', ), (b'name2', )])
 
187
        self.assertEqual((42, 19), (offset, length))
 
188
        self.assertOutput(
 
189
            b'Bazaar pack format 1 (introduced in 0.18)\n'
 
190
            b'B3\nname1\nname2\n\nabc')
155
191
 
156
192
    def test_add_bytes_record_two_element_name(self):
157
193
        """Add a bytes record with a two-element name."""
158
194
        self.writer.begin()
159
195
        offset, length = self.writer.add_bytes_record(
160
 
            'abc', names=[('name1', 'name2')])
 
196
            [b'abc'], len(b'abc'), names=[(b'name1', b'name2')])
161
197
        self.assertEqual((42, 19), (offset, length))
162
198
        self.assertOutput(
163
 
            'Bazaar pack format 1 (introduced in 0.18)\n'
164
 
            'B3\nname1\x00name2\n\nabc')
 
199
            b'Bazaar pack format 1 (introduced in 0.18)\n'
 
200
            b'B3\nname1\x00name2\n\nabc')
165
201
 
166
202
    def test_add_second_bytes_record_gets_higher_offset(self):
167
203
        self.writer.begin()
168
 
        self.writer.add_bytes_record('abc', names=[])
169
 
        offset, length = self.writer.add_bytes_record('abc', names=[])
 
204
        self.writer.add_bytes_record([b'a', b'bc'], len(b'abc'), names=[])
 
205
        offset, length = self.writer.add_bytes_record([b'abc'], len(b'abc'), names=[])
170
206
        self.assertEqual((49, 7), (offset, length))
171
207
        self.assertOutput(
172
 
            'Bazaar pack format 1 (introduced in 0.18)\n'
173
 
            'B3\n\nabc'
174
 
            'B3\n\nabc')
 
208
            b'Bazaar pack format 1 (introduced in 0.18)\n'
 
209
            b'B3\n\nabc'
 
210
            b'B3\n\nabc')
175
211
 
176
212
    def test_add_bytes_record_invalid_name(self):
177
213
        """Adding a Bytes record with a name with whitespace in it raises
180
216
        self.writer.begin()
181
217
        self.assertRaises(
182
218
            errors.InvalidRecordError,
183
 
            self.writer.add_bytes_record, 'abc', names=[('bad name', )])
 
219
            self.writer.add_bytes_record, [b'abc'], len(b'abc'), names=[(b'bad name', )])
184
220
 
185
221
    def test_add_bytes_records_add_to_records_written(self):
186
222
        """Adding a Bytes record increments the records_written counter."""
187
223
        self.writer.begin()
188
 
        self.writer.add_bytes_record('foo', names=[])
 
224
        self.writer.add_bytes_record([b'foo'], len(b'foo'), names=[])
189
225
        self.assertEqual(1, self.writer.records_written)
190
 
        self.writer.add_bytes_record('foo', names=[])
 
226
        self.writer.add_bytes_record([b'foo'], len(b'foo'), names=[])
191
227
        self.assertEqual(2, self.writer.records_written)
192
228
 
193
229
 
199
235
    added, then separate tests for that format should be added.
200
236
    """
201
237
 
202
 
    def get_reader_for(self, bytes):
203
 
        stream = StringIO(bytes)
 
238
    def get_reader_for(self, data):
 
239
        stream = BytesIO(data)
204
240
        reader = pack.ContainerReader(stream)
205
241
        return reader
206
242
 
207
243
    def test_construct(self):
208
244
        """Test constructing a ContainerReader.
209
245
 
210
 
        This uses None as the output stream to show that the constructor doesn't
211
 
        try to use the input stream.
 
246
        This uses None as the output stream to show that the constructor
 
247
        doesn't try to use the input stream.
212
248
        """
213
 
        reader = pack.ContainerReader(None)
 
249
        pack.ContainerReader(None)
214
250
 
215
251
    def test_empty_container(self):
216
252
        """Read an empty container."""
217
253
        reader = self.get_reader_for(
218
 
            "Bazaar pack format 1 (introduced in 0.18)\nE")
 
254
            b"Bazaar pack format 1 (introduced in 0.18)\nE")
219
255
        self.assertEqual([], list(reader.iter_records()))
220
256
 
221
257
    def test_unknown_format(self):
222
258
        """Unrecognised container formats raise UnknownContainerFormatError."""
223
 
        reader = self.get_reader_for("unknown format\n")
 
259
        reader = self.get_reader_for(b"unknown format\n")
224
260
        self.assertRaises(
225
261
            errors.UnknownContainerFormatError, reader.iter_records)
226
262
 
229
265
        UnexpectedEndOfContainerError to be raised.
230
266
        """
231
267
        reader = self.get_reader_for(
232
 
            "Bazaar pack format 1 (introduced in 0.18)\n")
 
268
            b"Bazaar pack format 1 (introduced in 0.18)\n")
233
269
        iterator = reader.iter_records()
234
270
        self.assertRaises(
235
 
            errors.UnexpectedEndOfContainerError, iterator.next)
 
271
            errors.UnexpectedEndOfContainerError, next, iterator)
236
272
 
237
273
    def test_unknown_record_type(self):
238
274
        """Unknown record types cause UnknownRecordTypeError to be raised."""
239
275
        reader = self.get_reader_for(
240
 
            "Bazaar pack format 1 (introduced in 0.18)\nX")
 
276
            b"Bazaar pack format 1 (introduced in 0.18)\nX")
241
277
        iterator = reader.iter_records()
242
278
        self.assertRaises(
243
 
            errors.UnknownRecordTypeError, iterator.next)
 
279
            errors.UnknownRecordTypeError, next, iterator)
244
280
 
245
281
    def test_container_with_one_unnamed_record(self):
246
282
        """Read a container with one Bytes record.
250
286
        ContainerReader's integration with BytesRecordReader is working.
251
287
        """
252
288
        reader = self.get_reader_for(
253
 
            "Bazaar pack format 1 (introduced in 0.18)\nB5\n\naaaaaE")
254
 
        expected_records = [([], 'aaaaa')]
 
289
            b"Bazaar pack format 1 (introduced in 0.18)\nB5\n\naaaaaE")
 
290
        expected_records = [([], b'aaaaa')]
255
291
        self.assertEqual(
256
292
            expected_records,
257
293
            [(names, read_bytes(None))
259
295
 
260
296
    def test_validate_empty_container(self):
261
297
        """validate does not raise an error for a container with no records."""
262
 
        reader = self.get_reader_for("Bazaar pack format 1 (introduced in 0.18)\nE")
 
298
        reader = self.get_reader_for(
 
299
            b"Bazaar pack format 1 (introduced in 0.18)\nE")
263
300
        # No exception raised
264
301
        reader.validate()
265
302
 
267
304
        """validate does not raise an error for a container with a valid record.
268
305
        """
269
306
        reader = self.get_reader_for(
270
 
            "Bazaar pack format 1 (introduced in 0.18)\nB3\nname\n\nabcE")
 
307
            b"Bazaar pack format 1 (introduced in 0.18)\nB3\nname\n\nabcE")
271
308
        # No exception raised
272
309
        reader.validate()
273
310
 
277
314
        It may raise either UnexpectedEndOfContainerError or
278
315
        UnknownContainerFormatError, depending on exactly what the string is.
279
316
        """
280
 
        inputs = ["", "x", "Bazaar pack format 1 (introduced in 0.18)", "bad\n"]
 
317
        inputs = [
 
318
            b"", b"x", b"Bazaar pack format 1 (introduced in 0.18)", b"bad\n"]
281
319
        for input in inputs:
282
320
            reader = self.get_reader_for(input)
283
321
            self.assertRaises(
290
328
        types.
291
329
        """
292
330
        reader = self.get_reader_for(
293
 
            "Bazaar pack format 1 (introduced in 0.18)\nX")
 
331
            b"Bazaar pack format 1 (introduced in 0.18)\nX")
294
332
        self.assertRaises(errors.UnknownRecordTypeError, reader.validate)
295
333
 
296
334
    def test_validate_data_after_end_marker(self):
298
336
        after the end of the container.
299
337
        """
300
338
        reader = self.get_reader_for(
301
 
            "Bazaar pack format 1 (introduced in 0.18)\nEcrud")
 
339
            b"Bazaar pack format 1 (introduced in 0.18)\nEcrud")
302
340
        self.assertRaises(
303
341
            errors.ContainerHasExcessDataError, reader.validate)
304
342
 
305
343
    def test_validate_no_end_marker(self):
306
344
        """validate raises UnexpectedEndOfContainerError if there's no end of
307
 
        container marker, even if the container up to this point has been valid.
 
345
        container marker, even if the container up to this point has been
 
346
        valid.
308
347
        """
309
348
        reader = self.get_reader_for(
310
 
            "Bazaar pack format 1 (introduced in 0.18)\n")
 
349
            b"Bazaar pack format 1 (introduced in 0.18)\n")
311
350
        self.assertRaises(
312
351
            errors.UnexpectedEndOfContainerError, reader.validate)
313
352
 
316
355
        multiple times in the container.
317
356
        """
318
357
        reader = self.get_reader_for(
319
 
            "Bazaar pack format 1 (introduced in 0.18)\n"
320
 
            "B0\nname\n\n"
321
 
            "B0\nname\n\n"
322
 
            "E")
 
358
            b"Bazaar pack format 1 (introduced in 0.18)\n"
 
359
            b"B0\nname\n\n"
 
360
            b"B0\nname\n\n"
 
361
            b"E")
323
362
        self.assertRaises(errors.DuplicateRecordNameError, reader.validate)
324
363
 
325
364
    def test_validate_undecodeable_name(self):
326
365
        """Names that aren't valid UTF-8 cause validate to fail."""
327
366
        reader = self.get_reader_for(
328
 
            "Bazaar pack format 1 (introduced in 0.18)\nB0\n\xcc\n\nE")
 
367
            b"Bazaar pack format 1 (introduced in 0.18)\nB0\n\xcc\n\nE")
329
368
        self.assertRaises(errors.InvalidRecordError, reader.validate)
330
369
 
331
370
 
338
377
    tests for reading that format should be added.
339
378
    """
340
379
 
341
 
    def get_reader_for(self, bytes):
342
 
        stream = StringIO(bytes)
 
380
    def get_reader_for(self, data):
 
381
        stream = BytesIO(data)
343
382
        reader = pack.BytesRecordReader(stream)
344
383
        return reader
345
384
 
347
386
        """Reading a Bytes record with no name returns an empty list of
348
387
        names.
349
388
        """
350
 
        reader = self.get_reader_for("5\n\naaaaa")
 
389
        reader = self.get_reader_for(b"5\n\naaaaa")
351
390
        names, get_bytes = reader.read()
352
391
        self.assertEqual([], names)
353
 
        self.assertEqual('aaaaa', get_bytes(None))
 
392
        self.assertEqual(b'aaaaa', get_bytes(None))
354
393
 
355
394
    def test_record_with_one_name(self):
356
395
        """Reading a Bytes record with one name returns a list of just that
357
396
        name.
358
397
        """
359
 
        reader = self.get_reader_for("5\nname1\n\naaaaa")
 
398
        reader = self.get_reader_for(b"5\nname1\n\naaaaa")
360
399
        names, get_bytes = reader.read()
361
 
        self.assertEqual([('name1', )], names)
362
 
        self.assertEqual('aaaaa', get_bytes(None))
 
400
        self.assertEqual([(b'name1', )], names)
 
401
        self.assertEqual(b'aaaaa', get_bytes(None))
363
402
 
364
403
    def test_record_with_two_names(self):
365
404
        """Reading a Bytes record with two names returns a list of both names.
366
405
        """
367
 
        reader = self.get_reader_for("5\nname1\nname2\n\naaaaa")
 
406
        reader = self.get_reader_for(b"5\nname1\nname2\n\naaaaa")
368
407
        names, get_bytes = reader.read()
369
 
        self.assertEqual([('name1', ), ('name2', )], names)
370
 
        self.assertEqual('aaaaa', get_bytes(None))
 
408
        self.assertEqual([(b'name1', ), (b'name2', )], names)
 
409
        self.assertEqual(b'aaaaa', get_bytes(None))
371
410
 
372
411
    def test_record_with_two_part_names(self):
373
412
        """Reading a Bytes record with a two_part name reads both."""
374
 
        reader = self.get_reader_for("5\nname1\x00name2\n\naaaaa")
 
413
        reader = self.get_reader_for(b"5\nname1\x00name2\n\naaaaa")
375
414
        names, get_bytes = reader.read()
376
 
        self.assertEqual([('name1', 'name2', )], names)
377
 
        self.assertEqual('aaaaa', get_bytes(None))
 
415
        self.assertEqual([(b'name1', b'name2', )], names)
 
416
        self.assertEqual(b'aaaaa', get_bytes(None))
378
417
 
379
418
    def test_invalid_length(self):
380
419
        """If the length-prefix is not a number, parsing raises
381
420
        InvalidRecordError.
382
421
        """
383
 
        reader = self.get_reader_for("not a number\n")
 
422
        reader = self.get_reader_for(b"not a number\n")
384
423
        self.assertRaises(errors.InvalidRecordError, reader.read)
385
424
 
386
425
    def test_early_eof(self):
393
432
 
394
433
        In all cases, UnexpectedEndOfContainerError should be raised.
395
434
        """
396
 
        complete_record = "6\nname\n\nabcdef"
 
435
        complete_record = b"6\nname\n\nabcdef"
397
436
        for count in range(0, len(complete_record)):
398
437
            incomplete_record = complete_record[:count]
399
438
            reader = self.get_reader_for(incomplete_record)
411
450
 
412
451
    def test_initial_eof(self):
413
452
        """EOF before any bytes read at all."""
414
 
        reader = self.get_reader_for("")
 
453
        reader = self.get_reader_for(b"")
415
454
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
416
455
 
417
456
    def test_eof_after_length(self):
418
457
        """EOF after reading the length and before reading name(s)."""
419
 
        reader = self.get_reader_for("123\n")
 
458
        reader = self.get_reader_for(b"123\n")
420
459
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
421
460
 
422
461
    def test_eof_during_name(self):
423
462
        """EOF during reading a name."""
424
 
        reader = self.get_reader_for("123\nname")
 
463
        reader = self.get_reader_for(b"123\nname")
425
464
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
426
465
 
427
466
    def test_read_invalid_name_whitespace(self):
428
467
        """Names must have no whitespace."""
429
468
        # A name with a space.
430
 
        reader = self.get_reader_for("0\nbad name\n\n")
 
469
        reader = self.get_reader_for(b"0\nbad name\n\n")
431
470
        self.assertRaises(errors.InvalidRecordError, reader.read)
432
471
 
433
472
        # A name with a tab.
434
 
        reader = self.get_reader_for("0\nbad\tname\n\n")
 
473
        reader = self.get_reader_for(b"0\nbad\tname\n\n")
435
474
        self.assertRaises(errors.InvalidRecordError, reader.read)
436
475
 
437
476
        # A name with a vertical tab.
438
 
        reader = self.get_reader_for("0\nbad\vname\n\n")
 
477
        reader = self.get_reader_for(b"0\nbad\vname\n\n")
439
478
        self.assertRaises(errors.InvalidRecordError, reader.read)
440
479
 
441
480
    def test_validate_whitespace_in_name(self):
442
481
        """Names must have no whitespace."""
443
 
        reader = self.get_reader_for("0\nbad name\n\n")
 
482
        reader = self.get_reader_for(b"0\nbad name\n\n")
444
483
        self.assertRaises(errors.InvalidRecordError, reader.validate)
445
484
 
446
485
    def test_validate_interrupted_prelude(self):
447
486
        """EOF during reading a record's prelude causes validate to fail."""
448
 
        reader = self.get_reader_for("")
 
487
        reader = self.get_reader_for(b"")
449
488
        self.assertRaises(
450
489
            errors.UnexpectedEndOfContainerError, reader.validate)
451
490
 
452
491
    def test_validate_interrupted_body(self):
453
492
        """EOF during reading a record's body causes validate to fail."""
454
 
        reader = self.get_reader_for("1\n\n")
 
493
        reader = self.get_reader_for(b"1\n\n")
455
494
        self.assertRaises(
456
495
            errors.UnexpectedEndOfContainerError, reader.validate)
457
496
 
458
497
    def test_validate_unparseable_length(self):
459
498
        """An unparseable record length causes validate to fail."""
460
 
        reader = self.get_reader_for("\n\n")
 
499
        reader = self.get_reader_for(b"\n\n")
461
500
        self.assertRaises(
462
501
            errors.InvalidRecordError, reader.validate)
463
502
 
464
503
    def test_validate_undecodeable_name(self):
465
504
        """Names that aren't valid UTF-8 cause validate to fail."""
466
 
        reader = self.get_reader_for("0\n\xcc\n\n")
 
505
        reader = self.get_reader_for(b"0\n\xcc\n\n")
467
506
        self.assertRaises(errors.InvalidRecordError, reader.validate)
468
507
 
469
508
    def test_read_max_length(self):
470
509
        """If the max_length passed to the callable returned by read is not
471
510
        None, then no more than that many bytes will be read.
472
511
        """
473
 
        reader = self.get_reader_for("6\n\nabcdef")
 
512
        reader = self.get_reader_for(b"6\n\nabcdef")
474
513
        names, get_bytes = reader.read()
475
 
        self.assertEqual('abc', get_bytes(3))
 
514
        self.assertEqual(b'abc', get_bytes(3))
476
515
 
477
516
    def test_read_no_max_length(self):
478
517
        """If the max_length passed to the callable returned by read is None,
479
518
        then all the bytes in the record will be read.
480
519
        """
481
 
        reader = self.get_reader_for("6\n\nabcdef")
 
520
        reader = self.get_reader_for(b"6\n\nabcdef")
482
521
        names, get_bytes = reader.read()
483
 
        self.assertEqual('abcdef', get_bytes(None))
 
522
        self.assertEqual(b'abcdef', get_bytes(None))
484
523
 
485
524
    def test_repeated_read_calls(self):
486
525
        """Repeated calls to the callable returned from BytesRecordReader.read
487
526
        will not read beyond the end of the record.
488
527
        """
489
 
        reader = self.get_reader_for("6\n\nabcdefB3\nnext-record\nXXX")
 
528
        reader = self.get_reader_for(b"6\n\nabcdefB3\nnext-record\nXXX")
490
529
        names, get_bytes = reader.read()
491
 
        self.assertEqual('abcdef', get_bytes(None))
492
 
        self.assertEqual('', get_bytes(None))
493
 
        self.assertEqual('', get_bytes(99))
 
530
        self.assertEqual(b'abcdef', get_bytes(None))
 
531
        self.assertEqual(b'', get_bytes(None))
 
532
        self.assertEqual(b'', get_bytes(99))
494
533
 
495
534
 
496
535
class TestMakeReadvReader(tests.TestCaseWithTransport):
497
536
 
498
537
    def test_read_skipping_records(self):
499
 
        pack_data = StringIO()
 
538
        pack_data = BytesIO()
500
539
        writer = pack.ContainerWriter(pack_data.write)
501
540
        writer.begin()
502
541
        memos = []
503
 
        memos.append(writer.add_bytes_record('abc', names=[]))
504
 
        memos.append(writer.add_bytes_record('def', names=[('name1', )]))
505
 
        memos.append(writer.add_bytes_record('ghi', names=[('name2', )]))
506
 
        memos.append(writer.add_bytes_record('jkl', names=[]))
 
542
        memos.append(writer.add_bytes_record([b'abc'], 3, names=[]))
 
543
        memos.append(writer.add_bytes_record([b'def'], 3, names=[(b'name1', )]))
 
544
        memos.append(writer.add_bytes_record([b'ghi'], 3, names=[(b'name2', )]))
 
545
        memos.append(writer.add_bytes_record([b'jkl'], 3, names=[]))
507
546
        writer.end()
508
547
        transport = self.get_transport()
509
548
        transport.put_bytes('mypack', pack_data.getvalue())
512
551
        result = []
513
552
        for names, reader_func in reader.iter_records():
514
553
            result.append((names, reader_func(None)))
515
 
        self.assertEqual([([], 'abc'), ([('name2', )], 'ghi')], result)
 
554
        self.assertEqual([([], b'abc'), ([(b'name2', )], b'ghi')], result)
516
555
 
517
556
 
518
557
class TestReadvFile(tests.TestCaseWithTransport):
526
565
    def test_read_bytes(self):
527
566
        """Test reading of both single bytes and all bytes in a hunk."""
528
567
        transport = self.get_transport()
529
 
        transport.put_bytes('sample', '0123456789')
530
 
        f = pack.ReadVFile(transport.readv('sample', [(0,1), (1,2), (4,1), (6,2)]))
 
568
        transport.put_bytes('sample', b'0123456789')
 
569
        f = pack.ReadVFile(transport.readv(
 
570
            'sample', [(0, 1), (1, 2), (4, 1), (6, 2)]))
531
571
        results = []
532
572
        results.append(f.read(1))
533
573
        results.append(f.read(2))
534
574
        results.append(f.read(1))
535
575
        results.append(f.read(1))
536
576
        results.append(f.read(1))
537
 
        self.assertEqual(['0', '12', '4', '6', '7'], results)
 
577
        self.assertEqual([b'0', b'12', b'4', b'6', b'7'], results)
538
578
 
539
579
    def test_readline(self):
540
580
        """Test using readline() as ContainerReader does.
542
582
        This is always within a readv hunk, never across it.
543
583
        """
544
584
        transport = self.get_transport()
545
 
        transport.put_bytes('sample', '0\n2\n4\n')
546
 
        f = pack.ReadVFile(transport.readv('sample', [(0,2), (2,4)]))
 
585
        transport.put_bytes('sample', b'0\n2\n4\n')
 
586
        f = pack.ReadVFile(transport.readv('sample', [(0, 2), (2, 4)]))
547
587
        results = []
548
588
        results.append(f.readline())
549
589
        results.append(f.readline())
550
590
        results.append(f.readline())
551
 
        self.assertEqual(['0\n', '2\n', '4\n'], results)
 
591
        self.assertEqual([b'0\n', b'2\n', b'4\n'], results)
552
592
 
553
593
    def test_readline_and_read(self):
554
594
        """Test exercising one byte reads, readline, and then read again."""
555
595
        transport = self.get_transport()
556
 
        transport.put_bytes('sample', '0\n2\n4\n')
557
 
        f = pack.ReadVFile(transport.readv('sample', [(0,6)]))
 
596
        transport.put_bytes('sample', b'0\n2\n4\n')
 
597
        f = pack.ReadVFile(transport.readv('sample', [(0, 6)]))
558
598
        results = []
559
599
        results.append(f.read(1))
560
600
        results.append(f.readline())
561
601
        results.append(f.read(4))
562
 
        self.assertEqual(['0', '\n', '2\n4\n'], results)
 
602
        self.assertEqual([b'0', b'\n', b'2\n4\n'], results)
563
603
 
564
604
 
565
605
class PushParserTestCase(tests.TestCase):
567
607
 
568
608
    def make_parser_expecting_record_type(self):
569
609
        parser = pack.ContainerPushParser()
570
 
        parser.accept_bytes("Bazaar pack format 1 (introduced in 0.18)\n")
 
610
        parser.accept_bytes(b"Bazaar pack format 1 (introduced in 0.18)\n")
571
611
        return parser
572
612
 
573
613
    def make_parser_expecting_bytes_record(self):
574
614
        parser = pack.ContainerPushParser()
575
 
        parser.accept_bytes("Bazaar pack format 1 (introduced in 0.18)\nB")
 
615
        parser.accept_bytes(b"Bazaar pack format 1 (introduced in 0.18)\nB")
576
616
        return parser
577
617
 
578
 
    def assertRecordParsing(self, expected_record, bytes):
 
618
    def assertRecordParsing(self, expected_record, data):
579
619
        """Assert that 'bytes' is parsed as a given bytes record.
580
620
 
581
621
        :param expected_record: A tuple of (names, bytes).
582
622
        """
583
623
        parser = self.make_parser_expecting_bytes_record()
584
 
        parser.accept_bytes(bytes)
 
624
        parser.accept_bytes(data)
585
625
        parsed_records = parser.read_pending_records()
586
626
        self.assertEqual([expected_record], parsed_records)
587
627
 
605
645
        (A naive implementation might stop after parsing the first record.)
606
646
        """
607
647
        parser = self.make_parser_expecting_record_type()
608
 
        parser.accept_bytes("B5\nname1\n\nbody1B5\nname2\n\nbody2")
 
648
        parser.accept_bytes(b"B5\nname1\n\nbody1B5\nname2\n\nbody2")
609
649
        self.assertEqual(
610
 
            [([('name1',)], 'body1'), ([('name2',)], 'body2')],
 
650
            [([(b'name1',)], b'body1'), ([(b'name2',)], b'body2')],
611
651
            parser.read_pending_records())
612
652
 
613
653
    def test_multiple_empty_records_at_once(self):
618
658
        record, because the buffer size had not changed.)
619
659
        """
620
660
        parser = self.make_parser_expecting_record_type()
621
 
        parser.accept_bytes("B0\nname1\n\nB0\nname2\n\n")
 
661
        parser.accept_bytes(b"B0\nname1\n\nB0\nname2\n\n")
622
662
        self.assertEqual(
623
 
            [([('name1',)], ''), ([('name2',)], '')],
 
663
            [([(b'name1',)], b''), ([(b'name2',)], b'')],
624
664
            parser.read_pending_records())
625
665
 
626
666
 
636
676
        """Reading a Bytes record with no name returns an empty list of
637
677
        names.
638
678
        """
639
 
        self.assertRecordParsing(([], 'aaaaa'), "5\n\naaaaa")
 
679
        self.assertRecordParsing(([], b'aaaaa'), b"5\n\naaaaa")
640
680
 
641
681
    def test_record_with_one_name(self):
642
682
        """Reading a Bytes record with one name returns a list of just that
643
683
        name.
644
684
        """
645
685
        self.assertRecordParsing(
646
 
            ([('name1', )], 'aaaaa'),
647
 
            "5\nname1\n\naaaaa")
 
686
            ([(b'name1', )], b'aaaaa'),
 
687
            b"5\nname1\n\naaaaa")
648
688
 
649
689
    def test_record_with_two_names(self):
650
690
        """Reading a Bytes record with two names returns a list of both names.
651
691
        """
652
692
        self.assertRecordParsing(
653
 
            ([('name1', ), ('name2', )], 'aaaaa'),
654
 
            "5\nname1\nname2\n\naaaaa")
 
693
            ([(b'name1', ), (b'name2', )], b'aaaaa'),
 
694
            b"5\nname1\nname2\n\naaaaa")
655
695
 
656
696
    def test_record_with_two_part_names(self):
657
697
        """Reading a Bytes record with a two_part name reads both."""
658
698
        self.assertRecordParsing(
659
 
            ([('name1', 'name2')], 'aaaaa'),
660
 
            "5\nname1\x00name2\n\naaaaa")
 
699
            ([(b'name1', b'name2')], b'aaaaa'),
 
700
            b"5\nname1\x00name2\n\naaaaa")
661
701
 
662
702
    def test_invalid_length(self):
663
703
        """If the length-prefix is not a number, parsing raises
665
705
        """
666
706
        parser = self.make_parser_expecting_bytes_record()
667
707
        self.assertRaises(
668
 
            errors.InvalidRecordError, parser.accept_bytes, "not a number\n")
 
708
            errors.InvalidRecordError, parser.accept_bytes, b"not a number\n")
669
709
 
670
710
    def test_incomplete_record(self):
671
711
        """If the bytes seen so far don't form a complete record, then there
672
712
        will be nothing returned by read_pending_records.
673
713
        """
674
714
        parser = self.make_parser_expecting_bytes_record()
675
 
        parser.accept_bytes("5\n\nabcd")
 
715
        parser.accept_bytes(b"5\n\nabcd")
676
716
        self.assertEqual([], parser.read_pending_records())
677
717
 
678
718
    def test_accept_nothing(self):
679
719
        """The edge case of parsing an empty string causes no error."""
680
720
        parser = self.make_parser_expecting_bytes_record()
681
 
        parser.accept_bytes("")
 
721
        parser.accept_bytes(b"")
682
722
 
683
 
    def assertInvalidRecord(self, bytes):
684
 
        """Assert that parsing the given bytes will raise an
685
 
        InvalidRecordError.
686
 
        """
 
723
    def assertInvalidRecord(self, data):
 
724
        """Assert that parsing the given bytes raises InvalidRecordError."""
687
725
        parser = self.make_parser_expecting_bytes_record()
688
726
        self.assertRaises(
689
 
            errors.InvalidRecordError, parser.accept_bytes, bytes)
 
727
            errors.InvalidRecordError, parser.accept_bytes, data)
690
728
 
691
729
    def test_read_invalid_name_whitespace(self):
692
730
        """Names must have no whitespace."""
693
731
        # A name with a space.
694
 
        self.assertInvalidRecord("0\nbad name\n\n")
 
732
        self.assertInvalidRecord(b"0\nbad name\n\n")
695
733
 
696
734
        # A name with a tab.
697
 
        self.assertInvalidRecord("0\nbad\tname\n\n")
 
735
        self.assertInvalidRecord(b"0\nbad\tname\n\n")
698
736
 
699
737
        # A name with a vertical tab.
700
 
        self.assertInvalidRecord("0\nbad\vname\n\n")
 
738
        self.assertInvalidRecord(b"0\nbad\vname\n\n")
701
739
 
702
740
    def test_repeated_read_pending_records(self):
703
741
        """read_pending_records will not return the same record twice."""
704
742
        parser = self.make_parser_expecting_bytes_record()
705
 
        parser.accept_bytes("6\n\nabcdef")
706
 
        self.assertEqual([([], 'abcdef')], parser.read_pending_records())
 
743
        parser.accept_bytes(b"6\n\nabcdef")
 
744
        self.assertEqual([([], b'abcdef')], parser.read_pending_records())
707
745
        self.assertEqual([], parser.read_pending_records())
708
 
 
709