/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-09-19 05:14:14 UTC
  • mto: (2835.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 2836.
  • Revision ID: robertc@robertcollins.net-20070919051414-2tgjqteg7k3ps4h0
* ``pull``, ``merge`` and ``push`` will no longer silently correct some
  repository index errors that occured as a result of the Weave disk format.
  Instead the ``reconcile`` command needs to be run to correct those
  problems if they exist (and it has been able to fix most such problems
  since bzr 0.8). Some new problems have been identified during this release
  and you should run ``bzr check`` once on every repository to see if you
  need to reconcile. If you cannot ``pull`` or ``merge`` from a remote
  repository due to mismatched parent errors - a symptom of index errors -
  you should simply take a full copy of that remote repository to a clean
  directory outside any local repositories, then run reconcile on it, and
  finally pull from it locally. (And naturally email the repositories owner
  to ask them to upgrade and run reconcile).
  (Robert Collins)

* ``VersionedFile.fix_parents`` has been removed as a harmful API.
  ``VersionedFile.join`` will no longer accept different parents on either
  side of a join - it will either ignore them, or error, depending on the
  implementation. See notes when upgrading for more information.
  (Robert Collins)

Show diffs side-by-side

added added

removed removed

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