/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 breezy/tests/test_inv.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-19 13:16:11 UTC
  • mto: (6968.4.3 git-archive)
  • mto: This revision was merged to the branch mainline in revision 6972.
  • Revision ID: jelmer@jelmer.uk-20180519131611-l9h9ud41j7qg1m03
Move tar/zip to breezy.archive.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
 
from bzrlib import (
19
 
    chk_map,
20
 
    groupcompress,
21
 
    bzrdir,
 
18
from .. import (
22
19
    errors,
23
 
    inventory,
24
20
    osutils,
25
21
    repository,
26
22
    revision,
27
23
    tests,
28
 
    )
29
 
from bzrlib.inventory import (CHKInventory, Inventory, ROOT_ID, InventoryFile,
30
 
    InventoryDirectory, InventoryEntry, TreeReference)
31
 
from bzrlib.tests import (
 
24
    workingtree,
 
25
    )
 
26
from ..bzr import (
 
27
    chk_map,
 
28
    groupcompress,
 
29
    inventory,
 
30
    )
 
31
from ..bzr.inventory import (
 
32
    CHKInventory,
 
33
    Inventory,
 
34
    ROOT_ID,
 
35
    InventoryFile,
 
36
    InventoryDirectory,
 
37
    InventoryEntry,
 
38
    TreeReference,
 
39
    mutable_inventory_from_tree,
 
40
    )
 
41
from . import (
32
42
    TestCase,
33
43
    TestCaseWithTransport,
34
 
    condition_isinstance,
35
 
    multiply_tests,
36
 
    split_suite_by_condition,
37
44
    )
38
 
from bzrlib.tests.per_workingtree import workingtree_formats
39
 
 
40
 
 
41
 
def load_tests(standard_tests, module, loader):
42
 
    """Parameterise some inventory tests."""
43
 
    to_adapt, result = split_suite_by_condition(standard_tests,
44
 
        condition_isinstance(TestDeltaApplication))
 
45
from .scenarios import load_tests_apply_scenarios
 
46
 
 
47
 
 
48
load_tests = load_tests_apply_scenarios
 
49
 
 
50
 
 
51
def delta_application_scenarios():
45
52
    scenarios = [
46
53
        ('Inventory', {'apply_delta':apply_inventory_Inventory}),
47
54
        ]
52
59
    # just creating trees.
53
60
    formats = set()
54
61
    for _, format in repository.format_registry.iteritems():
55
 
        scenarios.append((str(format.__name__), {
56
 
            'apply_delta':apply_inventory_Repository_add_inventory_by_delta,
57
 
            'format':format}))
58
 
    for format in workingtree_formats():
 
62
        if format.supports_full_versioned_files:
 
63
            scenarios.append((str(format.__name__), {
 
64
                'apply_delta':apply_inventory_Repository_add_inventory_by_delta,
 
65
                'format':format}))
 
66
    for format in workingtree.format_registry._get_all():
 
67
        repo_fmt = format._matchingcontroldir.repository_format
 
68
        if not repo_fmt.supports_full_versioned_files:
 
69
            continue
59
70
        scenarios.append(
60
71
            (str(format.__class__.__name__) + ".update_basis_by_delta", {
61
72
            'apply_delta':apply_inventory_WT_basis,
64
75
            (str(format.__class__.__name__) + ".apply_inventory_delta", {
65
76
            'apply_delta':apply_inventory_WT,
66
77
            'format':format}))
67
 
    return multiply_tests(to_adapt, scenarios, result)
 
78
    return scenarios
68
79
 
69
80
 
70
81
def create_texts_for_inv(repo, inv):
74
85
        else:
75
86
            lines = []
76
87
        repo.texts.add_lines((ie.file_id, ie.revision), [], lines)
77
 
    
78
 
def apply_inventory_Inventory(self, basis, delta):
 
88
 
 
89
 
 
90
def apply_inventory_Inventory(self, basis, delta, invalid_delta=True):
79
91
    """Apply delta to basis and return the result.
80
 
    
 
92
 
81
93
    :param basis: An inventory to be used as the basis.
82
94
    :param delta: The inventory delta to apply:
83
95
    :return: An inventory resulting from the application.
86
98
    return basis
87
99
 
88
100
 
89
 
def apply_inventory_WT(self, basis, delta):
 
101
def apply_inventory_WT(self, basis, delta, invalid_delta=True):
90
102
    """Apply delta to basis and return the result.
91
103
 
92
104
    This sets the tree state to be basis, and then calls apply_inventory_delta.
93
 
    
 
105
 
94
106
    :param basis: An inventory to be used as the basis.
95
107
    :param delta: The inventory delta to apply:
96
108
    :return: An inventory resulting from the application.
97
109
    """
98
 
    control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
 
110
    control = self.make_controldir('tree', format=self.format._matchingcontroldir)
99
111
    control.create_repository()
100
112
    control.create_branch()
101
113
    tree = self.format.initialize(control)
105
117
    finally:
106
118
        tree.unlock()
107
119
    # Fresh object, reads disk again.
108
 
    tree = tree.bzrdir.open_workingtree()
 
120
    tree = tree.controldir.open_workingtree()
109
121
    tree.lock_write()
110
122
    try:
111
123
        tree.apply_inventory_delta(delta)
112
124
    finally:
113
125
        tree.unlock()
114
126
    # reload tree - ensure we get what was written.
115
 
    tree = tree.bzrdir.open_workingtree()
 
127
    tree = tree.controldir.open_workingtree()
116
128
    tree.lock_read()
117
129
    self.addCleanup(tree.unlock)
118
 
    # One could add 'tree._validate' here but that would cause 'early' failues 
119
 
    # as far as higher level code is concerned. Possibly adding an
120
 
    # expect_fail parameter to this function and if that is False then do a
121
 
    # validate call.
122
 
    return tree.inventory
123
 
 
124
 
 
125
 
def apply_inventory_WT_basis(self, basis, delta):
 
130
    if not invalid_delta:
 
131
        tree._validate()
 
132
    return tree.root_inventory
 
133
 
 
134
 
 
135
def _create_repo_revisions(repo, basis, delta, invalid_delta):
 
136
    repo.start_write_group()
 
137
    try:
 
138
        rev = revision.Revision('basis', timestamp=0, timezone=None,
 
139
            message="", committer="foo@example.com")
 
140
        basis.revision_id = 'basis'
 
141
        create_texts_for_inv(repo, basis)
 
142
        repo.add_revision('basis', rev, basis)
 
143
        if invalid_delta:
 
144
            # We don't want to apply the delta to the basis, because we expect
 
145
            # the delta is invalid.
 
146
            result_inv = basis
 
147
            result_inv.revision_id = b'result'
 
148
            target_entries = None
 
149
        else:
 
150
            result_inv = basis.create_by_apply_delta(delta, 'result')
 
151
            create_texts_for_inv(repo, result_inv)
 
152
            target_entries = list(result_inv.iter_entries_by_dir())
 
153
        rev = revision.Revision('result', timestamp=0, timezone=None,
 
154
            message="", committer="foo@example.com")
 
155
        repo.add_revision('result', rev, result_inv)
 
156
        repo.commit_write_group()
 
157
    except:
 
158
        repo.abort_write_group()
 
159
        raise
 
160
    return target_entries
 
161
 
 
162
 
 
163
def _get_basis_entries(tree):
 
164
    basis_tree = tree.basis_tree()
 
165
    basis_tree.lock_read()
 
166
    basis_tree_entries = list(basis_tree.inventory.iter_entries_by_dir())
 
167
    basis_tree.unlock()
 
168
    return basis_tree_entries
 
169
 
 
170
 
 
171
def _populate_different_tree(tree, basis, delta):
 
172
    """Put all entries into tree, but at a unique location."""
 
173
    added_ids = set()
 
174
    added_paths = set()
 
175
    tree.add(['unique-dir'], [b'unique-dir-id'], ['directory'])
 
176
    for path, ie in basis.iter_entries_by_dir():
 
177
        if ie.file_id in added_ids:
 
178
            continue
 
179
        # We want a unique path for each of these, we use the file-id
 
180
        tree.add(['unique-dir/' + ie.file_id], [ie.file_id], [ie.kind])
 
181
        added_ids.add(ie.file_id)
 
182
    for old_path, new_path, file_id, ie in delta:
 
183
        if file_id in added_ids:
 
184
            continue
 
185
        tree.add(['unique-dir/' + file_id], [file_id], [ie.kind])
 
186
 
 
187
 
 
188
def apply_inventory_WT_basis(test, basis, delta, invalid_delta=True):
126
189
    """Apply delta to basis and return the result.
127
190
 
128
191
    This sets the parent and then calls update_basis_by_delta.
130
193
    allow safety checks made by the WT to succeed, and finally ensures that all
131
194
    items in the delta with a new path are present in the WT before calling
132
195
    update_basis_by_delta.
133
 
    
 
196
 
134
197
    :param basis: An inventory to be used as the basis.
135
198
    :param delta: The inventory delta to apply:
136
199
    :return: An inventory resulting from the application.
137
200
    """
138
 
    control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
 
201
    control = test.make_controldir('tree', format=test.format._matchingcontroldir)
139
202
    control.create_repository()
140
203
    control.create_branch()
141
 
    tree = self.format.initialize(control)
 
204
    tree = test.format.initialize(control)
142
205
    tree.lock_write()
143
206
    try:
144
 
        repo = tree.branch.repository
145
 
        repo.start_write_group()
146
 
        try:
147
 
            rev = revision.Revision('basis', timestamp=0, timezone=None,
148
 
                message="", committer="foo@example.com")
149
 
            basis.revision_id = 'basis'
150
 
            create_texts_for_inv(tree.branch.repository, basis)
151
 
            repo.add_revision('basis', rev, basis)
152
 
            # Add a revision for the result, with the basis content - 
153
 
            # update_basis_by_delta doesn't check that the delta results in
154
 
            # result, and we want inconsistent deltas to get called on the
155
 
            # tree, or else the code isn't actually checked.
156
 
            rev = revision.Revision('result', timestamp=0, timezone=None,
157
 
                message="", committer="foo@example.com")
158
 
            basis.revision_id = 'result'
159
 
            repo.add_revision('result', rev, basis)
160
 
            repo.commit_write_group()
161
 
        except:
162
 
            repo.abort_write_group()
163
 
            raise
 
207
        target_entries = _create_repo_revisions(tree.branch.repository, basis,
 
208
                                                delta, invalid_delta)
164
209
        # Set the basis state as the trees current state
165
210
        tree._write_inventory(basis)
166
211
        # This reads basis from the repo and puts it into the tree's local
167
212
        # cache, if it has one.
168
213
        tree.set_parent_ids(['basis'])
169
 
        paths = {}
170
 
        parents = set()
171
 
        for old, new, id, entry in delta:
172
 
            if None in (new, entry):
173
 
                continue
174
 
            paths[new] = (entry.file_id, entry.kind)
175
 
            parents.add(osutils.dirname(new))
176
 
        parents = osutils.minimum_path_selection(parents)
177
 
        parents.discard('')
178
 
        # Put place holders in the tree to permit adding the other entries.
179
 
        for pos, parent in enumerate(parents):
180
 
            if not tree.path2id(parent):
181
 
                # add a synthetic directory in the tree so we can can put the
182
 
                # tree0 entries in place for dirstate.
183
 
                tree.add([parent], ["id%d" % pos], ["directory"])
184
 
        if paths:
185
 
            # Many deltas may cause this mini-apply to fail, but we want to see what
186
 
            # the delta application code says, not the prep that we do to deal with 
187
 
            # limitations of dirstate's update_basis code.
188
 
            for path, (file_id, kind) in sorted(paths.items()):
189
 
                try:
190
 
                    tree.add([path], [file_id], [kind])
191
 
                except (KeyboardInterrupt, SystemExit):
192
 
                    raise
193
 
                except:
194
 
                    pass
195
214
    finally:
196
215
        tree.unlock()
197
216
    # Fresh lock, reads disk again.
198
217
    tree.lock_write()
199
218
    try:
200
219
        tree.update_basis_by_delta('result', delta)
 
220
        if not invalid_delta:
 
221
            tree._validate()
201
222
    finally:
202
223
        tree.unlock()
203
224
    # reload tree - ensure we get what was written.
204
 
    tree = tree.bzrdir.open_workingtree()
 
225
    tree = tree.controldir.open_workingtree()
205
226
    basis_tree = tree.basis_tree()
206
227
    basis_tree.lock_read()
207
 
    self.addCleanup(basis_tree.unlock)
208
 
    # Note, that if the tree does not have a local cache, the trick above of
209
 
    # setting the result as the basis, will come back to bite us. That said,
210
 
    # all the implementations in bzr do have a local cache.
211
 
    return basis_tree.inventory
212
 
 
213
 
 
214
 
def apply_inventory_Repository_add_inventory_by_delta(self, basis, delta):
 
228
    test.addCleanup(basis_tree.unlock)
 
229
    basis_inv = basis_tree.root_inventory
 
230
    if target_entries:
 
231
        basis_entries = list(basis_inv.iter_entries_by_dir())
 
232
        test.assertEqual(target_entries, basis_entries)
 
233
    return basis_inv
 
234
 
 
235
 
 
236
def apply_inventory_Repository_add_inventory_by_delta(self, basis, delta,
 
237
                                                      invalid_delta=True):
215
238
    """Apply delta to basis and return the result.
216
239
    
217
240
    This inserts basis as a whole inventory and then uses
222
245
    :return: An inventory resulting from the application.
223
246
    """
224
247
    format = self.format()
225
 
    control = self.make_bzrdir('tree', format=format._matchingbzrdir)
 
248
    control = self.make_controldir('tree', format=format._matchingcontroldir)
226
249
    repo = format.initialize(control)
227
250
    repo.lock_write()
228
251
    try:
253
276
    finally:
254
277
        repo.unlock()
255
278
    # Fresh lock, reads disk again.
256
 
    repo = repo.bzrdir.open_repository()
 
279
    repo = repo.controldir.open_repository()
257
280
    repo.lock_read()
258
281
    self.addCleanup(repo.unlock)
259
282
    return repo.get_inventory('result')
263
286
 
264
287
    def test_creation_from_root_id(self):
265
288
        # iff a root id is passed to the constructor, a root directory is made
266
 
        inv = inventory.Inventory(root_id='tree-root')
 
289
        inv = inventory.Inventory(root_id=b'tree-root')
267
290
        self.assertNotEqual(None, inv.root)
268
 
        self.assertEqual('tree-root', inv.root.file_id)
 
291
        self.assertEqual(b'tree-root', inv.root.file_id)
269
292
 
270
293
    def test_add_path_of_root(self):
271
294
        # if no root id is given at creation time, there is no root directory
272
295
        inv = inventory.Inventory(root_id=None)
273
296
        self.assertIs(None, inv.root)
274
297
        # add a root entry by adding its path
275
 
        ie = inv.add_path("", "directory", "my-root")
276
 
        ie.revision = 'test-rev'
277
 
        self.assertEqual("my-root", ie.file_id)
 
298
        ie = inv.add_path(u"", "directory", b"my-root")
 
299
        ie.revision = b'test-rev'
 
300
        self.assertEqual(b"my-root", ie.file_id)
278
301
        self.assertIs(ie, inv.root)
279
302
 
280
303
    def test_add_path(self):
281
 
        inv = inventory.Inventory(root_id='tree_root')
282
 
        ie = inv.add_path('hello', 'file', 'hello-id')
283
 
        self.assertEqual('hello-id', ie.file_id)
 
304
        inv = inventory.Inventory(root_id=b'tree_root')
 
305
        ie = inv.add_path(u'hello', 'file', b'hello-id')
 
306
        self.assertEqual(b'hello-id', ie.file_id)
284
307
        self.assertEqual('file', ie.kind)
285
308
 
286
309
    def test_copy(self):
287
310
        """Make sure copy() works and creates a deep copy."""
288
 
        inv = inventory.Inventory(root_id='some-tree-root')
289
 
        ie = inv.add_path('hello', 'file', 'hello-id')
 
311
        inv = inventory.Inventory(root_id=b'some-tree-root')
 
312
        ie = inv.add_path(u'hello', 'file', b'hello-id')
290
313
        inv2 = inv.copy()
291
 
        inv.root.file_id = 'some-new-root'
292
 
        ie.name = 'file2'
293
 
        self.assertEqual('some-tree-root', inv2.root.file_id)
294
 
        self.assertEqual('hello', inv2['hello-id'].name)
 
314
        inv.root.file_id = b'some-new-root'
 
315
        ie.name = u'file2'
 
316
        self.assertEqual(b'some-tree-root', inv2.root.file_id)
 
317
        self.assertEqual(u'hello', inv2.get_entry(b'hello-id').name)
295
318
 
296
319
    def test_copy_empty(self):
297
320
        """Make sure an empty inventory can be copied."""
301
324
 
302
325
    def test_copy_copies_root_revision(self):
303
326
        """Make sure the revision of the root gets copied."""
304
 
        inv = inventory.Inventory(root_id='someroot')
305
 
        inv.root.revision = 'therev'
 
327
        inv = inventory.Inventory(root_id=b'someroot')
 
328
        inv.root.revision = b'therev'
306
329
        inv2 = inv.copy()
307
 
        self.assertEquals('someroot', inv2.root.file_id)
308
 
        self.assertEquals('therev', inv2.root.revision)
 
330
        self.assertEqual(b'someroot', inv2.root.file_id)
 
331
        self.assertEqual(b'therev', inv2.root.revision)
309
332
 
310
333
    def test_create_tree_reference(self):
311
 
        inv = inventory.Inventory('tree-root-123')
312
 
        inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
313
 
                              revision='rev', reference_revision='rev2'))
 
334
        inv = inventory.Inventory(b'tree-root-123')
 
335
        inv.add(TreeReference(
 
336
            b'nested-id', 'nested', parent_id=b'tree-root-123',
 
337
            revision=b'rev', reference_revision=b'rev2'))
314
338
 
315
339
    def test_error_encoding(self):
316
 
        inv = inventory.Inventory('tree-root')
317
 
        inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
 
340
        inv = inventory.Inventory(b'tree-root')
 
341
        inv.add(InventoryFile(b'a-id', u'\u1234', b'tree-root'))
318
342
        e = self.assertRaises(errors.InconsistentDelta, inv.add,
319
 
            InventoryFile('b-id', u'\u1234', 'tree-root'))
 
343
            InventoryFile(b'b-id', u'\u1234', b'tree-root'))
320
344
        self.assertContainsRe(str(e), r'\\u1234')
321
345
 
322
346
    def test_add_recursive(self):
323
 
        parent = InventoryDirectory('src-id', 'src', 'tree-root')
324
 
        child = InventoryFile('hello-id', 'hello.c', 'src-id')
 
347
        parent = InventoryDirectory(b'src-id', 'src', b'tree-root')
 
348
        child = InventoryFile(b'hello-id', 'hello.c', b'src-id')
325
349
        parent.children[child.file_id] = child
326
 
        inv = inventory.Inventory('tree-root')
 
350
        inv = inventory.Inventory(b'tree-root')
327
351
        inv.add(parent)
328
 
        self.assertEqual('src/hello.c', inv.id2path('hello-id'))
 
352
        self.assertEqual('src/hello.c', inv.id2path(b'hello-id'))
329
353
 
330
354
 
331
355
 
332
356
class TestDeltaApplication(TestCaseWithTransport):
 
357
 
 
358
    scenarios = delta_application_scenarios()
333
359
 
334
360
    def get_empty_inventory(self, reference_inv=None):
335
361
        """Get an empty inventory.
350
376
            inv.root.revision = 'basis'
351
377
        return inv
352
378
 
 
379
    def make_file_ie(self, file_id=b'file-id', name='name', parent_id=None):
 
380
        ie_file = inventory.InventoryFile(file_id, name, parent_id)
 
381
        ie_file.revision = b'result'
 
382
        ie_file.text_size = 0
 
383
        ie_file.text_sha1 = ''
 
384
        return ie_file
 
385
 
353
386
    def test_empty_delta(self):
354
387
        inv = self.get_empty_inventory()
355
388
        delta = []
360
393
    def test_None_file_id(self):
361
394
        inv = self.get_empty_inventory()
362
395
        dir1 = inventory.InventoryDirectory(None, 'dir1', inv.root.file_id)
363
 
        dir1.revision = 'result'
 
396
        dir1.revision = b'result'
364
397
        delta = [(None, u'dir1', None, dir1)]
365
398
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
366
399
            inv, delta)
368
401
    def test_unicode_file_id(self):
369
402
        inv = self.get_empty_inventory()
370
403
        dir1 = inventory.InventoryDirectory(u'dirid', 'dir1', inv.root.file_id)
371
 
        dir1.revision = 'result'
 
404
        dir1.revision = b'result'
372
405
        delta = [(None, u'dir1', dir1.file_id, dir1)]
373
406
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
374
407
            inv, delta)
376
409
    def test_repeated_file_id(self):
377
410
        inv = self.get_empty_inventory()
378
411
        file1 = inventory.InventoryFile('id', 'path1', inv.root.file_id)
379
 
        file1.revision = 'result'
 
412
        file1.revision = b'result'
380
413
        file1.text_size = 0
381
414
        file1.text_sha1 = ""
382
 
        file2 = inventory.InventoryFile('id', 'path2', inv.root.file_id)
383
 
        file2.revision = 'result'
384
 
        file2.text_size = 0
385
 
        file2.text_sha1 = ""
 
415
        file2 = file1.copy()
 
416
        file2.name = 'path2'
386
417
        delta = [(None, u'path1', 'id', file1), (None, u'path2', 'id', file2)]
387
418
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
388
419
            inv, delta)
390
421
    def test_repeated_new_path(self):
391
422
        inv = self.get_empty_inventory()
392
423
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
393
 
        file1.revision = 'result'
 
424
        file1.revision = b'result'
394
425
        file1.text_size = 0
395
426
        file1.text_sha1 = ""
396
 
        file2 = inventory.InventoryFile('id2', 'path', inv.root.file_id)
397
 
        file2.revision = 'result'
398
 
        file2.text_size = 0
399
 
        file2.text_sha1 = ""
 
427
        file2 = file1.copy()
 
428
        file2.file_id = 'id2'
400
429
        delta = [(None, u'path', 'id1', file1), (None, u'path', 'id2', file2)]
401
430
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
402
431
            inv, delta)
404
433
    def test_repeated_old_path(self):
405
434
        inv = self.get_empty_inventory()
406
435
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
407
 
        file1.revision = 'result'
 
436
        file1.revision = b'result'
408
437
        file1.text_size = 0
409
438
        file1.text_sha1 = ""
410
439
        # We can't *create* a source inventory with the same path, but
414
443
        # location. Alternatively, we could have a repeated fileid, but that
415
444
        # is separately checked for.
416
445
        file2 = inventory.InventoryFile('id2', 'path2', inv.root.file_id)
417
 
        file2.revision = 'result'
 
446
        file2.revision = b'result'
418
447
        file2.text_size = 0
419
448
        file2.text_sha1 = ""
420
449
        inv.add(file1)
426
455
    def test_mismatched_id_entry_id(self):
427
456
        inv = self.get_empty_inventory()
428
457
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
429
 
        file1.revision = 'result'
 
458
        file1.revision = b'result'
430
459
        file1.text_size = 0
431
460
        file1.text_sha1 = ""
432
461
        delta = [(None, u'path', 'id', file1)]
442
471
    def test_mismatched_new_path_None_entry(self):
443
472
        inv = self.get_empty_inventory()
444
473
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
445
 
        file1.revision = 'result'
 
474
        file1.revision = b'result'
446
475
        file1.text_size = 0
447
476
        file1.text_sha1 = ""
448
477
        delta = [(u"path", None, 'id1', file1)]
452
481
    def test_parent_is_not_directory(self):
453
482
        inv = self.get_empty_inventory()
454
483
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
455
 
        file1.revision = 'result'
 
484
        file1.revision = b'result'
456
485
        file1.text_size = 0
457
486
        file1.text_sha1 = ""
458
487
        file2 = inventory.InventoryFile('id2', 'path2', 'id1')
459
 
        file2.revision = 'result'
 
488
        file2.revision = b'result'
460
489
        file2.text_size = 0
461
490
        file2.text_sha1 = ""
462
491
        inv.add(file1)
467
496
    def test_parent_is_missing(self):
468
497
        inv = self.get_empty_inventory()
469
498
        file2 = inventory.InventoryFile('id2', 'path2', 'missingparent')
470
 
        file2.revision = 'result'
 
499
        file2.revision = b'result'
471
500
        file2.text_size = 0
472
501
        file2.text_sha1 = ""
473
502
        delta = [(None, u'path/path2', 'id2', file2)]
477
506
    def test_new_parent_path_has_wrong_id(self):
478
507
        inv = self.get_empty_inventory()
479
508
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
480
 
        parent1.revision = 'result'
 
509
        parent1.revision = b'result'
481
510
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
482
 
        parent2.revision = 'result'
 
511
        parent2.revision = b'result'
483
512
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
484
 
        file1.revision = 'result'
 
513
        file1.revision = b'result'
485
514
        file1.text_size = 0
486
515
        file1.text_sha1 = ""
487
516
        inv.add(parent1)
495
524
    def test_old_parent_path_is_wrong(self):
496
525
        inv = self.get_empty_inventory()
497
526
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
498
 
        parent1.revision = 'result'
 
527
        parent1.revision = b'result'
499
528
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
500
 
        parent2.revision = 'result'
 
529
        parent2.revision = b'result'
501
530
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
502
 
        file1.revision = 'result'
 
531
        file1.revision = b'result'
503
532
        file1.text_size = 0
504
533
        file1.text_sha1 = ""
505
534
        inv.add(parent1)
514
543
    def test_old_parent_path_is_for_other_id(self):
515
544
        inv = self.get_empty_inventory()
516
545
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
517
 
        parent1.revision = 'result'
 
546
        parent1.revision = b'result'
518
547
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
519
 
        parent2.revision = 'result'
 
548
        parent2.revision = b'result'
520
549
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
521
 
        file1.revision = 'result'
 
550
        file1.revision = b'result'
522
551
        file1.text_size = 0
523
552
        file1.text_sha1 = ""
524
553
        file2 = inventory.InventoryFile('id2', 'path', 'p-1')
525
 
        file2.revision = 'result'
 
554
        file2.revision = b'result'
526
555
        file2.text_size = 0
527
556
        file2.text_sha1 = ""
528
557
        inv.add(parent1)
539
568
    def test_add_existing_id_new_path(self):
540
569
        inv = self.get_empty_inventory()
541
570
        parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
542
 
        parent1.revision = 'result'
 
571
        parent1.revision = b'result'
543
572
        parent2 = inventory.InventoryDirectory('p-1', 'dir2', inv.root.file_id)
544
 
        parent2.revision = 'result'
 
573
        parent2.revision = b'result'
545
574
        inv.add(parent1)
546
575
        delta = [(None, u'dir2', 'p-1', parent2)]
547
576
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
550
579
    def test_add_new_id_existing_path(self):
551
580
        inv = self.get_empty_inventory()
552
581
        parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
553
 
        parent1.revision = 'result'
 
582
        parent1.revision = b'result'
554
583
        parent2 = inventory.InventoryDirectory('p-2', 'dir1', inv.root.file_id)
555
 
        parent2.revision = 'result'
 
584
        parent2.revision = b'result'
556
585
        inv.add(parent1)
557
586
        delta = [(None, u'dir1', 'p-2', parent2)]
558
587
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
561
590
    def test_remove_dir_leaving_dangling_child(self):
562
591
        inv = self.get_empty_inventory()
563
592
        dir1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
564
 
        dir1.revision = 'result'
 
593
        dir1.revision = b'result'
565
594
        dir2 = inventory.InventoryDirectory('p-2', 'child1', 'p-1')
566
 
        dir2.revision = 'result'
 
595
        dir2.revision = b'result'
567
596
        dir3 = inventory.InventoryDirectory('p-3', 'child2', 'p-1')
568
 
        dir3.revision = 'result'
 
597
        dir3.revision = b'result'
569
598
        inv.add(dir1)
570
599
        inv.add(dir2)
571
600
        inv.add(dir3)
574
603
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
575
604
            inv, delta)
576
605
 
577
 
 
578
 
class TestInventory(TestCase):
 
606
    def test_add_file(self):
 
607
        inv = self.get_empty_inventory()
 
608
        file1 = inventory.InventoryFile(b'file-id', 'path', inv.root.file_id)
 
609
        file1.revision = b'result'
 
610
        file1.text_size = 0
 
611
        file1.text_sha1 = ''
 
612
        delta = [(None, u'path', b'file-id', file1)]
 
613
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
614
        self.assertEqual(b'file-id', res_inv.get_entry(b'file-id').file_id)
 
615
 
 
616
    def test_remove_file(self):
 
617
        inv = self.get_empty_inventory()
 
618
        file1 = inventory.InventoryFile(b'file-id', 'path', inv.root.file_id)
 
619
        file1.revision = b'result'
 
620
        file1.text_size = 0
 
621
        file1.text_sha1 = ''
 
622
        inv.add(file1)
 
623
        delta = [(u'path', None, b'file-id', None)]
 
624
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
625
        self.assertEqual(None, res_inv.path2id('path'))
 
626
        self.assertRaises(errors.NoSuchId, res_inv.id2path, b'file-id')
 
627
 
 
628
    def test_rename_file(self):
 
629
        inv = self.get_empty_inventory()
 
630
        file1 = self.make_file_ie(name='path', parent_id=inv.root.file_id)
 
631
        inv.add(file1)
 
632
        file2 = self.make_file_ie(name='path2', parent_id=inv.root.file_id)
 
633
        delta = [(u'path', 'path2', b'file-id', file2)]
 
634
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
635
        self.assertEqual(None, res_inv.path2id('path'))
 
636
        self.assertEqual(b'file-id', res_inv.path2id('path2'))
 
637
 
 
638
    def test_replaced_at_new_path(self):
 
639
        inv = self.get_empty_inventory()
 
640
        file1 = self.make_file_ie(file_id=b'id1', parent_id=inv.root.file_id)
 
641
        inv.add(file1)
 
642
        file2 = self.make_file_ie(file_id=b'id2', parent_id=inv.root.file_id)
 
643
        delta = [(u'name', None, b'id1', None),
 
644
                 (None, u'name', b'id2', file2)]
 
645
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
646
        self.assertEqual(b'id2', res_inv.path2id('name'))
 
647
 
 
648
    def test_rename_dir(self):
 
649
        inv = self.get_empty_inventory()
 
650
        dir1 = inventory.InventoryDirectory(b'dir-id', 'dir1', inv.root.file_id)
 
651
        dir1.revision = b'basis'
 
652
        file1 = self.make_file_ie(parent_id=b'dir-id')
 
653
        inv.add(dir1)
 
654
        inv.add(file1)
 
655
        dir2 = inventory.InventoryDirectory(b'dir-id', 'dir2', inv.root.file_id)
 
656
        dir2.revision = b'result'
 
657
        delta = [('dir1', 'dir2', b'dir-id', dir2)]
 
658
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
659
        # The file should be accessible under the new path
 
660
        self.assertEqual(b'file-id', res_inv.path2id('dir2/name'))
 
661
 
 
662
    def test_renamed_dir_with_renamed_child(self):
 
663
        inv = self.get_empty_inventory()
 
664
        dir1 = inventory.InventoryDirectory(b'dir-id', 'dir1', inv.root.file_id)
 
665
        dir1.revision = b'basis'
 
666
        file1 = self.make_file_ie(b'file-id-1', 'name1', parent_id=b'dir-id')
 
667
        file2 = self.make_file_ie(b'file-id-2', 'name2', parent_id=b'dir-id')
 
668
        inv.add(dir1)
 
669
        inv.add(file1)
 
670
        inv.add(file2)
 
671
        dir2 = inventory.InventoryDirectory(b'dir-id', 'dir2', inv.root.file_id)
 
672
        dir2.revision = b'result'
 
673
        file2b = self.make_file_ie(b'file-id-2', 'name2', inv.root.file_id)
 
674
        delta = [('dir1', 'dir2', b'dir-id', dir2),
 
675
                 ('dir1/name2', 'name2', b'file-id-2', file2b)]
 
676
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
677
        # The file should be accessible under the new path
 
678
        self.assertEqual(b'file-id-1', res_inv.path2id('dir2/name1'))
 
679
        self.assertEqual(None, res_inv.path2id('dir2/name2'))
 
680
        self.assertEqual(b'file-id-2', res_inv.path2id('name2'))
579
681
 
580
682
    def test_is_root(self):
581
683
        """Ensure our root-checking code is accurate."""
590
692
        self.assertFalse(inv.is_root('TREE_ROOT'))
591
693
        self.assertFalse(inv.is_root('booga'))
592
694
 
 
695
    def test_entries_for_empty_inventory(self):
 
696
        """Test that entries() will not fail for an empty inventory"""
 
697
        inv = Inventory(root_id=None)
 
698
        self.assertEqual([], inv.entries())
 
699
 
593
700
 
594
701
class TestInventoryEntry(TestCase):
595
702
 
 
703
    def test_file_invalid_entry_name(self):
 
704
        self.assertRaises(errors.InvalidEntryName, inventory.InventoryFile,
 
705
            '123', 'a/hello.c', ROOT_ID)
 
706
 
 
707
    def test_file_backslash(self):
 
708
        file = inventory.InventoryFile('123', 'h\\ello.c', ROOT_ID)
 
709
        self.assertEquals(file.name, 'h\\ello.c')
 
710
 
596
711
    def test_file_kind_character(self):
597
712
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
598
713
        self.assertEqual(file.kind_character(), '')
607
722
 
608
723
    def test_dir_detect_changes(self):
609
724
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
610
 
        left.text_sha1 = 123
611
 
        left.executable = True
612
 
        left.symlink_target='foo'
613
725
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
614
 
        right.text_sha1 = 321
615
 
        right.symlink_target='bar'
616
726
        self.assertEqual((False, False), left.detect_changes(right))
617
727
        self.assertEqual((False, False), right.detect_changes(left))
618
728
 
632
742
 
633
743
    def test_symlink_detect_changes(self):
634
744
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
635
 
        left.text_sha1 = 123
636
 
        left.executable = True
637
745
        left.symlink_target='foo'
638
746
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
639
 
        right.text_sha1 = 321
640
747
        right.symlink_target='foo'
641
748
        self.assertEqual((False, False), left.detect_changes(right))
642
749
        self.assertEqual((False, False), right.detect_changes(left))
646
753
 
647
754
    def test_file_has_text(self):
648
755
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
649
 
        self.failUnless(file.has_text())
 
756
        self.assertTrue(file.has_text())
650
757
 
651
758
    def test_directory_has_text(self):
652
759
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
653
 
        self.failIf(dir.has_text())
 
760
        self.assertFalse(dir.has_text())
654
761
 
655
762
    def test_link_has_text(self):
656
763
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
657
 
        self.failIf(link.has_text())
 
764
        self.assertFalse(link.has_text())
658
765
 
659
766
    def test_make_entry(self):
660
767
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
833
940
        inv.revision_id = "revid"
834
941
        inv.root.revision = "rootrev"
835
942
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
836
 
        inv["fileid"].revision = "filerev"
837
 
        inv["fileid"].executable = True
838
 
        inv["fileid"].text_sha1 = "ffff"
839
 
        inv["fileid"].text_size = 1
 
943
        inv.get_entry("fileid").revision = "filerev"
 
944
        inv.get_entry("fileid").executable = True
 
945
        inv.get_entry("fileid").text_sha1 = "ffff"
 
946
        inv.get_entry("fileid").text_size = 1
840
947
        chk_bytes = self.get_chk_bytes()
841
948
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
842
949
        bytes = ''.join(chk_inv.to_lines())
843
950
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
844
 
        root_entry = new_inv[inv.root.file_id]
 
951
        root_entry = new_inv.get_entry(inv.root.file_id)
845
952
        self.assertEqual(None, root_entry._children)
846
 
        self.assertEqual(['file'], root_entry.children.keys())
847
 
        file_direct = new_inv["fileid"]
 
953
        self.assertEqual({'file'}, set(root_entry.children))
 
954
        file_direct = new_inv.get_entry("fileid")
848
955
        file_found = root_entry.children['file']
849
956
        self.assertEqual(file_direct.kind, file_found.kind)
850
957
        self.assertEqual(file_direct.file_id, file_found.file_id)
870
977
        self.assertEqual(120, p_id_basename._root_node.maximum_size)
871
978
        self.assertEqual(2, p_id_basename._root_node._key_width)
872
979
 
873
 
    def test___iter__(self):
 
980
    def test_iter_all_ids(self):
874
981
        inv = Inventory()
875
982
        inv.revision_id = "revid"
876
983
        inv.root.revision = "rootrev"
877
984
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
878
 
        inv["fileid"].revision = "filerev"
879
 
        inv["fileid"].executable = True
880
 
        inv["fileid"].text_sha1 = "ffff"
881
 
        inv["fileid"].text_size = 1
 
985
        inv.get_entry("fileid").revision = "filerev"
 
986
        inv.get_entry("fileid").executable = True
 
987
        inv.get_entry("fileid").text_sha1 = "ffff"
 
988
        inv.get_entry("fileid").text_size = 1
882
989
        chk_bytes = self.get_chk_bytes()
883
990
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
884
991
        bytes = ''.join(chk_inv.to_lines())
885
992
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
886
 
        fileids = list(new_inv.__iter__())
887
 
        fileids.sort()
 
993
        fileids = sorted(new_inv.iter_all_ids())
888
994
        self.assertEqual([inv.root.file_id, "fileid"], fileids)
889
995
 
890
996
    def test__len__(self):
892
998
        inv.revision_id = "revid"
893
999
        inv.root.revision = "rootrev"
894
1000
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
895
 
        inv["fileid"].revision = "filerev"
896
 
        inv["fileid"].executable = True
897
 
        inv["fileid"].text_sha1 = "ffff"
898
 
        inv["fileid"].text_size = 1
 
1001
        inv.get_entry("fileid").revision = "filerev"
 
1002
        inv.get_entry("fileid").executable = True
 
1003
        inv.get_entry("fileid").text_sha1 = "ffff"
 
1004
        inv.get_entry("fileid").text_size = 1
899
1005
        chk_bytes = self.get_chk_bytes()
900
1006
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
901
1007
        self.assertEqual(2, len(chk_inv))
902
1008
 
903
 
    def test___getitem__(self):
 
1009
    def test_get_entry(self):
904
1010
        inv = Inventory()
905
 
        inv.revision_id = "revid"
906
 
        inv.root.revision = "rootrev"
907
 
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
908
 
        inv["fileid"].revision = "filerev"
909
 
        inv["fileid"].executable = True
910
 
        inv["fileid"].text_sha1 = "ffff"
911
 
        inv["fileid"].text_size = 1
 
1011
        inv.revision_id = b"revid"
 
1012
        inv.root.revision = b"rootrev"
 
1013
        inv.add(InventoryFile(b"fileid", u"file", inv.root.file_id))
 
1014
        inv.get_entry(b"fileid").revision = b"filerev"
 
1015
        inv.get_entry(b"fileid").executable = True
 
1016
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1017
        inv.get_entry(b"fileid").text_size = 1
912
1018
        chk_bytes = self.get_chk_bytes()
913
1019
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
914
 
        bytes = ''.join(chk_inv.to_lines())
915
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
916
 
        root_entry = new_inv[inv.root.file_id]
917
 
        file_entry = new_inv["fileid"]
 
1020
        data = b''.join(chk_inv.to_lines())
 
1021
        new_inv = CHKInventory.deserialise(chk_bytes, data, (b"revid",))
 
1022
        root_entry = new_inv.get_entry(inv.root.file_id)
 
1023
        file_entry = new_inv.get_entry(b"fileid")
918
1024
        self.assertEqual("directory", root_entry.kind)
919
1025
        self.assertEqual(inv.root.file_id, root_entry.file_id)
920
1026
        self.assertEqual(inv.root.parent_id, root_entry.parent_id)
921
1027
        self.assertEqual(inv.root.name, root_entry.name)
922
 
        self.assertEqual("rootrev", root_entry.revision)
 
1028
        self.assertEqual(b"rootrev", root_entry.revision)
923
1029
        self.assertEqual("file", file_entry.kind)
924
 
        self.assertEqual("fileid", file_entry.file_id)
 
1030
        self.assertEqual(b"fileid", file_entry.file_id)
925
1031
        self.assertEqual(inv.root.file_id, file_entry.parent_id)
926
 
        self.assertEqual("file", file_entry.name)
927
 
        self.assertEqual("filerev", file_entry.revision)
928
 
        self.assertEqual("ffff", file_entry.text_sha1)
 
1032
        self.assertEqual(u"file", file_entry.name)
 
1033
        self.assertEqual(b"filerev", file_entry.revision)
 
1034
        self.assertEqual(b"ffff", file_entry.text_sha1)
929
1035
        self.assertEqual(1, file_entry.text_size)
930
1036
        self.assertEqual(True, file_entry.executable)
931
 
        self.assertRaises(errors.NoSuchId, new_inv.__getitem__, 'missing')
 
1037
        self.assertRaises(errors.NoSuchId, new_inv.get_entry, 'missing')
932
1038
 
933
1039
    def test_has_id_true(self):
934
1040
        inv = Inventory()
935
 
        inv.revision_id = "revid"
936
 
        inv.root.revision = "rootrev"
937
 
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
938
 
        inv["fileid"].revision = "filerev"
939
 
        inv["fileid"].executable = True
940
 
        inv["fileid"].text_sha1 = "ffff"
941
 
        inv["fileid"].text_size = 1
 
1041
        inv.revision_id = b"revid"
 
1042
        inv.root.revision = b"rootrev"
 
1043
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
1044
        inv.get_entry(b"fileid").revision = b"filerev"
 
1045
        inv.get_entry(b"fileid").executable = True
 
1046
        inv.get_entry(b"fileid").text_sha1 = "ffff"
 
1047
        inv.get_entry(b"fileid").text_size = 1
942
1048
        chk_bytes = self.get_chk_bytes()
943
1049
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
944
 
        self.assertTrue(chk_inv.has_id('fileid'))
 
1050
        self.assertTrue(chk_inv.has_id(b'fileid'))
945
1051
        self.assertTrue(chk_inv.has_id(inv.root.file_id))
946
1052
 
947
1053
    def test_has_id_not(self):
948
1054
        inv = Inventory()
949
 
        inv.revision_id = "revid"
950
 
        inv.root.revision = "rootrev"
 
1055
        inv.revision_id = b"revid"
 
1056
        inv.root.revision = b"rootrev"
951
1057
        chk_bytes = self.get_chk_bytes()
952
1058
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
953
 
        self.assertFalse(chk_inv.has_id('fileid'))
 
1059
        self.assertFalse(chk_inv.has_id(b'fileid'))
954
1060
 
955
1061
    def test_id2path(self):
956
1062
        inv = Inventory()
957
 
        inv.revision_id = "revid"
958
 
        inv.root.revision = "rootrev"
959
 
        direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
 
1063
        inv.revision_id = b"revid"
 
1064
        inv.root.revision = b"rootrev"
 
1065
        direntry = InventoryDirectory(b"dirid", "dir", inv.root.file_id)
960
1066
        fileentry = InventoryFile("fileid", "file", "dirid")
961
1067
        inv.add(direntry)
962
1068
        inv.add(fileentry)
963
 
        inv["fileid"].revision = "filerev"
964
 
        inv["fileid"].executable = True
965
 
        inv["fileid"].text_sha1 = "ffff"
966
 
        inv["fileid"].text_size = 1
967
 
        inv["dirid"].revision = "filerev"
 
1069
        inv.get_entry(b"fileid").revision = b"filerev"
 
1070
        inv.get_entry(b"fileid").executable = True
 
1071
        inv.get_entry(b"fileid").text_sha1 = "ffff"
 
1072
        inv.get_entry(b"fileid").text_size = 1
 
1073
        inv.get_entry(b"dirid").revision = b"filerev"
968
1074
        chk_bytes = self.get_chk_bytes()
969
1075
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
970
1076
        bytes = ''.join(chk_inv.to_lines())
971
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1077
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, (b"revid",))
972
1078
        self.assertEqual('', new_inv.id2path(inv.root.file_id))
973
 
        self.assertEqual('dir', new_inv.id2path('dirid'))
974
 
        self.assertEqual('dir/file', new_inv.id2path('fileid'))
 
1079
        self.assertEqual('dir', new_inv.id2path(b'dirid'))
 
1080
        self.assertEqual('dir/file', new_inv.id2path(b'fileid'))
975
1081
 
976
1082
    def test_path2id(self):
977
1083
        inv = Inventory()
978
 
        inv.revision_id = "revid"
979
 
        inv.root.revision = "rootrev"
980
 
        direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
981
 
        fileentry = InventoryFile("fileid", "file", "dirid")
 
1084
        inv.revision_id = b"revid"
 
1085
        inv.root.revision = b"rootrev"
 
1086
        direntry = InventoryDirectory(b"dirid", "dir", inv.root.file_id)
 
1087
        fileentry = InventoryFile(b"fileid", "file", b"dirid")
982
1088
        inv.add(direntry)
983
1089
        inv.add(fileentry)
984
 
        inv["fileid"].revision = "filerev"
985
 
        inv["fileid"].executable = True
986
 
        inv["fileid"].text_sha1 = "ffff"
987
 
        inv["fileid"].text_size = 1
988
 
        inv["dirid"].revision = "filerev"
 
1090
        inv.get_entry(b"fileid").revision = b"filerev"
 
1091
        inv.get_entry(b"fileid").executable = True
 
1092
        inv.get_entry(b"fileid").text_sha1 = "ffff"
 
1093
        inv.get_entry(b"fileid").text_size = 1
 
1094
        inv.get_entry(b"dirid").revision = b"filerev"
989
1095
        chk_bytes = self.get_chk_bytes()
990
1096
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
991
1097
        bytes = ''.join(chk_inv.to_lines())
992
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1098
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, (b"revid",))
993
1099
        self.assertEqual(inv.root.file_id, new_inv.path2id(''))
994
 
        self.assertEqual('dirid', new_inv.path2id('dir'))
995
 
        self.assertEqual('fileid', new_inv.path2id('dir/file'))
 
1100
        self.assertEqual(b'dirid', new_inv.path2id('dir'))
 
1101
        self.assertEqual(b'fileid', new_inv.path2id('dir/file'))
996
1102
 
997
1103
    def test_create_by_apply_delta_sets_root(self):
998
1104
        inv = Inventory()
1005
1111
        delta = [("", None, base_inv.root.file_id, None),
1006
1112
            (None, "",  "myrootid", inv.root)]
1007
1113
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
1008
 
        self.assertEquals(reference_inv.root, new_inv.root)
 
1114
        self.assertEqual(reference_inv.root, new_inv.root)
1009
1115
 
1010
1116
    def test_create_by_apply_delta_empty_add_child(self):
1011
1117
        inv = Inventory()
1066
1172
        inv.revision_id = "revid"
1067
1173
        inv.root.revision = "rootrev"
1068
1174
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
1069
 
        inv["fileid"].revision = "filerev"
1070
 
        inv["fileid"].executable = True
1071
 
        inv["fileid"].text_sha1 = "ffff"
1072
 
        inv["fileid"].text_size = 1
 
1175
        inv.get_entry("fileid").revision = "filerev"
 
1176
        inv.get_entry("fileid").executable = True
 
1177
        inv.get_entry("fileid").text_sha1 = "ffff"
 
1178
        inv.get_entry("fileid").text_size = 1
1073
1179
        inv2 = Inventory()
1074
1180
        inv2.revision_id = "revid2"
1075
1181
        inv2.root.revision = "rootrev"
1076
1182
        inv2.add(InventoryFile("fileid", "file", inv.root.file_id))
1077
 
        inv2["fileid"].revision = "filerev2"
1078
 
        inv2["fileid"].executable = False
1079
 
        inv2["fileid"].text_sha1 = "bbbb"
1080
 
        inv2["fileid"].text_size = 2
 
1183
        inv2.get_entry("fileid").revision = "filerev2"
 
1184
        inv2.get_entry("fileid").executable = False
 
1185
        inv2.get_entry("fileid").text_sha1 = "bbbb"
 
1186
        inv2.get_entry("fileid").text_size = 2
1081
1187
        # get fresh objects.
1082
1188
        chk_bytes = self.get_chk_bytes()
1083
1189
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
1096
1202
        inv.revision_id = "revid"
1097
1203
        inv.root.revision = "rootrev"
1098
1204
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
1099
 
        inv["fileid"].revision = "filerev"
1100
 
        inv["fileid"].executable = True
1101
 
        inv["fileid"].text_sha1 = "ffff"
1102
 
        inv["fileid"].text_size = 1
 
1205
        inv.get_entry("fileid").revision = "filerev"
 
1206
        inv.get_entry("fileid").executable = True
 
1207
        inv.get_entry("fileid").text_sha1 = "ffff"
 
1208
        inv.get_entry("fileid").text_size = 1
1103
1209
        # get fresh objects.
1104
1210
        chk_bytes = self.get_chk_bytes()
1105
1211
        tmp_inv = CHKInventory.from_inventory(chk_bytes, inv)
1112
1218
 
1113
1219
    def test_file_entry_to_bytes(self):
1114
1220
        inv = CHKInventory(None)
1115
 
        ie = inventory.InventoryFile('file-id', 'filename', 'parent-id')
 
1221
        ie = inventory.InventoryFile(b'file-id', 'filename', 'parent-id')
1116
1222
        ie.executable = True
1117
 
        ie.revision = 'file-rev-id'
 
1223
        ie.revision = b'file-rev-id'
1118
1224
        ie.text_sha1 = 'abcdefgh'
1119
1225
        ie.text_size = 100
1120
1226
        bytes = inv._entry_to_bytes(ie)
1121
 
        self.assertEqual('file: file-id\nparent-id\nfilename\n'
1122
 
                         'file-rev-id\nabcdefgh\n100\nY', bytes)
 
1227
        self.assertEqual(b'file: file-id\nparent-id\nfilename\n'
 
1228
                         b'file-rev-id\nabcdefgh\n100\nY', bytes)
1123
1229
        ie2 = inv._bytes_to_entry(bytes)
1124
1230
        self.assertEqual(ie, ie2)
1125
1231
        self.assertIsInstance(ie2.name, unicode)
1126
 
        self.assertEqual(('filename', 'file-id', 'file-rev-id'),
 
1232
        self.assertEqual(('filename', b'file-id', b'file-rev-id'),
1127
1233
                         inv._bytes_to_utf8name_key(bytes))
1128
1234
 
1129
1235
    def test_file2_entry_to_bytes(self):
1130
1236
        inv = CHKInventory(None)
1131
1237
        # \u30a9 == 'omega'
1132
 
        ie = inventory.InventoryFile('file-id', u'\u03a9name', 'parent-id')
 
1238
        ie = inventory.InventoryFile(b'file-id', u'\u03a9name', b'parent-id')
1133
1239
        ie.executable = False
1134
 
        ie.revision = 'file-rev-id'
 
1240
        ie.revision = b'file-rev-id'
1135
1241
        ie.text_sha1 = '123456'
1136
1242
        ie.text_size = 25
1137
1243
        bytes = inv._entry_to_bytes(ie)
1138
 
        self.assertEqual('file: file-id\nparent-id\n\xce\xa9name\n'
1139
 
                         'file-rev-id\n123456\n25\nN', bytes)
 
1244
        self.assertEqual(b'file: file-id\nparent-id\n\xce\xa9name\n'
 
1245
                         b'file-rev-id\n123456\n25\nN', bytes)
1140
1246
        ie2 = inv._bytes_to_entry(bytes)
1141
1247
        self.assertEqual(ie, ie2)
1142
1248
        self.assertIsInstance(ie2.name, unicode)
1143
 
        self.assertEqual(('\xce\xa9name', 'file-id', 'file-rev-id'),
 
1249
        self.assertEqual((b'\xce\xa9name', b'file-id', b'file-rev-id'),
1144
1250
                         inv._bytes_to_utf8name_key(bytes))
1145
1251
 
1146
1252
    def test_dir_entry_to_bytes(self):
1147
1253
        inv = CHKInventory(None)
1148
 
        ie = inventory.InventoryDirectory('dir-id', 'dirname', 'parent-id')
1149
 
        ie.revision = 'dir-rev-id'
 
1254
        ie = inventory.InventoryDirectory(b'dir-id', 'dirname', b'parent-id')
 
1255
        ie.revision = b'dir-rev-id'
1150
1256
        bytes = inv._entry_to_bytes(ie)
1151
 
        self.assertEqual('dir: dir-id\nparent-id\ndirname\ndir-rev-id', bytes)
 
1257
        self.assertEqual(b'dir: dir-id\nparent-id\ndirname\ndir-rev-id', bytes)
1152
1258
        ie2 = inv._bytes_to_entry(bytes)
1153
1259
        self.assertEqual(ie, ie2)
1154
1260
        self.assertIsInstance(ie2.name, unicode)
1155
 
        self.assertEqual(('dirname', 'dir-id', 'dir-rev-id'),
 
1261
        self.assertEqual(('dirname', b'dir-id', b'dir-rev-id'),
1156
1262
                         inv._bytes_to_utf8name_key(bytes))
1157
1263
 
1158
1264
    def test_dir2_entry_to_bytes(self):
1159
1265
        inv = CHKInventory(None)
1160
 
        ie = inventory.InventoryDirectory('dir-id', u'dir\u03a9name',
 
1266
        ie = inventory.InventoryDirectory(b'dir-id', u'dir\u03a9name',
1161
1267
                                          None)
1162
 
        ie.revision = 'dir-rev-id'
 
1268
        ie.revision = b'dir-rev-id'
1163
1269
        bytes = inv._entry_to_bytes(ie)
1164
 
        self.assertEqual('dir: dir-id\n\ndir\xce\xa9name\n'
1165
 
                         'dir-rev-id', bytes)
 
1270
        self.assertEqual(b'dir: dir-id\n\ndir\xce\xa9name\n'
 
1271
                         b'dir-rev-id', bytes)
1166
1272
        ie2 = inv._bytes_to_entry(bytes)
1167
1273
        self.assertEqual(ie, ie2)
1168
1274
        self.assertIsInstance(ie2.name, unicode)
1169
1275
        self.assertIs(ie2.parent_id, None)
1170
 
        self.assertEqual(('dir\xce\xa9name', 'dir-id', 'dir-rev-id'),
 
1276
        self.assertEqual(('dir\xce\xa9name', b'dir-id', b'dir-rev-id'),
1171
1277
                         inv._bytes_to_utf8name_key(bytes))
1172
1278
 
1173
1279
    def test_symlink_entry_to_bytes(self):
1205
1311
        ie = inventory.TreeReference('tree-root-id', u'tree\u03a9name',
1206
1312
                                     'parent-id')
1207
1313
        ie.revision = 'tree-rev-id'
1208
 
        ie.reference_revision = 'ref-rev-id'
 
1314
        ie.reference_revision = b'ref-rev-id'
1209
1315
        bytes = inv._entry_to_bytes(ie)
1210
1316
        self.assertEqual('tree: tree-root-id\nparent-id\ntree\xce\xa9name\n'
1211
1317
                         'tree-rev-id\nref-rev-id', bytes)
1215
1321
        self.assertEqual(('tree\xce\xa9name', 'tree-root-id', 'tree-rev-id'),
1216
1322
                         inv._bytes_to_utf8name_key(bytes))
1217
1323
 
 
1324
    def make_basic_utf8_inventory(self):
 
1325
        inv = Inventory()
 
1326
        inv.revision_id = "revid"
 
1327
        inv.root.revision = "rootrev"
 
1328
        root_id = inv.root.file_id
 
1329
        inv.add(InventoryFile("fileid", u'f\xefle', root_id))
 
1330
        inv.get_entry("fileid").revision = "filerev"
 
1331
        inv.get_entry("fileid").text_sha1 = "ffff"
 
1332
        inv.get_entry("fileid").text_size = 0
 
1333
        inv.add(InventoryDirectory("dirid", u'dir-\N{EURO SIGN}', root_id))
 
1334
        inv.add(InventoryFile("childid", u'ch\xefld', "dirid"))
 
1335
        inv.get_entry("childid").revision = "filerev"
 
1336
        inv.get_entry("childid").text_sha1 = "ffff"
 
1337
        inv.get_entry("childid").text_size = 0
 
1338
        chk_bytes = self.get_chk_bytes()
 
1339
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
 
1340
        bytes = ''.join(chk_inv.to_lines())
 
1341
        return CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1342
 
 
1343
    def test__preload_handles_utf8(self):
 
1344
        new_inv = self.make_basic_utf8_inventory()
 
1345
        self.assertEqual({}, new_inv._fileid_to_entry_cache)
 
1346
        self.assertFalse(new_inv._fully_cached)
 
1347
        new_inv._preload_cache()
 
1348
        self.assertEqual(
 
1349
            sorted([new_inv.root_id, "fileid", "dirid", "childid"]),
 
1350
            sorted(new_inv._fileid_to_entry_cache.keys()))
 
1351
        ie_root = new_inv._fileid_to_entry_cache[new_inv.root_id]
 
1352
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1353
                         sorted(ie_root._children.keys()))
 
1354
        ie_dir = new_inv._fileid_to_entry_cache['dirid']
 
1355
        self.assertEqual([u'ch\xefld'], sorted(ie_dir._children.keys()))
 
1356
 
 
1357
    def test__preload_populates_cache(self):
 
1358
        inv = Inventory()
 
1359
        inv.revision_id = "revid"
 
1360
        inv.root.revision = "rootrev"
 
1361
        root_id = inv.root.file_id
 
1362
        inv.add(InventoryFile("fileid", "file", root_id))
 
1363
        inv.get_entry("fileid").revision = "filerev"
 
1364
        inv.get_entry("fileid").executable = True
 
1365
        inv.get_entry("fileid").text_sha1 = "ffff"
 
1366
        inv.get_entry("fileid").text_size = 1
 
1367
        inv.add(InventoryDirectory("dirid", "dir", root_id))
 
1368
        inv.add(InventoryFile("childid", "child", "dirid"))
 
1369
        inv.get_entry("childid").revision = "filerev"
 
1370
        inv.get_entry("childid").executable = False
 
1371
        inv.get_entry("childid").text_sha1 = "dddd"
 
1372
        inv.get_entry("childid").text_size = 1
 
1373
        chk_bytes = self.get_chk_bytes()
 
1374
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
 
1375
        bytes = ''.join(chk_inv.to_lines())
 
1376
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1377
        self.assertEqual({}, new_inv._fileid_to_entry_cache)
 
1378
        self.assertFalse(new_inv._fully_cached)
 
1379
        new_inv._preload_cache()
 
1380
        self.assertEqual(
 
1381
            sorted([root_id, "fileid", "dirid", "childid"]),
 
1382
            sorted(new_inv._fileid_to_entry_cache.keys()))
 
1383
        self.assertTrue(new_inv._fully_cached)
 
1384
        ie_root = new_inv._fileid_to_entry_cache[root_id]
 
1385
        self.assertEqual(['dir', 'file'], sorted(ie_root._children.keys()))
 
1386
        ie_dir = new_inv._fileid_to_entry_cache['dirid']
 
1387
        self.assertEqual(['child'], sorted(ie_dir._children.keys()))
 
1388
 
 
1389
    def test__preload_handles_partially_evaluated_inventory(self):
 
1390
        new_inv = self.make_basic_utf8_inventory()
 
1391
        ie = new_inv.get_entry(new_inv.root_id)
 
1392
        self.assertIs(None, ie._children)
 
1393
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1394
                         sorted(ie.children.keys()))
 
1395
        # Accessing .children loads _children
 
1396
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1397
                         sorted(ie._children.keys()))
 
1398
        new_inv._preload_cache()
 
1399
        # No change
 
1400
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1401
                         sorted(ie._children.keys()))
 
1402
        ie_dir = new_inv.get_entry("dirid")
 
1403
        self.assertEqual([u'ch\xefld'],
 
1404
                         sorted(ie_dir._children.keys()))
 
1405
 
 
1406
    def test_filter_change_in_renamed_subfolder(self):
 
1407
        inv = Inventory('tree-root')
 
1408
        src_ie = inv.add_path('src', 'directory', 'src-id')
 
1409
        inv.add_path('src/sub/', 'directory', 'sub-id')
 
1410
        a_ie = inv.add_path('src/sub/a', 'file', 'a-id')
 
1411
        a_ie.text_sha1 = osutils.sha_string('content\n')
 
1412
        a_ie.text_size = len('content\n')
 
1413
        chk_bytes = self.get_chk_bytes()
 
1414
        inv = CHKInventory.from_inventory(chk_bytes, inv)
 
1415
        inv = inv.create_by_apply_delta([
 
1416
            ("src/sub/a", "src/sub/a", "a-id", a_ie),
 
1417
            ("src", "src2", "src-id", src_ie),
 
1418
            ], 'new-rev-2')
 
1419
        new_inv = inv.filter(['a-id', 'src-id'])
 
1420
        self.assertEqual([
 
1421
            ('', 'tree-root'),
 
1422
            ('src', 'src-id'),
 
1423
            ('src/sub', 'sub-id'),
 
1424
            ('src/sub/a', 'a-id'),
 
1425
            ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()])
1218
1426
 
1219
1427
class TestCHKInventoryExpand(tests.TestCaseWithMemoryTransport):
1220
1428
 
1224
1432
        return factory(trans)
1225
1433
 
1226
1434
    def make_dir(self, inv, name, parent_id):
1227
 
        inv.add(inv.make_entry('directory', name, parent_id, name + '-id'))
 
1435
        inv.add(inv.make_entry('directory', name, parent_id, name.encode('utf-8') + b'-id'))
1228
1436
 
1229
1437
    def make_file(self, inv, name, parent_id, content='content\n'):
1230
1438
        ie = inv.make_entry('file', name, parent_id, name + '-id')
1257
1465
        #  use a small maximum_size to force internal paging structures
1258
1466
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
1259
1467
                        maximum_size=100,
1260
 
                        search_key_name='hash-255-way')
1261
 
        bytes = ''.join(chk_inv.to_lines())
1262
 
        return CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1468
                        search_key_name=b'hash-255-way')
 
1469
        bytes = b''.join(chk_inv.to_lines())
 
1470
        return CHKInventory.deserialise(chk_bytes, bytes, (b"revid",))
1263
1471
 
1264
1472
    def assert_Getitems(self, expected_fileids, inv, file_ids):
1265
1473
        self.assertEqual(sorted(expected_fileids),
1275
1483
            s = expected_children.setdefault(entry.parent_id, [])
1276
1484
            s.append(entry.file_id)
1277
1485
        val_children = dict((k, sorted(v)) for k, v
1278
 
                            in val_children.iteritems())
 
1486
                            in val_children.items())
1279
1487
        expected_children = dict((k, sorted(v)) for k, v
1280
 
                            in expected_children.iteritems())
 
1488
                            in expected_children.items())
1281
1489
        self.assertEqual(expected_children, val_children)
1282
1490
 
1283
1491
    def test_make_simple_inventory(self):
1346
1554
        inv = self.make_simple_inventory()
1347
1555
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id', 'top-id',
1348
1556
                           'subsub-file1-id'], inv, ['top-id', 'subsub-file1-id'])
 
1557
 
 
1558
 
 
1559
class TestMutableInventoryFromTree(TestCaseWithTransport):
 
1560
 
 
1561
    def test_empty(self):
 
1562
        repository = self.make_repository('.')
 
1563
        tree = repository.revision_tree(revision.NULL_REVISION)
 
1564
        inv = mutable_inventory_from_tree(tree)
 
1565
        self.assertEqual(revision.NULL_REVISION, inv.revision_id)
 
1566
        self.assertEqual(0, len(inv))
 
1567
 
 
1568
    def test_some_files(self):
 
1569
        wt = self.make_branch_and_tree('.')
 
1570
        self.build_tree(['a'])
 
1571
        wt.add(['a'], ['thefileid'])
 
1572
        revid = wt.commit("commit")
 
1573
        tree = wt.branch.repository.revision_tree(revid)
 
1574
        inv = mutable_inventory_from_tree(tree)
 
1575
        self.assertEqual(revid, inv.revision_id)
 
1576
        self.assertEqual(2, len(inv))
 
1577
        self.assertEqual("a", inv.get_entry('thefileid').name)
 
1578
        # The inventory should be mutable and independent of
 
1579
        # the original tree
 
1580
        self.assertFalse(tree.root_inventory.get_entry('thefileid').executable)
 
1581
        inv.get_entry('thefileid').executable = True
 
1582
        self.assertFalse(tree.root_inventory.get_entry('thefileid').executable)