~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_rio.py

Merge from mbp.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by 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 os
 
26
import sys
 
27
from tempfile import TemporaryFile
 
28
 
 
29
from bzrlib.tests import TestCaseInTempDir, TestCase
 
30
from bzrlib.rio import RioWriter, Stanza, read_stanza, read_stanzas
 
31
 
 
32
 
 
33
class TestRio(TestCase):
 
34
 
 
35
    def test_stanza(self):
 
36
        """Construct rio stanza in memory"""
 
37
        s = Stanza(number='42', name="fred")
 
38
        self.assertTrue('number' in s)
 
39
        self.assertFalse('color' in s)
 
40
        self.assertFalse('42' in s)
 
41
        self.assertEquals(list(s.iter_pairs()),
 
42
                [('name', 'fred'), ('number', '42')])
 
43
        self.assertEquals(s.get('number'), '42')
 
44
        self.assertEquals(s.get('name'), 'fred')
 
45
 
 
46
    def test_value_checks(self):
 
47
        """rio checks types on construction"""
 
48
        # these aren't enforced at construction time
 
49
        ## self.assertRaises(ValueError,
 
50
        ##        Stanza, complex=42 + 3j)
 
51
        ## self.assertRaises(ValueError, 
 
52
        ##        Stanza, several=range(10))
 
53
 
 
54
    def test_empty_value(self):
 
55
        """Serialize stanza with empty field"""
 
56
        s = Stanza(empty='')
 
57
        self.assertEqualDiff(s.to_string(),
 
58
                "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.assertEquals(list(s.to_lines()),
 
64
                ['name: fred\n',
 
65
                 'number: 42\n'])
 
66
 
 
67
    def test_to_file(self):
 
68
        """Write rio to file"""
 
69
        tmpf = TemporaryFile()
 
70
        s = Stanza(a_thing='something with "quotes like \\"this\\""', number='42', name='fred')
 
71
        s.write(tmpf)
 
72
        tmpf.seek(0)
 
73
        self.assertEqualDiff(tmpf.read(), r'''
 
74
a_thing: something with "quotes like \"this\""
 
75
name: fred
 
76
number: 42
 
77
'''[1:])
 
78
 
 
79
    def test_multiline_string(self):
 
80
        tmpf = TemporaryFile()
 
81
        s = Stanza(motto="war is peace\nfreedom is slavery\nignorance is strength")
 
82
        s.write(tmpf)
 
83
        tmpf.seek(0)
 
84
        self.assertEqualDiff(tmpf.read(), '''\
 
85
motto: war is peace
 
86
\tfreedom is slavery
 
87
\tignorance is strength
 
88
''')
 
89
        tmpf.seek(0)
 
90
        s2 = read_stanza(tmpf)
 
91
        self.assertEquals(s, s2)
 
92
 
 
93
    def test_read_stanza(self):
 
94
        """Load stanza from string"""
 
95
        lines = """\
 
96
revision: mbp@sourcefrog.net-123-abc
 
97
timestamp: 1130653962
 
98
timezone: 36000
 
99
committer: Martin Pool <mbp@test.sourcefrog.net>
 
100
""".splitlines(True)
 
101
        s = read_stanza(lines)
 
102
        self.assertTrue('revision' in s)
 
103
        self.assertEqualDiff(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
 
104
        self.assertEquals(list(s.iter_pairs()),
 
105
                [('revision', 'mbp@sourcefrog.net-123-abc'),
 
106
                 ('timestamp', '1130653962'),
 
107
                 ('timezone', '36000'),
 
108
                 ('committer', "Martin Pool <mbp@test.sourcefrog.net>")])
 
109
        self.assertEquals(len(s), 4)
 
110
 
 
111
    def test_repeated_field(self):
 
112
        """Repeated field in rio"""
 
113
        s = Stanza()
 
114
        for k, v in [('a', '10'), ('b', '20'), ('a', '100'), ('b', '200'), 
 
115
                     ('a', '1000'), ('b', '2000')]:
 
116
            s.add(k, v)
 
117
        s2 = read_stanza(s.to_lines())
 
118
        self.assertEquals(s, s2)
 
119
        self.assertEquals(s.get_all('a'), map(str, [10, 100, 1000]))
 
120
        self.assertEquals(s.get_all('b'), map(str, [20, 200, 2000]))
 
121
 
 
122
    def test_backslash(self):
 
123
        s = Stanza(q='\\')
 
124
        t = s.to_string()
 
125
        self.assertEqualDiff(t, 'q: \\\n')
 
126
        s2 = read_stanza(s.to_lines())
 
127
        self.assertEquals(s, s2)
 
128
 
 
129
    def test_blank_line(self):
 
130
        s = Stanza(none='', one='\n', two='\n\n')
 
131
        self.assertEqualDiff(s.to_string(), """\
 
132
none: 
 
133
one: 
 
134
\t
 
135
two: 
 
136
\t
 
137
\t
 
138
""")
 
139
        s2 = read_stanza(s.to_lines())
 
140
        self.assertEquals(s, s2)
 
141
 
 
142
    def test_whitespace_value(self):
 
143
        s = Stanza(space=' ', tabs='\t\t\t', combo='\n\t\t\n')
 
144
        self.assertEqualDiff(s.to_string(), """\
 
145
combo: 
 
146
\t\t\t
 
147
\t
 
148
space:  
 
149
tabs: \t\t\t
 
150
""")
 
151
        s2 = read_stanza(s.to_lines())
 
152
        self.assertEquals(s, s2)
 
153
 
 
154
    def test_quoted(self):
 
155
        """rio quoted string cases"""
 
156
        s = Stanza(q1='"hello"', 
 
157
                   q2=' "for', 
 
158
                   q3='\n\n"for"\n',
 
159
                   q4='for\n"\nfor',
 
160
                   q5='\n',
 
161
                   q6='"', 
 
162
                   q7='""',
 
163
                   q8='\\',
 
164
                   q9='\\"\\"',
 
165
                   )
 
166
        s2 = read_stanza(s.to_lines())
 
167
        self.assertEquals(s, s2)
 
168
 
 
169
    def test_read_empty(self):
 
170
        """Detect end of rio file"""
 
171
        s = read_stanza([])
 
172
        self.assertEqual(s, None)
 
173
        self.assertTrue(s is None)
 
174
        
 
175
    def test_read_iter(self):
 
176
        """Read several stanzas from file"""
 
177
        tmpf = TemporaryFile()
 
178
        tmpf.write("""\
 
179
version_header: 1
 
180
 
 
181
name: foo
 
182
val: 123
 
183
 
 
184
name: bar
 
185
val: 129319
 
186
""")
 
187
        tmpf.seek(0)
 
188
        reader = read_stanzas(tmpf)
 
189
        read_iter = iter(reader)
 
190
        stuff = list(reader)
 
191
        self.assertEqual(stuff, 
 
192
                [ Stanza(version_header='1'),
 
193
                  Stanza(name="foo", val='123'),
 
194
                  Stanza(name="bar", val='129319'), ])
 
195
 
 
196
    def test_read_several(self):
 
197
        """Read several stanzas from file"""
 
198
        tmpf = TemporaryFile()
 
199
        tmpf.write("""\
 
200
version_header: 1
 
201
 
 
202
name: foo
 
203
val: 123
 
204
 
 
205
name: quoted
 
206
address:   "Willowglen"
 
207
\t  42 Wallaby Way
 
208
\t  Sydney
 
209
 
 
210
name: bar
 
211
val: 129319
 
212
""")
 
213
        tmpf.seek(0)
 
214
        s = read_stanza(tmpf)
 
215
        self.assertEquals(s, Stanza(version_header='1'))
 
216
        s = read_stanza(tmpf)
 
217
        self.assertEquals(s, Stanza(name="foo", val='123'))
 
218
        s = read_stanza(tmpf)
 
219
        self.assertEqualDiff(s.get('name'), 'quoted')
 
220
        self.assertEqualDiff(s.get('address'), '  "Willowglen"\n  42 Wallaby Way\n  Sydney')
 
221
        s = read_stanza(tmpf)
 
222
        self.assertEquals(s, Stanza(name="bar", val='129319'))
 
223
        s = read_stanza(tmpf)
 
224
        self.assertEquals(s, None)
 
225
 
 
226
    def test_tricky_quoted(self):
 
227
        tmpf = TemporaryFile()
 
228
        tmpf.write('''\
 
229
s: "one"
 
230
 
 
231
s: 
 
232
\t"one"
 
233
\t
 
234
 
 
235
s: "
 
236
 
 
237
s: ""
 
238
 
 
239
s: """
 
240
 
 
241
s: 
 
242
\t
 
243
 
 
244
s: \\
 
245
 
 
246
s: 
 
247
\t\\
 
248
\t\\\\
 
249
\t
 
250
 
 
251
s: word\\
 
252
 
 
253
s: quote"
 
254
 
 
255
s: backslashes\\\\\\
 
256
 
 
257
s: both\\\"
 
258
 
 
259
''')
 
260
        tmpf.seek(0)
 
261
        expected_vals = ['"one"',
 
262
            '\n"one"\n',
 
263
            '"',
 
264
            '""',
 
265
            '"""',
 
266
            '\n',
 
267
            '\\',
 
268
            '\n\\\n\\\\\n',
 
269
            'word\\',
 
270
            'quote\"',
 
271
            'backslashes\\\\\\',
 
272
            'both\\\"',
 
273
            ]
 
274
        for expected in expected_vals:
 
275
            stanza = read_stanza(tmpf)
 
276
            self.assertEquals(len(stanza), 1)
 
277
            self.assertEqualDiff(stanza.get('s'), expected)
 
278
 
 
279
    def test_write_empty_stanza(self):
 
280
        """Write empty stanza"""
 
281
        l = list(Stanza().to_lines())
 
282
        self.assertEquals(l, [])