/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-02-18 01:57:45 UTC
  • mto: This revision was merged to the branch mainline in revision 7493.
  • Revision ID: jelmer@jelmer.uk-20200218015745-q2ss9tsk74h4nh61
drop use of future.

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