~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testbasicio.py

[merge] basic_io metaformat (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 basic_io serialization
 
18
 
 
19
A simple, reproducible structured IO format.
 
20
 
 
21
basic_io 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.selftest import TestCaseInTempDir, TestCase
 
30
from bzrlib.basicio import BasicWriter, Stanza, read_stanza, read_stanzas
 
31
 
 
32
 
 
33
class TestBasicIO(TestCase):
 
34
 
 
35
    def test_stanza(self):
 
36
        """Construct basic_io 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
        """basic_io 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_to_lines(self):
 
55
        """Write simple basic_io stanza to string"""
 
56
        s = Stanza(number=42, name='fred')
 
57
        self.assertEquals(list(s.to_lines()),
 
58
                ['  name "fred"\n',
 
59
                 'number 42\n'])
 
60
 
 
61
    def test_to_file(self):
 
62
        """Write basic_io to file"""
 
63
        tmpf = TemporaryFile()
 
64
        s = Stanza(a_thing='something with "quotes like \\"this\\""', number=42, name='fred')
 
65
        s.write(tmpf)
 
66
        tmpf.seek(0)
 
67
        self.assertEqualDiff(tmpf.read(), r'''
 
68
a_thing "something with \"quotes like \\\"this\\\"\""
 
69
   name "fred"
 
70
 number 42
 
71
'''[1:])
 
72
 
 
73
    def test_multiline_string(self):
 
74
        """Write basic_io with multiline string"""
 
75
        tmpf = TemporaryFile()
 
76
        s = Stanza(a=123, motto="war is peace\nfreedom is slavery\nignorance is strength\n",
 
77
                   charlie_horse=456)
 
78
        s.write(tmpf)
 
79
        tmp.seek(0)
 
80
        self.assertEqualDiff(tmpf.read(), r'''\
 
81
            a 123
 
82
        motto "war is peace
 
83
freedom is slavery
 
84
ignorance is strength
 
85
"
 
86
charlie_horse 456
 
87
''')
 
88
 
 
89
    def test_multiline_string(self):
 
90
        tmpf = TemporaryFile()
 
91
        s = Stanza(motto="war is peace\nfreedom is slavery\nignorance is strength")
 
92
        s.write(tmpf)
 
93
        tmpf.seek(0)
 
94
        self.assertEqualDiff(tmpf.read(), '''\
 
95
motto "war is peace
 
96
freedom is slavery
 
97
ignorance is strength"
 
98
''')
 
99
        tmpf.seek(0)
 
100
        s2 = read_stanza(tmpf)
 
101
        self.assertEquals(s, s2)
 
102
 
 
103
    def test_read_stanza(self):
 
104
        """Load stanza from string"""
 
105
        lines = """\
 
106
 revision "mbp@sourcefrog.net-123-abc"
 
107
timestamp 1130653962
 
108
 timezone 36000
 
109
committer "Martin Pool <mbp@test.sourcefrog.net>"
 
110
""".splitlines(True)
 
111
        s = read_stanza(lines)
 
112
        self.assertTrue('revision' in s)
 
113
        self.assertEqualDiff(s.get('revision'), 'mbp@sourcefrog.net-123-abc')
 
114
        self.assertEquals(list(s.iter_pairs()),
 
115
                [('revision', 'mbp@sourcefrog.net-123-abc'),
 
116
                 ('timestamp', 1130653962),
 
117
                 ('timezone', 36000),
 
118
                 ('committer', "Martin Pool <mbp@test.sourcefrog.net>")])
 
119
        self.assertEquals(len(s), 4)
 
120
 
 
121
    def test_repeated_field(self):
 
122
        """Repeated field in basic_io"""
 
123
        s = Stanza()
 
124
        for k, v in [('a', 10), ('b', 20), ('a', 100), ('b', 200), ('a', 1000), ('b', 2000)]:
 
125
            s.add(k, v)
 
126
        s2 = read_stanza(s.to_lines())
 
127
        self.assertEquals(s, s2)
 
128
        self.assertEquals(s.get_all('a'), [10, 100, 1000])
 
129
        self.assertEquals(s.get_all('b'), [20, 200, 2000])
 
130
 
 
131
    def test_longint(self):
 
132
        """basic_io packing long integers"""
 
133
        s = Stanza(x=-12345678901234567890,
 
134
                   y=1<<100)
 
135
        lines = s.to_lines()
 
136
        s2 = read_stanza(lines)
 
137
        self.assertEquals(s, s2)
 
138
 
 
139
    def test_quoted_0(self):
 
140
        """Backslash quoted cases"""
 
141
        s = Stanza(q='\\')
 
142
        t = s.to_string()
 
143
        self.assertEqualDiff(t, 'q "\\\\"\n')
 
144
        s2 = read_stanza(s.to_lines())
 
145
        self.assertEquals(s, s2)
 
146
 
 
147
    def test_quoted_1(self):
 
148
        """Backslash quoted cases"""
 
149
        s = Stanza(q=r'\"\"')
 
150
        self.assertEqualDiff(s.to_string(), r'q "\\\"\\\""' + '\n')
 
151
 
 
152
    def test_quoted_4(self):
 
153
        s = Stanza(q=r'""""')
 
154
        t = s.to_string()
 
155
        self.assertEqualDiff(t, r'q "\"\"\"\""' + '\n')
 
156
        s2 = read_stanza(s.to_lines())
 
157
        self.assertEquals(s, s2)
 
158
 
 
159
    def test_quoted_5(self):
 
160
        s = Stanza(q=r'\\\\\"')
 
161
        t = s.to_string()
 
162
        s2 = read_stanza(s.to_lines())
 
163
        self.assertEquals(s, s2)
 
164
 
 
165
    def test_quoted_6(self):
 
166
        qval = r'''
 
167
                "
 
168
                \"
 
169
'''
 
170
        s = Stanza(q=qval)
 
171
        t = s.to_string()
 
172
        self.log(t)
 
173
        s2 = read_stanza(s.to_lines())
 
174
        self.assertEquals(s2['q'], qval)
 
175
        
 
176
    def test_quoted_7(self):
 
177
        qval = r'''
 
178
                "
 
179
                \"
 
180
                \\"
 
181
trailing stuff'''
 
182
        s = Stanza(q=qval)
 
183
        t = s.to_string()
 
184
        self.log(t)
 
185
        s2 = read_stanza(s.to_lines())
 
186
        self.assertEquals(s2['q'], qval)
 
187
        
 
188
    def test_quoted_8(self):
 
189
        qval = r'''trailing
 
190
        quote"'''
 
191
        s = Stanza(q=qval)
 
192
        t = s.to_string()
 
193
        self.log(t)
 
194
        s2 = read_stanza(s.to_lines())
 
195
        self.assertEquals(s2['q'], qval)
 
196
        
 
197
    def test_quoted(self):
 
198
        """basic_io quoted string cases"""
 
199
        s = Stanza(q1='"hello"', 
 
200
                   q2=' "for', 
 
201
                   q3='\n\n"for"\n',
 
202
                   q4='for\n"\nfor',
 
203
                   q5='\n',
 
204
                   q6='"', 
 
205
                   q7='""',
 
206
                   q8='\\',
 
207
                   q9='\\"\\"',
 
208
                   )
 
209
        s2 = read_stanza(s.to_lines())
 
210
        self.assertEquals(s, s2)
 
211
 
 
212
    def test_read_empty(self):
 
213
        """Detect end of basic_io file"""
 
214
        s = read_stanza([])
 
215
        self.assertEqual(s, None)
 
216
        self.assertTrue(s is None)
 
217
        
 
218
    def test_read_iter(self):
 
219
        """Read several stanzas from file"""
 
220
        tmpf = TemporaryFile()
 
221
        tmpf.write("""\
 
222
version_header 1
 
223
 
 
224
name "foo"
 
225
val 123
 
226
 
 
227
name "bar"
 
228
val 129319
 
229
""")
 
230
        tmpf.seek(0)
 
231
        reader = read_stanzas(tmpf)
 
232
        read_iter = iter(reader)
 
233
        stuff = list(reader)
 
234
        self.assertEqual(stuff, 
 
235
                [ Stanza(version_header=1),
 
236
                  Stanza(name="foo", val=123),
 
237
                  Stanza(name="bar", val=129319), ])
 
238
 
 
239
    def test_read_several(self):
 
240
        """Read several stanzas from file"""
 
241
        tmpf = TemporaryFile()
 
242
        tmpf.write("""\
 
243
version_header 1
 
244
 
 
245
name "foo"
 
246
val 123
 
247
 
 
248
name "quoted"
 
249
address "  \\"Willowglen\\"
 
250
  42 Wallaby Way
 
251
  Sydney"
 
252
 
 
253
name "bar"
 
254
val 129319
 
255
""")
 
256
        tmpf.seek(0)
 
257
        s = read_stanza(tmpf)
 
258
        self.assertEquals(s, Stanza(version_header=1))
 
259
        s = read_stanza(tmpf)
 
260
        self.assertEquals(s, Stanza(name="foo", val=123))
 
261
        s = read_stanza(tmpf)
 
262
        self.assertEqualDiff(s.get('name'), 'quoted')
 
263
        self.assertEqualDiff(s.get('address'), '  "Willowglen"\n  42 Wallaby Way\n  Sydney')
 
264
        s = read_stanza(tmpf)
 
265
        self.assertEquals(s, Stanza(name="bar", val=129319))
 
266
        s = read_stanza(tmpf)
 
267
        self.assertEquals(s, None)
 
268
 
 
269
    def test_tricky_quoted(self):
 
270
        tmpf = TemporaryFile()
 
271
        tmpf.write(r"""
 
272
s "\"one\""
 
273
 
 
274
s "
 
275
\"one\"
 
276
"
 
277
 
 
278
s "\""
 
279
 
 
280
s "\"\""
 
281
 
 
282
s "\"\"\""
 
283
 
 
284
s "
 
285
"
 
286
 
 
287
s "\\"
 
288
 
 
289
s "
 
290
\\
 
291
\\\\
 
292
"
 
293
 
 
294
s "word\\"
 
295
 
 
296
s "quote\""
 
297
 
 
298
s "backslashes\\\\\\"
 
299
 
 
300
s "both\\\""
 
301
 
 
302
"""[1:]) # remove initial newline
 
303
        tmpf.seek(0)
 
304
        expected_vals = ['"one"',
 
305
            '\n"one"\n',
 
306
            '"',
 
307
            '""',
 
308
            '"""',
 
309
            '\n',
 
310
            '\\',
 
311
            '\n\\\n\\\\\n',
 
312
            'word\\',
 
313
            'quote\"',
 
314
            'backslashes\\\\\\',
 
315
            'both\\\"',
 
316
            ]
 
317
        for expected in expected_vals:
 
318
            stanza = read_stanza(tmpf)
 
319
            self.assertEquals(len(stanza), 1)
 
320
            self.assertEqualDiff(stanza.get('s'), expected)
 
321
 
 
322
    def test_write_bool(self):
 
323
        """Write bool to basic_io"""
 
324
        l = list(Stanza(my_bool=True).to_lines())
 
325
        self.assertEquals(l, ['my_bool 1\n'])
 
326
 
 
327
    def test_write_empty_stanza(self):
 
328
        """Write empty stanza"""
 
329
        l = list(Stanza().to_lines())
 
330
        self.assertEquals(l, [])