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
34
class TestRio(TestCase):
36
def test_stanza(self):
37
"""Construct rio stanza in memory"""
38
s = Stanza(number='42', name="fred")
39
self.assertTrue('number' in s)
40
self.assertFalse('color' in s)
41
self.assertFalse('42' in s)
42
self.assertEquals(list(s.iter_pairs()),
43
[('name', 'fred'), ('number', '42')])
44
self.assertEquals(s.get('number'), '42')
45
self.assertEquals(s.get('name'), 'fred')
47
def test_value_checks(self):
48
"""rio checks types on construction"""
49
# these aren't enforced at construction time
50
## self.assertRaises(ValueError,
51
## Stanza, complex=42 + 3j)
52
## self.assertRaises(ValueError,
53
## Stanza, several=range(10))
55
def test_empty_value(self):
56
"""Serialize stanza with empty field"""
58
self.assertEqualDiff(s.to_string(),
61
def test_to_lines(self):
62
"""Write simple rio stanza to string"""
63
s = Stanza(number='42', name='fred')
64
self.assertEquals(list(s.to_lines()),
68
def test_as_dict(self):
69
"""Convert rio Stanza to dictionary"""
70
s = Stanza(number='42', name='fred')
72
self.assertEquals(sd, dict(number='42', name='fred'))
74
def test_to_file(self):
75
"""Write rio to file"""
76
tmpf = TemporaryFile()
77
s = Stanza(a_thing='something with "quotes like \\"this\\""', number='42', name='fred')
80
self.assertEqualDiff(tmpf.read(), r'''
81
a_thing: something with "quotes like \"this\""
86
def test_multiline_string(self):
87
tmpf = TemporaryFile()
88
s = Stanza(motto="war is peace\nfreedom is slavery\nignorance is strength")
91
self.assertEqualDiff(tmpf.read(), '''\
94
\tignorance is strength
97
s2 = read_stanza(tmpf)
98
self.assertEquals(s, s2)
100
def test_read_stanza(self):
101
"""Load stanza from string"""
103
revision: mbp@sourcefrog.net-123-abc
104
timestamp: 1130653962
106
committer: Martin Pool <mbp@test.sourcefrog.net>
108
s = read_stanza(lines)
109
self.assertTrue('revision' in s)
110
self.assertEqualDiff(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
111
self.assertEquals(list(s.iter_pairs()),
112
[('revision', 'mbp@sourcefrog.net-123-abc'),
113
('timestamp', '1130653962'),
114
('timezone', '36000'),
115
('committer', "Martin Pool <mbp@test.sourcefrog.net>")])
116
self.assertEquals(len(s), 4)
118
def test_repeated_field(self):
119
"""Repeated field in rio"""
121
for k, v in [('a', '10'), ('b', '20'), ('a', '100'), ('b', '200'),
122
('a', '1000'), ('b', '2000')]:
124
s2 = read_stanza(s.to_lines())
125
self.assertEquals(s, s2)
126
self.assertEquals(s.get_all('a'), map(str, [10, 100, 1000]))
127
self.assertEquals(s.get_all('b'), map(str, [20, 200, 2000]))
129
def test_backslash(self):
132
self.assertEqualDiff(t, 'q: \\\n')
133
s2 = read_stanza(s.to_lines())
134
self.assertEquals(s, s2)
136
def test_blank_line(self):
137
s = Stanza(none='', one='\n', two='\n\n')
138
self.assertEqualDiff(s.to_string(), """\
146
s2 = read_stanza(s.to_lines())
147
self.assertEquals(s, s2)
149
def test_whitespace_value(self):
150
s = Stanza(space=' ', tabs='\t\t\t', combo='\n\t\t\n')
151
self.assertEqualDiff(s.to_string(), """\
158
s2 = read_stanza(s.to_lines())
159
self.assertEquals(s, s2)
161
def test_quoted(self):
162
"""rio quoted string cases"""
163
s = Stanza(q1='"hello"',
173
s2 = read_stanza(s.to_lines())
174
self.assertEquals(s, s2)
176
def test_read_empty(self):
177
"""Detect end of rio file"""
179
self.assertEqual(s, None)
180
self.assertTrue(s is None)
182
def test_read_iter(self):
183
"""Read several stanzas from file"""
184
tmpf = TemporaryFile()
195
reader = read_stanzas(tmpf)
196
read_iter = iter(reader)
198
self.assertEqual(stuff,
199
[ Stanza(version_header='1'),
200
Stanza(name="foo", val='123'),
201
Stanza(name="bar", val='129319'), ])
203
def test_read_several(self):
204
"""Read several stanzas from file"""
205
tmpf = TemporaryFile()
213
address: "Willowglen"
221
s = read_stanza(tmpf)
222
self.assertEquals(s, Stanza(version_header='1'))
223
s = read_stanza(tmpf)
224
self.assertEquals(s, Stanza(name="foo", val='123'))
225
s = read_stanza(tmpf)
226
self.assertEqualDiff(s.get('name'), 'quoted')
227
self.assertEqualDiff(s.get('address'), ' "Willowglen"\n 42 Wallaby Way\n Sydney')
228
s = read_stanza(tmpf)
229
self.assertEquals(s, Stanza(name="bar", val='129319'))
230
s = read_stanza(tmpf)
231
self.assertEquals(s, None)
233
def test_tricky_quoted(self):
234
tmpf = TemporaryFile()
268
expected_vals = ['"one"',
281
for expected in expected_vals:
282
stanza = read_stanza(tmpf)
283
self.assertEquals(len(stanza), 1)
284
self.assertEqualDiff(stanza.get('s'), expected)
286
def test_write_empty_stanza(self):
287
"""Write empty stanza"""
288
l = list(Stanza().to_lines())
289
self.assertEquals(l, [])
291
def test_rio_raises_type_error(self):
292
"""TypeError on adding invalid type to Stanza"""
294
self.assertRaises(TypeError, s.add, 'foo', {})
296
def test_rio_raises_type_error_key(self):
297
"""TypeError on adding invalid type to Stanza"""
299
self.assertRaises(TypeError, s.add, 10, {})
301
def test_rio_unicode(self):
302
# intentionally use cStringIO which doesn't accomodate unencoded unicode objects
303
sio = cStringIO.StringIO()
304
uni_data = u'\N{KATAKANA LETTER O}'
305
s = Stanza(foo=uni_data)
306
self.assertEquals(s.get('foo'), uni_data)
307
raw_lines = s.to_lines()
308
self.assertEquals(raw_lines,
309
['foo: ' + uni_data.encode('utf-8') + '\n'])
310
new_s = read_stanza(raw_lines)
311
self.assertEquals(new_s.get('foo'), uni_data)