~bzr-pqm/bzr/bzr.dev

2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
1
# Copyright (C) 2007 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
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
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
16
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
17
"""Tests for bzrlib.pack."""
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
18
19
20
from cStringIO import StringIO
21
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
22
from bzrlib import pack, errors, tests
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
23
24
2916.2.11 by Andrew Bennetts
Add direct unit tests for ContainerSerialiser.
25
class TestContainerSerialiser(tests.TestCase):
26
    """Tests for the ContainerSerialiser class."""
27
28
    def test_construct(self):
29
        """Test constructing a ContainerSerialiser."""
30
        pack.ContainerSerialiser()
31
32
    def test_begin(self):
33
        serialiser = pack.ContainerSerialiser()
34
        self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\n',
35
                         serialiser.begin())
36
37
    def test_end(self):
38
        serialiser = pack.ContainerSerialiser()
39
        self.assertEqual('E', serialiser.end())
40
41
    def test_bytes_record_no_name(self):
42
        serialiser = pack.ContainerSerialiser()
43
        record = serialiser.bytes_record('bytes', [])
44
        self.assertEqual('B5\n\nbytes', record)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
45
2916.2.11 by Andrew Bennetts
Add direct unit tests for ContainerSerialiser.
46
    def test_bytes_record_one_name_with_one_part(self):
47
        serialiser = pack.ContainerSerialiser()
48
        record = serialiser.bytes_record('bytes', [('name',)])
49
        self.assertEqual('B5\nname\n\nbytes', record)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
50
2916.2.11 by Andrew Bennetts
Add direct unit tests for ContainerSerialiser.
51
    def test_bytes_record_one_name_with_two_parts(self):
52
        serialiser = pack.ContainerSerialiser()
53
        record = serialiser.bytes_record('bytes', [('part1', 'part2')])
54
        self.assertEqual('B5\npart1\x00part2\n\nbytes', record)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
55
2916.2.11 by Andrew Bennetts
Add direct unit tests for ContainerSerialiser.
56
    def test_bytes_record_two_names(self):
57
        serialiser = pack.ContainerSerialiser()
58
        record = serialiser.bytes_record('bytes', [('name1',), ('name2',)])
59
        self.assertEqual('B5\nname1\nname2\n\nbytes', record)
60
61
    def test_bytes_record_whitespace_in_name_part(self):
62
        serialiser = pack.ContainerSerialiser()
63
        self.assertRaises(
64
            errors.InvalidRecordError,
65
            serialiser.bytes_record, 'bytes', [('bad name',)])
66
67
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
68
class TestContainerWriter(tests.TestCase):
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
69
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
70
    def setUp(self):
4153.1.2 by Andrew Bennetts
Add missing TestCase.setUp upcalls.
71
        tests.TestCase.setUp(self)
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
72
        self.output = StringIO()
73
        self.writer = pack.ContainerWriter(self.output.write)
74
75
    def assertOutput(self, expected_output):
76
        """Assert that the output of self.writer ContainerWriter is equal to
77
        expected_output.
78
        """
79
        self.assertEqual(expected_output, self.output.getvalue())
80
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
81
    def test_construct(self):
82
        """Test constructing a ContainerWriter.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
83
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
84
        This uses None as the output stream to show that the constructor
85
        doesn't try to use the output stream.
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
86
        """
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
87
        writer = pack.ContainerWriter(None)
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
88
89
    def test_begin(self):
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
90
        """The begin() method writes the container format marker line."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
91
        self.writer.begin()
92
        self.assertOutput('Bazaar pack format 1 (introduced in 0.18)\n')
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
93
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
94
    def test_zero_records_written_after_begin(self):
95
        """After begin is written, 0 records have been written."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
96
        self.writer.begin()
97
        self.assertEqual(0, self.writer.records_written)
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
98
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
99
    def test_end(self):
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
100
        """The end() method writes an End Marker record."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
101
        self.writer.begin()
102
        self.writer.end()
103
        self.assertOutput('Bazaar pack format 1 (introduced in 0.18)\nE')
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
104
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
105
    def test_empty_end_does_not_add_a_record_to_records_written(self):
106
        """The end() method does not count towards the records written."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
107
        self.writer.begin()
108
        self.writer.end()
109
        self.assertEqual(0, self.writer.records_written)
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
110
111
    def test_non_empty_end_does_not_add_a_record_to_records_written(self):
112
        """The end() method does not count towards the records written."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
113
        self.writer.begin()
114
        self.writer.add_bytes_record('foo', names=[])
115
        self.writer.end()
116
        self.assertEqual(1, self.writer.records_written)
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
117
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
118
    def test_add_bytes_record_no_name(self):
119
        """Add a bytes record with no name."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
120
        self.writer.begin()
121
        offset, length = self.writer.add_bytes_record('abc', names=[])
2661.2.1 by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to
122
        self.assertEqual((42, 7), (offset, length))
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
123
        self.assertOutput(
124
            'Bazaar pack format 1 (introduced in 0.18)\nB3\n\nabc')
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
125
126
    def test_add_bytes_record_one_name(self):
127
        """Add a bytes record with one name."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
128
        self.writer.begin()
129
        offset, length = self.writer.add_bytes_record(
130
            'abc', names=[('name1', )])
2661.2.1 by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to
131
        self.assertEqual((42, 13), (offset, length))
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
132
        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')
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
155
156
    def test_add_bytes_record_two_element_name(self):
157
        """Add a bytes record with a two-element name."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
158
        self.writer.begin()
159
        offset, length = self.writer.add_bytes_record(
160
            'abc', names=[('name1', 'name2')])
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
161
        self.assertEqual((42, 19), (offset, length))
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
162
        self.assertOutput(
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
163
            'Bazaar pack format 1 (introduced in 0.18)\n'
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
164
            'B3\nname1\x00name2\n\nabc')
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
165
2661.2.1 by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to
166
    def test_add_second_bytes_record_gets_higher_offset(self):
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
167
        self.writer.begin()
168
        self.writer.add_bytes_record('abc', names=[])
169
        offset, length = self.writer.add_bytes_record('abc', names=[])
2661.2.1 by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to
170
        self.assertEqual((49, 7), (offset, length))
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
171
        self.assertOutput(
2661.2.1 by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to
172
            'Bazaar pack format 1 (introduced in 0.18)\n'
173
            'B3\n\nabc'
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
174
            'B3\n\nabc')
2661.2.1 by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to
175
2506.5.2 by Andrew Bennetts
Raise InvalidRecordError on invalid names.
176
    def test_add_bytes_record_invalid_name(self):
177
        """Adding a Bytes record with a name with whitespace in it raises
178
        InvalidRecordError.
179
        """
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
180
        self.writer.begin()
2506.5.2 by Andrew Bennetts
Raise InvalidRecordError on invalid names.
181
        self.assertRaises(
182
            errors.InvalidRecordError,
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
183
            self.writer.add_bytes_record, 'abc', names=[('bad name', )])
2506.5.2 by Andrew Bennetts
Raise InvalidRecordError on invalid names.
184
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
185
    def test_add_bytes_records_add_to_records_written(self):
186
        """Adding a Bytes record increments the records_written counter."""
2916.2.12 by Andrew Bennetts
Refactor TestContainerWriter to be a little more concise.
187
        self.writer.begin()
188
        self.writer.add_bytes_record('foo', names=[])
189
        self.assertEqual(1, self.writer.records_written)
190
        self.writer.add_bytes_record('foo', names=[])
191
        self.assertEqual(2, self.writer.records_written)
2698.1.1 by Robert Collins
Add records_written attribute to ContainerWriter's. (Robert Collins).
192
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
193
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
194
class TestContainerReader(tests.TestCase):
2916.2.13 by Andrew Bennetts
Improve some docstrings.
195
    """Tests for the ContainerReader.
196
197
    The ContainerReader reads format 1 containers, so these tests explicitly
198
    test how it reacts to format 1 data.  If a new version of the format is
199
    added, then separate tests for that format should be added.
200
    """
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
201
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
202
    def get_reader_for(self, bytes):
203
        stream = StringIO(bytes)
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
204
        reader = pack.ContainerReader(stream)
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
205
        return reader
206
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
207
    def test_construct(self):
208
        """Test constructing a ContainerReader.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
209
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
210
        This uses None as the output stream to show that the constructor doesn't
211
        try to use the input stream.
212
        """
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
213
        reader = pack.ContainerReader(None)
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
214
215
    def test_empty_container(self):
216
        """Read an empty container."""
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
217
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
218
            "Bazaar pack format 1 (introduced in 0.18)\nE")
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
219
        self.assertEqual([], list(reader.iter_records()))
220
221
    def test_unknown_format(self):
222
        """Unrecognised container formats raise UnknownContainerFormatError."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
223
        reader = self.get_reader_for("unknown format\n")
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
224
        self.assertRaises(
225
            errors.UnknownContainerFormatError, reader.iter_records)
226
227
    def test_unexpected_end_of_container(self):
228
        """Containers that don't end with an End Marker record should cause
229
        UnexpectedEndOfContainerError to be raised.
230
        """
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
231
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
232
            "Bazaar pack format 1 (introduced in 0.18)\n")
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
233
        iterator = reader.iter_records()
234
        self.assertRaises(
235
            errors.UnexpectedEndOfContainerError, iterator.next)
236
237
    def test_unknown_record_type(self):
238
        """Unknown record types cause UnknownRecordTypeError to be raised."""
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
239
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
240
            "Bazaar pack format 1 (introduced in 0.18)\nX")
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
241
        iterator = reader.iter_records()
242
        self.assertRaises(
243
            errors.UnknownRecordTypeError, iterator.next)
244
2506.3.1 by Andrew Bennetts
More progress:
245
    def test_container_with_one_unnamed_record(self):
246
        """Read a container with one Bytes record.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
247
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
248
        Parsing Bytes records is more thoroughly exercised by
249
        TestBytesRecordReader.  This test is here to ensure that
250
        ContainerReader's integration with BytesRecordReader is working.
2506.3.1 by Andrew Bennetts
More progress:
251
        """
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
252
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
253
            "Bazaar pack format 1 (introduced in 0.18)\nB5\n\naaaaaE")
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
254
        expected_records = [([], 'aaaaa')]
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
255
        self.assertEqual(
256
            expected_records,
257
            [(names, read_bytes(None))
258
             for (names, read_bytes) in reader.iter_records()])
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
259
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
260
    def test_validate_empty_container(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
261
        """validate does not raise an error for a container with no records."""
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
262
        reader = self.get_reader_for("Bazaar pack format 1 (introduced in 0.18)\nE")
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
263
        # No exception raised
264
        reader.validate()
265
266
    def test_validate_non_empty_valid_container(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
267
        """validate does not raise an error for a container with a valid record.
268
        """
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
269
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
270
            "Bazaar pack format 1 (introduced in 0.18)\nB3\nname\n\nabcE")
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
271
        # No exception raised
272
        reader.validate()
273
274
    def test_validate_bad_format(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
275
        """validate raises an error for unrecognised format strings.
276
277
        It may raise either UnexpectedEndOfContainerError or
278
        UnknownContainerFormatError, depending on exactly what the string is.
279
        """
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
280
        inputs = ["", "x", "Bazaar pack format 1 (introduced in 0.18)", "bad\n"]
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
281
        for input in inputs:
282
            reader = self.get_reader_for(input)
283
            self.assertRaises(
284
                (errors.UnexpectedEndOfContainerError,
285
                 errors.UnknownContainerFormatError),
286
                reader.validate)
287
288
    def test_validate_bad_record_marker(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
289
        """validate raises UnknownRecordTypeError for unrecognised record
290
        types.
291
        """
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
292
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
293
            "Bazaar pack format 1 (introduced in 0.18)\nX")
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
294
        self.assertRaises(errors.UnknownRecordTypeError, reader.validate)
295
296
    def test_validate_data_after_end_marker(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
297
        """validate raises ContainerHasExcessDataError if there are any bytes
298
        after the end of the container.
299
        """
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
300
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
301
            "Bazaar pack format 1 (introduced in 0.18)\nEcrud")
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
302
        self.assertRaises(
303
            errors.ContainerHasExcessDataError, reader.validate)
304
305
    def test_validate_no_end_marker(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
306
        """validate raises UnexpectedEndOfContainerError if there's no end of
307
        container marker, even if the container up to this point has been valid.
308
        """
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
309
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
310
            "Bazaar pack format 1 (introduced in 0.18)\n")
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
311
        self.assertRaises(
312
            errors.UnexpectedEndOfContainerError, reader.validate)
313
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
314
    def test_validate_duplicate_name(self):
315
        """validate raises DuplicateRecordNameError if the same name occurs
316
        multiple times in the container.
317
        """
318
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
319
            "Bazaar pack format 1 (introduced in 0.18)\n"
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
320
            "B0\nname\n\n"
321
            "B0\nname\n\n"
322
            "E")
323
        self.assertRaises(errors.DuplicateRecordNameError, reader.validate)
324
325
    def test_validate_undecodeable_name(self):
326
        """Names that aren't valid UTF-8 cause validate to fail."""
2506.2.10 by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string.
327
        reader = self.get_reader_for(
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
328
            "Bazaar pack format 1 (introduced in 0.18)\nB0\n\xcc\n\nE")
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
329
        self.assertRaises(errors.InvalidRecordError, reader.validate)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
330
2506.3.1 by Andrew Bennetts
More progress:
331
2506.3.2 by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool.
332
class TestBytesRecordReader(tests.TestCase):
2916.2.13 by Andrew Bennetts
Improve some docstrings.
333
    """Tests for reading and validating Bytes records with
334
    BytesRecordReader.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
335
2916.2.13 by Andrew Bennetts
Improve some docstrings.
336
    Like TestContainerReader, this explicitly tests the reading of format 1
337
    data.  If a new version of the format is added, then a separate set of
338
    tests for reading that format should be added.
339
    """
2506.3.1 by Andrew Bennetts
More progress:
340
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
341
    def get_reader_for(self, bytes):
342
        stream = StringIO(bytes)
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
343
        reader = pack.BytesRecordReader(stream)
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
344
        return reader
345
2506.3.1 by Andrew Bennetts
More progress:
346
    def test_record_with_no_name(self):
347
        """Reading a Bytes record with no name returns an empty list of
348
        names.
349
        """
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
350
        reader = self.get_reader_for("5\n\naaaaa")
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
351
        names, get_bytes = reader.read()
2506.3.1 by Andrew Bennetts
More progress:
352
        self.assertEqual([], names)
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
353
        self.assertEqual('aaaaa', get_bytes(None))
2506.3.1 by Andrew Bennetts
More progress:
354
355
    def test_record_with_one_name(self):
356
        """Reading a Bytes record with one name returns a list of just that
357
        name.
358
        """
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
359
        reader = self.get_reader_for("5\nname1\n\naaaaa")
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
360
        names, get_bytes = reader.read()
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
361
        self.assertEqual([('name1', )], names)
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
362
        self.assertEqual('aaaaa', get_bytes(None))
2506.3.1 by Andrew Bennetts
More progress:
363
364
    def test_record_with_two_names(self):
365
        """Reading a Bytes record with two names returns a list of both names.
366
        """
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
367
        reader = self.get_reader_for("5\nname1\nname2\n\naaaaa")
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
368
        names, get_bytes = reader.read()
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
369
        self.assertEqual([('name1', ), ('name2', )], names)
370
        self.assertEqual('aaaaa', get_bytes(None))
371
372
    def test_record_with_two_part_names(self):
373
        """Reading a Bytes record with a two_part name reads both."""
374
        reader = self.get_reader_for("5\nname1\x00name2\n\naaaaa")
375
        names, get_bytes = reader.read()
376
        self.assertEqual([('name1', 'name2', )], names)
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
377
        self.assertEqual('aaaaa', get_bytes(None))
2506.3.1 by Andrew Bennetts
More progress:
378
379
    def test_invalid_length(self):
380
        """If the length-prefix is not a number, parsing raises
381
        InvalidRecordError.
382
        """
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
383
        reader = self.get_reader_for("not a number\n")
2506.3.1 by Andrew Bennetts
More progress:
384
        self.assertRaises(errors.InvalidRecordError, reader.read)
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
385
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
386
    def test_early_eof(self):
387
        """Tests for premature EOF occuring during parsing Bytes records with
388
        BytesRecordReader.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
389
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
390
        A incomplete container might be interrupted at any point.  The
391
        BytesRecordReader needs to cope with the input stream running out no
392
        matter where it is in the parsing process.
393
394
        In all cases, UnexpectedEndOfContainerError should be raised.
395
        """
396
        complete_record = "6\nname\n\nabcdef"
397
        for count in range(0, len(complete_record)):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
398
            incomplete_record = complete_record[:count]
399
            reader = self.get_reader_for(incomplete_record)
400
            # We don't use assertRaises to make diagnosing failures easier
401
            # (assertRaises doesn't allow a custom failure message).
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
402
            try:
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
403
                names, read_bytes = reader.read()
404
                read_bytes(None)
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
405
            except errors.UnexpectedEndOfContainerError:
406
                pass
407
            else:
408
                self.fail(
409
                    "UnexpectedEndOfContainerError not raised when parsing %r"
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
410
                    % (incomplete_record,))
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
411
2506.5.2 by Andrew Bennetts
Raise InvalidRecordError on invalid names.
412
    def test_initial_eof(self):
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
413
        """EOF before any bytes read at all."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
414
        reader = self.get_reader_for("")
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
415
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
416
2506.5.2 by Andrew Bennetts
Raise InvalidRecordError on invalid names.
417
    def test_eof_after_length(self):
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
418
        """EOF after reading the length and before reading name(s)."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
419
        reader = self.get_reader_for("123\n")
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
420
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
421
2506.5.2 by Andrew Bennetts
Raise InvalidRecordError on invalid names.
422
    def test_eof_during_name(self):
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
423
        """EOF during reading a name."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
424
        reader = self.get_reader_for("123\nname")
2506.3.3 by Andrew Bennetts
Deal with EOF in the middle of a bytes record.
425
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
426
2535.3.26 by Andrew Bennetts
Revert merge of container-format changes rejected for bzr.dev (i.e. undo andrew.bennetts@canonical.com-20070717044423-cetp5spep142xsr4).
427
    def test_read_invalid_name_whitespace(self):
428
        """Names must have no whitespace."""
429
        # A name with a space.
430
        reader = self.get_reader_for("0\nbad name\n\n")
431
        self.assertRaises(errors.InvalidRecordError, reader.read)
432
433
        # A name with a tab.
434
        reader = self.get_reader_for("0\nbad\tname\n\n")
435
        self.assertRaises(errors.InvalidRecordError, reader.read)
436
437
        # A name with a vertical tab.
438
        reader = self.get_reader_for("0\nbad\vname\n\n")
439
        self.assertRaises(errors.InvalidRecordError, reader.read)
440
441
    def test_validate_whitespace_in_name(self):
442
        """Names must have no whitespace."""
443
        reader = self.get_reader_for("0\nbad name\n\n")
444
        self.assertRaises(errors.InvalidRecordError, reader.validate)
445
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
446
    def test_validate_interrupted_prelude(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
447
        """EOF during reading a record's prelude causes validate to fail."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
448
        reader = self.get_reader_for("")
449
        self.assertRaises(
450
            errors.UnexpectedEndOfContainerError, reader.validate)
451
452
    def test_validate_interrupted_body(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
453
        """EOF during reading a record's body causes validate to fail."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
454
        reader = self.get_reader_for("1\n\n")
455
        self.assertRaises(
456
            errors.UnexpectedEndOfContainerError, reader.validate)
457
458
    def test_validate_unparseable_length(self):
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
459
        """An unparseable record length causes validate to fail."""
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
460
        reader = self.get_reader_for("\n\n")
461
        self.assertRaises(
462
            errors.InvalidRecordError, reader.validate)
463
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
464
    def test_validate_undecodeable_name(self):
465
        """Names that aren't valid UTF-8 cause validate to fail."""
466
        reader = self.get_reader_for("0\n\xcc\n\n")
467
        self.assertRaises(errors.InvalidRecordError, reader.validate)
468
469
    def test_read_max_length(self):
470
        """If the max_length passed to the callable returned by read is not
471
        None, then no more than that many bytes will be read.
472
        """
473
        reader = self.get_reader_for("6\n\nabcdef")
474
        names, get_bytes = reader.read()
475
        self.assertEqual('abc', get_bytes(3))
476
477
    def test_read_no_max_length(self):
478
        """If the max_length passed to the callable returned by read is None,
479
        then all the bytes in the record will be read.
480
        """
481
        reader = self.get_reader_for("6\n\nabcdef")
482
        names, get_bytes = reader.read()
483
        self.assertEqual('abcdef', get_bytes(None))
484
485
    def test_repeated_read_calls(self):
486
        """Repeated calls to the callable returned from BytesRecordReader.read
487
        will not read beyond the end of the record.
488
        """
489
        reader = self.get_reader_for("6\n\nabcdefB3\nnext-record\nXXX")
490
        names, get_bytes = reader.read()
491
        self.assertEqual('abcdef', get_bytes(None))
492
        self.assertEqual('', get_bytes(None))
493
        self.assertEqual('', get_bytes(99))
494
495
2661.2.3 by Robert Collins
Review feedback.
496
class TestMakeReadvReader(tests.TestCaseWithTransport):
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
497
498
    def test_read_skipping_records(self):
499
        pack_data = StringIO()
500
        writer = pack.ContainerWriter(pack_data.write)
501
        writer.begin()
502
        memos = []
503
        memos.append(writer.add_bytes_record('abc', names=[]))
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
504
        memos.append(writer.add_bytes_record('def', names=[('name1', )]))
505
        memos.append(writer.add_bytes_record('ghi', names=[('name2', )]))
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
506
        memos.append(writer.add_bytes_record('jkl', names=[]))
507
        writer.end()
508
        transport = self.get_transport()
2661.2.3 by Robert Collins
Review feedback.
509
        transport.put_bytes('mypack', pack_data.getvalue())
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
510
        requested_records = [memos[0], memos[2]]
511
        reader = pack.make_readv_reader(transport, 'mypack', requested_records)
512
        result = []
513
        for names, reader_func in reader.iter_records():
514
            result.append((names, reader_func(None)))
2682.1.1 by Robert Collins
* The ``bzrlib.pack`` interface has changed to use tuples of bytestrings
515
        self.assertEqual([([], 'abc'), ([('name2', )], 'ghi')], result)
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
516
517
518
class TestReadvFile(tests.TestCaseWithTransport):
2661.2.3 by Robert Collins
Review feedback.
519
    """Tests of the ReadVFile class.
520
521
    Error cases are deliberately undefined: this code adapts the underlying
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
522
    transport interface to a single 'streaming read' interface as
2661.2.3 by Robert Collins
Review feedback.
523
    ContainerReader needs.
524
    """
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
525
526
    def test_read_bytes(self):
2661.2.3 by Robert Collins
Review feedback.
527
        """Test reading of both single bytes and all bytes in a hunk."""
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
528
        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)]))
531
        results = []
532
        results.append(f.read(1))
533
        results.append(f.read(2))
534
        results.append(f.read(1))
535
        results.append(f.read(1))
536
        results.append(f.read(1))
537
        self.assertEqual(['0', '12', '4', '6', '7'], results)
538
539
    def test_readline(self):
2661.2.3 by Robert Collins
Review feedback.
540
        """Test using readline() as ContainerReader does.
541
542
        This is always within a readv hunk, never across it.
543
        """
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
544
        transport = self.get_transport()
545
        transport.put_bytes('sample', '0\n2\n4\n')
546
        f = pack.ReadVFile(transport.readv('sample', [(0,2), (2,4)]))
547
        results = []
548
        results.append(f.readline())
549
        results.append(f.readline())
550
        results.append(f.readline())
551
        self.assertEqual(['0\n', '2\n', '4\n'], results)
552
553
    def test_readline_and_read(self):
2661.2.3 by Robert Collins
Review feedback.
554
        """Test exercising one byte reads, readline, and then read again."""
2661.2.2 by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack
555
        transport = self.get_transport()
556
        transport.put_bytes('sample', '0\n2\n4\n')
557
        f = pack.ReadVFile(transport.readv('sample', [(0,6)]))
558
        results = []
559
        results.append(f.read(1))
560
        results.append(f.readline())
561
        results.append(f.read(4))
562
        self.assertEqual(['0', '\n', '2\n4\n'], results)
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
563
564
565
class PushParserTestCase(tests.TestCase):
2916.2.13 by Andrew Bennetts
Improve some docstrings.
566
    """Base class for TestCases involving ContainerPushParser."""
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
567
568
    def make_parser_expecting_record_type(self):
569
        parser = pack.ContainerPushParser()
570
        parser.accept_bytes("Bazaar pack format 1 (introduced in 0.18)\n")
571
        return parser
572
573
    def make_parser_expecting_bytes_record(self):
574
        parser = pack.ContainerPushParser()
575
        parser.accept_bytes("Bazaar pack format 1 (introduced in 0.18)\nB")
576
        return parser
577
578
    def assertRecordParsing(self, expected_record, bytes):
2916.2.13 by Andrew Bennetts
Improve some docstrings.
579
        """Assert that 'bytes' is parsed as a given bytes record.
580
581
        :param expected_record: A tuple of (names, bytes).
582
        """
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
583
        parser = self.make_parser_expecting_bytes_record()
584
        parser.accept_bytes(bytes)
585
        parsed_records = parser.read_pending_records()
586
        self.assertEqual([expected_record], parsed_records)
587
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
588
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
589
class TestContainerPushParser(PushParserTestCase):
2916.2.13 by Andrew Bennetts
Improve some docstrings.
590
    """Tests for ContainerPushParser.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
591
2916.2.13 by Andrew Bennetts
Improve some docstrings.
592
    The ContainerPushParser reads format 1 containers, so these tests
593
    explicitly test how it reacts to format 1 data.  If a new version of the
594
    format is added, then separate tests for that format should be added.
595
    """
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
596
597
    def test_construct(self):
598
        """ContainerPushParser can be constructed."""
599
        pack.ContainerPushParser()
600
601
    def test_multiple_records_at_once(self):
2916.2.2 by Andrew Bennetts
Add a couple of docstrings to the tests.
602
        """If multiple records worth of data are fed to the parser in one
603
        string, the parser will correctly parse all the records.
604
605
        (A naive implementation might stop after parsing the first record.)
606
        """
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
607
        parser = self.make_parser_expecting_record_type()
608
        parser.accept_bytes("B5\nname1\n\nbody1B5\nname2\n\nbody2")
609
        self.assertEqual(
610
            [([('name1',)], 'body1'), ([('name2',)], 'body2')],
611
            parser.read_pending_records())
612
4464.1.1 by Aaron Bentley
ContainerPushParser.accept_bytes handles zero-length records correctly.
613
    def test_multiple_empty_records_at_once(self):
614
        """If multiple empty records worth of data are fed to the parser in one
615
        string, the parser will correctly parse all the records.
616
617
        (A naive implementation might stop after parsing the first empty
618
        record, because the buffer size had not changed.)
619
        """
620
        parser = self.make_parser_expecting_record_type()
621
        parser.accept_bytes("B0\nname1\n\nB0\nname2\n\n")
622
        self.assertEqual(
623
            [([('name1',)], ''), ([('name2',)], '')],
624
            parser.read_pending_records())
625
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
626
627
class TestContainerPushParserBytesParsing(PushParserTestCase):
2916.2.13 by Andrew Bennetts
Improve some docstrings.
628
    """Tests for reading Bytes records with ContainerPushParser.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
629
2916.2.13 by Andrew Bennetts
Improve some docstrings.
630
    The ContainerPushParser reads format 1 containers, so these tests
631
    explicitly test how it reacts to format 1 data.  If a new version of the
632
    format is added, then separate tests for that format should be added.
633
    """
2916.2.1 by Andrew Bennetts
Initial implementation of a 'push' parser for the container format.
634
635
    def test_record_with_no_name(self):
636
        """Reading a Bytes record with no name returns an empty list of
637
        names.
638
        """
639
        self.assertRecordParsing(([], 'aaaaa'), "5\n\naaaaa")
640
641
    def test_record_with_one_name(self):
642
        """Reading a Bytes record with one name returns a list of just that
643
        name.
644
        """
645
        self.assertRecordParsing(
646
            ([('name1', )], 'aaaaa'),
647
            "5\nname1\n\naaaaa")
648
649
    def test_record_with_two_names(self):
650
        """Reading a Bytes record with two names returns a list of both names.
651
        """
652
        self.assertRecordParsing(
653
            ([('name1', ), ('name2', )], 'aaaaa'),
654
            "5\nname1\nname2\n\naaaaa")
655
656
    def test_record_with_two_part_names(self):
657
        """Reading a Bytes record with a two_part name reads both."""
658
        self.assertRecordParsing(
659
            ([('name1', 'name2')], 'aaaaa'),
660
            "5\nname1\x00name2\n\naaaaa")
661
662
    def test_invalid_length(self):
663
        """If the length-prefix is not a number, parsing raises
664
        InvalidRecordError.
665
        """
666
        parser = self.make_parser_expecting_bytes_record()
667
        self.assertRaises(
668
            errors.InvalidRecordError, parser.accept_bytes, "not a number\n")
669
670
    def test_incomplete_record(self):
671
        """If the bytes seen so far don't form a complete record, then there
672
        will be nothing returned by read_pending_records.
673
        """
674
        parser = self.make_parser_expecting_bytes_record()
675
        parser.accept_bytes("5\n\nabcd")
676
        self.assertEqual([], parser.read_pending_records())
677
678
    def test_accept_nothing(self):
679
        """The edge case of parsing an empty string causes no error."""
680
        parser = self.make_parser_expecting_bytes_record()
681
        parser.accept_bytes("")
682
683
    def assertInvalidRecord(self, bytes):
684
        """Assert that parsing the given bytes will raise an
685
        InvalidRecordError.
686
        """
687
        parser = self.make_parser_expecting_bytes_record()
688
        self.assertRaises(
689
            errors.InvalidRecordError, parser.accept_bytes, bytes)
690
691
    def test_read_invalid_name_whitespace(self):
692
        """Names must have no whitespace."""
693
        # A name with a space.
694
        self.assertInvalidRecord("0\nbad name\n\n")
695
696
        # A name with a tab.
697
        self.assertInvalidRecord("0\nbad\tname\n\n")
698
699
        # A name with a vertical tab.
700
        self.assertInvalidRecord("0\nbad\vname\n\n")
701
702
    def test_repeated_read_pending_records(self):
703
        """read_pending_records will not return the same record twice."""
704
        parser = self.make_parser_expecting_bytes_record()
705
        parser.accept_bytes("6\n\nabcdef")
706
        self.assertEqual([([], 'abcdef')], parser.read_pending_records())
707
        self.assertEqual([], parser.read_pending_records())
708
709