~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/test_xml.py

  • Committer: Martin Pool
  • Date: 2005-09-30 05:56:05 UTC
  • mto: (1185.14.2)
  • mto: This revision was merged to the branch mainline in revision 1396.
  • Revision ID: mbp@sourcefrog.net-20050930055605-a2c534529b392a7d
- fix upgrade for transport changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
from cStringIO import StringIO
18
18
 
19
 
from bzrlib.tests import TestCase
 
19
from bzrlib.selftest import TestCase
20
20
from bzrlib.inventory import Inventory, InventoryEntry
21
21
from bzrlib.xml4 import serializer_v4
22
 
import bzrlib.xml5
 
22
from bzrlib.xml5 import serializer_v5
23
23
 
24
24
_working_inventory_v4 = """<inventory file_id="TREE_ROOT">
25
25
<entry file_id="bar-20050901064931-73b4b1138abc9cd2" kind="file" name="bar" parent_id="TREE_ROOT" />
32
32
    inventory_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
33
33
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
34
34
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
35
 
    timestamp="1125907235.212"
 
35
    timestamp="1125907235.211783886"
36
36
    timezone="36000">
37
37
<message>- start splitting code for xml (de)serialization away from objects
38
38
  preparatory to supporting multiple formats by a single library
46
46
_revision_v5 = """<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
47
47
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
48
48
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
49
 
    timestamp="1125907235.212"
 
49
    timestamp="1125907235.211783886"
50
50
    timezone="36000">
51
51
<message>- start splitting code for xml (de)serialization away from objects
52
52
  preparatory to supporting multiple formats by a single library
57
57
</revision>
58
58
"""
59
59
 
60
 
_revision_v5_utc = """\
61
 
<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
62
 
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
63
 
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
64
 
    timestamp="1125907235.212"
65
 
    timezone="0">
66
 
<message>- start splitting code for xml (de)serialization away from objects
67
 
  preparatory to supporting multiple formats by a single library
68
 
</message>
69
 
<parents>
70
 
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"/>
71
 
</parents>
72
 
</revision>
73
 
"""
74
 
 
75
60
_committed_inv_v5 = """<inventory>
76
61
<file file_id="bar-20050901064931-73b4b1138abc9cd2" 
77
62
      name="bar" parent_id="TREE_ROOT" 
78
 
      revision="mbp@foo-123123"/>
79
 
<directory name="subdir"
80
 
           file_id="foo-20050801201819-4139aa4a272f4250"
81
 
           parent_id="TREE_ROOT" 
82
 
           revision="mbp@foo-00"/>
83
 
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" 
84
 
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 
85
 
      revision="mbp@foo-00"/>
86
 
</inventory>
87
 
"""
88
 
 
89
 
_basis_inv_v5 = """<inventory revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92">
90
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2" 
91
 
      name="bar" parent_id="TREE_ROOT" 
92
 
      revision="mbp@foo-123123"/>
93
 
<directory name="subdir"
94
 
           file_id="foo-20050801201819-4139aa4a272f4250"
95
 
           parent_id="TREE_ROOT" 
96
 
           revision="mbp@foo-00"/>
 
63
      text_version="mbp@foo-123123" name_version="mbp@foo-123123"
 
64
      />
 
65
<directory name="subdir"
 
66
           file_id="foo-20050801201819-4139aa4a272f4250"
 
67
           parent_id="TREE_ROOT" 
 
68
           name_version="mbp@foo-00"/>
97
69
<file file_id="bar-20050824000535-6bc48cfad47ed134" 
98
70
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 
99
 
      revision="mbp@foo-00"/>
100
 
</inventory>
101
 
"""
102
 
 
103
 
 
104
 
# DO NOT REFLOW THIS. Its the exact revision we want.
105
 
_expected_rev_v5 = """<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;" format="5" inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" timestamp="1125907235.212" timezone="36000">
106
 
<message>- start splitting code for xml (de)serialization away from objects
107
 
  preparatory to supporting multiple formats by a single library
108
 
</message>
109
 
<parents>
110
 
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" />
111
 
</parents>
112
 
</revision>
113
 
"""
114
 
 
115
 
 
116
 
# DO NOT REFLOW THIS. Its the exact inventory we want.
117
 
_expected_inv_v5 = """<inventory format="5">
118
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" revision="mbp@foo-123123" />
119
 
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" revision="mbp@foo-00" />
120
 
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
121
 
</inventory>
122
 
"""
123
 
 
124
 
 
125
 
_expected_inv_v5_root = """<inventory file_id="f&lt;" format="5" revision_id="mother!">
126
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" parent_id="f&lt;" revision="mbp@foo-123123" />
127
 
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" parent_id="f&lt;" revision="mbp@foo-00" />
128
 
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
129
 
</inventory>
130
 
"""
131
 
 
132
 
 
133
 
_revision_utf8_v5 = """<revision committer="Erik B&#229;gfors &lt;erik@foo.net&gt;"
134
 
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
135
 
    revision_id="erik@b&#229;gfors-02"
136
 
    timestamp="1125907235.212"
137
 
    timezone="36000">
138
 
<message>Include &#181;nicode characters
139
 
</message>
140
 
<parents>
141
 
<revision_ref revision_id="erik@b&#229;gfors-01"/>
142
 
</parents>
143
 
</revision>
144
 
"""
145
 
 
146
 
_inventory_utf8_v5 = """<inventory file_id="TRE&#233;_ROOT" format="5"
147
 
                                   revision_id="erik@b&#229;gfors-02">
148
 
<file file_id="b&#229;r-01"
149
 
      name="b&#229;r" parent_id="TRE&#233;_ROOT"
150
 
      revision="erik@b&#229;gfors-01"/>
151
 
<directory name="s&#181;bdir"
152
 
           file_id="s&#181;bdir-01"
153
 
           parent_id="TRE&#233;_ROOT"
154
 
           revision="erik@b&#229;gfors-01"/>
155
 
<file executable="yes" file_id="b&#229;r-02"
156
 
      name="b&#229;r" parent_id="s&#181;bdir-01"
157
 
      revision="erik@b&#229;gfors-02"/>
158
 
</inventory>
159
 
"""
160
 
 
 
71
      name_version="mbp@foo-00"
 
72
      text_version="mbp@foo-123123"/>
 
73
</inventory>
 
74
"""
161
75
 
162
76
class TestSerializer(TestCase):
163
77
    """Test XML serialization"""
184
98
    def test_unpack_revision_5(self):
185
99
        """Test unpacking a canned revision v5"""
186
100
        inp = StringIO(_revision_v5)
187
 
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
 
101
        rev = serializer_v5.read_revision(inp)
188
102
        eq = self.assertEqual
189
103
        eq(rev.committer,
190
104
           "Martin Pool <mbp@sourcefrog.net>")
193
107
        eq(rev.parent_ids[0],
194
108
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
195
109
 
196
 
    def test_unpack_revision_5_utc(self):
197
 
        inp = StringIO(_revision_v5_utc)
198
 
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
199
 
        eq = self.assertEqual
200
 
        eq(rev.committer,
201
 
           "Martin Pool <mbp@sourcefrog.net>")
202
 
        eq(len(rev.parent_ids), 1)
203
 
        eq(rev.timezone, 0)
204
 
        eq(rev.parent_ids[0],
205
 
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
206
 
 
207
110
    def test_unpack_inventory_5(self):
208
111
        """Unpack canned new-style inventory"""
209
112
        inp = StringIO(_committed_inv_v5)
210
 
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
211
 
        eq = self.assertEqual
212
 
        eq(len(inv), 4)
213
 
        ie = inv['bar-20050824000535-6bc48cfad47ed134']
214
 
        eq(ie.kind, 'file')
215
 
        eq(ie.revision, 'mbp@foo-00')
216
 
        eq(ie.name, 'bar')
217
 
        eq(inv[ie.parent_id].kind, 'directory')
218
 
 
219
 
    def test_unpack_basis_inventory_5(self):
220
 
        """Unpack canned new-style inventory"""
221
 
        inp = StringIO(_basis_inv_v5)
222
 
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
223
 
        eq = self.assertEqual
224
 
        eq(len(inv), 4)
225
 
        eq(inv.revision_id, 'mbp@sourcefrog.net-20050905063503-43948f59fa127d92')
226
 
        ie = inv['bar-20050824000535-6bc48cfad47ed134']
227
 
        eq(ie.kind, 'file')
228
 
        eq(ie.revision, 'mbp@foo-00')
 
113
        inv = serializer_v5.read_inventory(inp)
 
114
        eq = self.assertEqual
 
115
        eq(len(inv), 4)
 
116
        ie = inv['bar-20050824000535-6bc48cfad47ed134']
 
117
        eq(ie.kind, 'file')
 
118
        eq(ie.text_version, 'mbp@foo-123123')
 
119
        eq(ie.name_version, 'mbp@foo-00')
229
120
        eq(ie.name, 'bar')
230
121
        eq(inv[ie.parent_id].kind, 'directory')
231
122
 
232
123
    def test_repack_inventory_5(self):
233
124
        inp = StringIO(_committed_inv_v5)
234
 
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
235
 
        outp = StringIO()
236
 
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
237
 
        self.assertEqualDiff(_expected_inv_v5, outp.getvalue())
238
 
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
239
 
        self.assertEqual(inv, inv2)
240
 
    
241
 
    def assertRoundTrips(self, xml_string):
242
 
        inp = StringIO(xml_string)
243
 
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
244
 
        outp = StringIO()
245
 
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
246
 
        self.assertEqualDiff(xml_string, outp.getvalue())
247
 
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
248
 
        self.assertEqual(inv, inv2)
249
 
 
250
 
    def tests_serialize_inventory_v5_with_root(self):
251
 
        self.assertRoundTrips(_expected_inv_v5_root)
252
 
 
253
 
    def check_repack_revision(self, txt):
254
 
        """Check that repacking a revision yields the same information"""
255
 
        inp = StringIO(txt)
256
 
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
257
 
        outp = StringIO()
258
 
        bzrlib.xml5.serializer_v5.write_revision(rev, outp)
259
 
        outfile_contents = outp.getvalue()
260
 
        rev2 = bzrlib.xml5.serializer_v5.read_revision(StringIO(outfile_contents))
 
125
        inv = serializer_v5.read_inventory(inp)
 
126
        outp = StringIO()
 
127
        serializer_v5.write_inventory(inv, outp)
 
128
        inv2 = serializer_v5.read_inventory(StringIO(outp.getvalue()))
 
129
        self.assertEqual(inv, inv2)
 
130
 
 
131
    def test_repack_revision_5(self):
 
132
        inp = StringIO(_revision_v5)
 
133
        rev = serializer_v5.read_revision(inp)
 
134
        outp = StringIO()
 
135
        serializer_v5.write_revision(rev, outp)
 
136
        rev2 = serializer_v5.read_revision(StringIO(outp.getvalue()))
261
137
        self.assertEqual(rev, rev2)
262
138
 
263
 
    def test_repack_revision_5(self):
264
 
        """Round-trip revision to XML v5"""
265
 
        self.check_repack_revision(_revision_v5)
266
 
 
267
 
    def test_repack_revision_5_utc(self):
268
 
        self.check_repack_revision(_revision_v5_utc)
269
 
 
270
 
    def test_pack_revision_5(self):
271
 
        """Pack revision to XML v5"""
272
 
        # fixed 20051025, revisions should have final newline
273
 
        rev = bzrlib.xml5.serializer_v5.read_revision_from_string(_revision_v5)
274
 
        outp = StringIO()
275
 
        bzrlib.xml5.serializer_v5.write_revision(rev, outp)
276
 
        outfile_contents = outp.getvalue()
277
 
        self.assertEqual(outfile_contents[-1], '\n')
278
 
        self.assertEqualDiff(outfile_contents, bzrlib.xml5.serializer_v5.write_revision_to_string(rev))
279
 
        self.assertEqualDiff(outfile_contents, _expected_rev_v5)
280
 
 
281
 
    def test_empty_property_value(self):
282
 
        """Create an empty property value check that it serializes correctly"""
283
 
        s_v5 = bzrlib.xml5.serializer_v5
284
 
        rev = s_v5.read_revision_from_string(_revision_v5)
285
 
        outp = StringIO()
286
 
        props = {'empty':'', 'one':'one'}
287
 
        rev.properties = props
288
 
        txt = s_v5.write_revision_to_string(rev)
289
 
        new_rev = s_v5.read_revision_from_string(txt)
290
 
        self.assertEqual(props, new_rev.properties)
291
 
 
292
 
    def test_revision_ids_are_utf8(self):
293
 
        """Parsed revision_ids should all be utf-8 strings, not unicode."""
294
 
        s_v5 = bzrlib.xml5.serializer_v5
295
 
        rev = s_v5.read_revision_from_string(_revision_utf8_v5)
296
 
        self.assertEqual('erik@b\xc3\xa5gfors-02', rev.revision_id)
297
 
        self.assertIsInstance(rev.revision_id, str)
298
 
        self.assertEqual(['erik@b\xc3\xa5gfors-01'], rev.parent_ids)
299
 
        for parent_id in rev.parent_ids:
300
 
            self.assertIsInstance(parent_id, str)
301
 
        self.assertEqual(u'Include \xb5nicode characters\n', rev.message)
302
 
        self.assertIsInstance(rev.message, unicode)
303
 
 
304
 
        # ie.revision should either be None or a utf-8 revision id
305
 
        inv = s_v5.read_inventory_from_string(_inventory_utf8_v5)
306
 
        rev_id_1 = u'erik@b\xe5gfors-01'.encode('utf8')
307
 
        rev_id_2 = u'erik@b\xe5gfors-02'.encode('utf8')
308
 
        fid_root = u'TRE\xe9_ROOT'.encode('utf8')
309
 
        fid_bar1 = u'b\xe5r-01'.encode('utf8')
310
 
        fid_sub = u's\xb5bdir-01'.encode('utf8')
311
 
        fid_bar2 = u'b\xe5r-02'.encode('utf8')
312
 
        expected = [(u'', fid_root, None, None),
313
 
                    (u'b\xe5r', fid_bar1, fid_root, rev_id_1),
314
 
                    (u's\xb5bdir', fid_sub, fid_root, rev_id_1),
315
 
                    (u's\xb5bdir/b\xe5r', fid_bar2, fid_sub, rev_id_2),
316
 
                   ]
317
 
        self.assertEqual(rev_id_2, inv.revision_id)
318
 
        self.assertIsInstance(inv.revision_id, str)
319
 
 
320
 
        actual = list(inv.iter_entries_by_dir())
321
 
        for ((exp_path, exp_file_id, exp_parent_id, exp_rev_id),
322
 
             (act_path, act_ie)) in zip(expected, actual):
323
 
            self.assertEqual(exp_path, act_path)
324
 
            self.assertIsInstance(act_path, unicode)
325
 
            self.assertEqual(exp_file_id, act_ie.file_id)
326
 
            self.assertIsInstance(act_ie.file_id, str)
327
 
            self.assertEqual(exp_parent_id, act_ie.parent_id)
328
 
            if exp_parent_id is not None:
329
 
                self.assertIsInstance(act_ie.parent_id, str)
330
 
            self.assertEqual(exp_rev_id, act_ie.revision)
331
 
            if exp_rev_id is not None:
332
 
                self.assertIsInstance(act_ie.revision, str)
333
 
 
334
 
        self.assertEqual(len(expected), len(actual))
335
 
 
336
 
 
337
 
class TestEncodeAndEscape(TestCase):
338
 
    """Whitebox testing of the _encode_and_escape function."""
339
 
 
340
 
    def setUp(self):
341
 
        # Keep the cache clear before and after the test
342
 
        bzrlib.xml5._ensure_utf8_re()
343
 
        bzrlib.xml5._clear_cache()
344
 
        self.addCleanup(bzrlib.xml5._clear_cache)
345
 
 
346
 
    def test_simple_ascii(self):
347
 
        # _encode_and_escape always appends a final ", because these parameters
348
 
        # are being used in xml attributes, and by returning it now, we have to
349
 
        # do fewer string operations later.
350
 
        val = bzrlib.xml5._encode_and_escape('foo bar')
351
 
        self.assertEqual('foo bar"', val)
352
 
        # The second time should be cached
353
 
        val2 = bzrlib.xml5._encode_and_escape('foo bar')
354
 
        self.assertIs(val2, val)
355
 
 
356
 
    def test_ascii_with_xml(self):
357
 
        self.assertEqual('&amp;&apos;&quot;&lt;&gt;"',
358
 
                         bzrlib.xml5._encode_and_escape('&\'"<>'))
359
 
 
360
 
    def test_utf8_with_xml(self):
361
 
        # u'\xb5\xe5&\u062c'
362
 
        utf8_str = '\xc2\xb5\xc3\xa5&\xd8\xac'
363
 
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
364
 
                         bzrlib.xml5._encode_and_escape(utf8_str))
365
 
 
366
 
    def test_unicode(self):
367
 
        uni_str = u'\xb5\xe5&\u062c'
368
 
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
369
 
                         bzrlib.xml5._encode_and_escape(uni_str))