/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_xml.py

  • Committer: Robert Collins
  • Date: 2007-04-18 08:39:02 UTC
  • mto: (2425.1.2 integration)
  • mto: This revision was merged to the branch mainline in revision 2427.
  • Revision ID: robertc@robertcollins.net-20070418083902-4o66h9fk7zeisvwa
Command objects can now declare related help topics by having _see_also
set to a list of related topic. Updated the HACKING guide entry on
documentation to be more clear about how the help for commands is
generated and to reference this new feature. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005 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 import (
 
20
    errors, 
 
21
    inventory, 
 
22
    xml7,
 
23
    )
19
24
from bzrlib.tests import TestCase
20
25
from bzrlib.inventory import Inventory, InventoryEntry
21
26
from bzrlib.xml4 import serializer_v4
22
 
from bzrlib.xml5 import serializer_v5
 
27
import bzrlib.xml5
23
28
 
24
29
_working_inventory_v4 = """<inventory file_id="TREE_ROOT">
25
30
<entry file_id="bar-20050901064931-73b4b1138abc9cd2" kind="file" name="bar" parent_id="TREE_ROOT" />
32
37
    inventory_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
33
38
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
34
39
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
35
 
    timestamp="1125907235.211783886"
 
40
    timestamp="1125907235.212"
36
41
    timezone="36000">
37
42
<message>- start splitting code for xml (de)serialization away from objects
38
43
  preparatory to supporting multiple formats by a single library
46
51
_revision_v5 = """<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
47
52
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
48
53
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
49
 
    timestamp="1125907235.211783886"
 
54
    timestamp="1125907235.212"
50
55
    timezone="36000">
51
56
<message>- start splitting code for xml (de)serialization away from objects
52
57
  preparatory to supporting multiple formats by a single library
57
62
</revision>
58
63
"""
59
64
 
 
65
_revision_v5_utc = """\
 
66
<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
 
67
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
 
68
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
 
69
    timestamp="1125907235.212"
 
70
    timezone="0">
 
71
<message>- start splitting code for xml (de)serialization away from objects
 
72
  preparatory to supporting multiple formats by a single library
 
73
</message>
 
74
<parents>
 
75
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"/>
 
76
</parents>
 
77
</revision>
 
78
"""
 
79
 
60
80
_committed_inv_v5 = """<inventory>
61
81
<file file_id="bar-20050901064931-73b4b1138abc9cd2" 
62
82
      name="bar" parent_id="TREE_ROOT" 
65
85
           file_id="foo-20050801201819-4139aa4a272f4250"
66
86
           parent_id="TREE_ROOT" 
67
87
           revision="mbp@foo-00"/>
68
 
<file file_id="bar-20050824000535-6bc48cfad47ed134" 
 
88
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" 
69
89
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 
70
90
      revision="mbp@foo-00"/>
71
91
</inventory>
85
105
</inventory>
86
106
"""
87
107
 
 
108
 
 
109
# DO NOT REFLOW THIS. Its the exact revision we want.
 
110
_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">
 
111
<message>- start splitting code for xml (de)serialization away from objects
 
112
  preparatory to supporting multiple formats by a single library
 
113
</message>
 
114
<parents>
 
115
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" />
 
116
</parents>
 
117
</revision>
 
118
"""
 
119
 
 
120
 
 
121
# DO NOT REFLOW THIS. Its the exact inventory we want.
 
122
_expected_inv_v5 = """<inventory format="5">
 
123
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" revision="mbp@foo-123123" />
 
124
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" revision="mbp@foo-00" />
 
125
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
 
126
</inventory>
 
127
"""
 
128
 
 
129
 
 
130
_expected_inv_v5_root = """<inventory file_id="f&lt;" format="5" revision_id="mother!">
 
131
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" parent_id="f&lt;" revision="mbp@foo-123123" />
 
132
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" parent_id="f&lt;" revision="mbp@foo-00" />
 
133
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
 
134
</inventory>
 
135
"""
 
136
 
 
137
_expected_inv_v7 = """<inventory format="7" revision_id="rev_outer">
 
138
<directory file_id="tree-root-321" name="" revision="rev_outer" />
 
139
<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" />
 
140
<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" />
 
141
<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" />
 
142
<tree-reference file_id="nested-id" name="nested" parent_id="tree-root-321" revision="rev_outer" reference_revision="rev_inner" />
 
143
</inventory>
 
144
"""
 
145
 
 
146
_revision_utf8_v5 = """<revision committer="Erik B&#229;gfors &lt;erik@foo.net&gt;"
 
147
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
 
148
    revision_id="erik@b&#229;gfors-02"
 
149
    timestamp="1125907235.212"
 
150
    timezone="36000">
 
151
<message>Include &#181;nicode characters
 
152
</message>
 
153
<parents>
 
154
<revision_ref revision_id="erik@b&#229;gfors-01"/>
 
155
</parents>
 
156
</revision>
 
157
"""
 
158
 
 
159
_inventory_utf8_v5 = """<inventory file_id="TRE&#233;_ROOT" format="5"
 
160
                                   revision_id="erik@b&#229;gfors-02">
 
161
<file file_id="b&#229;r-01"
 
162
      name="b&#229;r" parent_id="TRE&#233;_ROOT"
 
163
      revision="erik@b&#229;gfors-01"/>
 
164
<directory name="s&#181;bdir"
 
165
           file_id="s&#181;bdir-01"
 
166
           parent_id="TRE&#233;_ROOT"
 
167
           revision="erik@b&#229;gfors-01"/>
 
168
<file executable="yes" file_id="b&#229;r-02"
 
169
      name="b&#229;r" parent_id="s&#181;bdir-01"
 
170
      revision="erik@b&#229;gfors-02"/>
 
171
</inventory>
 
172
"""
 
173
 
 
174
 
88
175
class TestSerializer(TestCase):
89
176
    """Test XML serialization"""
90
177
    def test_canned_inventory(self):
110
197
    def test_unpack_revision_5(self):
111
198
        """Test unpacking a canned revision v5"""
112
199
        inp = StringIO(_revision_v5)
113
 
        rev = serializer_v5.read_revision(inp)
 
200
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
114
201
        eq = self.assertEqual
115
202
        eq(rev.committer,
116
203
           "Martin Pool <mbp@sourcefrog.net>")
119
206
        eq(rev.parent_ids[0],
120
207
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
121
208
 
 
209
    def test_unpack_revision_5_utc(self):
 
210
        inp = StringIO(_revision_v5_utc)
 
211
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
 
212
        eq = self.assertEqual
 
213
        eq(rev.committer,
 
214
           "Martin Pool <mbp@sourcefrog.net>")
 
215
        eq(len(rev.parent_ids), 1)
 
216
        eq(rev.timezone, 0)
 
217
        eq(rev.parent_ids[0],
 
218
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
 
219
 
122
220
    def test_unpack_inventory_5(self):
123
221
        """Unpack canned new-style inventory"""
124
222
        inp = StringIO(_committed_inv_v5)
125
 
        inv = serializer_v5.read_inventory(inp)
 
223
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
126
224
        eq = self.assertEqual
127
225
        eq(len(inv), 4)
128
226
        ie = inv['bar-20050824000535-6bc48cfad47ed134']
134
232
    def test_unpack_basis_inventory_5(self):
135
233
        """Unpack canned new-style inventory"""
136
234
        inp = StringIO(_basis_inv_v5)
137
 
        inv = serializer_v5.read_inventory(inp)
 
235
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
138
236
        eq = self.assertEqual
139
237
        eq(len(inv), 4)
140
238
        eq(inv.revision_id, 'mbp@sourcefrog.net-20050905063503-43948f59fa127d92')
146
244
 
147
245
    def test_repack_inventory_5(self):
148
246
        inp = StringIO(_committed_inv_v5)
149
 
        inv = serializer_v5.read_inventory(inp)
150
 
        outp = StringIO()
151
 
        serializer_v5.write_inventory(inv, outp)
152
 
        inv2 = serializer_v5.read_inventory(StringIO(outp.getvalue()))
153
 
        self.assertEqual(inv, inv2)
 
247
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
 
248
        outp = StringIO()
 
249
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
 
250
        self.assertEqualDiff(_expected_inv_v5, outp.getvalue())
 
251
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
 
252
        self.assertEqual(inv, inv2)
 
253
    
 
254
    def assertRoundTrips(self, xml_string):
 
255
        inp = StringIO(xml_string)
 
256
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
 
257
        outp = StringIO()
 
258
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
 
259
        self.assertEqualDiff(xml_string, outp.getvalue())
 
260
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
 
261
        self.assertEqual(inv, inv2)
 
262
 
 
263
    def tests_serialize_inventory_v5_with_root(self):
 
264
        self.assertRoundTrips(_expected_inv_v5_root)
 
265
 
 
266
    def check_repack_revision(self, txt):
 
267
        """Check that repacking a revision yields the same information"""
 
268
        inp = StringIO(txt)
 
269
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
 
270
        outp = StringIO()
 
271
        bzrlib.xml5.serializer_v5.write_revision(rev, outp)
 
272
        outfile_contents = outp.getvalue()
 
273
        rev2 = bzrlib.xml5.serializer_v5.read_revision(StringIO(outfile_contents))
 
274
        self.assertEqual(rev, rev2)
154
275
 
155
276
    def test_repack_revision_5(self):
156
277
        """Round-trip revision to XML v5"""
157
 
        inp = StringIO(_revision_v5)
158
 
        rev = serializer_v5.read_revision(inp)
159
 
        outp = StringIO()
160
 
        serializer_v5.write_revision(rev, outp)
161
 
        outfile_contents = outp.getvalue()
162
 
        rev2 = serializer_v5.read_revision(StringIO(outfile_contents))
163
 
        self.assertEqual(rev, rev2)
 
278
        self.check_repack_revision(_revision_v5)
 
279
 
 
280
    def test_repack_revision_5_utc(self):
 
281
        self.check_repack_revision(_revision_v5_utc)
164
282
 
165
283
    def test_pack_revision_5(self):
166
284
        """Pack revision to XML v5"""
167
285
        # fixed 20051025, revisions should have final newline
168
 
        rev = serializer_v5.read_revision_from_string(_revision_v5)
 
286
        rev = bzrlib.xml5.serializer_v5.read_revision_from_string(_revision_v5)
169
287
        outp = StringIO()
170
 
        serializer_v5.write_revision(rev, outp)
 
288
        bzrlib.xml5.serializer_v5.write_revision(rev, outp)
171
289
        outfile_contents = outp.getvalue()
172
290
        self.assertEqual(outfile_contents[-1], '\n')
173
 
        self.assertEqualDiff(outfile_contents, serializer_v5.write_revision_to_string(rev))
 
291
        self.assertEqualDiff(outfile_contents, bzrlib.xml5.serializer_v5.write_revision_to_string(rev))
 
292
        self.assertEqualDiff(outfile_contents, _expected_rev_v5)
 
293
 
 
294
    def test_empty_property_value(self):
 
295
        """Create an empty property value check that it serializes correctly"""
 
296
        s_v5 = bzrlib.xml5.serializer_v5
 
297
        rev = s_v5.read_revision_from_string(_revision_v5)
 
298
        outp = StringIO()
 
299
        props = {'empty':'', 'one':'one'}
 
300
        rev.properties = props
 
301
        txt = s_v5.write_revision_to_string(rev)
 
302
        new_rev = s_v5.read_revision_from_string(txt)
 
303
        self.assertEqual(props, new_rev.properties)
 
304
 
 
305
    def test_roundtrip_inventory_v7(self):
 
306
        inv = Inventory('tree-root-321', revision_id='rev_outer')
 
307
        inv.add(inventory.TreeReference('nested-id', 'nested', 'tree-root-321',
 
308
                                        'rev_outer', 'rev_inner'))
 
309
        inv.add(inventory.InventoryFile('file-id', 'file', 'tree-root-321'))
 
310
        inv.add(inventory.InventoryDirectory('dir-id', 'dir', 
 
311
                                             'tree-root-321'))
 
312
        inv.add(inventory.InventoryLink('link-id', 'link', 'tree-root-321'))
 
313
        inv['tree-root-321'].revision = 'rev_outer'
 
314
        inv['dir-id'].revision = 'rev_outer'
 
315
        inv['file-id'].revision = 'rev_outer'
 
316
        inv['link-id'].revision = 'rev_outer'
 
317
        txt = xml7.serializer_v7.write_inventory_to_string(inv)
 
318
        self.assertEqualDiff(_expected_inv_v7, txt)
 
319
        inv2 = xml7.serializer_v7.read_inventory_from_string(txt)
 
320
        self.assertEqual(5, len(inv2))
 
321
        for path, ie in inv.iter_entries():
 
322
            self.assertEqual(ie, inv2[ie.file_id])
 
323
 
 
324
    def test_wrong_format_v7(self):
 
325
        """Can't accidentally open a file with wrong serializer"""
 
326
        s_v6 = bzrlib.xml6.serializer_v6
 
327
        s_v7 = xml7.serializer_v7
 
328
        self.assertRaises(errors.UnexpectedInventoryFormat, 
 
329
                          s_v7.read_inventory_from_string, _expected_inv_v5)
 
330
        self.assertRaises(errors.UnexpectedInventoryFormat, 
 
331
                          s_v6.read_inventory_from_string, _expected_inv_v7)
 
332
 
 
333
    def test_tree_reference(self):
 
334
        s_v5 = bzrlib.xml5.serializer_v5
 
335
        s_v6 = bzrlib.xml6.serializer_v6
 
336
        s_v7 = xml7.serializer_v7
 
337
        inv = Inventory('tree-root-321')
 
338
        inv.add(inventory.TreeReference('nested-id', 'nested', 'tree-root-321',
 
339
                                        'rev-outer', 'rev-inner'))
 
340
        self.assertRaises(errors.UnsupportedInventoryKind, 
 
341
                          s_v5.write_inventory_to_string, inv)
 
342
        self.assertRaises(errors.UnsupportedInventoryKind, 
 
343
                          s_v6.write_inventory_to_string, inv)
 
344
        txt = s_v7.write_inventory_to_string(inv)
 
345
        inv2 = s_v7.read_inventory_from_string(txt)
 
346
        self.assertEqual('tree-root-321', inv2['nested-id'].parent_id)
 
347
        self.assertEqual('rev-outer', inv2['nested-id'].revision)
 
348
        self.assertEqual('rev-inner', inv2['nested-id'].reference_revision)
 
349
        self.assertRaises(errors.UnsupportedInventoryKind, 
 
350
                          s_v6.read_inventory_from_string,
 
351
                          txt.replace('format="7"', 'format="6"'))
 
352
        self.assertRaises(errors.UnsupportedInventoryKind, 
 
353
                          s_v5.read_inventory_from_string,
 
354
                          txt.replace('format="7"', 'format="5"'))
 
355
 
 
356
    def test_revision_ids_are_utf8(self):
 
357
        """Parsed revision_ids should all be utf-8 strings, not unicode."""
 
358
        s_v5 = bzrlib.xml5.serializer_v5
 
359
        rev = s_v5.read_revision_from_string(_revision_utf8_v5)
 
360
        self.assertEqual('erik@b\xc3\xa5gfors-02', rev.revision_id)
 
361
        self.assertIsInstance(rev.revision_id, str)
 
362
        self.assertEqual(['erik@b\xc3\xa5gfors-01'], rev.parent_ids)
 
363
        for parent_id in rev.parent_ids:
 
364
            self.assertIsInstance(parent_id, str)
 
365
        self.assertEqual(u'Include \xb5nicode characters\n', rev.message)
 
366
        self.assertIsInstance(rev.message, unicode)
 
367
 
 
368
        # ie.revision should either be None or a utf-8 revision id
 
369
        inv = s_v5.read_inventory_from_string(_inventory_utf8_v5)
 
370
        rev_id_1 = u'erik@b\xe5gfors-01'.encode('utf8')
 
371
        rev_id_2 = u'erik@b\xe5gfors-02'.encode('utf8')
 
372
        fid_root = u'TRE\xe9_ROOT'.encode('utf8')
 
373
        fid_bar1 = u'b\xe5r-01'.encode('utf8')
 
374
        fid_sub = u's\xb5bdir-01'.encode('utf8')
 
375
        fid_bar2 = u'b\xe5r-02'.encode('utf8')
 
376
        expected = [(u'', fid_root, None, None),
 
377
                    (u'b\xe5r', fid_bar1, fid_root, rev_id_1),
 
378
                    (u's\xb5bdir', fid_sub, fid_root, rev_id_1),
 
379
                    (u's\xb5bdir/b\xe5r', fid_bar2, fid_sub, rev_id_2),
 
380
                   ]
 
381
        self.assertEqual(rev_id_2, inv.revision_id)
 
382
        self.assertIsInstance(inv.revision_id, str)
 
383
 
 
384
        actual = list(inv.iter_entries_by_dir())
 
385
        for ((exp_path, exp_file_id, exp_parent_id, exp_rev_id),
 
386
             (act_path, act_ie)) in zip(expected, actual):
 
387
            self.assertEqual(exp_path, act_path)
 
388
            self.assertIsInstance(act_path, unicode)
 
389
            self.assertEqual(exp_file_id, act_ie.file_id)
 
390
            self.assertIsInstance(act_ie.file_id, str)
 
391
            self.assertEqual(exp_parent_id, act_ie.parent_id)
 
392
            if exp_parent_id is not None:
 
393
                self.assertIsInstance(act_ie.parent_id, str)
 
394
            self.assertEqual(exp_rev_id, act_ie.revision)
 
395
            if exp_rev_id is not None:
 
396
                self.assertIsInstance(act_ie.revision, str)
 
397
 
 
398
        self.assertEqual(len(expected), len(actual))
 
399
 
 
400
 
 
401
class TestEncodeAndEscape(TestCase):
 
402
    """Whitebox testing of the _encode_and_escape function."""
 
403
 
 
404
    def setUp(self):
 
405
        # Keep the cache clear before and after the test
 
406
        bzrlib.xml5._ensure_utf8_re()
 
407
        bzrlib.xml5._clear_cache()
 
408
        self.addCleanup(bzrlib.xml5._clear_cache)
 
409
 
 
410
    def test_simple_ascii(self):
 
411
        # _encode_and_escape always appends a final ", because these parameters
 
412
        # are being used in xml attributes, and by returning it now, we have to
 
413
        # do fewer string operations later.
 
414
        val = bzrlib.xml5._encode_and_escape('foo bar')
 
415
        self.assertEqual('foo bar"', val)
 
416
        # The second time should be cached
 
417
        val2 = bzrlib.xml5._encode_and_escape('foo bar')
 
418
        self.assertIs(val2, val)
 
419
 
 
420
    def test_ascii_with_xml(self):
 
421
        self.assertEqual('&amp;&apos;&quot;&lt;&gt;"',
 
422
                         bzrlib.xml5._encode_and_escape('&\'"<>'))
 
423
 
 
424
    def test_utf8_with_xml(self):
 
425
        # u'\xb5\xe5&\u062c'
 
426
        utf8_str = '\xc2\xb5\xc3\xa5&\xd8\xac'
 
427
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
 
428
                         bzrlib.xml5._encode_and_escape(utf8_str))
 
429
 
 
430
    def test_unicode(self):
 
431
        uni_str = u'\xb5\xe5&\u062c'
 
432
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
 
433
                         bzrlib.xml5._encode_and_escape(uni_str))