/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_rio.py

[merge] robertc's integration, updated tests to check for retcode=3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
"""Tests for rio serialization
18
 
 
19
 
A simple, reproducible structured IO format.
20
 
 
21
 
rio itself works in Unicode strings.  It is typically encoded to UTF-8,
22
 
but this depends on the transport.
23
 
"""
24
 
 
25
 
import re
26
 
from tempfile import TemporaryFile
27
 
 
28
 
from breezy import (
29
 
    rio,
30
 
    )
31
 
from breezy.tests import TestCase
32
 
from breezy.rio import (
33
 
    RioReader,
34
 
    Stanza,
35
 
    read_stanza,
36
 
    read_stanzas,
37
 
    rio_file,
38
 
    )
39
 
 
40
 
 
41
 
class TestRio(TestCase):
42
 
 
43
 
    def test_stanza(self):
44
 
        """Construct rio stanza in memory"""
45
 
        s = Stanza(number='42', name="fred")
46
 
        self.assertTrue('number' in s)
47
 
        self.assertFalse('color' in s)
48
 
        self.assertFalse('42' in s)
49
 
        self.assertEqual(list(s.iter_pairs()),
50
 
                         [('name', 'fred'), ('number', '42')])
51
 
        self.assertEqual(s.get('number'), '42')
52
 
        self.assertEqual(s.get('name'), 'fred')
53
 
 
54
 
    def test_empty_value(self):
55
 
        """Serialize stanza with empty field"""
56
 
        s = Stanza(empty='')
57
 
        self.assertEquals(s.to_string(),
58
 
                          b"empty: \n")
59
 
 
60
 
    def test_to_lines(self):
61
 
        """Write simple rio stanza to string"""
62
 
        s = Stanza(number='42', name='fred')
63
 
        self.assertEqual(list(s.to_lines()),
64
 
                         [b'name: fred\n',
65
 
                          b'number: 42\n'])
66
 
 
67
 
    def test_as_dict(self):
68
 
        """Convert rio Stanza to dictionary"""
69
 
        s = Stanza(number='42', name='fred')
70
 
        sd = s.as_dict()
71
 
        self.assertEqual(sd, dict(number='42', name='fred'))
72
 
 
73
 
    def test_to_file(self):
74
 
        """Write rio to file"""
75
 
        tmpf = TemporaryFile()
76
 
        s = Stanza(a_thing='something with "quotes like \\"this\\""',
77
 
                   number='42', name='fred')
78
 
        s.write(tmpf)
79
 
        tmpf.seek(0)
80
 
        self.assertEqual(tmpf.read(), b'''\
81
 
a_thing: something with "quotes like \\"this\\""
82
 
name: fred
83
 
number: 42
84
 
''')
85
 
 
86
 
    def test_multiline_string(self):
87
 
        tmpf = TemporaryFile()
88
 
        s = Stanza(
89
 
            motto="war is peace\nfreedom is slavery\nignorance is strength")
90
 
        s.write(tmpf)
91
 
        tmpf.seek(0)
92
 
        self.assertEqual(tmpf.read(), b'''\
93
 
motto: war is peace
94
 
\tfreedom is slavery
95
 
\tignorance is strength
96
 
''')
97
 
        tmpf.seek(0)
98
 
        s2 = read_stanza(tmpf)
99
 
        self.assertEqual(s, s2)
100
 
 
101
 
    def test_read_stanza(self):
102
 
        """Load stanza from string"""
103
 
        lines = b"""\
104
 
revision: mbp@sourcefrog.net-123-abc
105
 
timestamp: 1130653962
106
 
timezone: 36000
107
 
committer: Martin Pool <mbp@test.sourcefrog.net>
108
 
""".splitlines(True)
109
 
        s = read_stanza(lines)
110
 
        self.assertTrue('revision' in s)
111
 
        self.assertEqual(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
112
 
        self.assertEqual(list(s.iter_pairs()),
113
 
                         [('revision', 'mbp@sourcefrog.net-123-abc'),
114
 
                          ('timestamp', '1130653962'),
115
 
                          ('timezone', '36000'),
116
 
                          ('committer', "Martin Pool <mbp@test.sourcefrog.net>")])
117
 
        self.assertEqual(len(s), 4)
118
 
 
119
 
    def test_repeated_field(self):
120
 
        """Repeated field in rio"""
121
 
        s = Stanza()
122
 
        for k, v in [('a', '10'), ('b', '20'), ('a', '100'), ('b', '200'),
123
 
                     ('a', '1000'), ('b', '2000')]:
124
 
            s.add(k, v)
125
 
        s2 = read_stanza(s.to_lines())
126
 
        self.assertEqual(s, s2)
127
 
        self.assertEqual(s.get_all('a'), ['10', '100', '1000'])
128
 
        self.assertEqual(s.get_all('b'), ['20', '200', '2000'])
129
 
 
130
 
    def test_backslash(self):
131
 
        s = Stanza(q='\\')
132
 
        t = s.to_string()
133
 
        self.assertEqual(t, b'q: \\\n')
134
 
        s2 = read_stanza(s.to_lines())
135
 
        self.assertEqual(s, s2)
136
 
 
137
 
    def test_blank_line(self):
138
 
        s = Stanza(none='', one='\n', two='\n\n')
139
 
        self.assertEqual(s.to_string(), b"""\
140
 
none:\x20
141
 
one:\x20
142
 
\t
143
 
two:\x20
144
 
\t
145
 
\t
146
 
""")
147
 
        s2 = read_stanza(s.to_lines())
148
 
        self.assertEqual(s, s2)
149
 
 
150
 
    def test_whitespace_value(self):
151
 
        s = Stanza(space=' ', tabs='\t\t\t', combo='\n\t\t\n')
152
 
        self.assertEqual(s.to_string(), b"""\
153
 
combo:\x20
154
 
\t\t\t
155
 
\t
156
 
space:\x20\x20
157
 
tabs: \t\t\t
158
 
""")
159
 
        s2 = read_stanza(s.to_lines())
160
 
        self.assertEqual(s, s2)
161
 
        self.rio_file_stanzas([s])
162
 
 
163
 
    def test_quoted(self):
164
 
        """rio quoted string cases"""
165
 
        s = Stanza(q1='"hello"',
166
 
                   q2=' "for',
167
 
                   q3='\n\n"for"\n',
168
 
                   q4='for\n"\nfor',
169
 
                   q5='\n',
170
 
                   q6='"',
171
 
                   q7='""',
172
 
                   q8='\\',
173
 
                   q9='\\"\\"',
174
 
                   )
175
 
        s2 = read_stanza(s.to_lines())
176
 
        self.assertEqual(s, s2)
177
 
        # apparent bug in read_stanza
178
 
        # s3 = read_stanza(self.stanzas_to_str([s]))
179
 
        # self.assertEqual(s, s3)
180
 
 
181
 
    def test_read_empty(self):
182
 
        """Detect end of rio file"""
183
 
        s = read_stanza([])
184
 
        self.assertEqual(s, None)
185
 
        self.assertTrue(s is None)
186
 
 
187
 
    def test_read_nul_byte(self):
188
 
        """File consisting of a nul byte causes an error."""
189
 
        self.assertRaises(ValueError, read_stanza, [b'\0'])
190
 
 
191
 
    def test_read_nul_bytes(self):
192
 
        """File consisting of many nul bytes causes an error."""
193
 
        self.assertRaises(ValueError, read_stanza, [b'\0' * 100])
194
 
 
195
 
    def test_read_iter(self):
196
 
        """Read several stanzas from file"""
197
 
        tmpf = TemporaryFile()
198
 
        tmpf.write(b"""\
199
 
version_header: 1
200
 
 
201
 
name: foo
202
 
val: 123
203
 
 
204
 
name: bar
205
 
val: 129319
206
 
""")
207
 
        tmpf.seek(0)
208
 
        reader = read_stanzas(tmpf)
209
 
        read_iter = iter(reader)
210
 
        stuff = list(reader)
211
 
        self.assertEqual(stuff,
212
 
                         [Stanza(version_header='1'),
213
 
                          Stanza(name="foo", val='123'),
214
 
                             Stanza(name="bar", val='129319'), ])
215
 
 
216
 
    def test_read_several(self):
217
 
        """Read several stanzas from file"""
218
 
        tmpf = TemporaryFile()
219
 
        tmpf.write(b"""\
220
 
version_header: 1
221
 
 
222
 
name: foo
223
 
val: 123
224
 
 
225
 
name: quoted
226
 
address:   "Willowglen"
227
 
\t  42 Wallaby Way
228
 
\t  Sydney
229
 
 
230
 
name: bar
231
 
val: 129319
232
 
""")
233
 
        tmpf.seek(0)
234
 
        s = read_stanza(tmpf)
235
 
        self.assertEqual(s, Stanza(version_header='1'))
236
 
        s = read_stanza(tmpf)
237
 
        self.assertEqual(s, Stanza(name="foo", val='123'))
238
 
        s = read_stanza(tmpf)
239
 
        self.assertEqual(s.get('name'), 'quoted')
240
 
        self.assertEqual(
241
 
            s.get('address'), '  "Willowglen"\n  42 Wallaby Way\n  Sydney')
242
 
        s = read_stanza(tmpf)
243
 
        self.assertEqual(s, Stanza(name="bar", val='129319'))
244
 
        s = read_stanza(tmpf)
245
 
        self.assertEqual(s, None)
246
 
        self.check_rio_file(tmpf)
247
 
 
248
 
    def check_rio_file(self, real_file):
249
 
        real_file.seek(0)
250
 
        read_write = rio_file(RioReader(real_file)).read()
251
 
        real_file.seek(0)
252
 
        self.assertEqual(read_write, real_file.read())
253
 
 
254
 
    @staticmethod
255
 
    def stanzas_to_str(stanzas):
256
 
        return rio_file(stanzas).read()
257
 
 
258
 
    def rio_file_stanzas(self, stanzas):
259
 
        new_stanzas = list(RioReader(rio_file(stanzas)))
260
 
        self.assertEqual(new_stanzas, stanzas)
261
 
 
262
 
    def test_tricky_quoted(self):
263
 
        tmpf = TemporaryFile()
264
 
        tmpf.write(b'''\
265
 
s: "one"
266
 
 
267
 
s:\x20
268
 
\t"one"
269
 
\t
270
 
 
271
 
s: "
272
 
 
273
 
s: ""
274
 
 
275
 
s: """
276
 
 
277
 
s:\x20
278
 
\t
279
 
 
280
 
s: \\
281
 
 
282
 
s:\x20
283
 
\t\\
284
 
\t\\\\
285
 
\t
286
 
 
287
 
s: word\\
288
 
 
289
 
s: quote"
290
 
 
291
 
s: backslashes\\\\\\
292
 
 
293
 
s: both\\\"
294
 
 
295
 
''')
296
 
        tmpf.seek(0)
297
 
        expected_vals = ['"one"',
298
 
                         '\n"one"\n',
299
 
                         '"',
300
 
                         '""',
301
 
                         '"""',
302
 
                         '\n',
303
 
                         '\\',
304
 
                         '\n\\\n\\\\\n',
305
 
                         'word\\',
306
 
                         'quote\"',
307
 
                         'backslashes\\\\\\',
308
 
                         'both\\\"',
309
 
                         ]
310
 
        for expected in expected_vals:
311
 
            stanza = read_stanza(tmpf)
312
 
            self.rio_file_stanzas([stanza])
313
 
            self.assertEqual(len(stanza), 1)
314
 
            self.assertEqual(stanza.get('s'), expected)
315
 
 
316
 
    def test_write_empty_stanza(self):
317
 
        """Write empty stanza"""
318
 
        l = list(Stanza().to_lines())
319
 
        self.assertEqual(l, [])
320
 
 
321
 
    def test_rio_raises_type_error(self):
322
 
        """TypeError on adding invalid type to Stanza"""
323
 
        s = Stanza()
324
 
        self.assertRaises(TypeError, s.add, 'foo', {})
325
 
 
326
 
    def test_rio_raises_type_error_key(self):
327
 
        """TypeError on adding invalid type to Stanza"""
328
 
        s = Stanza()
329
 
        self.assertRaises(TypeError, s.add, 10, {})
330
 
 
331
 
    def test_rio_unicode(self):
332
 
        uni_data = u'\N{KATAKANA LETTER O}'
333
 
        s = Stanza(foo=uni_data)
334
 
        self.assertEqual(s.get('foo'), uni_data)
335
 
        raw_lines = s.to_lines()
336
 
        self.assertEqual(raw_lines,
337
 
                         [b'foo: ' + uni_data.encode('utf-8') + b'\n'])
338
 
        new_s = read_stanza(raw_lines)
339
 
        self.assertEqual(new_s.get('foo'), uni_data)
340
 
 
341
 
    def test_rio_to_unicode(self):
342
 
        uni_data = u'\N{KATAKANA LETTER O}'
343
 
        s = Stanza(foo=uni_data)
344
 
        unicode_str = s.to_unicode()
345
 
        self.assertEqual(u'foo: %s\n' % (uni_data,), unicode_str)
346
 
        new_s = rio.read_stanza_unicode(unicode_str.splitlines(True))
347
 
        self.assertEqual(uni_data, new_s.get('foo'))
348
 
 
349
 
    def test_nested_rio_unicode(self):
350
 
        uni_data = u'\N{KATAKANA LETTER O}'
351
 
        s = Stanza(foo=uni_data)
352
 
        parent_stanza = Stanza(child=s.to_unicode())
353
 
        raw_lines = parent_stanza.to_lines()
354
 
        self.assertEqual([b'child: foo: ' + uni_data.encode('utf-8') + b'\n',
355
 
                          b'\t\n',
356
 
                          ], raw_lines)
357
 
        new_parent = read_stanza(raw_lines)
358
 
        child_text = new_parent.get('child')
359
 
        self.assertEqual(u'foo: %s\n' % uni_data, child_text)
360
 
        new_child = rio.read_stanza_unicode(child_text.splitlines(True))
361
 
        self.assertEqual(uni_data, new_child.get('foo'))
362
 
 
363
 
    def mail_munge(self, lines, dos_nl=True):
364
 
        new_lines = []
365
 
        for line in lines:
366
 
            line = re.sub(b' *\n', b'\n', line)
367
 
            if dos_nl:
368
 
                line = re.sub(b'([^\r])\n', b'\\1\r\n', line)
369
 
            new_lines.append(line)
370
 
        return new_lines
371
 
 
372
 
    def test_patch_rio(self):
373
 
        stanza = Stanza(data='#\n\r\\r ', space=' ' * 255, hash='#' * 255)
374
 
        lines = rio.to_patch_lines(stanza)
375
 
        for line in lines:
376
 
            self.assertContainsRe(line, b'^# ')
377
 
            self.assertTrue(72 >= len(line))
378
 
        for line in rio.to_patch_lines(stanza, max_width=12):
379
 
            self.assertTrue(12 >= len(line))
380
 
        new_stanza = rio.read_patch_stanza(self.mail_munge(lines,
381
 
                                                           dos_nl=False))
382
 
        lines = self.mail_munge(lines)
383
 
        new_stanza = rio.read_patch_stanza(lines)
384
 
        self.assertEqual('#\n\r\\r ', new_stanza.get('data'))
385
 
        self.assertEqual(' ' * 255, new_stanza.get('space'))
386
 
        self.assertEqual('#' * 255, new_stanza.get('hash'))
387
 
 
388
 
    def test_patch_rio_linebreaks(self):
389
 
        stanza = Stanza(breaktest='linebreak -/' * 30)
390
 
        self.assertContainsRe(rio.to_patch_lines(stanza, 71)[0],
391
 
                              b'linebreak\\\\\n')
392
 
        stanza = Stanza(breaktest='linebreak-/' * 30)
393
 
        self.assertContainsRe(rio.to_patch_lines(stanza, 70)[0],
394
 
                              b'linebreak-\\\\\n')
395
 
        stanza = Stanza(breaktest='linebreak/' * 30)
396
 
        self.assertContainsRe(rio.to_patch_lines(stanza, 70)[0],
397
 
                              b'linebreak\\\\\n')