/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-07-15 15:40:37 UTC
  • mto: (2592.3.33 repository)
  • mto: This revision was merged to the branch mainline in revision 2624.
  • Revision ID: robertc@robertcollins.net-20070715154037-3ar8g89decddc9su
Make GraphIndex accept nodes as key, value, references, so that the method
signature is closer to what a simple key->value index delivers. Also
change the behaviour when the reference list count is zero to accept
key, value as nodes, and emit key, value to make it identical in that case
to a simple key->value index. This may not be a good idea, but for now it
seems ok.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005 Canonical Ltd
2
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
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
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
from cStringIO import StringIO
18
18
 
19
19
from bzrlib import (
20
 
    errors,
21
 
    fifo_cache,
22
 
    inventory,
23
 
    xml6,
 
20
    errors, 
 
21
    inventory, 
24
22
    xml7,
25
 
    xml8,
26
 
    serializer,
27
23
    )
28
24
from bzrlib.tests import TestCase
29
25
from bzrlib.inventory import Inventory, InventoryEntry
82
78
"""
83
79
 
84
80
_committed_inv_v5 = """<inventory>
85
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2"
86
 
      name="bar" parent_id="TREE_ROOT"
87
 
      revision="mbp@foo-123123"
88
 
      text_sha1="A" text_size="1"/>
 
81
<file file_id="bar-20050901064931-73b4b1138abc9cd2" 
 
82
      name="bar" parent_id="TREE_ROOT" 
 
83
      revision="mbp@foo-123123"/>
89
84
<directory name="subdir"
90
85
           file_id="foo-20050801201819-4139aa4a272f4250"
91
 
           parent_id="TREE_ROOT"
 
86
           parent_id="TREE_ROOT" 
92
87
           revision="mbp@foo-00"/>
93
 
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134"
94
 
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250"
95
 
      revision="mbp@foo-00"
96
 
      text_sha1="B" text_size="0"/>
 
88
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" 
 
89
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 
 
90
      revision="mbp@foo-00"/>
97
91
</inventory>
98
92
"""
99
93
 
100
94
_basis_inv_v5 = """<inventory revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92">
101
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2"
102
 
      name="bar" parent_id="TREE_ROOT"
 
95
<file file_id="bar-20050901064931-73b4b1138abc9cd2" 
 
96
      name="bar" parent_id="TREE_ROOT" 
103
97
      revision="mbp@foo-123123"/>
104
98
<directory name="subdir"
105
99
           file_id="foo-20050801201819-4139aa4a272f4250"
106
 
           parent_id="TREE_ROOT"
 
100
           parent_id="TREE_ROOT" 
107
101
           revision="mbp@foo-00"/>
108
 
<file file_id="bar-20050824000535-6bc48cfad47ed134"
109
 
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250"
 
102
<file file_id="bar-20050824000535-6bc48cfad47ed134" 
 
103
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 
110
104
      revision="mbp@foo-00"/>
111
105
</inventory>
112
106
"""
126
120
 
127
121
# DO NOT REFLOW THIS. Its the exact inventory we want.
128
122
_expected_inv_v5 = """<inventory format="5">
129
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" revision="mbp@foo-123123" text_sha1="A" text_size="1" />
 
123
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" revision="mbp@foo-123123" />
130
124
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" revision="mbp@foo-00" />
131
 
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" text_sha1="B" text_size="0" />
 
125
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
132
126
</inventory>
133
127
"""
134
128
 
135
129
 
136
130
_expected_inv_v5_root = """<inventory file_id="f&lt;" format="5" revision_id="mother!">
137
 
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" parent_id="f&lt;" revision="mbp@foo-123123" text_sha1="A" text_size="1" />
 
131
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" parent_id="f&lt;" revision="mbp@foo-123123" />
138
132
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" parent_id="f&lt;" revision="mbp@foo-00" />
139
 
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" text_sha1="B" text_size="0" />
140
 
<symlink file_id="link-1" name="link" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" symlink_target="a" />
141
 
</inventory>
142
 
"""
143
 
 
144
 
_expected_inv_v6 = """<inventory format="6" revision_id="rev_outer">
145
 
<directory file_id="tree-root-321" name="" revision="rev_outer" />
146
 
<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" />
147
 
<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" text_sha1="A" text_size="1" />
148
 
<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" symlink_target="a" />
 
133
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
149
134
</inventory>
150
135
"""
151
136
 
152
137
_expected_inv_v7 = """<inventory format="7" revision_id="rev_outer">
153
138
<directory file_id="tree-root-321" name="" revision="rev_outer" />
154
139
<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" />
155
 
<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" text_sha1="A" text_size="1" />
156
 
<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" symlink_target="a" />
 
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" />
157
142
<tree-reference file_id="nested-id" name="nested" parent_id="tree-root-321" revision="rev_outer" reference_revision="rev_inner" />
158
143
</inventory>
159
144
"""
160
145
 
161
 
_expected_rev_v8 = """<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;" format="8" inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" timestamp="1125907235.212" timezone="36000">
162
 
<message>- start splitting code for xml (de)serialization away from objects
163
 
  preparatory to supporting multiple formats by a single library
164
 
</message>
165
 
<parents>
166
 
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" />
167
 
</parents>
168
 
</revision>
169
 
"""
170
 
 
171
 
_expected_inv_v8 = """<inventory format="8" revision_id="rev_outer">
172
 
<directory file_id="tree-root-321" name="" revision="rev_outer" />
173
 
<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" />
174
 
<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" text_sha1="A" text_size="1" />
175
 
<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" symlink_target="a" />
176
 
</inventory>
177
 
"""
178
 
 
179
146
_revision_utf8_v5 = """<revision committer="Erik B&#229;gfors &lt;erik@foo.net&gt;"
180
147
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
181
148
    revision_id="erik@b&#229;gfors-02"
204
171
</inventory>
205
172
"""
206
173
 
207
 
# Before revision_id was always stored as an attribute
208
 
_inventory_v5a = """<inventory format="5">
209
 
</inventory>
210
 
"""
211
 
 
212
 
# Before revision_id was always stored as an attribute
213
 
_inventory_v5b = """<inventory format="5" revision_id="a-rev-id">
214
 
</inventory>
215
 
"""
216
 
 
217
174
 
218
175
class TestSerializer(TestCase):
219
176
    """Test XML serialization"""
220
 
 
221
177
    def test_canned_inventory(self):
222
178
        """Test unpacked a canned inventory v4 file."""
223
179
        inp = StringIO(_working_inventory_v4)
286
242
        eq(ie.name, 'bar')
287
243
        eq(inv[ie.parent_id].kind, 'directory')
288
244
 
289
 
    def test_unpack_inventory_5a(self):
290
 
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(
291
 
                _inventory_v5a, revision_id='test-rev-id')
292
 
        self.assertEqual('test-rev-id', inv.root.revision)
293
 
 
294
 
    def test_unpack_inventory_5a_cache_and_copy(self):
295
 
        # Passing an entry_cache should get populated with the objects
296
 
        # But the returned objects should be copies if return_from_cache is
297
 
        # False
298
 
        entry_cache = fifo_cache.FIFOCache()
299
 
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(
300
 
            _inventory_v5a, revision_id='test-rev-id',
301
 
            entry_cache=entry_cache, return_from_cache=False)
302
 
        for entry in inv.iter_just_entries():
303
 
            key = (entry.file_id, entry.revision)
304
 
            if entry.file_id is inv.root.file_id:
305
 
                # The root id is inferred for xml v5
306
 
                self.assertFalse(key in entry_cache)
307
 
            else:
308
 
                self.assertIsNot(entry, entry_cache[key])
309
 
 
310
 
    def test_unpack_inventory_5a_cache_no_copy(self):
311
 
        # Passing an entry_cache should get populated with the objects
312
 
        # The returned objects should be exact if return_from_cache is
313
 
        # True
314
 
        entry_cache = fifo_cache.FIFOCache()
315
 
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(
316
 
            _inventory_v5a, revision_id='test-rev-id',
317
 
            entry_cache=entry_cache, return_from_cache=True)
318
 
        for entry in inv.iter_just_entries():
319
 
            key = (entry.file_id, entry.revision)
320
 
            if entry.file_id is inv.root.file_id:
321
 
                # The root id is inferred for xml v5
322
 
                self.assertFalse(key in entry_cache)
323
 
            else:
324
 
                self.assertIs(entry, entry_cache[key])
325
 
 
326
 
    def test_unpack_inventory_5b(self):
327
 
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(
328
 
                _inventory_v5b, revision_id='test-rev-id')
329
 
        self.assertEqual('a-rev-id', inv.root.revision)
330
 
 
331
245
    def test_repack_inventory_5(self):
332
246
        inp = StringIO(_committed_inv_v5)
333
247
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
336
250
        self.assertEqualDiff(_expected_inv_v5, outp.getvalue())
337
251
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
338
252
        self.assertEqual(inv, inv2)
339
 
 
 
253
    
340
254
    def assertRoundTrips(self, xml_string):
341
255
        inp = StringIO(xml_string)
342
256
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
343
257
        outp = StringIO()
344
258
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
345
259
        self.assertEqualDiff(xml_string, outp.getvalue())
346
 
        lines = bzrlib.xml5.serializer_v5.write_inventory_to_lines(inv)
347
 
        outp.seek(0)
348
 
        self.assertEqual(outp.readlines(), lines)
349
260
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
350
261
        self.assertEqual(inv, inv2)
351
262
 
391
302
        new_rev = s_v5.read_revision_from_string(txt)
392
303
        self.assertEqual(props, new_rev.properties)
393
304
 
394
 
    def get_sample_inventory(self):
 
305
    def test_roundtrip_inventory_v7(self):
395
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'))
396
309
        inv.add(inventory.InventoryFile('file-id', 'file', 'tree-root-321'))
397
 
        inv.add(inventory.InventoryDirectory('dir-id', 'dir',
 
310
        inv.add(inventory.InventoryDirectory('dir-id', 'dir', 
398
311
                                             'tree-root-321'))
399
312
        inv.add(inventory.InventoryLink('link-id', 'link', 'tree-root-321'))
400
313
        inv['tree-root-321'].revision = 'rev_outer'
401
314
        inv['dir-id'].revision = 'rev_outer'
402
315
        inv['file-id'].revision = 'rev_outer'
403
 
        inv['file-id'].text_sha1 = 'A'
404
 
        inv['file-id'].text_size = 1
405
316
        inv['link-id'].revision = 'rev_outer'
406
 
        inv['link-id'].symlink_target = 'a'
407
 
        return inv
408
 
 
409
 
    def test_roundtrip_inventory_v7(self):
410
 
        inv = self.get_sample_inventory()
411
 
        inv.add(inventory.TreeReference('nested-id', 'nested', 'tree-root-321',
412
 
                                        'rev_outer', 'rev_inner'))
413
317
        txt = xml7.serializer_v7.write_inventory_to_string(inv)
414
 
        lines = xml7.serializer_v7.write_inventory_to_lines(inv)
415
 
        self.assertEqual(bzrlib.osutils.split_lines(txt), lines)
416
318
        self.assertEqualDiff(_expected_inv_v7, txt)
417
319
        inv2 = xml7.serializer_v7.read_inventory_from_string(txt)
418
320
        self.assertEqual(5, len(inv2))
419
321
        for path, ie in inv.iter_entries():
420
322
            self.assertEqual(ie, inv2[ie.file_id])
421
323
 
422
 
    def test_roundtrip_inventory_v6(self):
423
 
        inv = self.get_sample_inventory()
424
 
        txt = xml6.serializer_v6.write_inventory_to_string(inv)
425
 
        lines = xml6.serializer_v6.write_inventory_to_lines(inv)
426
 
        self.assertEqual(bzrlib.osutils.split_lines(txt), lines)
427
 
        self.assertEqualDiff(_expected_inv_v6, txt)
428
 
        inv2 = xml6.serializer_v6.read_inventory_from_string(txt)
429
 
        self.assertEqual(4, len(inv2))
430
 
        for path, ie in inv.iter_entries():
431
 
            self.assertEqual(ie, inv2[ie.file_id])
432
 
 
433
324
    def test_wrong_format_v7(self):
434
325
        """Can't accidentally open a file with wrong serializer"""
435
326
        s_v6 = bzrlib.xml6.serializer_v6
436
327
        s_v7 = xml7.serializer_v7
437
 
        self.assertRaises(errors.UnexpectedInventoryFormat,
 
328
        self.assertRaises(errors.UnexpectedInventoryFormat, 
438
329
                          s_v7.read_inventory_from_string, _expected_inv_v5)
439
 
        self.assertRaises(errors.UnexpectedInventoryFormat,
 
330
        self.assertRaises(errors.UnexpectedInventoryFormat, 
440
331
                          s_v6.read_inventory_from_string, _expected_inv_v7)
441
332
 
442
333
    def test_tree_reference(self):
443
334
        s_v5 = bzrlib.xml5.serializer_v5
444
335
        s_v6 = bzrlib.xml6.serializer_v6
445
336
        s_v7 = xml7.serializer_v7
446
 
        inv = Inventory('tree-root-321', revision_id='rev-outer')
447
 
        inv.root.revision = 'root-rev'
 
337
        inv = Inventory('tree-root-321')
448
338
        inv.add(inventory.TreeReference('nested-id', 'nested', 'tree-root-321',
449
339
                                        'rev-outer', 'rev-inner'))
450
 
        self.assertRaises(errors.UnsupportedInventoryKind,
 
340
        self.assertRaises(errors.UnsupportedInventoryKind, 
451
341
                          s_v5.write_inventory_to_string, inv)
452
 
        self.assertRaises(errors.UnsupportedInventoryKind,
 
342
        self.assertRaises(errors.UnsupportedInventoryKind, 
453
343
                          s_v6.write_inventory_to_string, inv)
454
344
        txt = s_v7.write_inventory_to_string(inv)
455
 
        lines = s_v7.write_inventory_to_lines(inv)
456
 
        self.assertEqual(bzrlib.osutils.split_lines(txt), lines)
457
345
        inv2 = s_v7.read_inventory_from_string(txt)
458
346
        self.assertEqual('tree-root-321', inv2['nested-id'].parent_id)
459
347
        self.assertEqual('rev-outer', inv2['nested-id'].revision)
460
348
        self.assertEqual('rev-inner', inv2['nested-id'].reference_revision)
461
 
        self.assertRaises(errors.UnsupportedInventoryKind,
 
349
        self.assertRaises(errors.UnsupportedInventoryKind, 
462
350
                          s_v6.read_inventory_from_string,
463
351
                          txt.replace('format="7"', 'format="6"'))
464
 
        self.assertRaises(errors.UnsupportedInventoryKind,
 
352
        self.assertRaises(errors.UnsupportedInventoryKind, 
465
353
                          s_v5.read_inventory_from_string,
466
354
                          txt.replace('format="7"', 'format="5"'))
467
355
 
468
 
    def test_roundtrip_inventory_v8(self):
469
 
        inv = self.get_sample_inventory()
470
 
        txt = xml8.serializer_v8.write_inventory_to_string(inv)
471
 
        inv2 = xml8.serializer_v8.read_inventory_from_string(txt)
472
 
        self.assertEqual(4, len(inv2))
473
 
        for path, ie in inv.iter_entries():
474
 
            self.assertEqual(ie, inv2[ie.file_id])
475
 
 
476
 
    def test_inventory_text_v8(self):
477
 
        inv = self.get_sample_inventory()
478
 
        txt = xml8.serializer_v8.write_inventory_to_string(inv)
479
 
        lines = xml8.serializer_v8.write_inventory_to_lines(inv)
480
 
        self.assertEqual(bzrlib.osutils.split_lines(txt), lines)
481
 
        self.assertEqualDiff(_expected_inv_v8, txt)
482
 
 
483
 
    def test_revision_text_v6(self):
484
 
        """Pack revision to XML v6"""
485
 
        rev = bzrlib.xml6.serializer_v6.read_revision_from_string(
486
 
            _expected_rev_v5)
487
 
        serialized = bzrlib.xml6.serializer_v6.write_revision_to_string(rev)
488
 
        self.assertEqualDiff(serialized, _expected_rev_v5)
489
 
 
490
 
    def test_revision_text_v7(self):
491
 
        """Pack revision to XML v7"""
492
 
        rev = bzrlib.xml7.serializer_v7.read_revision_from_string(
493
 
            _expected_rev_v5)
494
 
        serialized = bzrlib.xml7.serializer_v7.write_revision_to_string(rev)
495
 
        self.assertEqualDiff(serialized, _expected_rev_v5)
496
 
 
497
 
    def test_revision_text_v8(self):
498
 
        """Pack revision to XML v8"""
499
 
        rev = bzrlib.xml8.serializer_v8.read_revision_from_string(
500
 
            _expected_rev_v8)
501
 
        serialized = bzrlib.xml8.serializer_v8.write_revision_to_string(rev)
502
 
        self.assertEqualDiff(serialized, _expected_rev_v8)
503
 
 
504
356
    def test_revision_ids_are_utf8(self):
505
357
        """Parsed revision_ids should all be utf-8 strings, not unicode."""
506
358
        s_v5 = bzrlib.xml5.serializer_v5
521
373
        fid_bar1 = u'b\xe5r-01'.encode('utf8')
522
374
        fid_sub = u's\xb5bdir-01'.encode('utf8')
523
375
        fid_bar2 = u'b\xe5r-02'.encode('utf8')
524
 
        expected = [(u'', fid_root, None, rev_id_2),
 
376
        expected = [(u'', fid_root, None, None),
525
377
                    (u'b\xe5r', fid_bar1, fid_root, rev_id_1),
526
378
                    (u's\xb5bdir', fid_sub, fid_root, rev_id_1),
527
379
                    (u's\xb5bdir/b\xe5r', fid_bar2, fid_sub, rev_id_2),
550
402
    """Whitebox testing of the _encode_and_escape function."""
551
403
 
552
404
    def setUp(self):
553
 
        TestCase.setUp(self)
554
405
        # Keep the cache clear before and after the test
555
 
        bzrlib.xml8._ensure_utf8_re()
556
 
        bzrlib.xml8._clear_cache()
557
 
        self.addCleanup(bzrlib.xml8._clear_cache)
 
406
        bzrlib.xml5._ensure_utf8_re()
 
407
        bzrlib.xml5._clear_cache()
 
408
        self.addCleanup(bzrlib.xml5._clear_cache)
558
409
 
559
410
    def test_simple_ascii(self):
560
411
        # _encode_and_escape always appends a final ", because these parameters
561
412
        # are being used in xml attributes, and by returning it now, we have to
562
413
        # do fewer string operations later.
563
 
        val = bzrlib.xml8._encode_and_escape('foo bar')
 
414
        val = bzrlib.xml5._encode_and_escape('foo bar')
564
415
        self.assertEqual('foo bar"', val)
565
416
        # The second time should be cached
566
 
        val2 = bzrlib.xml8._encode_and_escape('foo bar')
 
417
        val2 = bzrlib.xml5._encode_and_escape('foo bar')
567
418
        self.assertIs(val2, val)
568
419
 
569
420
    def test_ascii_with_xml(self):
570
421
        self.assertEqual('&amp;&apos;&quot;&lt;&gt;"',
571
 
                         bzrlib.xml8._encode_and_escape('&\'"<>'))
 
422
                         bzrlib.xml5._encode_and_escape('&\'"<>'))
572
423
 
573
424
    def test_utf8_with_xml(self):
574
425
        # u'\xb5\xe5&\u062c'
575
426
        utf8_str = '\xc2\xb5\xc3\xa5&\xd8\xac'
576
427
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
577
 
                         bzrlib.xml8._encode_and_escape(utf8_str))
 
428
                         bzrlib.xml5._encode_and_escape(utf8_str))
578
429
 
579
430
    def test_unicode(self):
580
431
        uni_str = u'\xb5\xe5&\u062c'
581
432
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
582
 
                         bzrlib.xml8._encode_and_escape(uni_str))
 
433
                         bzrlib.xml5._encode_and_escape(uni_str))