22
22
from bzrlib import pack, errors, tests
25
class TestContainerSerialiser(tests.TestCase):
26
"""Tests for the ContainerSerialiser class."""
28
def test_construct(self):
29
"""Test constructing a ContainerSerialiser."""
30
pack.ContainerSerialiser()
33
serialiser = pack.ContainerSerialiser()
34
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\n',
38
serialiser = pack.ContainerSerialiser()
39
self.assertEqual('E', serialiser.end())
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)
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)
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)
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)
61
def test_bytes_record_whitespace_in_name_part(self):
62
serialiser = pack.ContainerSerialiser()
64
errors.InvalidRecordError,
65
serialiser.bytes_record, 'bytes', [('bad name',)])
67
def test_bytes_record_header(self):
68
serialiser = pack.ContainerSerialiser()
69
record = serialiser.bytes_header(32, [('name1',), ('name2',)])
70
self.assertEqual('B32\nname1\nname2\n\n', record)
73
25
class TestContainerWriter(tests.TestCase):
76
super(TestContainerWriter, self).setUp()
77
self.output = StringIO()
78
self.writer = pack.ContainerWriter(self.output.write)
80
def assertOutput(self, expected_output):
81
"""Assert that the output of self.writer ContainerWriter is equal to
84
self.assertEqual(expected_output, self.output.getvalue())
86
27
def test_construct(self):
87
28
"""Test constructing a ContainerWriter.
89
This uses None as the output stream to show that the constructor
90
doesn't try to use the output stream.
30
This uses None as the output stream to show that the constructor doesn't
31
try to use the output stream.
92
33
writer = pack.ContainerWriter(None)
94
35
def test_begin(self):
95
36
"""The begin() method writes the container format marker line."""
97
self.assertOutput('Bazaar pack format 1 (introduced in 0.18)\n')
38
writer = pack.ContainerWriter(output.write)
40
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\n',
99
43
def test_zero_records_written_after_begin(self):
100
44
"""After begin is written, 0 records have been written."""
102
self.assertEqual(0, self.writer.records_written)
46
writer = pack.ContainerWriter(output.write)
48
self.assertEqual(0, writer.records_written)
104
50
def test_end(self):
105
51
"""The end() method writes an End Marker record."""
108
self.assertOutput('Bazaar pack format 1 (introduced in 0.18)\nE')
53
writer = pack.ContainerWriter(output.write)
56
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\nE',
110
59
def test_empty_end_does_not_add_a_record_to_records_written(self):
111
60
"""The end() method does not count towards the records written."""
114
self.assertEqual(0, self.writer.records_written)
62
writer = pack.ContainerWriter(output.write)
65
self.assertEqual(0, writer.records_written)
116
67
def test_non_empty_end_does_not_add_a_record_to_records_written(self):
117
68
"""The end() method does not count towards the records written."""
119
self.writer.add_bytes_record('foo', names=[])
121
self.assertEqual(1, self.writer.records_written)
70
writer = pack.ContainerWriter(output.write)
72
writer.add_bytes_record('foo', names=[])
74
self.assertEqual(1, writer.records_written)
123
76
def test_add_bytes_record_no_name(self):
124
77
"""Add a bytes record with no name."""
126
offset, length = self.writer.add_bytes_record('abc', names=[])
79
writer = pack.ContainerWriter(output.write)
81
offset, length = writer.add_bytes_record('abc', names=[])
127
82
self.assertEqual((42, 7), (offset, length))
129
'Bazaar pack format 1 (introduced in 0.18)\nB3\n\nabc')
83
self.assertEqual('Bazaar pack format 1 (introduced in 0.18)\nB3\n\nabc',
131
86
def test_add_bytes_record_one_name(self):
132
87
"""Add a bytes record with one name."""
135
offset, length = self.writer.add_bytes_record(
136
'abc', names=[('name1', )])
89
writer = pack.ContainerWriter(output.write)
91
offset, length = writer.add_bytes_record('abc', names=[('name1', )])
137
92
self.assertEqual((42, 13), (offset, length))
139
'Bazaar pack format 1 (introduced in 0.18)\n'
142
def test_add_bytes_record_split_writes(self):
143
"""Write a large record which does multiple IOs"""
146
real_write = self.writer.write_func
148
def record_writes(bytes):
150
return real_write(bytes)
152
self.writer.write_func = record_writes
153
self.writer._JOIN_WRITES_THRESHOLD = 2
156
offset, length = self.writer.add_bytes_record(
157
'abcabc', names=[('name1', )])
158
self.assertEqual((42, 16), (offset, length))
160
'Bazaar pack format 1 (introduced in 0.18)\n'
161
'B6\nname1\n\nabcabc')
164
'Bazaar pack format 1 (introduced in 0.18)\n',
169
def test_add_bytes_record_two_names(self):
170
"""Add a bytes record with two names."""
172
offset, length = self.writer.add_bytes_record(
173
'abc', names=[('name1', ), ('name2', )])
174
self.assertEqual((42, 19), (offset, length))
176
'Bazaar pack format 1 (introduced in 0.18)\n'
177
'B3\nname1\nname2\n\nabc')
179
def test_add_bytes_record_two_names(self):
180
"""Add a bytes record with two names."""
182
offset, length = self.writer.add_bytes_record(
183
'abc', names=[('name1', ), ('name2', )])
184
self.assertEqual((42, 19), (offset, length))
186
'Bazaar pack format 1 (introduced in 0.18)\n'
187
'B3\nname1\nname2\n\nabc')
94
'Bazaar pack format 1 (introduced in 0.18)\n'
98
def test_add_bytes_record_two_names(self):
99
"""Add a bytes record with two names."""
101
writer = pack.ContainerWriter(output.write)
103
offset, length = writer.add_bytes_record('abc', names=[('name1', ), ('name2', )])
104
self.assertEqual((42, 19), (offset, length))
106
'Bazaar pack format 1 (introduced in 0.18)\n'
107
'B3\nname1\nname2\n\nabc',
110
def test_add_bytes_record_two_names(self):
111
"""Add a bytes record with two names."""
113
writer = pack.ContainerWriter(output.write)
115
offset, length = writer.add_bytes_record('abc', names=[('name1', ), ('name2', )])
116
self.assertEqual((42, 19), (offset, length))
118
'Bazaar pack format 1 (introduced in 0.18)\n'
119
'B3\nname1\nname2\n\nabc',
189
122
def test_add_bytes_record_two_element_name(self):
190
123
"""Add a bytes record with a two-element name."""
192
offset, length = self.writer.add_bytes_record(
193
'abc', names=[('name1', 'name2')])
125
writer = pack.ContainerWriter(output.write)
127
offset, length = writer.add_bytes_record('abc', names=[('name1', 'name2')])
194
128
self.assertEqual((42, 19), (offset, length))
196
130
'Bazaar pack format 1 (introduced in 0.18)\n'
197
'B3\nname1\x00name2\n\nabc')
131
'B3\nname1\x00name2\n\nabc',
199
134
def test_add_second_bytes_record_gets_higher_offset(self):
201
self.writer.add_bytes_record('abc', names=[])
202
offset, length = self.writer.add_bytes_record('abc', names=[])
136
writer = pack.ContainerWriter(output.write)
138
writer.add_bytes_record('abc', names=[])
139
offset, length = writer.add_bytes_record('abc', names=[])
203
140
self.assertEqual((49, 7), (offset, length))
205
142
'Bazaar pack format 1 (introduced in 0.18)\n'
209
147
def test_add_bytes_record_invalid_name(self):
210
148
"""Adding a Bytes record with a name with whitespace in it raises
211
149
InvalidRecordError.
152
writer = pack.ContainerWriter(output.write)
214
154
self.assertRaises(
215
155
errors.InvalidRecordError,
216
self.writer.add_bytes_record, 'abc', names=[('bad name', )])
156
writer.add_bytes_record, 'abc', names=[('bad name', )])
218
158
def test_add_bytes_records_add_to_records_written(self):
219
159
"""Adding a Bytes record increments the records_written counter."""
221
self.writer.add_bytes_record('foo', names=[])
222
self.assertEqual(1, self.writer.records_written)
223
self.writer.add_bytes_record('foo', names=[])
224
self.assertEqual(2, self.writer.records_written)
161
writer = pack.ContainerWriter(output.write)
163
writer.add_bytes_record('foo', names=[])
164
self.assertEqual(1, writer.records_written)
165
writer.add_bytes_record('foo', names=[])
166
self.assertEqual(2, writer.records_written)
227
169
class TestContainerReader(tests.TestCase):
228
"""Tests for the ContainerReader.
230
The ContainerReader reads format 1 containers, so these tests explicitly
231
test how it reacts to format 1 data. If a new version of the format is
232
added, then separate tests for that format should be added.
235
171
def get_reader_for(self, bytes):
236
172
stream = StringIO(bytes)
594
523
results.append(f.readline())
595
524
results.append(f.read(4))
596
525
self.assertEqual(['0', '\n', '2\n4\n'], results)
599
class PushParserTestCase(tests.TestCase):
600
"""Base class for TestCases involving ContainerPushParser."""
602
def make_parser_expecting_record_type(self):
603
parser = pack.ContainerPushParser()
604
parser.accept_bytes("Bazaar pack format 1 (introduced in 0.18)\n")
607
def make_parser_expecting_bytes_record(self):
608
parser = pack.ContainerPushParser()
609
parser.accept_bytes("Bazaar pack format 1 (introduced in 0.18)\nB")
612
def assertRecordParsing(self, expected_record, bytes):
613
"""Assert that 'bytes' is parsed as a given bytes record.
615
:param expected_record: A tuple of (names, bytes).
617
parser = self.make_parser_expecting_bytes_record()
618
parser.accept_bytes(bytes)
619
parsed_records = parser.read_pending_records()
620
self.assertEqual([expected_record], parsed_records)
623
class TestContainerPushParser(PushParserTestCase):
624
"""Tests for ContainerPushParser.
626
The ContainerPushParser reads format 1 containers, so these tests
627
explicitly test how it reacts to format 1 data. If a new version of the
628
format is added, then separate tests for that format should be added.
631
def test_construct(self):
632
"""ContainerPushParser can be constructed."""
633
pack.ContainerPushParser()
635
def test_multiple_records_at_once(self):
636
"""If multiple records worth of data are fed to the parser in one
637
string, the parser will correctly parse all the records.
639
(A naive implementation might stop after parsing the first record.)
641
parser = self.make_parser_expecting_record_type()
642
parser.accept_bytes("B5\nname1\n\nbody1B5\nname2\n\nbody2")
644
[([('name1',)], 'body1'), ([('name2',)], 'body2')],
645
parser.read_pending_records())
647
def test_multiple_empty_records_at_once(self):
648
"""If multiple empty records worth of data are fed to the parser in one
649
string, the parser will correctly parse all the records.
651
(A naive implementation might stop after parsing the first empty
652
record, because the buffer size had not changed.)
654
parser = self.make_parser_expecting_record_type()
655
parser.accept_bytes("B0\nname1\n\nB0\nname2\n\n")
657
[([('name1',)], ''), ([('name2',)], '')],
658
parser.read_pending_records())
661
class TestContainerPushParserBytesParsing(PushParserTestCase):
662
"""Tests for reading Bytes records with ContainerPushParser.
664
The ContainerPushParser reads format 1 containers, so these tests
665
explicitly test how it reacts to format 1 data. If a new version of the
666
format is added, then separate tests for that format should be added.
669
def test_record_with_no_name(self):
670
"""Reading a Bytes record with no name returns an empty list of
673
self.assertRecordParsing(([], 'aaaaa'), "5\n\naaaaa")
675
def test_record_with_one_name(self):
676
"""Reading a Bytes record with one name returns a list of just that
679
self.assertRecordParsing(
680
([('name1', )], 'aaaaa'),
683
def test_record_with_two_names(self):
684
"""Reading a Bytes record with two names returns a list of both names.
686
self.assertRecordParsing(
687
([('name1', ), ('name2', )], 'aaaaa'),
688
"5\nname1\nname2\n\naaaaa")
690
def test_record_with_two_part_names(self):
691
"""Reading a Bytes record with a two_part name reads both."""
692
self.assertRecordParsing(
693
([('name1', 'name2')], 'aaaaa'),
694
"5\nname1\x00name2\n\naaaaa")
696
def test_invalid_length(self):
697
"""If the length-prefix is not a number, parsing raises
700
parser = self.make_parser_expecting_bytes_record()
702
errors.InvalidRecordError, parser.accept_bytes, "not a number\n")
704
def test_incomplete_record(self):
705
"""If the bytes seen so far don't form a complete record, then there
706
will be nothing returned by read_pending_records.
708
parser = self.make_parser_expecting_bytes_record()
709
parser.accept_bytes("5\n\nabcd")
710
self.assertEqual([], parser.read_pending_records())
712
def test_accept_nothing(self):
713
"""The edge case of parsing an empty string causes no error."""
714
parser = self.make_parser_expecting_bytes_record()
715
parser.accept_bytes("")
717
def assertInvalidRecord(self, bytes):
718
"""Assert that parsing the given bytes will raise an
721
parser = self.make_parser_expecting_bytes_record()
723
errors.InvalidRecordError, parser.accept_bytes, bytes)
725
def test_read_invalid_name_whitespace(self):
726
"""Names must have no whitespace."""
727
# A name with a space.
728
self.assertInvalidRecord("0\nbad name\n\n")
731
self.assertInvalidRecord("0\nbad\tname\n\n")
733
# A name with a vertical tab.
734
self.assertInvalidRecord("0\nbad\vname\n\n")
736
def test_repeated_read_pending_records(self):
737
"""read_pending_records will not return the same record twice."""
738
parser = self.make_parser_expecting_bytes_record()
739
parser.accept_bytes("6\n\nabcdef")
740
self.assertEqual([([], 'abcdef')], parser.read_pending_records())
741
self.assertEqual([], parser.read_pending_records())