/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: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

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