bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
|
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
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
||
|
2506.3.1
by Andrew Bennetts
More progress: |
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 |
||
|
2506.3.2
by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool. |
22 |
from bzrlib import pack, errors, tests |
23 |
||
24 |
||
25 |
class TestContainerWriter(tests.TestCase): |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
26 |
|
27 |
def test_construct(self): |
|
28 |
"""Test constructing a ContainerWriter. |
|
29 |
|
|
30 |
This uses None as the output stream to show that the constructor doesn't
|
|
31 |
try to use the output stream.
|
|
32 |
"""
|
|
|
2506.3.1
by Andrew Bennetts
More progress: |
33 |
writer = pack.ContainerWriter(None) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
34 |
|
35 |
def test_begin(self): |
|
|
2506.3.2
by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool. |
36 |
"""The begin() method writes the container format marker line.""" |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
37 |
output = StringIO() |
|
2506.3.1
by Andrew Bennetts
More progress: |
38 |
writer = pack.ContainerWriter(output.write) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
39 |
writer.begin() |
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
40 |
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\n', |
41 |
output.getvalue()) |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
42 |
|
43 |
def test_end(self): |
|
|
2506.3.2
by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool. |
44 |
"""The end() method writes an End Marker record.""" |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
45 |
output = StringIO() |
|
2506.3.1
by Andrew Bennetts
More progress: |
46 |
writer = pack.ContainerWriter(output.write) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
47 |
writer.begin() |
48 |
writer.end() |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
49 |
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\nE', |
50 |
output.getvalue()) |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
51 |
|
52 |
def test_add_bytes_record_no_name(self): |
|
53 |
"""Add a bytes record with no name.""" |
|
54 |
output = StringIO() |
|
|
2506.3.1
by Andrew Bennetts
More progress: |
55 |
writer = pack.ContainerWriter(output.write) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
56 |
writer.begin() |
|
2661.2.1
by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to |
57 |
offset, length = writer.add_bytes_record('abc', names=[]) |
58 |
self.assertEqual((42, 7), (offset, length)) |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
59 |
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\nB3\n\nabc', |
60 |
output.getvalue()) |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
61 |
|
62 |
def test_add_bytes_record_one_name(self): |
|
63 |
"""Add a bytes record with one name.""" |
|
64 |
output = StringIO() |
|
|
2506.3.1
by Andrew Bennetts
More progress: |
65 |
writer = pack.ContainerWriter(output.write) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
66 |
writer.begin() |
|
2661.2.1
by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to |
67 |
offset, length = writer.add_bytes_record('abc', names=['name1']) |
68 |
self.assertEqual((42, 13), (offset, length)) |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
69 |
self.assertEqual( |
70 |
'Bazaar pack format 1 (introduced in 0.18)\n' |
|
71 |
'B3\nname1\n\nabc', |
|
72 |
output.getvalue()) |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
73 |
|
74 |
def test_add_bytes_record_two_names(self): |
|
75 |
"""Add a bytes record with two names.""" |
|
76 |
output = StringIO() |
|
|
2506.3.1
by Andrew Bennetts
More progress: |
77 |
writer = pack.ContainerWriter(output.write) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
78 |
writer.begin() |
|
2661.2.1
by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to |
79 |
offset, length = writer.add_bytes_record('abc', names=['name1', 'name2']) |
80 |
self.assertEqual((42, 19), (offset, length)) |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
81 |
self.assertEqual( |
82 |
'Bazaar pack format 1 (introduced in 0.18)\n' |
|
83 |
'B3\nname1\nname2\n\nabc', |
|
84 |
output.getvalue()) |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
85 |
|
|
2661.2.1
by Robert Collins
* ``bzrlib.pack.ContainerWriter`` now returns an offset, length tuple to |
86 |
def test_add_second_bytes_record_gets_higher_offset(self): |
87 |
output = StringIO() |
|
88 |
writer = pack.ContainerWriter(output.write) |
|
89 |
writer.begin() |
|
90 |
writer.add_bytes_record('abc', names=[]) |
|
91 |
offset, length = writer.add_bytes_record('abc', names=[]) |
|
92 |
self.assertEqual((49, 7), (offset, length)) |
|
93 |
self.assertEqual( |
|
94 |
'Bazaar pack format 1 (introduced in 0.18)\n' |
|
95 |
'B3\n\nabc' |
|
96 |
'B3\n\nabc', |
|
97 |
output.getvalue()) |
|
98 |
||
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
99 |
def test_add_bytes_record_invalid_name(self): |
100 |
"""Adding a Bytes record with a name with whitespace in it raises |
|
101 |
InvalidRecordError.
|
|
102 |
"""
|
|
103 |
output = StringIO() |
|
104 |
writer = pack.ContainerWriter(output.write) |
|
105 |
writer.begin() |
|
106 |
self.assertRaises( |
|
107 |
errors.InvalidRecordError, |
|
108 |
writer.add_bytes_record, 'abc', names=['bad name']) |
|
109 |
||
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
110 |
|
|
2506.3.2
by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool. |
111 |
class TestContainerReader(tests.TestCase): |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
112 |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
113 |
def get_reader_for(self, bytes): |
114 |
stream = StringIO(bytes) |
|
|
2506.2.9
by Aaron Bentley
Use file-like objects as container input, not callables |
115 |
reader = pack.ContainerReader(stream) |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
116 |
return reader |
117 |
||
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
118 |
def test_construct(self): |
119 |
"""Test constructing a ContainerReader. |
|
120 |
|
|
121 |
This uses None as the output stream to show that the constructor doesn't
|
|
122 |
try to use the input stream.
|
|
123 |
"""
|
|
|
2506.3.1
by Andrew Bennetts
More progress: |
124 |
reader = pack.ContainerReader(None) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
125 |
|
126 |
def test_empty_container(self): |
|
127 |
"""Read an empty container.""" |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
128 |
reader = self.get_reader_for( |
129 |
"Bazaar pack format 1 (introduced in 0.18)\nE") |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
130 |
self.assertEqual([], list(reader.iter_records())) |
131 |
||
132 |
def test_unknown_format(self): |
|
133 |
"""Unrecognised container formats raise UnknownContainerFormatError.""" |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
134 |
reader = self.get_reader_for("unknown format\n") |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
135 |
self.assertRaises( |
136 |
errors.UnknownContainerFormatError, reader.iter_records) |
|
137 |
||
138 |
def test_unexpected_end_of_container(self): |
|
139 |
"""Containers that don't end with an End Marker record should cause |
|
140 |
UnexpectedEndOfContainerError to be raised.
|
|
141 |
"""
|
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
142 |
reader = self.get_reader_for( |
143 |
"Bazaar pack format 1 (introduced in 0.18)\n") |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
144 |
iterator = reader.iter_records() |
145 |
self.assertRaises( |
|
146 |
errors.UnexpectedEndOfContainerError, iterator.next) |
|
147 |
||
148 |
def test_unknown_record_type(self): |
|
149 |
"""Unknown record types cause UnknownRecordTypeError to be raised.""" |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
150 |
reader = self.get_reader_for( |
151 |
"Bazaar pack format 1 (introduced in 0.18)\nX") |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
152 |
iterator = reader.iter_records() |
153 |
self.assertRaises( |
|
154 |
errors.UnknownRecordTypeError, iterator.next) |
|
155 |
||
|
2506.3.1
by Andrew Bennetts
More progress: |
156 |
def test_container_with_one_unnamed_record(self): |
157 |
"""Read a container with one Bytes record. |
|
158 |
|
|
|
2506.3.2
by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool. |
159 |
Parsing Bytes records is more thoroughly exercised by
|
160 |
TestBytesRecordReader. This test is here to ensure that
|
|
161 |
ContainerReader's integration with BytesRecordReader is working.
|
|
|
2506.3.1
by Andrew Bennetts
More progress: |
162 |
"""
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
163 |
reader = self.get_reader_for( |
164 |
"Bazaar pack format 1 (introduced in 0.18)\nB5\n\naaaaaE") |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
165 |
expected_records = [([], 'aaaaa')] |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
166 |
self.assertEqual( |
167 |
expected_records, |
|
168 |
[(names, read_bytes(None)) |
|
169 |
for (names, read_bytes) in reader.iter_records()]) |
|
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
170 |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
171 |
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. |
172 |
"""validate does not raise an error for a container with no records.""" |
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
173 |
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. |
174 |
# No exception raised
|
175 |
reader.validate() |
|
176 |
||
177 |
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. |
178 |
"""validate does not raise an error for a container with a valid record. |
179 |
"""
|
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
180 |
reader = self.get_reader_for( |
181 |
"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. |
182 |
# No exception raised
|
183 |
reader.validate() |
|
184 |
||
185 |
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. |
186 |
"""validate raises an error for unrecognised format strings. |
187 |
||
188 |
It may raise either UnexpectedEndOfContainerError or
|
|
189 |
UnknownContainerFormatError, depending on exactly what the string is.
|
|
190 |
"""
|
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
191 |
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. |
192 |
for input in inputs: |
193 |
reader = self.get_reader_for(input) |
|
194 |
self.assertRaises( |
|
195 |
(errors.UnexpectedEndOfContainerError, |
|
196 |
errors.UnknownContainerFormatError), |
|
197 |
reader.validate) |
|
198 |
||
199 |
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. |
200 |
"""validate raises UnknownRecordTypeError for unrecognised record |
201 |
types.
|
|
202 |
"""
|
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
203 |
reader = self.get_reader_for( |
204 |
"Bazaar pack format 1 (introduced in 0.18)\nX") |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
205 |
self.assertRaises(errors.UnknownRecordTypeError, reader.validate) |
206 |
||
207 |
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. |
208 |
"""validate raises ContainerHasExcessDataError if there are any bytes |
209 |
after the end of the container.
|
|
210 |
"""
|
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
211 |
reader = self.get_reader_for( |
212 |
"Bazaar pack format 1 (introduced in 0.18)\nEcrud") |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
213 |
self.assertRaises( |
214 |
errors.ContainerHasExcessDataError, reader.validate) |
|
215 |
||
216 |
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. |
217 |
"""validate raises UnexpectedEndOfContainerError if there's no end of |
218 |
container marker, even if the container up to this point has been valid.
|
|
219 |
"""
|
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
220 |
reader = self.get_reader_for( |
221 |
"Bazaar pack format 1 (introduced in 0.18)\n") |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
222 |
self.assertRaises( |
223 |
errors.UnexpectedEndOfContainerError, reader.validate) |
|
224 |
||
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
225 |
def test_validate_duplicate_name(self): |
226 |
"""validate raises DuplicateRecordNameError if the same name occurs |
|
227 |
multiple times in the container.
|
|
228 |
"""
|
|
229 |
reader = self.get_reader_for( |
|
|
2506.2.10
by Andrew Bennetts
Add '(introduced in 0.18)' to pack format string. |
230 |
"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. |
231 |
"B0\nname\n\n" |
232 |
"B0\nname\n\n" |
|
233 |
"E") |
|
234 |
self.assertRaises(errors.DuplicateRecordNameError, reader.validate) |
|
235 |
||
236 |
def test_validate_undecodeable_name(self): |
|
237 |
"""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. |
238 |
reader = self.get_reader_for( |
239 |
"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. |
240 |
self.assertRaises(errors.InvalidRecordError, reader.validate) |
241 |
||
|
2506.3.1
by Andrew Bennetts
More progress: |
242 |
|
|
2506.3.2
by Andrew Bennetts
Test docstring tweaks, inspired by looking over the output of jml's testdoc tool. |
243 |
class TestBytesRecordReader(tests.TestCase): |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
244 |
"""Tests for reading and validating Bytes records with BytesRecordReader.""" |
|
2506.3.1
by Andrew Bennetts
More progress: |
245 |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
246 |
def get_reader_for(self, bytes): |
247 |
stream = StringIO(bytes) |
|
|
2506.2.9
by Aaron Bentley
Use file-like objects as container input, not callables |
248 |
reader = pack.BytesRecordReader(stream) |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
249 |
return reader |
250 |
||
|
2506.3.1
by Andrew Bennetts
More progress: |
251 |
def test_record_with_no_name(self): |
252 |
"""Reading a Bytes record with no name returns an empty list of |
|
253 |
names.
|
|
254 |
"""
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
255 |
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. |
256 |
names, get_bytes = reader.read() |
|
2506.3.1
by Andrew Bennetts
More progress: |
257 |
self.assertEqual([], names) |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
258 |
self.assertEqual('aaaaa', get_bytes(None)) |
|
2506.3.1
by Andrew Bennetts
More progress: |
259 |
|
260 |
def test_record_with_one_name(self): |
|
261 |
"""Reading a Bytes record with one name returns a list of just that |
|
262 |
name.
|
|
263 |
"""
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
264 |
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. |
265 |
names, get_bytes = reader.read() |
|
2506.3.1
by Andrew Bennetts
More progress: |
266 |
self.assertEqual(['name1'], names) |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
267 |
self.assertEqual('aaaaa', get_bytes(None)) |
|
2506.3.1
by Andrew Bennetts
More progress: |
268 |
|
269 |
def test_record_with_two_names(self): |
|
270 |
"""Reading a Bytes record with two names returns a list of both names. |
|
271 |
"""
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
272 |
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. |
273 |
names, get_bytes = reader.read() |
|
2506.3.1
by Andrew Bennetts
More progress: |
274 |
self.assertEqual(['name1', 'name2'], names) |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
275 |
self.assertEqual('aaaaa', get_bytes(None)) |
|
2506.3.1
by Andrew Bennetts
More progress: |
276 |
|
277 |
def test_invalid_length(self): |
|
278 |
"""If the length-prefix is not a number, parsing raises |
|
279 |
InvalidRecordError.
|
|
280 |
"""
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
281 |
reader = self.get_reader_for("not a number\n") |
|
2506.3.1
by Andrew Bennetts
More progress: |
282 |
self.assertRaises(errors.InvalidRecordError, reader.read) |
|
2506.2.1
by Andrew Bennetts
Start implementing container format reading and writing. |
283 |
|
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
284 |
def test_early_eof(self): |
285 |
"""Tests for premature EOF occuring during parsing Bytes records with |
|
286 |
BytesRecordReader.
|
|
287 |
|
|
288 |
A incomplete container might be interrupted at any point. The
|
|
289 |
BytesRecordReader needs to cope with the input stream running out no
|
|
290 |
matter where it is in the parsing process.
|
|
291 |
||
292 |
In all cases, UnexpectedEndOfContainerError should be raised.
|
|
293 |
"""
|
|
294 |
complete_record = "6\nname\n\nabcdef" |
|
295 |
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. |
296 |
incomplete_record = complete_record[:count] |
297 |
reader = self.get_reader_for(incomplete_record) |
|
298 |
# We don't use assertRaises to make diagnosing failures easier
|
|
299 |
# (assertRaises doesn't allow a custom failure message).
|
|
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
300 |
try: |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
301 |
names, read_bytes = reader.read() |
302 |
read_bytes(None) |
|
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
303 |
except errors.UnexpectedEndOfContainerError: |
304 |
pass
|
|
305 |
else: |
|
306 |
self.fail( |
|
307 |
"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. |
308 |
% (incomplete_record,)) |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
309 |
|
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
310 |
def test_initial_eof(self): |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
311 |
"""EOF before any bytes read at all.""" |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
312 |
reader = self.get_reader_for("") |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
313 |
self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read) |
314 |
||
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
315 |
def test_eof_after_length(self): |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
316 |
"""EOF after reading the length and before reading name(s).""" |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
317 |
reader = self.get_reader_for("123\n") |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
318 |
self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read) |
319 |
||
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
320 |
def test_eof_during_name(self): |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
321 |
"""EOF during reading a name.""" |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
322 |
reader = self.get_reader_for("123\nname") |
|
2506.3.3
by Andrew Bennetts
Deal with EOF in the middle of a bytes record. |
323 |
self.assertRaises(errors.UnexpectedEndOfContainerError, reader.read) |
324 |
||
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
325 |
def test_read_invalid_name_whitespace(self): |
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
326 |
"""Names must have no whitespace.""" |
327 |
# A name with a space.
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
328 |
reader = self.get_reader_for("0\nbad name\n\n") |
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
329 |
self.assertRaises(errors.InvalidRecordError, reader.read) |
330 |
||
331 |
# A name with a tab.
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
332 |
reader = self.get_reader_for("0\nbad\tname\n\n") |
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
333 |
self.assertRaises(errors.InvalidRecordError, reader.read) |
334 |
||
335 |
# A name with a vertical tab.
|
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
336 |
reader = self.get_reader_for("0\nbad\vname\n\n") |
|
2506.5.2
by Andrew Bennetts
Raise InvalidRecordError on invalid names. |
337 |
self.assertRaises(errors.InvalidRecordError, reader.read) |
338 |
||
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
339 |
def test_validate_whitespace_in_name(self): |
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
340 |
"""Names must have no whitespace.""" |
341 |
reader = self.get_reader_for("0\nbad name\n\n") |
|
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
342 |
self.assertRaises(errors.InvalidRecordError, reader.validate) |
343 |
||
344 |
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. |
345 |
"""EOF during reading a record's prelude causes validate to fail.""" |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
346 |
reader = self.get_reader_for("") |
347 |
self.assertRaises( |
|
348 |
errors.UnexpectedEndOfContainerError, reader.validate) |
|
349 |
||
350 |
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. |
351 |
"""EOF during reading a record's body causes validate to fail.""" |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
352 |
reader = self.get_reader_for("1\n\n") |
353 |
self.assertRaises( |
|
354 |
errors.UnexpectedEndOfContainerError, reader.validate) |
|
355 |
||
356 |
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. |
357 |
"""An unparseable record length causes validate to fail.""" |
|
2506.2.6
by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader. |
358 |
reader = self.get_reader_for("\n\n") |
359 |
self.assertRaises( |
|
360 |
errors.InvalidRecordError, reader.validate) |
|
361 |
||
|
2506.6.1
by Andrew Bennetts
Return a callable instead of a str from read, and add more validation. |
362 |
def test_validate_undecodeable_name(self): |
363 |
"""Names that aren't valid UTF-8 cause validate to fail.""" |
|
364 |
reader = self.get_reader_for("0\n\xcc\n\n") |
|
365 |
self.assertRaises(errors.InvalidRecordError, reader.validate) |
|
366 |
||
367 |
def test_read_max_length(self): |
|
368 |
"""If the max_length passed to the callable returned by read is not |
|
369 |
None, then no more than that many bytes will be read.
|
|
370 |
"""
|
|
371 |
reader = self.get_reader_for("6\n\nabcdef") |
|
372 |
names, get_bytes = reader.read() |
|
373 |
self.assertEqual('abc', get_bytes(3)) |
|
374 |
||
375 |
def test_read_no_max_length(self): |
|
376 |
"""If the max_length passed to the callable returned by read is None, |
|
377 |
then all the bytes in the record will be read.
|
|
378 |
"""
|
|
379 |
reader = self.get_reader_for("6\n\nabcdef") |
|
380 |
names, get_bytes = reader.read() |
|
381 |
self.assertEqual('abcdef', get_bytes(None)) |
|
382 |
||
383 |
def test_repeated_read_calls(self): |
|
384 |
"""Repeated calls to the callable returned from BytesRecordReader.read |
|
385 |
will not read beyond the end of the record.
|
|
386 |
"""
|
|
387 |
reader = self.get_reader_for("6\n\nabcdefB3\nnext-record\nXXX") |
|
388 |
names, get_bytes = reader.read() |
|
389 |
self.assertEqual('abcdef', get_bytes(None)) |
|
390 |
self.assertEqual('', get_bytes(None)) |
|
391 |
self.assertEqual('', get_bytes(99)) |
|
392 |
||
393 |
||
|
2661.2.3
by Robert Collins
Review feedback. |
394 |
class TestMakeReadvReader(tests.TestCaseWithTransport): |
|
2661.2.2
by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack |
395 |
|
396 |
def test_read_skipping_records(self): |
|
397 |
pack_data = StringIO() |
|
398 |
writer = pack.ContainerWriter(pack_data.write) |
|
399 |
writer.begin() |
|
400 |
memos = [] |
|
401 |
memos.append(writer.add_bytes_record('abc', names=[])) |
|
402 |
memos.append(writer.add_bytes_record('def', names=['name1'])) |
|
403 |
memos.append(writer.add_bytes_record('ghi', names=['name2'])) |
|
404 |
memos.append(writer.add_bytes_record('jkl', names=[])) |
|
405 |
writer.end() |
|
406 |
transport = self.get_transport() |
|
|
2661.2.3
by Robert Collins
Review feedback. |
407 |
transport.put_bytes('mypack', pack_data.getvalue()) |
|
2661.2.2
by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack |
408 |
requested_records = [memos[0], memos[2]] |
409 |
reader = pack.make_readv_reader(transport, 'mypack', requested_records) |
|
410 |
result = [] |
|
411 |
for names, reader_func in reader.iter_records(): |
|
412 |
result.append((names, reader_func(None))) |
|
413 |
self.assertEqual([([], 'abc'), (['name2'], 'ghi')], result) |
|
414 |
||
415 |
||
416 |
class TestReadvFile(tests.TestCaseWithTransport): |
|
|
2661.2.3
by Robert Collins
Review feedback. |
417 |
"""Tests of the ReadVFile class. |
418 |
||
419 |
Error cases are deliberately undefined: this code adapts the underlying
|
|
420 |
transport interface to a single 'streaming read' interface as
|
|
421 |
ContainerReader needs.
|
|
422 |
"""
|
|
|
2661.2.2
by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack |
423 |
|
424 |
def test_read_bytes(self): |
|
|
2661.2.3
by Robert Collins
Review feedback. |
425 |
"""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 |
426 |
transport = self.get_transport() |
427 |
transport.put_bytes('sample', '0123456789') |
|
428 |
f = pack.ReadVFile(transport.readv('sample', [(0,1), (1,2), (4,1), (6,2)])) |
|
429 |
results = [] |
|
430 |
results.append(f.read(1)) |
|
431 |
results.append(f.read(2)) |
|
432 |
results.append(f.read(1)) |
|
433 |
results.append(f.read(1)) |
|
434 |
results.append(f.read(1)) |
|
435 |
self.assertEqual(['0', '12', '4', '6', '7'], results) |
|
436 |
||
437 |
def test_readline(self): |
|
|
2661.2.3
by Robert Collins
Review feedback. |
438 |
"""Test using readline() as ContainerReader does. |
439 |
||
440 |
This is always within a readv hunk, never across it.
|
|
441 |
"""
|
|
|
2661.2.2
by Robert Collins
* ``bzrlib.pack.make_readv_reader`` allows readv based access to pack |
442 |
transport = self.get_transport() |
443 |
transport.put_bytes('sample', '0\n2\n4\n') |
|
444 |
f = pack.ReadVFile(transport.readv('sample', [(0,2), (2,4)])) |
|
445 |
results = [] |
|
446 |
results.append(f.readline()) |
|
447 |
results.append(f.readline()) |
|
448 |
results.append(f.readline()) |
|
449 |
self.assertEqual(['0\n', '2\n', '4\n'], results) |
|
450 |
||
451 |
def test_readline_and_read(self): |
|
|
2661.2.3
by Robert Collins
Review feedback. |
452 |
"""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 |
453 |
transport = self.get_transport() |
454 |
transport.put_bytes('sample', '0\n2\n4\n') |
|
455 |
f = pack.ReadVFile(transport.readv('sample', [(0,6)])) |
|
456 |
results = [] |
|
457 |
results.append(f.read(1)) |
|
458 |
results.append(f.readline()) |
|
459 |
results.append(f.read(4)) |
|
460 |
self.assertEqual(['0', '\n', '2\n4\n'], results) |