1
# Copyright (C) 2005, 2006 by Canonical Ltd
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.
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.
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
17
"""Tests for rio serialization
19
A simple, reproducible structured IO format.
21
rio itself works in Unicode strings. It is typically encoded to UTF-8,
22
but this depends on the transport.
28
from tempfile import TemporaryFile
30
from bzrlib.tests import TestCaseInTempDir, TestCase
31
from bzrlib.rio import (RioWriter, Stanza, read_stanza, read_stanzas, rio_file,
35
class TestRio(TestCase):
37
def test_stanza(self):
38
"""Construct rio stanza in memory"""
39
s = Stanza(number='42', name="fred")
40
self.assertTrue('number' in s)
41
self.assertFalse('color' in s)
42
self.assertFalse('42' in s)
43
self.assertEquals(list(s.iter_pairs()),
44
[('name', 'fred'), ('number', '42')])
45
self.assertEquals(s.get('number'), '42')
46
self.assertEquals(s.get('name'), 'fred')
48
def test_value_checks(self):
49
"""rio checks types on construction"""
50
# these aren't enforced at construction time
51
## self.assertRaises(ValueError,
52
## Stanza, complex=42 + 3j)
53
## self.assertRaises(ValueError,
54
## Stanza, several=range(10))
56
def test_empty_value(self):
57
"""Serialize stanza with empty field"""
59
self.assertEqualDiff(s.to_string(),
62
def test_to_lines(self):
63
"""Write simple rio stanza to string"""
64
s = Stanza(number='42', name='fred')
65
self.assertEquals(list(s.to_lines()),
69
def test_as_dict(self):
70
"""Convert rio Stanza to dictionary"""
71
s = Stanza(number='42', name='fred')
73
self.assertEquals(sd, dict(number='42', name='fred'))
75
def test_to_file(self):
76
"""Write rio to file"""
77
tmpf = TemporaryFile()
78
s = Stanza(a_thing='something with "quotes like \\"this\\""', number='42', name='fred')
81
self.assertEqualDiff(tmpf.read(), r'''
82
a_thing: something with "quotes like \"this\""
87
def test_multiline_string(self):
88
tmpf = TemporaryFile()
89
s = Stanza(motto="war is peace\nfreedom is slavery\nignorance is strength")
92
self.assertEqualDiff(tmpf.read(), '''\
95
\tignorance is strength
98
s2 = read_stanza(tmpf)
99
self.assertEquals(s, s2)
101
def test_read_stanza(self):
102
"""Load stanza from string"""
104
revision: mbp@sourcefrog.net-123-abc
105
timestamp: 1130653962
107
committer: Martin Pool <mbp@test.sourcefrog.net>
109
s = read_stanza(lines)
110
self.assertTrue('revision' in s)
111
self.assertEqualDiff(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
112
self.assertEquals(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.assertEquals(len(s), 4)
119
def test_repeated_field(self):
120
"""Repeated field in rio"""
122
for k, v in [('a', '10'), ('b', '20'), ('a', '100'), ('b', '200'),
123
('a', '1000'), ('b', '2000')]:
125
s2 = read_stanza(s.to_lines())
126
self.assertEquals(s, s2)
127
self.assertEquals(s.get_all('a'), map(str, [10, 100, 1000]))
128
self.assertEquals(s.get_all('b'), map(str, [20, 200, 2000]))
130
def test_backslash(self):
133
self.assertEqualDiff(t, 'q: \\\n')
134
s2 = read_stanza(s.to_lines())
135
self.assertEquals(s, s2)
137
def test_blank_line(self):
138
s = Stanza(none='', one='\n', two='\n\n')
139
self.assertEqualDiff(s.to_string(), """\
147
s2 = read_stanza(s.to_lines())
148
self.assertEquals(s, s2)
150
def test_whitespace_value(self):
151
s = Stanza(space=' ', tabs='\t\t\t', combo='\n\t\t\n')
152
self.assertEqualDiff(s.to_string(), """\
159
s2 = read_stanza(s.to_lines())
160
self.assertEquals(s, s2)
161
self.rio_file_stanzas([s])
163
def test_quoted(self):
164
"""rio quoted string cases"""
165
s = Stanza(q1='"hello"',
175
s2 = read_stanza(s.to_lines())
176
self.assertEquals(s, s2)
177
# apparent bug in read_stanza
178
# s3 = read_stanza(self.stanzas_to_str([s]))
179
# self.assertEquals(s, s3)
181
def test_read_empty(self):
182
"""Detect end of rio file"""
184
self.assertEqual(s, None)
185
self.assertTrue(s is None)
187
def test_read_iter(self):
188
"""Read several stanzas from file"""
189
tmpf = TemporaryFile()
200
reader = read_stanzas(tmpf)
201
read_iter = iter(reader)
203
self.assertEqual(stuff,
204
[ Stanza(version_header='1'),
205
Stanza(name="foo", val='123'),
206
Stanza(name="bar", val='129319'), ])
208
def test_read_several(self):
209
"""Read several stanzas from file"""
210
tmpf = TemporaryFile()
218
address: "Willowglen"
226
s = read_stanza(tmpf)
227
self.assertEquals(s, Stanza(version_header='1'))
228
s = read_stanza(tmpf)
229
self.assertEquals(s, Stanza(name="foo", val='123'))
230
s = read_stanza(tmpf)
231
self.assertEqualDiff(s.get('name'), 'quoted')
232
self.assertEqualDiff(s.get('address'), ' "Willowglen"\n 42 Wallaby Way\n Sydney')
233
s = read_stanza(tmpf)
234
self.assertEquals(s, Stanza(name="bar", val='129319'))
235
s = read_stanza(tmpf)
236
self.assertEquals(s, None)
237
self.check_rio_file(tmpf)
239
def check_rio_file(self, real_file):
241
read_write = rio_file(RioReader(real_file)).read()
243
self.assertEquals(read_write, real_file.read())
246
def stanzas_to_str(stanzas):
247
return rio_file(stanzas).read()
249
def rio_file_stanzas(self, stanzas):
250
new_stanzas = list(RioReader(rio_file(stanzas)))
251
self.assertEqual(new_stanzas, stanzas)
253
def test_tricky_quoted(self):
254
tmpf = TemporaryFile()
288
expected_vals = ['"one"',
301
for expected in expected_vals:
302
stanza = read_stanza(tmpf)
303
self.rio_file_stanzas([stanza])
304
self.assertEquals(len(stanza), 1)
305
self.assertEqualDiff(stanza.get('s'), expected)
307
def test_write_empty_stanza(self):
308
"""Write empty stanza"""
309
l = list(Stanza().to_lines())
310
self.assertEquals(l, [])
312
def test_rio_raises_type_error(self):
313
"""TypeError on adding invalid type to Stanza"""
315
self.assertRaises(TypeError, s.add, 'foo', {})
317
def test_rio_raises_type_error_key(self):
318
"""TypeError on adding invalid type to Stanza"""
320
self.assertRaises(TypeError, s.add, 10, {})
322
def test_rio_unicode(self):
323
# intentionally use cStringIO which doesn't accomodate unencoded unicode objects
324
sio = cStringIO.StringIO()
325
uni_data = u'\N{KATAKANA LETTER O}'
326
s = Stanza(foo=uni_data)
327
self.assertEquals(s.get('foo'), uni_data)
328
raw_lines = s.to_lines()
329
self.assertEquals(raw_lines,
330
['foo: ' + uni_data.encode('utf-8') + '\n'])
331
new_s = read_stanza(raw_lines)
332
self.assertEquals(new_s.get('foo'), uni_data)