~bzr-pqm/bzr/bzr.dev

1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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"""
1185.47.2 by Martin Pool
Finish rio format and tests.
37
        s = Stanza(number='42', name="fred")
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
38
        self.assertTrue('number' in s)
39
        self.assertFalse('color' in s)
1185.47.2 by Martin Pool
Finish rio format and tests.
40
        self.assertFalse('42' in s)
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
41
        self.assertEquals(list(s.iter_pairs()),
1185.47.2 by Martin Pool
Finish rio format and tests.
42
                [('name', 'fred'), ('number', '42')])
43
        self.assertEquals(s.get('number'), '42')
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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"""
1185.47.2 by Martin Pool
Finish rio format and tests.
62
        s = Stanza(number='42', name='fred')
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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()
1185.47.2 by Martin Pool
Finish rio format and tests.
70
        s = Stanza(a_thing='something with "quotes like \\"this\\""', number='42', name='fred')
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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
1185.47.2 by Martin Pool
Finish rio format and tests.
122
    def test_backslash(self):
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
123
        s = Stanza(q='\\')
124
        t = s.to_string()
1185.47.2 by Martin Pool
Finish rio format and tests.
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
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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("""\
1185.47.2 by Martin Pool
Finish rio format and tests.
179
version_header: 1
180
181
name: foo
182
val: 123
183
184
name: bar
185
val: 129319
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
186
""")
187
        tmpf.seek(0)
188
        reader = read_stanzas(tmpf)
189
        read_iter = iter(reader)
190
        stuff = list(reader)
191
        self.assertEqual(stuff, 
1185.47.2 by Martin Pool
Finish rio format and tests.
192
                [ Stanza(version_header='1'),
193
                  Stanza(name="foo", val='123'),
194
                  Stanza(name="bar", val='129319'), ])
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
195
196
    def test_read_several(self):
197
        """Read several stanzas from file"""
198
        tmpf = TemporaryFile()
199
        tmpf.write("""\
1185.47.2 by Martin Pool
Finish rio format and tests.
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
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
212
""")
213
        tmpf.seek(0)
214
        s = read_stanza(tmpf)
1185.47.2 by Martin Pool
Finish rio format and tests.
215
        self.assertEquals(s, Stanza(version_header='1'))
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
216
        s = read_stanza(tmpf)
1185.47.2 by Martin Pool
Finish rio format and tests.
217
        self.assertEquals(s, Stanza(name="foo", val='123'))
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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)
1185.47.2 by Martin Pool
Finish rio format and tests.
222
        self.assertEquals(s, Stanza(name="bar", val='129319'))
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
223
        s = read_stanza(tmpf)
224
        self.assertEquals(s, None)
225
226
    def test_tricky_quoted(self):
227
        tmpf = TemporaryFile()
1185.47.2 by Martin Pool
Finish rio format and tests.
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
''')
1185.47.1 by Martin Pool
[broken] start converting basic_io to more rfc822-like format
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, [])