/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: John Arbash Meinel
  • Date: 2009-12-22 16:28:47 UTC
  • mto: This revision was merged to the branch mainline in revision 4922.
  • Revision ID: john@arbash-meinel.com-20091222162847-tvnsc69to4l4uf5r
Implement a permute_for_extension helper.

Use it for all of the 'simple' extension permutations.
It basically permutes all tests in the current module, by setting TestCase.module.
Which works well for most of our extension tests. Some had more advanced
handling of permutations (extra permutations, custom vars, etc.)

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., 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
    serializer,
 
27
    )
 
28
from bzrlib.tests import TestCase
 
29
from bzrlib.inventory import Inventory, InventoryEntry
 
30
from bzrlib.xml4 import serializer_v4
 
31
import bzrlib.xml5
 
32
 
 
33
_working_inventory_v4 = """<inventory file_id="TREE_ROOT">
 
34
<entry file_id="bar-20050901064931-73b4b1138abc9cd2" kind="file" name="bar" parent_id="TREE_ROOT" />
 
35
<entry file_id="foo-20050801201819-4139aa4a272f4250" kind="directory" name="foo" parent_id="TREE_ROOT" />
 
36
<entry file_id="bar-20050824000535-6bc48cfad47ed134" kind="file" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" />
 
37
</inventory>"""
 
38
 
 
39
 
 
40
_revision_v4 = """<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
 
41
    inventory_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
 
42
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
 
43
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
 
44
    timestamp="1125907235.212"
 
45
    timezone="36000">
 
46
<message>- start splitting code for xml (de)serialization away from objects
 
47
  preparatory to supporting multiple formats by a single library
 
48
</message>
 
49
<parents>
 
50
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" revision_sha1="7bdf4cc8c5bdac739f8cf9b10b78cf4b68f915ff" />
 
51
</parents>
 
52
</revision>
 
53
"""
 
54
 
 
55
_revision_v5 = """<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
 
56
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
 
57
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
 
58
    timestamp="1125907235.212"
 
59
    timezone="36000">
 
60
<message>- start splitting code for xml (de)serialization away from objects
 
61
  preparatory to supporting multiple formats by a single library
 
62
</message>
 
63
<parents>
 
64
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"/>
 
65
</parents>
 
66
</revision>
 
67
"""
 
68
 
 
69
_revision_v5_utc = """\
 
70
<revision committer="Martin Pool &lt;mbp@sourcefrog.net&gt;"
 
71
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
 
72
    revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9"
 
73
    timestamp="1125907235.212"
 
74
    timezone="0">
 
75
<message>- start splitting code for xml (de)serialization away from objects
 
76
  preparatory to supporting multiple formats by a single library
 
77
</message>
 
78
<parents>
 
79
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"/>
 
80
</parents>
 
81
</revision>
 
82
"""
 
83
 
 
84
_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"/>
 
89
<directory name="subdir"
 
90
           file_id="foo-20050801201819-4139aa4a272f4250"
 
91
           parent_id="TREE_ROOT"
 
92
           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"/>
 
97
</inventory>
 
98
"""
 
99
 
 
100
_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"
 
103
      revision="mbp@foo-123123"/>
 
104
<directory name="subdir"
 
105
           file_id="foo-20050801201819-4139aa4a272f4250"
 
106
           parent_id="TREE_ROOT"
 
107
           revision="mbp@foo-00"/>
 
108
<file file_id="bar-20050824000535-6bc48cfad47ed134"
 
109
      name="bar" parent_id="foo-20050801201819-4139aa4a272f4250"
 
110
      revision="mbp@foo-00"/>
 
111
</inventory>
 
112
"""
 
113
 
 
114
 
 
115
# DO NOT REFLOW THIS. Its the exact revision we want.
 
116
_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">
 
117
<message>- start splitting code for xml (de)serialization away from objects
 
118
  preparatory to supporting multiple formats by a single library
 
119
</message>
 
120
<parents>
 
121
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" />
 
122
</parents>
 
123
</revision>
 
124
"""
 
125
 
 
126
 
 
127
# DO NOT REFLOW THIS. Its the exact inventory we want.
 
128
_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" />
 
130
<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" />
 
132
</inventory>
 
133
"""
 
134
 
 
135
 
 
136
_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" />
 
138
<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" />
 
149
</inventory>
 
150
"""
 
151
 
 
152
_expected_inv_v7 = """<inventory format="7" revision_id="rev_outer">
 
153
<directory file_id="tree-root-321" name="" revision="rev_outer" />
 
154
<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" />
 
157
<tree-reference file_id="nested-id" name="nested" parent_id="tree-root-321" revision="rev_outer" reference_revision="rev_inner" />
 
158
</inventory>
 
159
"""
 
160
 
 
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
_revision_utf8_v5 = """<revision committer="Erik B&#229;gfors &lt;erik@foo.net&gt;"
 
180
    inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41"
 
181
    revision_id="erik@b&#229;gfors-02"
 
182
    timestamp="1125907235.212"
 
183
    timezone="36000">
 
184
<message>Include &#181;nicode characters
 
185
</message>
 
186
<parents>
 
187
<revision_ref revision_id="erik@b&#229;gfors-01"/>
 
188
</parents>
 
189
</revision>
 
190
"""
 
191
 
 
192
_inventory_utf8_v5 = """<inventory file_id="TRE&#233;_ROOT" format="5"
 
193
                                   revision_id="erik@b&#229;gfors-02">
 
194
<file file_id="b&#229;r-01"
 
195
      name="b&#229;r" parent_id="TRE&#233;_ROOT"
 
196
      revision="erik@b&#229;gfors-01"/>
 
197
<directory name="s&#181;bdir"
 
198
           file_id="s&#181;bdir-01"
 
199
           parent_id="TRE&#233;_ROOT"
 
200
           revision="erik@b&#229;gfors-01"/>
 
201
<file executable="yes" file_id="b&#229;r-02"
 
202
      name="b&#229;r" parent_id="s&#181;bdir-01"
 
203
      revision="erik@b&#229;gfors-02"/>
 
204
</inventory>
 
205
"""
 
206
 
 
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
 
 
218
class TestSerializer(TestCase):
 
219
    """Test XML serialization"""
 
220
 
 
221
    def test_canned_inventory(self):
 
222
        """Test unpacked a canned inventory v4 file."""
 
223
        inp = StringIO(_working_inventory_v4)
 
224
        inv = serializer_v4.read_inventory(inp)
 
225
        self.assertEqual(len(inv), 4)
 
226
        self.assert_('bar-20050901064931-73b4b1138abc9cd2' in inv)
 
227
 
 
228
    def test_unpack_revision(self):
 
229
        """Test unpacking a canned revision v4"""
 
230
        inp = StringIO(_revision_v4)
 
231
        rev = serializer_v4.read_revision(inp)
 
232
        eq = self.assertEqual
 
233
        eq(rev.committer,
 
234
           "Martin Pool <mbp@sourcefrog.net>")
 
235
        eq(rev.inventory_id,
 
236
           "mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9")
 
237
        eq(len(rev.parent_ids), 1)
 
238
        eq(rev.parent_ids[0],
 
239
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
 
240
 
 
241
    def test_unpack_revision_5(self):
 
242
        """Test unpacking a canned revision v5"""
 
243
        inp = StringIO(_revision_v5)
 
244
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
 
245
        eq = self.assertEqual
 
246
        eq(rev.committer,
 
247
           "Martin Pool <mbp@sourcefrog.net>")
 
248
        eq(len(rev.parent_ids), 1)
 
249
        eq(rev.timezone, 36000)
 
250
        eq(rev.parent_ids[0],
 
251
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
 
252
 
 
253
    def test_unpack_revision_5_utc(self):
 
254
        inp = StringIO(_revision_v5_utc)
 
255
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
 
256
        eq = self.assertEqual
 
257
        eq(rev.committer,
 
258
           "Martin Pool <mbp@sourcefrog.net>")
 
259
        eq(len(rev.parent_ids), 1)
 
260
        eq(rev.timezone, 0)
 
261
        eq(rev.parent_ids[0],
 
262
           "mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
 
263
 
 
264
    def test_unpack_inventory_5(self):
 
265
        """Unpack canned new-style inventory"""
 
266
        inp = StringIO(_committed_inv_v5)
 
267
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
 
268
        eq = self.assertEqual
 
269
        eq(len(inv), 4)
 
270
        ie = inv['bar-20050824000535-6bc48cfad47ed134']
 
271
        eq(ie.kind, 'file')
 
272
        eq(ie.revision, 'mbp@foo-00')
 
273
        eq(ie.name, 'bar')
 
274
        eq(inv[ie.parent_id].kind, 'directory')
 
275
 
 
276
    def test_unpack_basis_inventory_5(self):
 
277
        """Unpack canned new-style inventory"""
 
278
        inp = StringIO(_basis_inv_v5)
 
279
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
 
280
        eq = self.assertEqual
 
281
        eq(len(inv), 4)
 
282
        eq(inv.revision_id, 'mbp@sourcefrog.net-20050905063503-43948f59fa127d92')
 
283
        ie = inv['bar-20050824000535-6bc48cfad47ed134']
 
284
        eq(ie.kind, 'file')
 
285
        eq(ie.revision, 'mbp@foo-00')
 
286
        eq(ie.name, 'bar')
 
287
        eq(inv[ie.parent_id].kind, 'directory')
 
288
 
 
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
    def test_repack_inventory_5(self):
 
332
        inp = StringIO(_committed_inv_v5)
 
333
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
 
334
        outp = StringIO()
 
335
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
 
336
        self.assertEqualDiff(_expected_inv_v5, outp.getvalue())
 
337
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
 
338
        self.assertEqual(inv, inv2)
 
339
 
 
340
    def assertRoundTrips(self, xml_string):
 
341
        inp = StringIO(xml_string)
 
342
        inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
 
343
        outp = StringIO()
 
344
        bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
 
345
        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
        inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
 
350
        self.assertEqual(inv, inv2)
 
351
 
 
352
    def tests_serialize_inventory_v5_with_root(self):
 
353
        self.assertRoundTrips(_expected_inv_v5_root)
 
354
 
 
355
    def check_repack_revision(self, txt):
 
356
        """Check that repacking a revision yields the same information"""
 
357
        inp = StringIO(txt)
 
358
        rev = bzrlib.xml5.serializer_v5.read_revision(inp)
 
359
        outp = StringIO()
 
360
        bzrlib.xml5.serializer_v5.write_revision(rev, outp)
 
361
        outfile_contents = outp.getvalue()
 
362
        rev2 = bzrlib.xml5.serializer_v5.read_revision(StringIO(outfile_contents))
 
363
        self.assertEqual(rev, rev2)
 
364
 
 
365
    def test_repack_revision_5(self):
 
366
        """Round-trip revision to XML v5"""
 
367
        self.check_repack_revision(_revision_v5)
 
368
 
 
369
    def test_repack_revision_5_utc(self):
 
370
        self.check_repack_revision(_revision_v5_utc)
 
371
 
 
372
    def test_pack_revision_5(self):
 
373
        """Pack revision to XML v5"""
 
374
        # fixed 20051025, revisions should have final newline
 
375
        rev = bzrlib.xml5.serializer_v5.read_revision_from_string(_revision_v5)
 
376
        outp = StringIO()
 
377
        bzrlib.xml5.serializer_v5.write_revision(rev, outp)
 
378
        outfile_contents = outp.getvalue()
 
379
        self.assertEqual(outfile_contents[-1], '\n')
 
380
        self.assertEqualDiff(outfile_contents, bzrlib.xml5.serializer_v5.write_revision_to_string(rev))
 
381
        self.assertEqualDiff(outfile_contents, _expected_rev_v5)
 
382
 
 
383
    def test_empty_property_value(self):
 
384
        """Create an empty property value check that it serializes correctly"""
 
385
        s_v5 = bzrlib.xml5.serializer_v5
 
386
        rev = s_v5.read_revision_from_string(_revision_v5)
 
387
        outp = StringIO()
 
388
        props = {'empty':'', 'one':'one'}
 
389
        rev.properties = props
 
390
        txt = s_v5.write_revision_to_string(rev)
 
391
        new_rev = s_v5.read_revision_from_string(txt)
 
392
        self.assertEqual(props, new_rev.properties)
 
393
 
 
394
    def get_sample_inventory(self):
 
395
        inv = Inventory('tree-root-321', revision_id='rev_outer')
 
396
        inv.add(inventory.InventoryFile('file-id', 'file', 'tree-root-321'))
 
397
        inv.add(inventory.InventoryDirectory('dir-id', 'dir',
 
398
                                             'tree-root-321'))
 
399
        inv.add(inventory.InventoryLink('link-id', 'link', 'tree-root-321'))
 
400
        inv['tree-root-321'].revision = 'rev_outer'
 
401
        inv['dir-id'].revision = 'rev_outer'
 
402
        inv['file-id'].revision = 'rev_outer'
 
403
        inv['file-id'].text_sha1 = 'A'
 
404
        inv['file-id'].text_size = 1
 
405
        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
        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
        self.assertEqualDiff(_expected_inv_v7, txt)
 
417
        inv2 = xml7.serializer_v7.read_inventory_from_string(txt)
 
418
        self.assertEqual(5, len(inv2))
 
419
        for path, ie in inv.iter_entries():
 
420
            self.assertEqual(ie, inv2[ie.file_id])
 
421
 
 
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
    def test_wrong_format_v7(self):
 
434
        """Can't accidentally open a file with wrong serializer"""
 
435
        s_v6 = bzrlib.xml6.serializer_v6
 
436
        s_v7 = xml7.serializer_v7
 
437
        self.assertRaises(errors.UnexpectedInventoryFormat,
 
438
                          s_v7.read_inventory_from_string, _expected_inv_v5)
 
439
        self.assertRaises(errors.UnexpectedInventoryFormat,
 
440
                          s_v6.read_inventory_from_string, _expected_inv_v7)
 
441
 
 
442
    def test_tree_reference(self):
 
443
        s_v5 = bzrlib.xml5.serializer_v5
 
444
        s_v6 = bzrlib.xml6.serializer_v6
 
445
        s_v7 = xml7.serializer_v7
 
446
        inv = Inventory('tree-root-321', revision_id='rev-outer')
 
447
        inv.root.revision = 'root-rev'
 
448
        inv.add(inventory.TreeReference('nested-id', 'nested', 'tree-root-321',
 
449
                                        'rev-outer', 'rev-inner'))
 
450
        self.assertRaises(errors.UnsupportedInventoryKind,
 
451
                          s_v5.write_inventory_to_string, inv)
 
452
        self.assertRaises(errors.UnsupportedInventoryKind,
 
453
                          s_v6.write_inventory_to_string, inv)
 
454
        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
        inv2 = s_v7.read_inventory_from_string(txt)
 
458
        self.assertEqual('tree-root-321', inv2['nested-id'].parent_id)
 
459
        self.assertEqual('rev-outer', inv2['nested-id'].revision)
 
460
        self.assertEqual('rev-inner', inv2['nested-id'].reference_revision)
 
461
        self.assertRaises(errors.UnsupportedInventoryKind,
 
462
                          s_v6.read_inventory_from_string,
 
463
                          txt.replace('format="7"', 'format="6"'))
 
464
        self.assertRaises(errors.UnsupportedInventoryKind,
 
465
                          s_v5.read_inventory_from_string,
 
466
                          txt.replace('format="7"', 'format="5"'))
 
467
 
 
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
    def test_revision_ids_are_utf8(self):
 
505
        """Parsed revision_ids should all be utf-8 strings, not unicode."""
 
506
        s_v5 = bzrlib.xml5.serializer_v5
 
507
        rev = s_v5.read_revision_from_string(_revision_utf8_v5)
 
508
        self.assertEqual('erik@b\xc3\xa5gfors-02', rev.revision_id)
 
509
        self.assertIsInstance(rev.revision_id, str)
 
510
        self.assertEqual(['erik@b\xc3\xa5gfors-01'], rev.parent_ids)
 
511
        for parent_id in rev.parent_ids:
 
512
            self.assertIsInstance(parent_id, str)
 
513
        self.assertEqual(u'Include \xb5nicode characters\n', rev.message)
 
514
        self.assertIsInstance(rev.message, unicode)
 
515
 
 
516
        # ie.revision should either be None or a utf-8 revision id
 
517
        inv = s_v5.read_inventory_from_string(_inventory_utf8_v5)
 
518
        rev_id_1 = u'erik@b\xe5gfors-01'.encode('utf8')
 
519
        rev_id_2 = u'erik@b\xe5gfors-02'.encode('utf8')
 
520
        fid_root = u'TRE\xe9_ROOT'.encode('utf8')
 
521
        fid_bar1 = u'b\xe5r-01'.encode('utf8')
 
522
        fid_sub = u's\xb5bdir-01'.encode('utf8')
 
523
        fid_bar2 = u'b\xe5r-02'.encode('utf8')
 
524
        expected = [(u'', fid_root, None, rev_id_2),
 
525
                    (u'b\xe5r', fid_bar1, fid_root, rev_id_1),
 
526
                    (u's\xb5bdir', fid_sub, fid_root, rev_id_1),
 
527
                    (u's\xb5bdir/b\xe5r', fid_bar2, fid_sub, rev_id_2),
 
528
                   ]
 
529
        self.assertEqual(rev_id_2, inv.revision_id)
 
530
        self.assertIsInstance(inv.revision_id, str)
 
531
 
 
532
        actual = list(inv.iter_entries_by_dir())
 
533
        for ((exp_path, exp_file_id, exp_parent_id, exp_rev_id),
 
534
             (act_path, act_ie)) in zip(expected, actual):
 
535
            self.assertEqual(exp_path, act_path)
 
536
            self.assertIsInstance(act_path, unicode)
 
537
            self.assertEqual(exp_file_id, act_ie.file_id)
 
538
            self.assertIsInstance(act_ie.file_id, str)
 
539
            self.assertEqual(exp_parent_id, act_ie.parent_id)
 
540
            if exp_parent_id is not None:
 
541
                self.assertIsInstance(act_ie.parent_id, str)
 
542
            self.assertEqual(exp_rev_id, act_ie.revision)
 
543
            if exp_rev_id is not None:
 
544
                self.assertIsInstance(act_ie.revision, str)
 
545
 
 
546
        self.assertEqual(len(expected), len(actual))
 
547
 
 
548
 
 
549
class TestEncodeAndEscape(TestCase):
 
550
    """Whitebox testing of the _encode_and_escape function."""
 
551
 
 
552
    def setUp(self):
 
553
        TestCase.setUp(self)
 
554
        # 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)
 
558
 
 
559
    def test_simple_ascii(self):
 
560
        # _encode_and_escape always appends a final ", because these parameters
 
561
        # are being used in xml attributes, and by returning it now, we have to
 
562
        # do fewer string operations later.
 
563
        val = bzrlib.xml8._encode_and_escape('foo bar')
 
564
        self.assertEqual('foo bar"', val)
 
565
        # The second time should be cached
 
566
        val2 = bzrlib.xml8._encode_and_escape('foo bar')
 
567
        self.assertIs(val2, val)
 
568
 
 
569
    def test_ascii_with_xml(self):
 
570
        self.assertEqual('&amp;&apos;&quot;&lt;&gt;"',
 
571
                         bzrlib.xml8._encode_and_escape('&\'"<>'))
 
572
 
 
573
    def test_utf8_with_xml(self):
 
574
        # u'\xb5\xe5&\u062c'
 
575
        utf8_str = '\xc2\xb5\xc3\xa5&\xd8\xac'
 
576
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
 
577
                         bzrlib.xml8._encode_and_escape(utf8_str))
 
578
 
 
579
    def test_unicode(self):
 
580
        uni_str = u'\xb5\xe5&\u062c'
 
581
        self.assertEqual('&#181;&#229;&amp;&#1580;"',
 
582
                         bzrlib.xml8._encode_and_escape(uni_str))