/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_inventory_delta.py

  • Committer: Martin von Gagern
  • Date: 2010-04-20 08:47:38 UTC
  • mfrom: (5167 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5195.
  • Revision ID: martin.vgagern@gmx.net-20100420084738-ygymnqmdllzrhpfn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008, 2009 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
"""Tests for bzrlib.inventory_delta.
 
18
 
 
19
See doc/developer/inventory.txt for more information.
 
20
"""
 
21
 
 
22
from cStringIO import StringIO
 
23
 
 
24
from bzrlib import (
 
25
    errors,
 
26
    inventory,
 
27
    inventory_delta,
 
28
    )
 
29
from bzrlib.inventory_delta import InventoryDeltaError
 
30
from bzrlib.inventory import Inventory
 
31
from bzrlib.revision import NULL_REVISION
 
32
from bzrlib.tests import TestCase
 
33
 
 
34
### DO NOT REFLOW THESE TEXTS. NEW LINES ARE SIGNIFICANT. ###
 
35
empty_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
36
parent: null:
 
37
version: null:
 
38
versioned_root: true
 
39
tree_references: true
 
40
"""
 
41
 
 
42
root_only_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
43
parent: null:
 
44
version: entry-version
 
45
versioned_root: true
 
46
tree_references: true
 
47
None\x00/\x00an-id\x00\x00a@e\xc3\xa5ample.com--2004\x00dir
 
48
"""
 
49
 
 
50
 
 
51
root_change_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
52
parent: entry-version
 
53
version: changed-root
 
54
versioned_root: true
 
55
tree_references: true
 
56
/\x00an-id\x00\x00different-version\x00dir
 
57
"""
 
58
 
 
59
corrupt_parent_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
60
parent: entry-version
 
61
version: changed-root
 
62
versioned_root: false
 
63
tree_references: false
 
64
/\x00an-id\x00\x00different-version\x00dir
 
65
"""
 
66
 
 
67
root_only_unversioned = """format: bzr inventory delta v1 (bzr 1.14)
 
68
parent: null:
 
69
version: entry-version
 
70
versioned_root: false
 
71
tree_references: false
 
72
None\x00/\x00TREE_ROOT\x00\x00entry-version\x00dir
 
73
"""
 
74
 
 
75
reference_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
76
parent: null:
 
77
version: entry-version
 
78
versioned_root: true
 
79
tree_references: true
 
80
None\x00/\x00TREE_ROOT\x00\x00a@e\xc3\xa5ample.com--2004\x00dir
 
81
None\x00/foo\x00id\x00TREE_ROOT\x00changed\x00tree\x00subtree-version
 
82
"""
 
83
 
 
84
change_tree_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
85
parent: entry-version
 
86
version: change-tree
 
87
versioned_root: false
 
88
tree_references: false
 
89
/foo\x00id\x00TREE_ROOT\x00changed-twice\x00tree\x00subtree-version2
 
90
"""
 
91
 
 
92
 
 
93
class TestDeserialization(TestCase):
 
94
    """Test InventoryDeltaSerializer.parse_text_bytes."""
 
95
 
 
96
    def test_parse_no_bytes(self):
 
97
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
98
        err = self.assertRaises(
 
99
            InventoryDeltaError, deserializer.parse_text_bytes, '')
 
100
        self.assertContainsRe(str(err), 'last line not empty')
 
101
 
 
102
    def test_parse_bad_format(self):
 
103
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
104
        err = self.assertRaises(InventoryDeltaError,
 
105
            deserializer.parse_text_bytes, 'format: foo\n')
 
106
        self.assertContainsRe(str(err), 'unknown format')
 
107
 
 
108
    def test_parse_no_parent(self):
 
109
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
110
        err = self.assertRaises(InventoryDeltaError,
 
111
            deserializer.parse_text_bytes,
 
112
            'format: bzr inventory delta v1 (bzr 1.14)\n')
 
113
        self.assertContainsRe(str(err), 'missing parent: marker')
 
114
 
 
115
    def test_parse_no_version(self):
 
116
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
117
        err = self.assertRaises(InventoryDeltaError,
 
118
            deserializer.parse_text_bytes,
 
119
            'format: bzr inventory delta v1 (bzr 1.14)\n'
 
120
            'parent: null:\n')
 
121
        self.assertContainsRe(str(err), 'missing version: marker')
 
122
            
 
123
    def test_parse_duplicate_key_errors(self):
 
124
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
125
        double_root_lines = \
 
126
"""format: bzr inventory delta v1 (bzr 1.14)
 
127
parent: null:
 
128
version: null:
 
129
versioned_root: true
 
130
tree_references: true
 
131
None\x00/\x00an-id\x00\x00a@e\xc3\xa5ample.com--2004\x00dir\x00\x00
 
132
None\x00/\x00an-id\x00\x00a@e\xc3\xa5ample.com--2004\x00dir\x00\x00
 
133
"""
 
134
        err = self.assertRaises(InventoryDeltaError,
 
135
            deserializer.parse_text_bytes, double_root_lines)
 
136
        self.assertContainsRe(str(err), 'duplicate file id')
 
137
 
 
138
    def test_parse_versioned_root_only(self):
 
139
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
140
        parse_result = deserializer.parse_text_bytes(root_only_lines)
 
141
        expected_entry = inventory.make_entry(
 
142
            'directory', u'', None, 'an-id')
 
143
        expected_entry.revision = 'a@e\xc3\xa5ample.com--2004'
 
144
        self.assertEqual(
 
145
            ('null:', 'entry-version', True, True,
 
146
             [(None, '', 'an-id', expected_entry)]),
 
147
            parse_result)
 
148
 
 
149
    def test_parse_special_revid_not_valid_last_mod(self):
 
150
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
151
        root_only_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
152
parent: null:
 
153
version: null:
 
154
versioned_root: false
 
155
tree_references: true
 
156
None\x00/\x00TREE_ROOT\x00\x00null:\x00dir\x00\x00
 
157
"""
 
158
        err = self.assertRaises(InventoryDeltaError,
 
159
            deserializer.parse_text_bytes, root_only_lines)
 
160
        self.assertContainsRe(str(err), 'special revisionid found')
 
161
 
 
162
    def test_parse_versioned_root_versioned_disabled(self):
 
163
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
164
        root_only_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
165
parent: null:
 
166
version: null:
 
167
versioned_root: false
 
168
tree_references: true
 
169
None\x00/\x00TREE_ROOT\x00\x00a@e\xc3\xa5ample.com--2004\x00dir\x00\x00
 
170
"""
 
171
        err = self.assertRaises(InventoryDeltaError,
 
172
            deserializer.parse_text_bytes, root_only_lines)
 
173
        self.assertContainsRe(str(err), 'Versioned root found')
 
174
 
 
175
    def test_parse_unique_root_id_root_versioned_disabled(self):
 
176
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
177
        root_only_lines = """format: bzr inventory delta v1 (bzr 1.14)
 
178
parent: parent-id
 
179
version: a@e\xc3\xa5ample.com--2004
 
180
versioned_root: false
 
181
tree_references: true
 
182
None\x00/\x00an-id\x00\x00parent-id\x00dir\x00\x00
 
183
"""
 
184
        err = self.assertRaises(InventoryDeltaError,
 
185
            deserializer.parse_text_bytes, root_only_lines)
 
186
        self.assertContainsRe(str(err), 'Versioned root found')
 
187
 
 
188
    def test_parse_unversioned_root_versioning_enabled(self):
 
189
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
190
        parse_result = deserializer.parse_text_bytes(root_only_unversioned)
 
191
        expected_entry = inventory.make_entry(
 
192
            'directory', u'', None, 'TREE_ROOT')
 
193
        expected_entry.revision = 'entry-version'
 
194
        self.assertEqual(
 
195
            ('null:', 'entry-version', False, False,
 
196
             [(None, u'', 'TREE_ROOT', expected_entry)]),
 
197
            parse_result)
 
198
 
 
199
    def test_parse_versioned_root_when_disabled(self):
 
200
        deserializer = inventory_delta.InventoryDeltaDeserializer(
 
201
            allow_versioned_root=False)
 
202
        err = self.assertRaises(inventory_delta.IncompatibleInventoryDelta,
 
203
            deserializer.parse_text_bytes, root_only_lines)
 
204
        self.assertEquals("versioned_root not allowed", str(err))
 
205
 
 
206
    def test_parse_tree_when_disabled(self):
 
207
        deserializer = inventory_delta.InventoryDeltaDeserializer(
 
208
            allow_tree_references=False)
 
209
        err = self.assertRaises(inventory_delta.IncompatibleInventoryDelta,
 
210
            deserializer.parse_text_bytes, reference_lines)
 
211
        self.assertEquals("Tree reference not allowed", str(err))
 
212
 
 
213
    def test_parse_tree_when_header_disallows(self):
 
214
        # A deserializer that allows tree_references to be set or unset.
 
215
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
216
        # A serialised inventory delta with a header saying no tree refs, but
 
217
        # that has a tree ref in its content.
 
218
        lines = """format: bzr inventory delta v1 (bzr 1.14)
 
219
parent: null:
 
220
version: entry-version
 
221
versioned_root: false
 
222
tree_references: false
 
223
None\x00/foo\x00id\x00TREE_ROOT\x00changed\x00tree\x00subtree-version
 
224
"""
 
225
        err = self.assertRaises(InventoryDeltaError,
 
226
            deserializer.parse_text_bytes, lines)
 
227
        self.assertContainsRe(str(err), 'Tree reference found')
 
228
 
 
229
    def test_parse_versioned_root_when_header_disallows(self):
 
230
        # A deserializer that allows tree_references to be set or unset.
 
231
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
232
        # A serialised inventory delta with a header saying no tree refs, but
 
233
        # that has a tree ref in its content.
 
234
        lines = """format: bzr inventory delta v1 (bzr 1.14)
 
235
parent: null:
 
236
version: entry-version
 
237
versioned_root: false
 
238
tree_references: false
 
239
None\x00/\x00TREE_ROOT\x00\x00a@e\xc3\xa5ample.com--2004\x00dir
 
240
"""
 
241
        err = self.assertRaises(InventoryDeltaError,
 
242
            deserializer.parse_text_bytes, lines)
 
243
        self.assertContainsRe(str(err), 'Versioned root found')
 
244
 
 
245
    def test_parse_last_line_not_empty(self):
 
246
        """newpath must start with / if it is not None."""
 
247
        # Trim the trailing newline from a valid serialization
 
248
        lines = root_only_lines[:-1]
 
249
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
250
        err = self.assertRaises(InventoryDeltaError,
 
251
            deserializer.parse_text_bytes, lines)
 
252
        self.assertContainsRe(str(err), 'last line not empty')
 
253
 
 
254
    def test_parse_invalid_newpath(self):
 
255
        """newpath must start with / if it is not None."""
 
256
        lines = empty_lines
 
257
        lines += "None\x00bad\x00TREE_ROOT\x00\x00version\x00dir\n"
 
258
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
259
        err = self.assertRaises(InventoryDeltaError,
 
260
            deserializer.parse_text_bytes, lines)
 
261
        self.assertContainsRe(str(err), 'newpath invalid')
 
262
 
 
263
    def test_parse_invalid_oldpath(self):
 
264
        """oldpath must start with / if it is not None."""
 
265
        lines = root_only_lines
 
266
        lines += "bad\x00/new\x00file-id\x00\x00version\x00dir\n"
 
267
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
268
        err = self.assertRaises(InventoryDeltaError,
 
269
            deserializer.parse_text_bytes, lines)
 
270
        self.assertContainsRe(str(err), 'oldpath invalid')
 
271
    
 
272
    def test_parse_new_file(self):
 
273
        """a new file is parsed correctly"""
 
274
        lines = root_only_lines
 
275
        fake_sha = "deadbeef" * 5
 
276
        lines += (
 
277
            "None\x00/new\x00file-id\x00an-id\x00version\x00file\x00123\x00" +
 
278
            "\x00" + fake_sha + "\n")
 
279
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
280
        parse_result = deserializer.parse_text_bytes(lines)
 
281
        expected_entry = inventory.make_entry(
 
282
            'file', u'new', 'an-id', 'file-id')
 
283
        expected_entry.revision = 'version'
 
284
        expected_entry.text_size = 123
 
285
        expected_entry.text_sha1 = fake_sha
 
286
        delta = parse_result[4]
 
287
        self.assertEqual(
 
288
             (None, u'new', 'file-id', expected_entry), delta[-1])
 
289
 
 
290
    def test_parse_delete(self):
 
291
        lines = root_only_lines
 
292
        lines += (
 
293
            "/old-file\x00None\x00deleted-id\x00\x00null:\x00deleted\x00\x00\n")
 
294
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
295
        parse_result = deserializer.parse_text_bytes(lines)
 
296
        delta = parse_result[4]
 
297
        self.assertEqual(
 
298
             (u'old-file', None, 'deleted-id', None), delta[-1])
 
299
 
 
300
 
 
301
class TestSerialization(TestCase):
 
302
    """Tests for InventoryDeltaSerializer.delta_to_lines."""
 
303
 
 
304
    def test_empty_delta_to_lines(self):
 
305
        old_inv = Inventory(None)
 
306
        new_inv = Inventory(None)
 
307
        delta = new_inv._make_delta(old_inv)
 
308
        serializer = inventory_delta.InventoryDeltaSerializer(
 
309
            versioned_root=True, tree_references=True)
 
310
        self.assertEqual(StringIO(empty_lines).readlines(),
 
311
            serializer.delta_to_lines(NULL_REVISION, NULL_REVISION, delta))
 
312
 
 
313
    def test_root_only_to_lines(self):
 
314
        old_inv = Inventory(None)
 
315
        new_inv = Inventory(None)
 
316
        root = new_inv.make_entry('directory', '', None, 'an-id')
 
317
        root.revision = 'a@e\xc3\xa5ample.com--2004'
 
318
        new_inv.add(root)
 
319
        delta = new_inv._make_delta(old_inv)
 
320
        serializer = inventory_delta.InventoryDeltaSerializer(
 
321
            versioned_root=True, tree_references=True)
 
322
        self.assertEqual(StringIO(root_only_lines).readlines(),
 
323
            serializer.delta_to_lines(NULL_REVISION, 'entry-version', delta))
 
324
 
 
325
    def test_unversioned_root(self):
 
326
        old_inv = Inventory(None)
 
327
        new_inv = Inventory(None)
 
328
        root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
 
329
        # Implicit roots are considered modified in every revision.
 
330
        root.revision = 'entry-version'
 
331
        new_inv.add(root)
 
332
        delta = new_inv._make_delta(old_inv)
 
333
        serializer = inventory_delta.InventoryDeltaSerializer(
 
334
            versioned_root=False, tree_references=False)
 
335
        serialized_lines = serializer.delta_to_lines(
 
336
            NULL_REVISION, 'entry-version', delta)
 
337
        self.assertEqual(StringIO(root_only_unversioned).readlines(),
 
338
            serialized_lines)
 
339
        deserializer = inventory_delta.InventoryDeltaDeserializer()
 
340
        self.assertEqual(
 
341
            (NULL_REVISION, 'entry-version', False, False, delta),
 
342
            deserializer.parse_text_bytes(''.join(serialized_lines)))
 
343
 
 
344
    def test_unversioned_non_root_errors(self):
 
345
        old_inv = Inventory(None)
 
346
        new_inv = Inventory(None)
 
347
        root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
 
348
        root.revision = 'a@e\xc3\xa5ample.com--2004'
 
349
        new_inv.add(root)
 
350
        non_root = new_inv.make_entry('directory', 'foo', root.file_id, 'id')
 
351
        new_inv.add(non_root)
 
352
        delta = new_inv._make_delta(old_inv)
 
353
        serializer = inventory_delta.InventoryDeltaSerializer(
 
354
            versioned_root=True, tree_references=True)
 
355
        err = self.assertRaises(InventoryDeltaError,
 
356
            serializer.delta_to_lines, NULL_REVISION, 'entry-version', delta)
 
357
        self.assertEqual(str(err), 'no version for fileid id')
 
358
 
 
359
    def test_richroot_unversioned_root_errors(self):
 
360
        old_inv = Inventory(None)
 
361
        new_inv = Inventory(None)
 
362
        root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
 
363
        new_inv.add(root)
 
364
        delta = new_inv._make_delta(old_inv)
 
365
        serializer = inventory_delta.InventoryDeltaSerializer(
 
366
            versioned_root=True, tree_references=True)
 
367
        err = self.assertRaises(InventoryDeltaError,
 
368
            serializer.delta_to_lines, NULL_REVISION, 'entry-version', delta)
 
369
        self.assertEqual(str(err), 'no version for fileid TREE_ROOT')
 
370
 
 
371
    def test_nonrichroot_versioned_root_errors(self):
 
372
        old_inv = Inventory(None)
 
373
        new_inv = Inventory(None)
 
374
        root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
 
375
        root.revision = 'a@e\xc3\xa5ample.com--2004'
 
376
        new_inv.add(root)
 
377
        delta = new_inv._make_delta(old_inv)
 
378
        serializer = inventory_delta.InventoryDeltaSerializer(
 
379
            versioned_root=False, tree_references=True)
 
380
        err = self.assertRaises(InventoryDeltaError,
 
381
            serializer.delta_to_lines, NULL_REVISION, 'entry-version', delta)
 
382
        self.assertStartsWith(str(err), 'Version present for / in TREE_ROOT')
 
383
 
 
384
    def test_unknown_kind_errors(self):
 
385
        old_inv = Inventory(None)
 
386
        new_inv = Inventory(None)
 
387
        root = new_inv.make_entry('directory', '', None, 'my-rich-root-id')
 
388
        root.revision = 'changed'
 
389
        new_inv.add(root)
 
390
        non_root = new_inv.make_entry('directory', 'foo', root.file_id, 'id')
 
391
        non_root.revision = 'changed'
 
392
        non_root.kind = 'strangelove'
 
393
        new_inv.add(non_root)
 
394
        delta = new_inv._make_delta(old_inv)
 
395
        serializer = inventory_delta.InventoryDeltaSerializer(
 
396
            versioned_root=True, tree_references=True)
 
397
        # we expect keyerror because there is little value wrapping this.
 
398
        # This test aims to prove that it errors more than how it errors.
 
399
        err = self.assertRaises(KeyError,
 
400
            serializer.delta_to_lines, NULL_REVISION, 'entry-version', delta)
 
401
        self.assertEqual(('strangelove',), err.args)
 
402
 
 
403
    def test_tree_reference_disabled(self):
 
404
        old_inv = Inventory(None)
 
405
        new_inv = Inventory(None)
 
406
        root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
 
407
        root.revision = 'a@e\xc3\xa5ample.com--2004'
 
408
        new_inv.add(root)
 
409
        non_root = new_inv.make_entry(
 
410
            'tree-reference', 'foo', root.file_id, 'id')
 
411
        non_root.revision = 'changed'
 
412
        non_root.reference_revision = 'subtree-version'
 
413
        new_inv.add(non_root)
 
414
        delta = new_inv._make_delta(old_inv)
 
415
        serializer = inventory_delta.InventoryDeltaSerializer(
 
416
            versioned_root=True, tree_references=False)
 
417
        # we expect keyerror because there is little value wrapping this.
 
418
        # This test aims to prove that it errors more than how it errors.
 
419
        err = self.assertRaises(KeyError,
 
420
            serializer.delta_to_lines, NULL_REVISION, 'entry-version', delta)
 
421
        self.assertEqual(('tree-reference',), err.args)
 
422
 
 
423
    def test_tree_reference_enabled(self):
 
424
        old_inv = Inventory(None)
 
425
        new_inv = Inventory(None)
 
426
        root = new_inv.make_entry('directory', '', None, 'TREE_ROOT')
 
427
        root.revision = 'a@e\xc3\xa5ample.com--2004'
 
428
        new_inv.add(root)
 
429
        non_root = new_inv.make_entry(
 
430
            'tree-reference', 'foo', root.file_id, 'id')
 
431
        non_root.revision = 'changed'
 
432
        non_root.reference_revision = 'subtree-version'
 
433
        new_inv.add(non_root)
 
434
        delta = new_inv._make_delta(old_inv)
 
435
        serializer = inventory_delta.InventoryDeltaSerializer(
 
436
            versioned_root=True, tree_references=True)
 
437
        self.assertEqual(StringIO(reference_lines).readlines(),
 
438
            serializer.delta_to_lines(NULL_REVISION, 'entry-version', delta))
 
439
 
 
440
    def test_to_inventory_root_id_versioned_not_permitted(self):
 
441
        root_entry = inventory.make_entry('directory', '', None, 'TREE_ROOT')
 
442
        root_entry.revision = 'some-version'
 
443
        delta = [(None, '', 'TREE_ROOT', root_entry)]
 
444
        serializer = inventory_delta.InventoryDeltaSerializer(
 
445
            versioned_root=False, tree_references=True)
 
446
        self.assertRaises(
 
447
            InventoryDeltaError, serializer.delta_to_lines, 'old-version',
 
448
            'new-version', delta)
 
449
 
 
450
    def test_to_inventory_root_id_not_versioned(self):
 
451
        delta = [(None, '', 'an-id', inventory.make_entry(
 
452
            'directory', '', None, 'an-id'))]
 
453
        serializer = inventory_delta.InventoryDeltaSerializer(
 
454
            versioned_root=True, tree_references=True)
 
455
        self.assertRaises(
 
456
            InventoryDeltaError, serializer.delta_to_lines, 'old-version',
 
457
            'new-version', delta)
 
458
 
 
459
    def test_to_inventory_has_tree_not_meant_to(self):
 
460
        make_entry = inventory.make_entry
 
461
        tree_ref = make_entry('tree-reference', 'foo', 'changed-in', 'ref-id')
 
462
        tree_ref.reference_revision = 'ref-revision'
 
463
        delta = [
 
464
            (None, '', 'an-id',
 
465
             make_entry('directory', '', 'changed-in', 'an-id')),
 
466
            (None, 'foo', 'ref-id', tree_ref)
 
467
            # a file that followed the root move
 
468
            ]
 
469
        serializer = inventory_delta.InventoryDeltaSerializer(
 
470
            versioned_root=True, tree_references=True)
 
471
        self.assertRaises(InventoryDeltaError, serializer.delta_to_lines,
 
472
            'old-version', 'new-version', delta)
 
473
 
 
474
    def test_to_inventory_torture(self):
 
475
        def make_entry(kind, name, parent_id, file_id, **attrs):
 
476
            entry = inventory.make_entry(kind, name, parent_id, file_id)
 
477
            for name, value in attrs.items():
 
478
                setattr(entry, name, value)
 
479
            return entry
 
480
        # this delta is crafted to have all the following:
 
481
        # - deletes
 
482
        # - renamed roots
 
483
        # - deep dirs
 
484
        # - files moved after parent dir was renamed
 
485
        # - files with and without exec bit
 
486
        delta = [
 
487
            # new root:
 
488
            (None, '', 'new-root-id',
 
489
                make_entry('directory', '', None, 'new-root-id',
 
490
                    revision='changed-in')),
 
491
            # an old root:
 
492
            ('', 'old-root', 'TREE_ROOT',
 
493
                make_entry('directory', 'subdir-now', 'new-root-id',
 
494
                'TREE_ROOT', revision='moved-root')),
 
495
            # a file that followed the root move
 
496
            ('under-old-root', 'old-root/under-old-root', 'moved-id',
 
497
                make_entry('file', 'under-old-root', 'TREE_ROOT', 'moved-id',
 
498
                   revision='old-rev', executable=False, text_size=30,
 
499
                   text_sha1='some-sha')),
 
500
            # a deleted path
 
501
            ('old-file', None, 'deleted-id', None),
 
502
            # a tree reference moved to the new root
 
503
            ('ref', 'ref', 'ref-id',
 
504
                make_entry('tree-reference', 'ref', 'new-root-id', 'ref-id',
 
505
                    reference_revision='tree-reference-id',
 
506
                    revision='new-rev')),
 
507
            # a symlink now in a deep dir
 
508
            ('dir/link', 'old-root/dir/link', 'link-id',
 
509
                make_entry('symlink', 'link', 'deep-id', 'link-id',
 
510
                   symlink_target='target', revision='new-rev')),
 
511
            # a deep dir
 
512
            ('dir', 'old-root/dir', 'deep-id',
 
513
                make_entry('directory', 'dir', 'TREE_ROOT', 'deep-id',
 
514
                    revision='new-rev')),
 
515
            # a file with an exec bit set
 
516
            (None, 'configure', 'exec-id',
 
517
                make_entry('file', 'configure', 'new-root-id', 'exec-id',
 
518
                   executable=True, text_size=30, text_sha1='some-sha',
 
519
                   revision='old-rev')),
 
520
            ]
 
521
        serializer = inventory_delta.InventoryDeltaSerializer(
 
522
            versioned_root=True, tree_references=True)
 
523
        lines = serializer.delta_to_lines(NULL_REVISION, 'something', delta)
 
524
        expected = """format: bzr inventory delta v1 (bzr 1.14)
 
525
parent: null:
 
526
version: something
 
527
versioned_root: true
 
528
tree_references: true
 
529
/\x00/old-root\x00TREE_ROOT\x00new-root-id\x00moved-root\x00dir
 
530
/dir\x00/old-root/dir\x00deep-id\x00TREE_ROOT\x00new-rev\x00dir
 
531
/dir/link\x00/old-root/dir/link\x00link-id\x00deep-id\x00new-rev\x00link\x00target
 
532
/old-file\x00None\x00deleted-id\x00\x00null:\x00deleted\x00\x00
 
533
/ref\x00/ref\x00ref-id\x00new-root-id\x00new-rev\x00tree\x00tree-reference-id
 
534
/under-old-root\x00/old-root/under-old-root\x00moved-id\x00TREE_ROOT\x00old-rev\x00file\x0030\x00\x00some-sha
 
535
None\x00/\x00new-root-id\x00\x00changed-in\x00dir
 
536
None\x00/configure\x00exec-id\x00new-root-id\x00old-rev\x00file\x0030\x00Y\x00some-sha
 
537
"""
 
538
        serialized = ''.join(lines)
 
539
        self.assertIsInstance(serialized, str)
 
540
        self.assertEqual(expected, serialized)
 
541
 
 
542
 
 
543
class TestContent(TestCase):
 
544
    """Test serialization of the content part of a line."""
 
545
 
 
546
    def test_dir(self):
 
547
        entry = inventory.make_entry('directory', 'a dir', None)
 
548
        self.assertEqual('dir', inventory_delta._directory_content(entry))
 
549
 
 
550
    def test_file_0_short_sha(self):
 
551
        file_entry = inventory.make_entry('file', 'a file', None, 'file-id')
 
552
        file_entry.text_sha1 = ''
 
553
        file_entry.text_size = 0
 
554
        self.assertEqual('file\x000\x00\x00',
 
555
            inventory_delta._file_content(file_entry))
 
556
 
 
557
    def test_file_10_foo(self):
 
558
        file_entry = inventory.make_entry('file', 'a file', None, 'file-id')
 
559
        file_entry.text_sha1 = 'foo'
 
560
        file_entry.text_size = 10
 
561
        self.assertEqual('file\x0010\x00\x00foo',
 
562
            inventory_delta._file_content(file_entry))
 
563
 
 
564
    def test_file_executable(self):
 
565
        file_entry = inventory.make_entry('file', 'a file', None, 'file-id')
 
566
        file_entry.executable = True
 
567
        file_entry.text_sha1 = 'foo'
 
568
        file_entry.text_size = 10
 
569
        self.assertEqual('file\x0010\x00Y\x00foo',
 
570
            inventory_delta._file_content(file_entry))
 
571
 
 
572
    def test_file_without_size(self):
 
573
        file_entry = inventory.make_entry('file', 'a file', None, 'file-id')
 
574
        file_entry.text_sha1 = 'foo'
 
575
        self.assertRaises(InventoryDeltaError,
 
576
            inventory_delta._file_content, file_entry)
 
577
 
 
578
    def test_file_without_sha1(self):
 
579
        file_entry = inventory.make_entry('file', 'a file', None, 'file-id')
 
580
        file_entry.text_size = 10
 
581
        self.assertRaises(InventoryDeltaError,
 
582
            inventory_delta._file_content, file_entry)
 
583
 
 
584
    def test_link_empty_target(self):
 
585
        entry = inventory.make_entry('symlink', 'a link', None)
 
586
        entry.symlink_target = ''
 
587
        self.assertEqual('link\x00',
 
588
            inventory_delta._link_content(entry))
 
589
 
 
590
    def test_link_unicode_target(self):
 
591
        entry = inventory.make_entry('symlink', 'a link', None)
 
592
        entry.symlink_target = ' \xc3\xa5'.decode('utf8')
 
593
        self.assertEqual('link\x00 \xc3\xa5',
 
594
            inventory_delta._link_content(entry))
 
595
 
 
596
    def test_link_space_target(self):
 
597
        entry = inventory.make_entry('symlink', 'a link', None)
 
598
        entry.symlink_target = ' '
 
599
        self.assertEqual('link\x00 ',
 
600
            inventory_delta._link_content(entry))
 
601
 
 
602
    def test_link_no_target(self):
 
603
        entry = inventory.make_entry('symlink', 'a link', None)
 
604
        self.assertRaises(InventoryDeltaError,
 
605
            inventory_delta._link_content, entry)
 
606
 
 
607
    def test_reference_null(self):
 
608
        entry = inventory.make_entry('tree-reference', 'a tree', None)
 
609
        entry.reference_revision = NULL_REVISION
 
610
        self.assertEqual('tree\x00null:',
 
611
            inventory_delta._reference_content(entry))
 
612
 
 
613
    def test_reference_revision(self):
 
614
        entry = inventory.make_entry('tree-reference', 'a tree', None)
 
615
        entry.reference_revision = 'foo@\xc3\xa5b-lah'
 
616
        self.assertEqual('tree\x00foo@\xc3\xa5b-lah',
 
617
            inventory_delta._reference_content(entry))
 
618
 
 
619
    def test_reference_no_reference(self):
 
620
        entry = inventory.make_entry('tree-reference', 'a tree', None)
 
621
        self.assertRaises(InventoryDeltaError,
 
622
            inventory_delta._reference_content, entry)