1
# Copyright (C) 2005, 2006 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2016 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
22
22
but this depends on the transport.
29
26
from tempfile import TemporaryFile
34
from bzrlib.tests import TestCaseInTempDir, TestCase
35
from bzrlib.rio import (RioWriter, Stanza, read_stanza, read_stanzas, rio_file,
31
from breezy.tests import TestCase
32
from breezy.rio import (
39
41
class TestRio(TestCase):
44
46
self.assertTrue('number' in s)
45
47
self.assertFalse('color' in s)
46
48
self.assertFalse('42' in s)
47
self.assertEquals(list(s.iter_pairs()),
49
self.assertEqual(list(s.iter_pairs()),
48
50
[('name', 'fred'), ('number', '42')])
49
self.assertEquals(s.get('number'), '42')
50
self.assertEquals(s.get('name'), 'fred')
52
def test_value_checks(self):
53
"""rio checks types on construction"""
54
# these aren't enforced at construction time
55
## self.assertRaises(ValueError,
56
## Stanza, complex=42 + 3j)
57
## self.assertRaises(ValueError,
58
## Stanza, several=range(10))
51
self.assertEqual(s.get('number'), '42')
52
self.assertEqual(s.get('name'), 'fred')
60
54
def test_empty_value(self):
61
55
"""Serialize stanza with empty field"""
62
56
s = Stanza(empty='')
63
self.assertEqualDiff(s.to_string(),
57
self.assertEquals(s.to_string(),
66
60
def test_to_lines(self):
67
61
"""Write simple rio stanza to string"""
68
62
s = Stanza(number='42', name='fred')
69
self.assertEquals(list(s.to_lines()),
63
self.assertEqual(list(s.to_lines()),
73
67
def test_as_dict(self):
74
68
"""Convert rio Stanza to dictionary"""
75
69
s = Stanza(number='42', name='fred')
77
self.assertEquals(sd, dict(number='42', name='fred'))
71
self.assertEqual(sd, dict(number='42', name='fred'))
79
73
def test_to_file(self):
80
74
"""Write rio to file"""
82
76
s = Stanza(a_thing='something with "quotes like \\"this\\""', number='42', name='fred')
85
self.assertEqualDiff(tmpf.read(), r'''
86
a_thing: something with "quotes like \"this\""
79
self.assertEqual(tmpf.read(), b'''\
80
a_thing: something with "quotes like \\"this\\""
91
85
def test_multiline_string(self):
92
86
tmpf = TemporaryFile()
93
87
s = Stanza(motto="war is peace\nfreedom is slavery\nignorance is strength")
96
self.assertEqualDiff(tmpf.read(), '''\
90
self.assertEqual(tmpf.read(), b'''\
97
91
motto: war is peace
98
92
\tfreedom is slavery
99
93
\tignorance is strength
102
96
s2 = read_stanza(tmpf)
103
self.assertEquals(s, s2)
97
self.assertEqual(s, s2)
105
99
def test_read_stanza(self):
106
100
"""Load stanza from string"""
108
102
revision: mbp@sourcefrog.net-123-abc
109
103
timestamp: 1130653962
112
106
""".splitlines(True)
113
107
s = read_stanza(lines)
114
108
self.assertTrue('revision' in s)
115
self.assertEqualDiff(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
116
self.assertEquals(list(s.iter_pairs()),
109
self.assertEqual(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
110
self.assertEqual(list(s.iter_pairs()),
117
111
[('revision', 'mbp@sourcefrog.net-123-abc'),
118
112
('timestamp', '1130653962'),
119
113
('timezone', '36000'),
120
114
('committer', "Martin Pool <mbp@test.sourcefrog.net>")])
121
self.assertEquals(len(s), 4)
115
self.assertEqual(len(s), 4)
123
117
def test_repeated_field(self):
124
118
"""Repeated field in rio"""
127
121
('a', '1000'), ('b', '2000')]:
129
123
s2 = read_stanza(s.to_lines())
130
self.assertEquals(s, s2)
131
self.assertEquals(s.get_all('a'), map(str, [10, 100, 1000]))
132
self.assertEquals(s.get_all('b'), map(str, [20, 200, 2000]))
124
self.assertEqual(s, s2)
125
self.assertEqual(s.get_all('a'), ['10', '100', '1000'])
126
self.assertEqual(s.get_all('b'), ['20', '200', '2000'])
134
128
def test_backslash(self):
135
129
s = Stanza(q='\\')
136
130
t = s.to_string()
137
self.assertEqualDiff(t, 'q: \\\n')
131
self.assertEqual(t, b'q: \\\n')
138
132
s2 = read_stanza(s.to_lines())
139
self.assertEquals(s, s2)
133
self.assertEqual(s, s2)
141
135
def test_blank_line(self):
142
136
s = Stanza(none='', one='\n', two='\n\n')
143
self.assertEqualDiff(s.to_string(), """\
137
self.assertEqual(s.to_string(), b"""\
151
145
s2 = read_stanza(s.to_lines())
152
self.assertEquals(s, s2)
146
self.assertEqual(s, s2)
154
148
def test_whitespace_value(self):
155
149
s = Stanza(space=' ', tabs='\t\t\t', combo='\n\t\t\n')
156
self.assertEqualDiff(s.to_string(), """\
150
self.assertEqual(s.to_string(), b"""\
179
173
s2 = read_stanza(s.to_lines())
180
self.assertEquals(s, s2)
174
self.assertEqual(s, s2)
181
175
# apparent bug in read_stanza
182
176
# s3 = read_stanza(self.stanzas_to_str([s]))
183
# self.assertEquals(s, s3)
177
# self.assertEqual(s, s3)
185
179
def test_read_empty(self):
186
180
"""Detect end of rio file"""
188
182
self.assertEqual(s, None)
189
183
self.assertTrue(s is None)
185
def test_read_nul_byte(self):
186
"""File consisting of a nul byte causes an error."""
187
self.assertRaises(ValueError, read_stanza, [b'\0'])
189
def test_read_nul_bytes(self):
190
"""File consisting of many nul bytes causes an error."""
191
self.assertRaises(ValueError, read_stanza, [b'\0' * 100])
191
193
def test_read_iter(self):
192
194
"""Read several stanzas from file"""
193
195
tmpf = TemporaryFile()
195
197
version_header: 1
230
232
s = read_stanza(tmpf)
231
self.assertEquals(s, Stanza(version_header='1'))
232
s = read_stanza(tmpf)
233
self.assertEquals(s, Stanza(name="foo", val='123'))
234
s = read_stanza(tmpf)
235
self.assertEqualDiff(s.get('name'), 'quoted')
236
self.assertEqualDiff(s.get('address'), ' "Willowglen"\n 42 Wallaby Way\n Sydney')
237
s = read_stanza(tmpf)
238
self.assertEquals(s, Stanza(name="bar", val='129319'))
239
s = read_stanza(tmpf)
240
self.assertEquals(s, None)
233
self.assertEqual(s, Stanza(version_header='1'))
234
s = read_stanza(tmpf)
235
self.assertEqual(s, Stanza(name="foo", val='123'))
236
s = read_stanza(tmpf)
237
self.assertEqual(s.get('name'), 'quoted')
239
s.get('address'), ' "Willowglen"\n 42 Wallaby Way\n Sydney')
240
s = read_stanza(tmpf)
241
self.assertEqual(s, Stanza(name="bar", val='129319'))
242
s = read_stanza(tmpf)
243
self.assertEqual(s, None)
241
244
self.check_rio_file(tmpf)
243
246
def check_rio_file(self, real_file):
244
247
real_file.seek(0)
245
248
read_write = rio_file(RioReader(real_file)).read()
246
249
real_file.seek(0)
247
self.assertEquals(read_write, real_file.read())
250
self.assertEqual(read_write, real_file.read())
250
253
def stanzas_to_str(stanzas):
305
308
for expected in expected_vals:
306
309
stanza = read_stanza(tmpf)
307
310
self.rio_file_stanzas([stanza])
308
self.assertEquals(len(stanza), 1)
309
self.assertEqualDiff(stanza.get('s'), expected)
311
self.assertEqual(len(stanza), 1)
312
self.assertEqual(stanza.get('s'), expected)
311
314
def test_write_empty_stanza(self):
312
315
"""Write empty stanza"""
313
316
l = list(Stanza().to_lines())
314
self.assertEquals(l, [])
317
self.assertEqual(l, [])
316
319
def test_rio_raises_type_error(self):
317
320
"""TypeError on adding invalid type to Stanza"""
326
329
def test_rio_unicode(self):
327
330
uni_data = u'\N{KATAKANA LETTER O}'
328
331
s = Stanza(foo=uni_data)
329
self.assertEquals(s.get('foo'), uni_data)
332
self.assertEqual(s.get('foo'), uni_data)
330
333
raw_lines = s.to_lines()
331
self.assertEquals(raw_lines,
332
['foo: ' + uni_data.encode('utf-8') + '\n'])
334
self.assertEqual(raw_lines,
335
[b'foo: ' + uni_data.encode('utf-8') + b'\n'])
333
336
new_s = read_stanza(raw_lines)
334
self.assertEquals(new_s.get('foo'), uni_data)
337
self.assertEqual(new_s.get('foo'), uni_data)
336
339
def test_rio_to_unicode(self):
337
340
uni_data = u'\N{KATAKANA LETTER O}'
346
349
s = Stanza(foo=uni_data)
347
350
parent_stanza = Stanza(child=s.to_unicode())
348
351
raw_lines = parent_stanza.to_lines()
349
self.assertEqual(['child: foo: ' + uni_data.encode('utf-8') + '\n',
352
self.assertEqual([b'child: foo: ' + uni_data.encode('utf-8') + b'\n',
352
355
new_parent = read_stanza(raw_lines)
353
356
child_text = new_parent.get('child')
358
361
def mail_munge(self, lines, dos_nl=True):
360
363
for line in lines:
361
line = re.sub(' *\n', '\n', line)
364
line = re.sub(b' *\n', b'\n', line)
363
line = re.sub('([^\r])\n', '\\1\r\n', line)
366
line = re.sub(b'([^\r])\n', b'\\1\r\n', line)
364
367
new_lines.append(line)
368
371
stanza = Stanza(data='#\n\r\\r ', space=' ' * 255, hash='#' * 255)
369
372
lines = rio.to_patch_lines(stanza)
370
373
for line in lines:
371
self.assertContainsRe(line, '^# ')
374
self.assertContainsRe(line, b'^# ')
372
375
self.assertTrue(72 >= len(line))
373
376
for line in rio.to_patch_lines(stanza, max_width=12):
374
377
self.assertTrue(12 >= len(line))
383
386
def test_patch_rio_linebreaks(self):
384
387
stanza = Stanza(breaktest='linebreak -/'*30)
385
388
self.assertContainsRe(rio.to_patch_lines(stanza, 71)[0],
387
390
stanza = Stanza(breaktest='linebreak-/'*30)
388
391
self.assertContainsRe(rio.to_patch_lines(stanza, 70)[0],
390
393
stanza = Stanza(breaktest='linebreak/'*30)
391
394
self.assertContainsRe(rio.to_patch_lines(stanza, 70)[0],