~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_xml.py

  • Committer: Martin Pool
  • Date: 2005-08-24 08:59:32 UTC
  • Revision ID: mbp@sourcefrog.net-20050824085932-c61f1f1f1c930e13
- Add a simple UIFactory 

  The idea of this is to let a client of bzrlib set some 
  policy about how output is displayed.

  In this revision all that's done is that progress bars
  are constructed by a policy established by the application
  rather than being randomly constructed in the library 
  or passed down the calls.  This avoids progress bars
  popping up while running the test suite and cleans up
  some code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 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))