~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_rio.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-01-25 05:18:17 UTC
  • mfrom: (2241.1.3 repoformats)
  • Revision ID: pqm@pqm.ubuntu.com-20070125051817-53a80525dbdf87b4
(mbp) Change RepositoryFormat to use a registry (r=john)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 cStringIO
 
26
import os
 
27
import sys
 
28
from tempfile import TemporaryFile
 
29
 
 
30
from bzrlib import (
 
31
    rio,
 
32
    )
 
33
from bzrlib.tests import TestCaseInTempDir, TestCase
 
34
from bzrlib.rio import (RioWriter, Stanza, read_stanza, read_stanzas, rio_file,
 
35
                        RioReader)
 
36
 
 
37
 
 
38
class TestRio(TestCase):
 
39
 
 
40
    def test_stanza(self):
 
41
        """Construct rio stanza in memory"""
 
42
        s = Stanza(number='42', name="fred")
 
43
        self.assertTrue('number' in s)
 
44
        self.assertFalse('color' in s)
 
45
        self.assertFalse('42' in s)
 
46
        self.assertEquals(list(s.iter_pairs()),
 
47
                [('name', 'fred'), ('number', '42')])
 
48
        self.assertEquals(s.get('number'), '42')
 
49
        self.assertEquals(s.get('name'), 'fred')
 
50
 
 
51
    def test_value_checks(self):
 
52
        """rio checks types on construction"""
 
53
        # these aren't enforced at construction time
 
54
        ## self.assertRaises(ValueError,
 
55
        ##        Stanza, complex=42 + 3j)
 
56
        ## self.assertRaises(ValueError, 
 
57
        ##        Stanza, several=range(10))
 
58
 
 
59
    def test_empty_value(self):
 
60
        """Serialize stanza with empty field"""
 
61
        s = Stanza(empty='')
 
62
        self.assertEqualDiff(s.to_string(),
 
63
                "empty: \n")
 
64
 
 
65
    def test_to_lines(self):
 
66
        """Write simple rio stanza to string"""
 
67
        s = Stanza(number='42', name='fred')
 
68
        self.assertEquals(list(s.to_lines()),
 
69
                ['name: fred\n',
 
70
                 'number: 42\n'])
 
71
 
 
72
    def test_as_dict(self):
 
73
        """Convert rio Stanza to dictionary"""
 
74
        s = Stanza(number='42', name='fred')
 
75
        sd = s.as_dict()
 
76
        self.assertEquals(sd, dict(number='42', name='fred'))
 
77
 
 
78
    def test_to_file(self):
 
79
        """Write rio to file"""
 
80
        tmpf = TemporaryFile()
 
81
        s = Stanza(a_thing='something with "quotes like \\"this\\""', number='42', name='fred')
 
82
        s.write(tmpf)
 
83
        tmpf.seek(0)
 
84
        self.assertEqualDiff(tmpf.read(), r'''
 
85
a_thing: something with "quotes like \"this\""
 
86
name: fred
 
87
number: 42
 
88
'''[1:])
 
89
 
 
90
    def test_multiline_string(self):
 
91
        tmpf = TemporaryFile()
 
92
        s = Stanza(motto="war is peace\nfreedom is slavery\nignorance is strength")
 
93
        s.write(tmpf)
 
94
        tmpf.seek(0)
 
95
        self.assertEqualDiff(tmpf.read(), '''\
 
96
motto: war is peace
 
97
\tfreedom is slavery
 
98
\tignorance is strength
 
99
''')
 
100
        tmpf.seek(0)
 
101
        s2 = read_stanza(tmpf)
 
102
        self.assertEquals(s, s2)
 
103
 
 
104
    def test_read_stanza(self):
 
105
        """Load stanza from string"""
 
106
        lines = """\
 
107
revision: mbp@sourcefrog.net-123-abc
 
108
timestamp: 1130653962
 
109
timezone: 36000
 
110
committer: Martin Pool <mbp@test.sourcefrog.net>
 
111
""".splitlines(True)
 
112
        s = read_stanza(lines)
 
113
        self.assertTrue('revision' in s)
 
114
        self.assertEqualDiff(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
 
115
        self.assertEquals(list(s.iter_pairs()),
 
116
                [('revision', 'mbp@sourcefrog.net-123-abc'),
 
117
                 ('timestamp', '1130653962'),
 
118
                 ('timezone', '36000'),
 
119
                 ('committer', "Martin Pool <mbp@test.sourcefrog.net>")])
 
120
        self.assertEquals(len(s), 4)
 
121
 
 
122
    def test_repeated_field(self):
 
123
        """Repeated field in rio"""
 
124
        s = Stanza()
 
125
        for k, v in [('a', '10'), ('b', '20'), ('a', '100'), ('b', '200'), 
 
126
                     ('a', '1000'), ('b', '2000')]:
 
127
            s.add(k, v)
 
128
        s2 = read_stanza(s.to_lines())
 
129
        self.assertEquals(s, s2)
 
130
        self.assertEquals(s.get_all('a'), map(str, [10, 100, 1000]))
 
131
        self.assertEquals(s.get_all('b'), map(str, [20, 200, 2000]))
 
132
 
 
133
    def test_backslash(self):
 
134
        s = Stanza(q='\\')
 
135
        t = s.to_string()
 
136
        self.assertEqualDiff(t, 'q: \\\n')
 
137
        s2 = read_stanza(s.to_lines())
 
138
        self.assertEquals(s, s2)
 
139
 
 
140
    def test_blank_line(self):
 
141
        s = Stanza(none='', one='\n', two='\n\n')
 
142
        self.assertEqualDiff(s.to_string(), """\
 
143
none: 
 
144
one: 
 
145
\t
 
146
two: 
 
147
\t
 
148
\t
 
149
""")
 
150
        s2 = read_stanza(s.to_lines())
 
151
        self.assertEquals(s, s2)
 
152
 
 
153
    def test_whitespace_value(self):
 
154
        s = Stanza(space=' ', tabs='\t\t\t', combo='\n\t\t\n')
 
155
        self.assertEqualDiff(s.to_string(), """\
 
156
combo: 
 
157
\t\t\t
 
158
\t
 
159
space:  
 
160
tabs: \t\t\t
 
161
""")
 
162
        s2 = read_stanza(s.to_lines())
 
163
        self.assertEquals(s, s2)
 
164
        self.rio_file_stanzas([s])
 
165
 
 
166
    def test_quoted(self):
 
167
        """rio quoted string cases"""
 
168
        s = Stanza(q1='"hello"', 
 
169
                   q2=' "for', 
 
170
                   q3='\n\n"for"\n',
 
171
                   q4='for\n"\nfor',
 
172
                   q5='\n',
 
173
                   q6='"', 
 
174
                   q7='""',
 
175
                   q8='\\',
 
176
                   q9='\\"\\"',
 
177
                   )
 
178
        s2 = read_stanza(s.to_lines())
 
179
        self.assertEquals(s, s2)
 
180
        # apparent bug in read_stanza
 
181
        # s3 = read_stanza(self.stanzas_to_str([s]))
 
182
        # self.assertEquals(s, s3)
 
183
 
 
184
    def test_read_empty(self):
 
185
        """Detect end of rio file"""
 
186
        s = read_stanza([])
 
187
        self.assertEqual(s, None)
 
188
        self.assertTrue(s is None)
 
189
        
 
190
    def test_read_iter(self):
 
191
        """Read several stanzas from file"""
 
192
        tmpf = TemporaryFile()
 
193
        tmpf.write("""\
 
194
version_header: 1
 
195
 
 
196
name: foo
 
197
val: 123
 
198
 
 
199
name: bar
 
200
val: 129319
 
201
""")
 
202
        tmpf.seek(0)
 
203
        reader = read_stanzas(tmpf)
 
204
        read_iter = iter(reader)
 
205
        stuff = list(reader)
 
206
        self.assertEqual(stuff, 
 
207
                [ Stanza(version_header='1'),
 
208
                  Stanza(name="foo", val='123'),
 
209
                  Stanza(name="bar", val='129319'), ])
 
210
 
 
211
    def test_read_several(self):
 
212
        """Read several stanzas from file"""
 
213
        tmpf = TemporaryFile()
 
214
        tmpf.write("""\
 
215
version_header: 1
 
216
 
 
217
name: foo
 
218
val: 123
 
219
 
 
220
name: quoted
 
221
address:   "Willowglen"
 
222
\t  42 Wallaby Way
 
223
\t  Sydney
 
224
 
 
225
name: bar
 
226
val: 129319
 
227
""")
 
228
        tmpf.seek(0)
 
229
        s = read_stanza(tmpf)
 
230
        self.assertEquals(s, Stanza(version_header='1'))
 
231
        s = read_stanza(tmpf)
 
232
        self.assertEquals(s, Stanza(name="foo", val='123'))
 
233
        s = read_stanza(tmpf)
 
234
        self.assertEqualDiff(s.get('name'), 'quoted')
 
235
        self.assertEqualDiff(s.get('address'), '  "Willowglen"\n  42 Wallaby Way\n  Sydney')
 
236
        s = read_stanza(tmpf)
 
237
        self.assertEquals(s, Stanza(name="bar", val='129319'))
 
238
        s = read_stanza(tmpf)
 
239
        self.assertEquals(s, None)
 
240
        self.check_rio_file(tmpf)
 
241
 
 
242
    def check_rio_file(self, real_file):
 
243
        real_file.seek(0)
 
244
        read_write = rio_file(RioReader(real_file)).read()
 
245
        real_file.seek(0)
 
246
        self.assertEquals(read_write, real_file.read())
 
247
 
 
248
    @staticmethod
 
249
    def stanzas_to_str(stanzas):
 
250
        return rio_file(stanzas).read()
 
251
 
 
252
    def rio_file_stanzas(self, stanzas):
 
253
        new_stanzas = list(RioReader(rio_file(stanzas)))
 
254
        self.assertEqual(new_stanzas, stanzas)
 
255
 
 
256
    def test_tricky_quoted(self):
 
257
        tmpf = TemporaryFile()
 
258
        tmpf.write('''\
 
259
s: "one"
 
260
 
 
261
s: 
 
262
\t"one"
 
263
\t
 
264
 
 
265
s: "
 
266
 
 
267
s: ""
 
268
 
 
269
s: """
 
270
 
 
271
s: 
 
272
\t
 
273
 
 
274
s: \\
 
275
 
 
276
s: 
 
277
\t\\
 
278
\t\\\\
 
279
\t
 
280
 
 
281
s: word\\
 
282
 
 
283
s: quote"
 
284
 
 
285
s: backslashes\\\\\\
 
286
 
 
287
s: both\\\"
 
288
 
 
289
''')
 
290
        tmpf.seek(0)
 
291
        expected_vals = ['"one"',
 
292
            '\n"one"\n',
 
293
            '"',
 
294
            '""',
 
295
            '"""',
 
296
            '\n',
 
297
            '\\',
 
298
            '\n\\\n\\\\\n',
 
299
            'word\\',
 
300
            'quote\"',
 
301
            'backslashes\\\\\\',
 
302
            'both\\\"',
 
303
            ]
 
304
        for expected in expected_vals:
 
305
            stanza = read_stanza(tmpf)
 
306
            self.rio_file_stanzas([stanza])
 
307
            self.assertEquals(len(stanza), 1)
 
308
            self.assertEqualDiff(stanza.get('s'), expected)
 
309
 
 
310
    def test_write_empty_stanza(self):
 
311
        """Write empty stanza"""
 
312
        l = list(Stanza().to_lines())
 
313
        self.assertEquals(l, [])
 
314
 
 
315
    def test_rio_raises_type_error(self):
 
316
        """TypeError on adding invalid type to Stanza"""
 
317
        s = Stanza()
 
318
        self.assertRaises(TypeError, s.add, 'foo', {})
 
319
 
 
320
    def test_rio_raises_type_error_key(self):
 
321
        """TypeError on adding invalid type to Stanza"""
 
322
        s = Stanza()
 
323
        self.assertRaises(TypeError, s.add, 10, {})
 
324
 
 
325
    def test_rio_unicode(self):
 
326
        uni_data = u'\N{KATAKANA LETTER O}'
 
327
        s = Stanza(foo=uni_data)
 
328
        self.assertEquals(s.get('foo'), uni_data)
 
329
        raw_lines = s.to_lines()
 
330
        self.assertEquals(raw_lines,
 
331
                ['foo: ' + uni_data.encode('utf-8') + '\n'])
 
332
        new_s = read_stanza(raw_lines)
 
333
        self.assertEquals(new_s.get('foo'), uni_data)
 
334
 
 
335
    def test_rio_to_unicode(self):
 
336
        uni_data = u'\N{KATAKANA LETTER O}'
 
337
        s = Stanza(foo=uni_data)
 
338
        unicode_str = s.to_unicode()
 
339
        self.assertEqual(u'foo: %s\n' % (uni_data,), unicode_str)
 
340
        new_s = rio.read_stanza_unicode(unicode_str.splitlines(True))
 
341
        self.assertEqual(uni_data, new_s.get('foo'))
 
342
 
 
343
    def test_nested_rio_unicode(self):
 
344
        uni_data = u'\N{KATAKANA LETTER O}'
 
345
        s = Stanza(foo=uni_data)
 
346
        parent_stanza = Stanza(child=s.to_unicode())
 
347
        raw_lines = parent_stanza.to_lines()
 
348
        self.assertEqual(['child: foo: ' + uni_data.encode('utf-8') + '\n',
 
349
                          '\t\n',
 
350
                         ], raw_lines)
 
351
        new_parent = read_stanza(raw_lines)
 
352
        child_text = new_parent.get('child')
 
353
        self.assertEqual(u'foo: %s\n' % uni_data, child_text)
 
354
        new_child = rio.read_stanza_unicode(child_text.splitlines(True))
 
355
        self.assertEqual(uni_data, new_child.get('foo'))