~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_pack.py

Change read/iter_records to return a callable, add more validation, and
improve docstrings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
136
136
        """
137
137
        reader = self.get_reader_for("Bazaar pack format 1\nB5\n\naaaaaE")
138
138
        expected_records = [([], 'aaaaa')]
139
 
        self.assertEqual(expected_records, list(reader.iter_records()))
 
139
        self.assertEqual(
 
140
            expected_records,
 
141
            [(names, read_bytes(None))
 
142
             for (names, read_bytes) in reader.iter_records()])
140
143
 
141
144
    def test_validate_empty_container(self):
 
145
        """validate does not raise an error for a container with no records."""
142
146
        reader = self.get_reader_for("Bazaar pack format 1\nE")
143
147
        # No exception raised
144
148
        reader.validate()
145
149
 
146
150
    def test_validate_non_empty_valid_container(self):
 
151
        """validate does not raise an error for a container with a valid record.
 
152
        """
147
153
        reader = self.get_reader_for("Bazaar pack format 1\nB3\nname\n\nabcE")
148
154
        # No exception raised
149
155
        reader.validate()
150
156
 
151
157
    def test_validate_bad_format(self):
 
158
        """validate raises an error for unrecognised format strings.
 
159
 
 
160
        It may raise either UnexpectedEndOfContainerError or
 
161
        UnknownContainerFormatError, depending on exactly what the string is.
 
162
        """
152
163
        inputs = ["", "x", "Bazaar pack format 1", "bad\n"]
153
164
        for input in inputs:
154
165
            reader = self.get_reader_for(input)
158
169
                reader.validate)
159
170
 
160
171
    def test_validate_bad_record_marker(self):
 
172
        """validate raises UnknownRecordTypeError for unrecognised record
 
173
        types.
 
174
        """
161
175
        reader = self.get_reader_for("Bazaar pack format 1\nX")
162
176
        self.assertRaises(errors.UnknownRecordTypeError, reader.validate)
163
177
 
164
178
    def test_validate_data_after_end_marker(self):
 
179
        """validate raises ContainerHasExcessDataError if there are any bytes
 
180
        after the end of the container.
 
181
        """
165
182
        reader = self.get_reader_for("Bazaar pack format 1\nEcrud")
166
183
        self.assertRaises(
167
184
            errors.ContainerHasExcessDataError, reader.validate)
168
185
 
169
186
    def test_validate_no_end_marker(self):
 
187
        """validate raises UnexpectedEndOfContainerError if there's no end of
 
188
        container marker, even if the container up to this point has been valid.
 
189
        """
170
190
        reader = self.get_reader_for("Bazaar pack format 1\n")
171
191
        self.assertRaises(
172
192
            errors.UnexpectedEndOfContainerError, reader.validate)
173
193
 
 
194
    def test_validate_duplicate_name(self):
 
195
        """validate raises DuplicateRecordNameError if the same name occurs
 
196
        multiple times in the container.
 
197
        """
 
198
        reader = self.get_reader_for(
 
199
            "Bazaar pack format 1\n"
 
200
            "B0\nname\n\n"
 
201
            "B0\nname\n\n"
 
202
            "E")
 
203
        self.assertRaises(errors.DuplicateRecordNameError, reader.validate)
 
204
 
 
205
    def test_validate_undecodeable_name(self):
 
206
        """Names that aren't valid UTF-8 cause validate to fail."""
 
207
        reader = self.get_reader_for("Bazaar pack format 1\nB0\n\xcc\n\nE")
 
208
        self.assertRaises(errors.InvalidRecordError, reader.validate)
 
209
        
174
210
 
175
211
class TestBytesRecordReader(tests.TestCase):
176
 
    """Tests for parsing Bytes records with BytesRecordReader."""
 
212
    """Tests for reading and validating Bytes records with BytesRecordReader."""
177
213
 
178
214
    def get_reader_for(self, bytes):
179
215
        stream = StringIO(bytes)
185
221
        names.
186
222
        """
187
223
        reader = self.get_reader_for("5\n\naaaaa")
188
 
        names, bytes = reader.read()
 
224
        names, get_bytes = reader.read()
189
225
        self.assertEqual([], names)
190
 
        self.assertEqual('aaaaa', bytes)
 
226
        self.assertEqual('aaaaa', get_bytes(None))
191
227
 
192
228
    def test_record_with_one_name(self):
193
229
        """Reading a Bytes record with one name returns a list of just that
194
230
        name.
195
231
        """
196
232
        reader = self.get_reader_for("5\nname1\n\naaaaa")
197
 
        names, bytes = reader.read()
 
233
        names, get_bytes = reader.read()
198
234
        self.assertEqual(['name1'], names)
199
 
        self.assertEqual('aaaaa', bytes)
 
235
        self.assertEqual('aaaaa', get_bytes(None))
200
236
 
201
237
    def test_record_with_two_names(self):
202
238
        """Reading a Bytes record with two names returns a list of both names.
203
239
        """
204
240
        reader = self.get_reader_for("5\nname1\nname2\n\naaaaa")
205
 
        names, bytes = reader.read()
 
241
        names, get_bytes = reader.read()
206
242
        self.assertEqual(['name1', 'name2'], names)
207
 
        self.assertEqual('aaaaa', bytes)
 
243
        self.assertEqual('aaaaa', get_bytes(None))
208
244
 
209
245
    def test_invalid_length(self):
210
246
        """If the length-prefix is not a number, parsing raises
225
261
        """
226
262
        complete_record = "6\nname\n\nabcdef"
227
263
        for count in range(0, len(complete_record)):
228
 
            reader = self.get_reader_for(complete_record[:count])
229
 
            # We don't use assertRaises to make diagnosing failures easier.
 
264
            incomplete_record = complete_record[:count]
 
265
            reader = self.get_reader_for(incomplete_record)
 
266
            # We don't use assertRaises to make diagnosing failures easier
 
267
            # (assertRaises doesn't allow a custom failure message).
230
268
            try:
231
 
                reader.read()
 
269
                names, read_bytes = reader.read()
 
270
                read_bytes(None)
232
271
            except errors.UnexpectedEndOfContainerError:
233
272
                pass
234
273
            else:
235
274
                self.fail(
236
275
                    "UnexpectedEndOfContainerError not raised when parsing %r"
237
 
                    % (input.getvalue()))
 
276
                    % (incomplete_record,))
238
277
 
239
278
    def test_initial_eof(self):
240
279
        """EOF before any bytes read at all."""
251
290
        reader = self.get_reader_for("123\nname")
252
291
        self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read)
253
292
 
254
 
    def test_invalid_name_whitespace(self):
 
293
    def test_read_invalid_name_whitespace(self):
255
294
        """Names must have no whitespace."""
256
295
        # A name with a space.
257
296
        reader = self.get_reader_for("0\nbad name\n\n")
266
305
        self.assertRaises(errors.InvalidRecordError, reader.read)
267
306
 
268
307
    def test_validate_whitespace_in_name(self):
269
 
        reader = self.get_reader_for("0\nbad name\n\nE")
 
308
        """Names must have no whitespace."""
 
309
        reader = self.get_reader_for("0\nbad name\n\n")
270
310
        self.assertRaises(errors.InvalidRecordError, reader.validate)
271
311
 
272
312
    def test_validate_interrupted_prelude(self):
 
313
        """EOF during reading a record's prelude causes validate to fail."""
273
314
        reader = self.get_reader_for("")
274
315
        self.assertRaises(
275
316
            errors.UnexpectedEndOfContainerError, reader.validate)
276
317
 
277
318
    def test_validate_interrupted_body(self):
 
319
        """EOF during reading a record's body causes validate to fail."""
278
320
        reader = self.get_reader_for("1\n\n")
279
321
        self.assertRaises(
280
322
            errors.UnexpectedEndOfContainerError, reader.validate)
281
323
 
282
324
    def test_validate_unparseable_length(self):
 
325
        """An unparseable record length causes validate to fail."""
283
326
        reader = self.get_reader_for("\n\n")
284
327
        self.assertRaises(
285
328
            errors.InvalidRecordError, reader.validate)
286
329
 
 
330
    def test_validate_undecodeable_name(self):
 
331
        """Names that aren't valid UTF-8 cause validate to fail."""
 
332
        reader = self.get_reader_for("0\n\xcc\n\n")
 
333
        self.assertRaises(errors.InvalidRecordError, reader.validate)
 
334
 
 
335
    def test_read_max_length(self):
 
336
        """If the max_length passed to the callable returned by read is not
 
337
        None, then no more than that many bytes will be read.
 
338
        """
 
339
        reader = self.get_reader_for("6\n\nabcdef")
 
340
        names, get_bytes = reader.read()
 
341
        self.assertEqual('abc', get_bytes(3))
 
342
 
 
343
    def test_read_no_max_length(self):
 
344
        """If the max_length passed to the callable returned by read is None,
 
345
        then all the bytes in the record will be read.
 
346
        """
 
347
        reader = self.get_reader_for("6\n\nabcdef")
 
348
        names, get_bytes = reader.read()
 
349
        self.assertEqual('abcdef', get_bytes(None))
 
350
 
 
351
    def test_repeated_read_calls(self):
 
352
        """Repeated calls to the callable returned from BytesRecordReader.read
 
353
        will not read beyond the end of the record.
 
354
        """
 
355
        reader = self.get_reader_for("6\n\nabcdefB3\nnext-record\nXXX")
 
356
        names, get_bytes = reader.read()
 
357
        self.assertEqual('abcdef', get_bytes(None))
 
358
        self.assertEqual('', get_bytes(None))
 
359
        self.assertEqual('', get_bytes(99))
 
360
 
 
361