/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: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

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 ..sixish import text_type
 
27
from ..bzr import (
 
28
    chk_map,
 
29
    groupcompress,
 
30
    inventory,
 
31
    )
 
32
from ..bzr.inventory import (
 
33
    CHKInventory,
 
34
    Inventory,
 
35
    ROOT_ID,
 
36
    InventoryFile,
 
37
    InventoryDirectory,
 
38
    InventoryEntry,
 
39
    TreeReference,
 
40
    mutable_inventory_from_tree,
 
41
    )
 
42
from . import (
32
43
    TestCase,
33
44
    TestCaseWithTransport,
34
 
    condition_isinstance,
35
 
    multiply_tests,
36
 
    split_suite_by_condition,
37
45
    )
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))
 
46
from .scenarios import load_tests_apply_scenarios
 
47
 
 
48
 
 
49
load_tests = load_tests_apply_scenarios
 
50
 
 
51
 
 
52
def delta_application_scenarios():
45
53
    scenarios = [
46
 
        ('Inventory', {'apply_delta':apply_inventory_Inventory}),
 
54
        ('Inventory', {'apply_delta': apply_inventory_Inventory}),
47
55
        ]
48
56
    # Working tree basis delta application
49
57
    # Repository add_inv_by_delta.
52
60
    # just creating trees.
53
61
    formats = set()
54
62
    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():
 
63
        if format.supports_full_versioned_files:
 
64
            scenarios.append((str(format.__name__), {
 
65
                'apply_delta': apply_inventory_Repository_add_inventory_by_delta,
 
66
                'format': format}))
 
67
    for getter in workingtree.format_registry._get_all_lazy():
 
68
        try:
 
69
            format = getter()
 
70
            if callable(format):
 
71
                format = format()
 
72
        except ImportError:
 
73
            pass  # Format with unmet dependency
 
74
        repo_fmt = format._matchingcontroldir.repository_format
 
75
        if not repo_fmt.supports_full_versioned_files:
 
76
            continue
59
77
        scenarios.append(
60
78
            (str(format.__class__.__name__) + ".update_basis_by_delta", {
61
 
            'apply_delta':apply_inventory_WT_basis,
62
 
            'format':format}))
 
79
                'apply_delta': apply_inventory_WT_basis,
 
80
                'format': format}))
63
81
        scenarios.append(
64
82
            (str(format.__class__.__name__) + ".apply_inventory_delta", {
65
 
            'apply_delta':apply_inventory_WT,
66
 
            'format':format}))
67
 
    return multiply_tests(to_adapt, scenarios, result)
 
83
                'apply_delta': apply_inventory_WT,
 
84
                'format': format}))
 
85
    return scenarios
68
86
 
69
87
 
70
88
def create_texts_for_inv(repo, inv):
71
89
    for path, ie in inv.iter_entries():
72
90
        if ie.text_size:
73
 
            lines = ['a' * ie.text_size]
 
91
            lines = [b'a' * ie.text_size]
74
92
        else:
75
93
            lines = []
76
94
        repo.texts.add_lines((ie.file_id, ie.revision), [], lines)
77
 
    
78
 
def apply_inventory_Inventory(self, basis, delta):
 
95
 
 
96
 
 
97
def apply_inventory_Inventory(self, basis, delta, invalid_delta=True):
79
98
    """Apply delta to basis and return the result.
80
 
    
 
99
 
81
100
    :param basis: An inventory to be used as the basis.
82
101
    :param delta: The inventory delta to apply:
83
102
    :return: An inventory resulting from the application.
86
105
    return basis
87
106
 
88
107
 
89
 
def apply_inventory_WT(self, basis, delta):
 
108
def apply_inventory_WT(self, basis, delta, invalid_delta=True):
90
109
    """Apply delta to basis and return the result.
91
110
 
92
111
    This sets the tree state to be basis, and then calls apply_inventory_delta.
93
 
    
 
112
 
94
113
    :param basis: An inventory to be used as the basis.
95
114
    :param delta: The inventory delta to apply:
96
115
    :return: An inventory resulting from the application.
97
116
    """
98
 
    control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
 
117
    control = self.make_controldir(
 
118
        'tree', format=self.format._matchingcontroldir)
99
119
    control.create_repository()
100
120
    control.create_branch()
101
121
    tree = self.format.initialize(control)
105
125
    finally:
106
126
        tree.unlock()
107
127
    # Fresh object, reads disk again.
108
 
    tree = tree.bzrdir.open_workingtree()
 
128
    tree = tree.controldir.open_workingtree()
109
129
    tree.lock_write()
110
130
    try:
111
131
        tree.apply_inventory_delta(delta)
112
132
    finally:
113
133
        tree.unlock()
114
134
    # reload tree - ensure we get what was written.
115
 
    tree = tree.bzrdir.open_workingtree()
 
135
    tree = tree.controldir.open_workingtree()
116
136
    tree.lock_read()
117
137
    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):
 
138
    if not invalid_delta:
 
139
        tree._validate()
 
140
    return tree.root_inventory
 
141
 
 
142
 
 
143
def _create_repo_revisions(repo, basis, delta, invalid_delta):
 
144
    with repository.WriteGroup(repo):
 
145
        rev = revision.Revision(b'basis', timestamp=0, timezone=None,
 
146
                                message="", committer="foo@example.com")
 
147
        basis.revision_id = b'basis'
 
148
        create_texts_for_inv(repo, basis)
 
149
        repo.add_revision(b'basis', rev, basis)
 
150
        if invalid_delta:
 
151
            # We don't want to apply the delta to the basis, because we expect
 
152
            # the delta is invalid.
 
153
            result_inv = basis
 
154
            result_inv.revision_id = b'result'
 
155
            target_entries = None
 
156
        else:
 
157
            result_inv = basis.create_by_apply_delta(delta, b'result')
 
158
            create_texts_for_inv(repo, result_inv)
 
159
            target_entries = list(result_inv.iter_entries_by_dir())
 
160
        rev = revision.Revision(b'result', timestamp=0, timezone=None,
 
161
                                message="", committer="foo@example.com")
 
162
        repo.add_revision(b'result', rev, result_inv)
 
163
    return target_entries
 
164
 
 
165
 
 
166
def _get_basis_entries(tree):
 
167
    basis_tree = tree.basis_tree()
 
168
    with basis_tree.lock_read():
 
169
        return list(basis_tree.inventory.iter_entries_by_dir())
 
170
 
 
171
 
 
172
def _populate_different_tree(tree, basis, delta):
 
173
    """Put all entries into tree, but at a unique location."""
 
174
    added_ids = set()
 
175
    added_paths = set()
 
176
    tree.add(['unique-dir'], [b'unique-dir-id'], ['directory'])
 
177
    for path, ie in basis.iter_entries_by_dir():
 
178
        if ie.file_id in added_ids:
 
179
            continue
 
180
        # We want a unique path for each of these, we use the file-id
 
181
        tree.add(['unique-dir/' + ie.file_id], [ie.file_id], [ie.kind])
 
182
        added_ids.add(ie.file_id)
 
183
    for old_path, new_path, file_id, ie in delta:
 
184
        if file_id in added_ids:
 
185
            continue
 
186
        tree.add(['unique-dir/' + file_id], [file_id], [ie.kind])
 
187
 
 
188
 
 
189
def apply_inventory_WT_basis(test, basis, delta, invalid_delta=True):
126
190
    """Apply delta to basis and return the result.
127
191
 
128
192
    This sets the parent and then calls update_basis_by_delta.
130
194
    allow safety checks made by the WT to succeed, and finally ensures that all
131
195
    items in the delta with a new path are present in the WT before calling
132
196
    update_basis_by_delta.
133
 
    
 
197
 
134
198
    :param basis: An inventory to be used as the basis.
135
199
    :param delta: The inventory delta to apply:
136
200
    :return: An inventory resulting from the application.
137
201
    """
138
 
    control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
 
202
    control = test.make_controldir(
 
203
        'tree', format=test.format._matchingcontroldir)
139
204
    control.create_repository()
140
205
    control.create_branch()
141
 
    tree = self.format.initialize(control)
 
206
    tree = test.format.initialize(control)
142
207
    tree.lock_write()
143
208
    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
 
209
        target_entries = _create_repo_revisions(tree.branch.repository, basis,
 
210
                                                delta, invalid_delta)
164
211
        # Set the basis state as the trees current state
165
212
        tree._write_inventory(basis)
166
213
        # This reads basis from the repo and puts it into the tree's local
167
214
        # cache, if it has one.
168
 
        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
 
215
        tree.set_parent_ids([b'basis'])
195
216
    finally:
196
217
        tree.unlock()
197
218
    # Fresh lock, reads disk again.
198
 
    tree.lock_write()
199
 
    try:
200
 
        tree.update_basis_by_delta('result', delta)
201
 
    finally:
202
 
        tree.unlock()
 
219
    with tree.lock_write():
 
220
        tree.update_basis_by_delta(b'result', delta)
 
221
        if not invalid_delta:
 
222
            tree._validate()
203
223
    # reload tree - ensure we get what was written.
204
 
    tree = tree.bzrdir.open_workingtree()
 
224
    tree = tree.controldir.open_workingtree()
205
225
    basis_tree = tree.basis_tree()
206
226
    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):
 
227
    test.addCleanup(basis_tree.unlock)
 
228
    basis_inv = basis_tree.root_inventory
 
229
    if target_entries:
 
230
        basis_entries = list(basis_inv.iter_entries_by_dir())
 
231
        test.assertEqual(target_entries, basis_entries)
 
232
    return basis_inv
 
233
 
 
234
 
 
235
def apply_inventory_Repository_add_inventory_by_delta(self, basis, delta,
 
236
                                                      invalid_delta=True):
215
237
    """Apply delta to basis and return the result.
216
 
    
 
238
 
217
239
    This inserts basis as a whole inventory and then uses
218
240
    add_inventory_by_delta to add delta.
219
241
 
222
244
    :return: An inventory resulting from the application.
223
245
    """
224
246
    format = self.format()
225
 
    control = self.make_bzrdir('tree', format=format._matchingbzrdir)
 
247
    control = self.make_controldir('tree', format=format._matchingcontroldir)
226
248
    repo = format.initialize(control)
227
 
    repo.lock_write()
228
 
    try:
229
 
        repo.start_write_group()
230
 
        try:
231
 
            rev = revision.Revision('basis', timestamp=0, timezone=None,
232
 
                message="", committer="foo@example.com")
233
 
            basis.revision_id = 'basis'
234
 
            create_texts_for_inv(repo, basis)
235
 
            repo.add_revision('basis', rev, basis)
236
 
            repo.commit_write_group()
237
 
        except:
238
 
            repo.abort_write_group()
239
 
            raise
240
 
    finally:
241
 
        repo.unlock()
242
 
    repo.lock_write()
243
 
    try:
244
 
        repo.start_write_group()
245
 
        try:
246
 
            inv_sha1 = repo.add_inventory_by_delta('basis', delta,
247
 
                'result', ['basis'])
248
 
        except:
249
 
            repo.abort_write_group()
250
 
            raise
251
 
        else:
252
 
            repo.commit_write_group()
253
 
    finally:
254
 
        repo.unlock()
 
249
    with repo.lock_write(), repository.WriteGroup(repo):
 
250
        rev = revision.Revision(
 
251
            b'basis', timestamp=0, timezone=None, message="",
 
252
            committer="foo@example.com")
 
253
        basis.revision_id = b'basis'
 
254
        create_texts_for_inv(repo, basis)
 
255
        repo.add_revision(b'basis', rev, basis)
 
256
    with repo.lock_write(), repository.WriteGroup(repo):
 
257
        inv_sha1 = repo.add_inventory_by_delta(
 
258
            b'basis', delta, b'result', [b'basis'])
255
259
    # Fresh lock, reads disk again.
256
 
    repo = repo.bzrdir.open_repository()
 
260
    repo = repo.controldir.open_repository()
257
261
    repo.lock_read()
258
262
    self.addCleanup(repo.unlock)
259
 
    return repo.get_inventory('result')
 
263
    return repo.get_inventory(b'result')
260
264
 
261
265
 
262
266
class TestInventoryUpdates(TestCase):
263
267
 
264
268
    def test_creation_from_root_id(self):
265
269
        # iff a root id is passed to the constructor, a root directory is made
266
 
        inv = inventory.Inventory(root_id='tree-root')
 
270
        inv = inventory.Inventory(root_id=b'tree-root')
267
271
        self.assertNotEqual(None, inv.root)
268
 
        self.assertEqual('tree-root', inv.root.file_id)
 
272
        self.assertEqual(b'tree-root', inv.root.file_id)
269
273
 
270
274
    def test_add_path_of_root(self):
271
275
        # if no root id is given at creation time, there is no root directory
272
276
        inv = inventory.Inventory(root_id=None)
273
277
        self.assertIs(None, inv.root)
274
278
        # 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)
 
279
        ie = inv.add_path(u"", "directory", b"my-root")
 
280
        ie.revision = b'test-rev'
 
281
        self.assertEqual(b"my-root", ie.file_id)
278
282
        self.assertIs(ie, inv.root)
279
283
 
280
284
    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)
 
285
        inv = inventory.Inventory(root_id=b'tree_root')
 
286
        ie = inv.add_path(u'hello', 'file', b'hello-id')
 
287
        self.assertEqual(b'hello-id', ie.file_id)
284
288
        self.assertEqual('file', ie.kind)
285
289
 
286
290
    def test_copy(self):
287
291
        """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')
 
292
        inv = inventory.Inventory(root_id=b'some-tree-root')
 
293
        ie = inv.add_path(u'hello', 'file', b'hello-id')
290
294
        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)
 
295
        inv.root.file_id = b'some-new-root'
 
296
        ie.name = u'file2'
 
297
        self.assertEqual(b'some-tree-root', inv2.root.file_id)
 
298
        self.assertEqual(u'hello', inv2.get_entry(b'hello-id').name)
295
299
 
296
300
    def test_copy_empty(self):
297
301
        """Make sure an empty inventory can be copied."""
301
305
 
302
306
    def test_copy_copies_root_revision(self):
303
307
        """Make sure the revision of the root gets copied."""
304
 
        inv = inventory.Inventory(root_id='someroot')
305
 
        inv.root.revision = 'therev'
 
308
        inv = inventory.Inventory(root_id=b'someroot')
 
309
        inv.root.revision = b'therev'
306
310
        inv2 = inv.copy()
307
 
        self.assertEquals('someroot', inv2.root.file_id)
308
 
        self.assertEquals('therev', inv2.root.revision)
 
311
        self.assertEqual(b'someroot', inv2.root.file_id)
 
312
        self.assertEqual(b'therev', inv2.root.revision)
309
313
 
310
314
    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'))
 
315
        inv = inventory.Inventory(b'tree-root-123')
 
316
        inv.add(TreeReference(
 
317
            b'nested-id', 'nested', parent_id=b'tree-root-123',
 
318
            revision=b'rev', reference_revision=b'rev2'))
314
319
 
315
320
    def test_error_encoding(self):
316
 
        inv = inventory.Inventory('tree-root')
317
 
        inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
 
321
        inv = inventory.Inventory(b'tree-root')
 
322
        inv.add(InventoryFile(b'a-id', u'\u1234', b'tree-root'))
318
323
        e = self.assertRaises(errors.InconsistentDelta, inv.add,
319
 
            InventoryFile('b-id', u'\u1234', 'tree-root'))
320
 
        self.assertContainsRe(str(e), r'\\u1234')
 
324
                              InventoryFile(b'b-id', u'\u1234', b'tree-root'))
 
325
        self.assertContainsRe(str(e), '\\u1234')
321
326
 
322
327
    def test_add_recursive(self):
323
 
        parent = InventoryDirectory('src-id', 'src', 'tree-root')
324
 
        child = InventoryFile('hello-id', 'hello.c', 'src-id')
 
328
        parent = InventoryDirectory(b'src-id', 'src', b'tree-root')
 
329
        child = InventoryFile(b'hello-id', 'hello.c', b'src-id')
325
330
        parent.children[child.file_id] = child
326
 
        inv = inventory.Inventory('tree-root')
 
331
        inv = inventory.Inventory(b'tree-root')
327
332
        inv.add(parent)
328
 
        self.assertEqual('src/hello.c', inv.id2path('hello-id'))
329
 
 
 
333
        self.assertEqual('src/hello.c', inv.id2path(b'hello-id'))
330
334
 
331
335
 
332
336
class TestDeltaApplication(TestCaseWithTransport):
333
 
 
 
337
 
 
338
    scenarios = delta_application_scenarios()
 
339
 
334
340
    def get_empty_inventory(self, reference_inv=None):
335
341
        """Get an empty inventory.
336
342
 
347
353
        if reference_inv is not None:
348
354
            inv.root.revision = reference_inv.root.revision
349
355
        else:
350
 
            inv.root.revision = 'basis'
 
356
            inv.root.revision = b'basis'
351
357
        return inv
352
358
 
 
359
    def make_file_ie(self, file_id=b'file-id', name='name', parent_id=None):
 
360
        ie_file = inventory.InventoryFile(file_id, name, parent_id)
 
361
        ie_file.revision = b'result'
 
362
        ie_file.text_size = 0
 
363
        ie_file.text_sha1 = b''
 
364
        return ie_file
 
365
 
353
366
    def test_empty_delta(self):
354
367
        inv = self.get_empty_inventory()
355
368
        delta = []
359
372
 
360
373
    def test_None_file_id(self):
361
374
        inv = self.get_empty_inventory()
362
 
        dir1 = inventory.InventoryDirectory(None, 'dir1', inv.root.file_id)
363
 
        dir1.revision = 'result'
 
375
        dir1 = inventory.InventoryDirectory(b'dirid', 'dir1', inv.root.file_id)
 
376
        dir1.file_id = None
 
377
        dir1.revision = b'result'
364
378
        delta = [(None, u'dir1', None, dir1)]
365
379
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
366
 
            inv, delta)
 
380
                          inv, delta)
367
381
 
368
382
    def test_unicode_file_id(self):
369
383
        inv = self.get_empty_inventory()
370
 
        dir1 = inventory.InventoryDirectory(u'dirid', 'dir1', inv.root.file_id)
371
 
        dir1.revision = 'result'
 
384
        dir1 = inventory.InventoryDirectory(b'dirid', 'dir1', inv.root.file_id)
 
385
        dir1.file_id = u'dirid'
 
386
        dir1.revision = b'result'
372
387
        delta = [(None, u'dir1', dir1.file_id, dir1)]
373
388
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
374
 
            inv, delta)
 
389
                          inv, delta)
375
390
 
376
391
    def test_repeated_file_id(self):
377
392
        inv = self.get_empty_inventory()
378
 
        file1 = inventory.InventoryFile('id', 'path1', inv.root.file_id)
379
 
        file1.revision = 'result'
 
393
        file1 = inventory.InventoryFile(b'id', 'path1', inv.root.file_id)
 
394
        file1.revision = b'result'
380
395
        file1.text_size = 0
381
 
        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 = ""
386
 
        delta = [(None, u'path1', 'id', file1), (None, u'path2', 'id', file2)]
 
396
        file1.text_sha1 = b""
 
397
        file2 = file1.copy()
 
398
        file2.name = 'path2'
 
399
        delta = [(None, u'path1', b'id', file1),
 
400
                 (None, u'path2', b'id', file2)]
387
401
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
388
 
            inv, delta)
 
402
                          inv, delta)
389
403
 
390
404
    def test_repeated_new_path(self):
391
405
        inv = self.get_empty_inventory()
392
 
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
393
 
        file1.revision = 'result'
 
406
        file1 = inventory.InventoryFile(b'id1', 'path', inv.root.file_id)
 
407
        file1.revision = b'result'
394
408
        file1.text_size = 0
395
 
        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 = ""
400
 
        delta = [(None, u'path', 'id1', file1), (None, u'path', 'id2', file2)]
 
409
        file1.text_sha1 = b""
 
410
        file2 = file1.copy()
 
411
        file2.file_id = b'id2'
 
412
        delta = [(None, u'path', b'id1', file1),
 
413
                 (None, u'path', b'id2', file2)]
401
414
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
402
 
            inv, delta)
 
415
                          inv, delta)
403
416
 
404
417
    def test_repeated_old_path(self):
405
418
        inv = self.get_empty_inventory()
406
 
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
407
 
        file1.revision = 'result'
 
419
        file1 = inventory.InventoryFile(b'id1', 'path', inv.root.file_id)
 
420
        file1.revision = b'result'
408
421
        file1.text_size = 0
409
 
        file1.text_sha1 = ""
 
422
        file1.text_sha1 = b""
410
423
        # We can't *create* a source inventory with the same path, but
411
424
        # a badly generated partial delta might claim the same source twice.
412
425
        # This would be buggy in two ways: the path is repeated in the delta,
413
426
        # And the path for one of the file ids doesn't match the source
414
427
        # location. Alternatively, we could have a repeated fileid, but that
415
428
        # is separately checked for.
416
 
        file2 = inventory.InventoryFile('id2', 'path2', inv.root.file_id)
417
 
        file2.revision = 'result'
 
429
        file2 = inventory.InventoryFile(b'id2', 'path2', inv.root.file_id)
 
430
        file2.revision = b'result'
418
431
        file2.text_size = 0
419
 
        file2.text_sha1 = ""
 
432
        file2.text_sha1 = b""
420
433
        inv.add(file1)
421
434
        inv.add(file2)
422
 
        delta = [(u'path', None, 'id1', None), (u'path', None, 'id2', None)]
 
435
        delta = [(u'path', None, b'id1', None), (u'path', None, b'id2', None)]
423
436
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
424
 
            inv, delta)
 
437
                          inv, delta)
425
438
 
426
439
    def test_mismatched_id_entry_id(self):
427
440
        inv = self.get_empty_inventory()
428
 
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
429
 
        file1.revision = 'result'
 
441
        file1 = inventory.InventoryFile(b'id1', 'path', inv.root.file_id)
 
442
        file1.revision = b'result'
430
443
        file1.text_size = 0
431
 
        file1.text_sha1 = ""
432
 
        delta = [(None, u'path', 'id', file1)]
 
444
        file1.text_sha1 = b""
 
445
        delta = [(None, u'path', b'id', file1)]
433
446
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
434
 
            inv, delta)
 
447
                          inv, delta)
435
448
 
436
449
    def test_mismatched_new_path_entry_None(self):
437
450
        inv = self.get_empty_inventory()
438
 
        delta = [(None, u'path', 'id', None)]
 
451
        delta = [(None, u'path', b'id', None)]
439
452
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
440
 
            inv, delta)
 
453
                          inv, delta)
441
454
 
442
455
    def test_mismatched_new_path_None_entry(self):
443
456
        inv = self.get_empty_inventory()
444
 
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
445
 
        file1.revision = 'result'
 
457
        file1 = inventory.InventoryFile(b'id1', 'path', inv.root.file_id)
 
458
        file1.revision = b'result'
446
459
        file1.text_size = 0
447
 
        file1.text_sha1 = ""
448
 
        delta = [(u"path", None, 'id1', file1)]
 
460
        file1.text_sha1 = b""
 
461
        delta = [(u"path", None, b'id1', file1)]
449
462
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
450
 
            inv, delta)
 
463
                          inv, delta)
451
464
 
452
465
    def test_parent_is_not_directory(self):
453
466
        inv = self.get_empty_inventory()
454
 
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
455
 
        file1.revision = 'result'
 
467
        file1 = inventory.InventoryFile(b'id1', 'path', inv.root.file_id)
 
468
        file1.revision = b'result'
456
469
        file1.text_size = 0
457
 
        file1.text_sha1 = ""
458
 
        file2 = inventory.InventoryFile('id2', 'path2', 'id1')
459
 
        file2.revision = 'result'
 
470
        file1.text_sha1 = b""
 
471
        file2 = inventory.InventoryFile(b'id2', 'path2', b'id1')
 
472
        file2.revision = b'result'
460
473
        file2.text_size = 0
461
 
        file2.text_sha1 = ""
 
474
        file2.text_sha1 = b""
462
475
        inv.add(file1)
463
 
        delta = [(None, u'path/path2', 'id2', file2)]
 
476
        delta = [(None, u'path/path2', b'id2', file2)]
464
477
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
465
 
            inv, delta)
 
478
                          inv, delta)
466
479
 
467
480
    def test_parent_is_missing(self):
468
481
        inv = self.get_empty_inventory()
469
 
        file2 = inventory.InventoryFile('id2', 'path2', 'missingparent')
470
 
        file2.revision = 'result'
 
482
        file2 = inventory.InventoryFile(b'id2', 'path2', b'missingparent')
 
483
        file2.revision = b'result'
471
484
        file2.text_size = 0
472
 
        file2.text_sha1 = ""
473
 
        delta = [(None, u'path/path2', 'id2', file2)]
 
485
        file2.text_sha1 = b""
 
486
        delta = [(None, u'path/path2', b'id2', file2)]
474
487
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
475
 
            inv, delta)
 
488
                          inv, delta)
476
489
 
477
490
    def test_new_parent_path_has_wrong_id(self):
478
491
        inv = self.get_empty_inventory()
479
 
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
480
 
        parent1.revision = 'result'
481
 
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
482
 
        parent2.revision = 'result'
483
 
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
484
 
        file1.revision = 'result'
 
492
        parent1 = inventory.InventoryDirectory(b'p-1', 'dir', inv.root.file_id)
 
493
        parent1.revision = b'result'
 
494
        parent2 = inventory.InventoryDirectory(
 
495
            b'p-2', 'dir2', inv.root.file_id)
 
496
        parent2.revision = b'result'
 
497
        file1 = inventory.InventoryFile(b'id', 'path', b'p-2')
 
498
        file1.revision = b'result'
485
499
        file1.text_size = 0
486
 
        file1.text_sha1 = ""
 
500
        file1.text_sha1 = b""
487
501
        inv.add(parent1)
488
502
        inv.add(parent2)
489
503
        # This delta claims that file1 is at dir/path, but actually its at
490
504
        # dir2/path if you follow the inventory parent structure.
491
 
        delta = [(None, u'dir/path', 'id', file1)]
 
505
        delta = [(None, u'dir/path', b'id', file1)]
492
506
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
493
 
            inv, delta)
 
507
                          inv, delta)
494
508
 
495
509
    def test_old_parent_path_is_wrong(self):
496
510
        inv = self.get_empty_inventory()
497
 
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
498
 
        parent1.revision = 'result'
499
 
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
500
 
        parent2.revision = 'result'
501
 
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
502
 
        file1.revision = 'result'
 
511
        parent1 = inventory.InventoryDirectory(b'p-1', 'dir', inv.root.file_id)
 
512
        parent1.revision = b'result'
 
513
        parent2 = inventory.InventoryDirectory(
 
514
            b'p-2', 'dir2', inv.root.file_id)
 
515
        parent2.revision = b'result'
 
516
        file1 = inventory.InventoryFile(b'id', 'path', b'p-2')
 
517
        file1.revision = b'result'
503
518
        file1.text_size = 0
504
 
        file1.text_sha1 = ""
 
519
        file1.text_sha1 = b""
505
520
        inv.add(parent1)
506
521
        inv.add(parent2)
507
522
        inv.add(file1)
508
523
        # This delta claims that file1 was at dir/path, but actually it was at
509
524
        # dir2/path if you follow the inventory parent structure.
510
 
        delta = [(u'dir/path', None, 'id', None)]
 
525
        delta = [(u'dir/path', None, b'id', None)]
511
526
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
512
 
            inv, delta)
 
527
                          inv, delta)
513
528
 
514
529
    def test_old_parent_path_is_for_other_id(self):
515
530
        inv = self.get_empty_inventory()
516
 
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
517
 
        parent1.revision = 'result'
518
 
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
519
 
        parent2.revision = 'result'
520
 
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
521
 
        file1.revision = 'result'
 
531
        parent1 = inventory.InventoryDirectory(b'p-1', 'dir', inv.root.file_id)
 
532
        parent1.revision = b'result'
 
533
        parent2 = inventory.InventoryDirectory(
 
534
            b'p-2', 'dir2', inv.root.file_id)
 
535
        parent2.revision = b'result'
 
536
        file1 = inventory.InventoryFile(b'id', 'path', b'p-2')
 
537
        file1.revision = b'result'
522
538
        file1.text_size = 0
523
 
        file1.text_sha1 = ""
524
 
        file2 = inventory.InventoryFile('id2', 'path', 'p-1')
525
 
        file2.revision = 'result'
 
539
        file1.text_sha1 = b""
 
540
        file2 = inventory.InventoryFile(b'id2', 'path', b'p-1')
 
541
        file2.revision = b'result'
526
542
        file2.text_size = 0
527
 
        file2.text_sha1 = ""
 
543
        file2.text_sha1 = b""
528
544
        inv.add(parent1)
529
545
        inv.add(parent2)
530
546
        inv.add(file1)
532
548
        # This delta claims that file1 was at dir/path, but actually it was at
533
549
        # dir2/path if you follow the inventory parent structure. At dir/path
534
550
        # is another entry we should not delete.
535
 
        delta = [(u'dir/path', None, 'id', None)]
 
551
        delta = [(u'dir/path', None, b'id', None)]
536
552
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
537
 
            inv, delta)
 
553
                          inv, delta)
538
554
 
539
555
    def test_add_existing_id_new_path(self):
540
556
        inv = self.get_empty_inventory()
541
 
        parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
542
 
        parent1.revision = 'result'
543
 
        parent2 = inventory.InventoryDirectory('p-1', 'dir2', inv.root.file_id)
544
 
        parent2.revision = 'result'
 
557
        parent1 = inventory.InventoryDirectory(
 
558
            b'p-1', 'dir1', inv.root.file_id)
 
559
        parent1.revision = b'result'
 
560
        parent2 = inventory.InventoryDirectory(
 
561
            b'p-1', 'dir2', inv.root.file_id)
 
562
        parent2.revision = b'result'
545
563
        inv.add(parent1)
546
 
        delta = [(None, u'dir2', 'p-1', parent2)]
 
564
        delta = [(None, u'dir2', b'p-1', parent2)]
547
565
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
548
 
            inv, delta)
 
566
                          inv, delta)
549
567
 
550
568
    def test_add_new_id_existing_path(self):
551
569
        inv = self.get_empty_inventory()
552
 
        parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
553
 
        parent1.revision = 'result'
554
 
        parent2 = inventory.InventoryDirectory('p-2', 'dir1', inv.root.file_id)
555
 
        parent2.revision = 'result'
 
570
        parent1 = inventory.InventoryDirectory(
 
571
            b'p-1', 'dir1', inv.root.file_id)
 
572
        parent1.revision = b'result'
 
573
        parent2 = inventory.InventoryDirectory(
 
574
            b'p-2', 'dir1', inv.root.file_id)
 
575
        parent2.revision = b'result'
556
576
        inv.add(parent1)
557
 
        delta = [(None, u'dir1', 'p-2', parent2)]
 
577
        delta = [(None, u'dir1', b'p-2', parent2)]
558
578
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
559
 
            inv, delta)
 
579
                          inv, delta)
560
580
 
561
581
    def test_remove_dir_leaving_dangling_child(self):
562
582
        inv = self.get_empty_inventory()
563
 
        dir1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
564
 
        dir1.revision = 'result'
565
 
        dir2 = inventory.InventoryDirectory('p-2', 'child1', 'p-1')
566
 
        dir2.revision = 'result'
567
 
        dir3 = inventory.InventoryDirectory('p-3', 'child2', 'p-1')
568
 
        dir3.revision = 'result'
 
583
        dir1 = inventory.InventoryDirectory(b'p-1', 'dir1', inv.root.file_id)
 
584
        dir1.revision = b'result'
 
585
        dir2 = inventory.InventoryDirectory(b'p-2', 'child1', b'p-1')
 
586
        dir2.revision = b'result'
 
587
        dir3 = inventory.InventoryDirectory(b'p-3', 'child2', b'p-1')
 
588
        dir3.revision = b'result'
569
589
        inv.add(dir1)
570
590
        inv.add(dir2)
571
591
        inv.add(dir3)
572
 
        delta = [(u'dir1', None, 'p-1', None),
573
 
            (u'dir1/child2', None, 'p-3', None)]
 
592
        delta = [(u'dir1', None, b'p-1', None),
 
593
                 (u'dir1/child2', None, b'p-3', None)]
574
594
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
575
 
            inv, delta)
576
 
 
577
 
 
578
 
class TestInventory(TestCase):
 
595
                          inv, delta)
 
596
 
 
597
    def test_add_file(self):
 
598
        inv = self.get_empty_inventory()
 
599
        file1 = inventory.InventoryFile(b'file-id', 'path', inv.root.file_id)
 
600
        file1.revision = b'result'
 
601
        file1.text_size = 0
 
602
        file1.text_sha1 = b''
 
603
        delta = [(None, u'path', b'file-id', file1)]
 
604
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
605
        self.assertEqual(b'file-id', res_inv.get_entry(b'file-id').file_id)
 
606
 
 
607
    def test_remove_file(self):
 
608
        inv = self.get_empty_inventory()
 
609
        file1 = inventory.InventoryFile(b'file-id', 'path', inv.root.file_id)
 
610
        file1.revision = b'result'
 
611
        file1.text_size = 0
 
612
        file1.text_sha1 = b''
 
613
        inv.add(file1)
 
614
        delta = [(u'path', None, b'file-id', None)]
 
615
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
616
        self.assertEqual(None, res_inv.path2id('path'))
 
617
        self.assertRaises(errors.NoSuchId, res_inv.id2path, b'file-id')
 
618
 
 
619
    def test_rename_file(self):
 
620
        inv = self.get_empty_inventory()
 
621
        file1 = self.make_file_ie(name='path', parent_id=inv.root.file_id)
 
622
        inv.add(file1)
 
623
        file2 = self.make_file_ie(name='path2', parent_id=inv.root.file_id)
 
624
        delta = [(u'path', 'path2', b'file-id', file2)]
 
625
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
626
        self.assertEqual(None, res_inv.path2id('path'))
 
627
        self.assertEqual(b'file-id', res_inv.path2id('path2'))
 
628
 
 
629
    def test_replaced_at_new_path(self):
 
630
        inv = self.get_empty_inventory()
 
631
        file1 = self.make_file_ie(file_id=b'id1', parent_id=inv.root.file_id)
 
632
        inv.add(file1)
 
633
        file2 = self.make_file_ie(file_id=b'id2', parent_id=inv.root.file_id)
 
634
        delta = [(u'name', None, b'id1', None),
 
635
                 (None, u'name', b'id2', file2)]
 
636
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
637
        self.assertEqual(b'id2', res_inv.path2id('name'))
 
638
 
 
639
    def test_rename_dir(self):
 
640
        inv = self.get_empty_inventory()
 
641
        dir1 = inventory.InventoryDirectory(
 
642
            b'dir-id', 'dir1', inv.root.file_id)
 
643
        dir1.revision = b'basis'
 
644
        file1 = self.make_file_ie(parent_id=b'dir-id')
 
645
        inv.add(dir1)
 
646
        inv.add(file1)
 
647
        dir2 = inventory.InventoryDirectory(
 
648
            b'dir-id', 'dir2', inv.root.file_id)
 
649
        dir2.revision = b'result'
 
650
        delta = [('dir1', 'dir2', b'dir-id', dir2)]
 
651
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
652
        # The file should be accessible under the new path
 
653
        self.assertEqual(b'file-id', res_inv.path2id('dir2/name'))
 
654
 
 
655
    def test_renamed_dir_with_renamed_child(self):
 
656
        inv = self.get_empty_inventory()
 
657
        dir1 = inventory.InventoryDirectory(
 
658
            b'dir-id', 'dir1', inv.root.file_id)
 
659
        dir1.revision = b'basis'
 
660
        file1 = self.make_file_ie(b'file-id-1', 'name1', parent_id=b'dir-id')
 
661
        file2 = self.make_file_ie(b'file-id-2', 'name2', parent_id=b'dir-id')
 
662
        inv.add(dir1)
 
663
        inv.add(file1)
 
664
        inv.add(file2)
 
665
        dir2 = inventory.InventoryDirectory(
 
666
            b'dir-id', 'dir2', inv.root.file_id)
 
667
        dir2.revision = b'result'
 
668
        file2b = self.make_file_ie(b'file-id-2', 'name2', inv.root.file_id)
 
669
        delta = [('dir1', 'dir2', b'dir-id', dir2),
 
670
                 ('dir1/name2', 'name2', b'file-id-2', file2b)]
 
671
        res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
 
672
        # The file should be accessible under the new path
 
673
        self.assertEqual(b'file-id-1', res_inv.path2id('dir2/name1'))
 
674
        self.assertEqual(None, res_inv.path2id('dir2/name2'))
 
675
        self.assertEqual(b'file-id-2', res_inv.path2id('name2'))
579
676
 
580
677
    def test_is_root(self):
581
678
        """Ensure our root-checking code is accurate."""
582
 
        inv = inventory.Inventory('TREE_ROOT')
583
 
        self.assertTrue(inv.is_root('TREE_ROOT'))
584
 
        self.assertFalse(inv.is_root('booga'))
585
 
        inv.root.file_id = 'booga'
586
 
        self.assertFalse(inv.is_root('TREE_ROOT'))
587
 
        self.assertTrue(inv.is_root('booga'))
 
679
        inv = inventory.Inventory(b'TREE_ROOT')
 
680
        self.assertTrue(inv.is_root(b'TREE_ROOT'))
 
681
        self.assertFalse(inv.is_root(b'booga'))
 
682
        inv.root.file_id = b'booga'
 
683
        self.assertFalse(inv.is_root(b'TREE_ROOT'))
 
684
        self.assertTrue(inv.is_root(b'booga'))
588
685
        # works properly even if no root is set
589
686
        inv.root = None
590
 
        self.assertFalse(inv.is_root('TREE_ROOT'))
591
 
        self.assertFalse(inv.is_root('booga'))
 
687
        self.assertFalse(inv.is_root(b'TREE_ROOT'))
 
688
        self.assertFalse(inv.is_root(b'booga'))
 
689
 
 
690
    def test_entries_for_empty_inventory(self):
 
691
        """Test that entries() will not fail for an empty inventory"""
 
692
        inv = Inventory(root_id=None)
 
693
        self.assertEqual([], inv.entries())
592
694
 
593
695
 
594
696
class TestInventoryEntry(TestCase):
595
697
 
 
698
    def test_file_invalid_entry_name(self):
 
699
        self.assertRaises(errors.InvalidEntryName, inventory.InventoryFile,
 
700
                          b'123', 'a/hello.c', ROOT_ID)
 
701
 
 
702
    def test_file_backslash(self):
 
703
        file = inventory.InventoryFile(b'123', 'h\\ello.c', ROOT_ID)
 
704
        self.assertEquals(file.name, 'h\\ello.c')
 
705
 
596
706
    def test_file_kind_character(self):
597
 
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
707
        file = inventory.InventoryFile(b'123', 'hello.c', ROOT_ID)
598
708
        self.assertEqual(file.kind_character(), '')
599
709
 
600
710
    def test_dir_kind_character(self):
601
 
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
 
711
        dir = inventory.InventoryDirectory(b'123', 'hello.c', ROOT_ID)
602
712
        self.assertEqual(dir.kind_character(), '/')
603
713
 
604
714
    def test_link_kind_character(self):
605
 
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
 
715
        dir = inventory.InventoryLink(b'123', 'hello.c', ROOT_ID)
606
716
        self.assertEqual(dir.kind_character(), '')
607
717
 
 
718
    def test_link_kind_character(self):
 
719
        dir = TreeReference(b'123', 'hello.c', ROOT_ID)
 
720
        self.assertEqual(dir.kind_character(), '+')
 
721
 
608
722
    def test_dir_detect_changes(self):
609
 
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
610
 
        left.text_sha1 = 123
611
 
        left.executable = True
612
 
        left.symlink_target='foo'
613
 
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
614
 
        right.text_sha1 = 321
615
 
        right.symlink_target='bar'
 
723
        left = inventory.InventoryDirectory(b'123', 'hello.c', ROOT_ID)
 
724
        right = inventory.InventoryDirectory(b'123', 'hello.c', ROOT_ID)
616
725
        self.assertEqual((False, False), left.detect_changes(right))
617
726
        self.assertEqual((False, False), right.detect_changes(left))
618
727
 
619
728
    def test_file_detect_changes(self):
620
 
        left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
729
        left = inventory.InventoryFile(b'123', 'hello.c', ROOT_ID)
621
730
        left.text_sha1 = 123
622
 
        right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
731
        right = inventory.InventoryFile(b'123', 'hello.c', ROOT_ID)
623
732
        right.text_sha1 = 123
624
733
        self.assertEqual((False, False), left.detect_changes(right))
625
734
        self.assertEqual((False, False), right.detect_changes(left))
631
740
        self.assertEqual((True, True), right.detect_changes(left))
632
741
 
633
742
    def test_symlink_detect_changes(self):
634
 
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
635
 
        left.text_sha1 = 123
636
 
        left.executable = True
637
 
        left.symlink_target='foo'
638
 
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
639
 
        right.text_sha1 = 321
640
 
        right.symlink_target='foo'
 
743
        left = inventory.InventoryLink(b'123', 'hello.c', ROOT_ID)
 
744
        left.symlink_target = 'foo'
 
745
        right = inventory.InventoryLink(b'123', 'hello.c', ROOT_ID)
 
746
        right.symlink_target = 'foo'
641
747
        self.assertEqual((False, False), left.detect_changes(right))
642
748
        self.assertEqual((False, False), right.detect_changes(left))
643
749
        left.symlink_target = 'different'
645
751
        self.assertEqual((True, False), right.detect_changes(left))
646
752
 
647
753
    def test_file_has_text(self):
648
 
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
649
 
        self.failUnless(file.has_text())
 
754
        file = inventory.InventoryFile(b'123', 'hello.c', ROOT_ID)
 
755
        self.assertTrue(file.has_text())
650
756
 
651
757
    def test_directory_has_text(self):
652
 
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
653
 
        self.failIf(dir.has_text())
 
758
        dir = inventory.InventoryDirectory(b'123', 'hello.c', ROOT_ID)
 
759
        self.assertFalse(dir.has_text())
654
760
 
655
761
    def test_link_has_text(self):
656
 
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
657
 
        self.failIf(link.has_text())
 
762
        link = inventory.InventoryLink(b'123', 'hello.c', ROOT_ID)
 
763
        self.assertFalse(link.has_text())
658
764
 
659
765
    def test_make_entry(self):
660
766
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
661
 
            inventory.InventoryFile)
 
767
                              inventory.InventoryFile)
662
768
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
663
 
            inventory.InventoryLink)
 
769
                              inventory.InventoryLink)
664
770
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
665
 
            inventory.InventoryDirectory)
 
771
                              inventory.InventoryDirectory)
666
772
 
667
773
    def test_make_entry_non_normalized(self):
668
774
        orig_normalized_filename = osutils.normalized_filename
675
781
 
676
782
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
677
783
            self.assertRaises(errors.InvalidNormalization,
678
 
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
 
784
                              inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
679
785
        finally:
680
786
            osutils.normalized_filename = orig_normalized_filename
681
787
 
692
798
        # renamed/reparented and modified
693
799
        # change kind (perhaps can't be done yet?)
694
800
        # also, merged in combination with all of these?
695
 
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
696
 
        old_a.text_sha1 = '123132'
 
801
        old_a = InventoryFile(b'a-id', 'a_file', ROOT_ID)
 
802
        old_a.text_sha1 = b'123132'
697
803
        old_a.text_size = 0
698
 
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
699
 
        new_a.text_sha1 = '123132'
 
804
        new_a = InventoryFile(b'a-id', 'a_file', ROOT_ID)
 
805
        new_a.text_sha1 = b'123132'
700
806
        new_a.text_size = 0
701
807
 
702
808
        self.assertChangeDescription('unchanged', old_a, new_a)
703
809
 
704
810
        new_a.text_size = 10
705
 
        new_a.text_sha1 = 'abcabc'
 
811
        new_a.text_sha1 = b'abcabc'
706
812
        self.assertChangeDescription('modified', old_a, new_a)
707
813
 
708
814
        self.assertChangeDescription('added', None, new_a)
717
823
 
718
824
        # reparenting is 'renaming'
719
825
        new_a.name = old_a.name
720
 
        new_a.parent_id = 'somedir-id'
 
826
        new_a.parent_id = b'somedir-id'
721
827
        self.assertChangeDescription('modified and renamed', old_a, new_a)
722
828
 
723
829
        # reset the content values so its not modified
730
836
 
731
837
        # reparenting is 'renaming'
732
838
        new_a.name = old_a.name
733
 
        new_a.parent_id = 'somedir-id'
 
839
        new_a.parent_id = b'somedir-id'
734
840
        self.assertChangeDescription('renamed', old_a, new_a)
735
841
 
736
842
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
747
853
 
748
854
    def read_bytes(self, chk_bytes, key):
749
855
        stream = chk_bytes.get_record_stream([key], 'unordered', True)
750
 
        return stream.next().get_bytes_as("fulltext")
 
856
        return next(stream).get_bytes_as("fulltext")
751
857
 
752
858
    def test_deserialise_gives_CHKInventory(self):
753
859
        inv = Inventory()
754
 
        inv.revision_id = "revid"
755
 
        inv.root.revision = "rootrev"
 
860
        inv.revision_id = b"revid"
 
861
        inv.root.revision = b"rootrev"
756
862
        chk_bytes = self.get_chk_bytes()
757
863
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
758
 
        bytes = ''.join(chk_inv.to_lines())
759
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
760
 
        self.assertEqual("revid", new_inv.revision_id)
 
864
        lines = chk_inv.to_lines()
 
865
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
866
        self.assertEqual(b"revid", new_inv.revision_id)
761
867
        self.assertEqual("directory", new_inv.root.kind)
762
868
        self.assertEqual(inv.root.file_id, new_inv.root.file_id)
763
869
        self.assertEqual(inv.root.parent_id, new_inv.root.parent_id)
764
870
        self.assertEqual(inv.root.name, new_inv.root.name)
765
 
        self.assertEqual("rootrev", new_inv.root.revision)
766
 
        self.assertEqual('plain', new_inv._search_key_name)
 
871
        self.assertEqual(b"rootrev", new_inv.root.revision)
 
872
        self.assertEqual(b'plain', new_inv._search_key_name)
767
873
 
768
874
    def test_deserialise_wrong_revid(self):
769
875
        inv = Inventory()
770
 
        inv.revision_id = "revid"
771
 
        inv.root.revision = "rootrev"
 
876
        inv.revision_id = b"revid"
 
877
        inv.root.revision = b"rootrev"
772
878
        chk_bytes = self.get_chk_bytes()
773
879
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
774
 
        bytes = ''.join(chk_inv.to_lines())
 
880
        lines = chk_inv.to_lines()
775
881
        self.assertRaises(ValueError, CHKInventory.deserialise, chk_bytes,
776
 
            bytes, ("revid2",))
 
882
                          lines, (b"revid2",))
777
883
 
778
884
    def test_captures_rev_root_byid(self):
779
885
        inv = Inventory()
780
 
        inv.revision_id = "foo"
781
 
        inv.root.revision = "bar"
 
886
        inv.revision_id = b"foo"
 
887
        inv.root.revision = b"bar"
782
888
        chk_bytes = self.get_chk_bytes()
783
889
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
784
890
        lines = chk_inv.to_lines()
785
891
        self.assertEqual([
786
 
            'chkinventory:\n',
787
 
            'revision_id: foo\n',
788
 
            'root_id: TREE_ROOT\n',
789
 
            'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
790
 
            'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
 
892
            b'chkinventory:\n',
 
893
            b'revision_id: foo\n',
 
894
            b'root_id: TREE_ROOT\n',
 
895
            b'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
 
896
            b'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
791
897
            ], lines)
792
 
        chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
793
 
        self.assertEqual('plain', chk_inv._search_key_name)
 
898
        chk_inv = CHKInventory.deserialise(
 
899
            chk_bytes, lines, (b'foo',))
 
900
        self.assertEqual(b'plain', chk_inv._search_key_name)
794
901
 
795
902
    def test_captures_parent_id_basename_index(self):
796
903
        inv = Inventory()
797
 
        inv.revision_id = "foo"
798
 
        inv.root.revision = "bar"
 
904
        inv.revision_id = b"foo"
 
905
        inv.root.revision = b"bar"
799
906
        chk_bytes = self.get_chk_bytes()
800
907
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
801
908
        lines = chk_inv.to_lines()
802
909
        self.assertEqual([
803
 
            'chkinventory:\n',
804
 
            'revision_id: foo\n',
805
 
            'root_id: TREE_ROOT\n',
806
 
            'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
807
 
            'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
 
910
            b'chkinventory:\n',
 
911
            b'revision_id: foo\n',
 
912
            b'root_id: TREE_ROOT\n',
 
913
            b'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
 
914
            b'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
808
915
            ], lines)
809
 
        chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
810
 
        self.assertEqual('plain', chk_inv._search_key_name)
 
916
        chk_inv = CHKInventory.deserialise(
 
917
            chk_bytes, lines, (b'foo',))
 
918
        self.assertEqual(b'plain', chk_inv._search_key_name)
811
919
 
812
920
    def test_captures_search_key_name(self):
813
921
        inv = Inventory()
814
 
        inv.revision_id = "foo"
815
 
        inv.root.revision = "bar"
 
922
        inv.revision_id = b"foo"
 
923
        inv.root.revision = b"bar"
816
924
        chk_bytes = self.get_chk_bytes()
817
925
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
818
 
                                              search_key_name='hash-16-way')
 
926
                                              search_key_name=b'hash-16-way')
819
927
        lines = chk_inv.to_lines()
820
928
        self.assertEqual([
821
 
            'chkinventory:\n',
822
 
            'search_key_name: hash-16-way\n',
823
 
            'root_id: TREE_ROOT\n',
824
 
            'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
825
 
            'revision_id: foo\n',
826
 
            'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
 
929
            b'chkinventory:\n',
 
930
            b'search_key_name: hash-16-way\n',
 
931
            b'root_id: TREE_ROOT\n',
 
932
            b'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
 
933
            b'revision_id: foo\n',
 
934
            b'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
827
935
            ], lines)
828
 
        chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
829
 
        self.assertEqual('hash-16-way', chk_inv._search_key_name)
 
936
        chk_inv = CHKInventory.deserialise(
 
937
            chk_bytes, lines, (b'foo',))
 
938
        self.assertEqual(b'hash-16-way', chk_inv._search_key_name)
830
939
 
831
940
    def test_directory_children_on_demand(self):
832
941
        inv = Inventory()
833
 
        inv.revision_id = "revid"
834
 
        inv.root.revision = "rootrev"
835
 
        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
 
942
        inv.revision_id = b"revid"
 
943
        inv.root.revision = b"rootrev"
 
944
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
945
        inv.get_entry(b"fileid").revision = b"filerev"
 
946
        inv.get_entry(b"fileid").executable = True
 
947
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
948
        inv.get_entry(b"fileid").text_size = 1
840
949
        chk_bytes = self.get_chk_bytes()
841
950
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
842
 
        bytes = ''.join(chk_inv.to_lines())
843
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
844
 
        root_entry = new_inv[inv.root.file_id]
 
951
        lines = chk_inv.to_lines()
 
952
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
953
        root_entry = new_inv.get_entry(inv.root.file_id)
845
954
        self.assertEqual(None, root_entry._children)
846
 
        self.assertEqual(['file'], root_entry.children.keys())
847
 
        file_direct = new_inv["fileid"]
 
955
        self.assertEqual({'file'}, set(root_entry.children))
 
956
        file_direct = new_inv.get_entry(b"fileid")
848
957
        file_found = root_entry.children['file']
849
958
        self.assertEqual(file_direct.kind, file_found.kind)
850
959
        self.assertEqual(file_direct.file_id, file_found.file_id)
858
967
    def test_from_inventory_maximum_size(self):
859
968
        # from_inventory supports the maximum_size parameter.
860
969
        inv = Inventory()
861
 
        inv.revision_id = "revid"
862
 
        inv.root.revision = "rootrev"
 
970
        inv.revision_id = b"revid"
 
971
        inv.root.revision = b"rootrev"
863
972
        chk_bytes = self.get_chk_bytes()
864
973
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv, 120)
865
974
        chk_inv.id_to_entry._ensure_root()
870
979
        self.assertEqual(120, p_id_basename._root_node.maximum_size)
871
980
        self.assertEqual(2, p_id_basename._root_node._key_width)
872
981
 
873
 
    def test___iter__(self):
 
982
    def test_iter_all_ids(self):
874
983
        inv = Inventory()
875
 
        inv.revision_id = "revid"
876
 
        inv.root.revision = "rootrev"
877
 
        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
 
984
        inv.revision_id = b"revid"
 
985
        inv.root.revision = b"rootrev"
 
986
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
987
        inv.get_entry(b"fileid").revision = b"filerev"
 
988
        inv.get_entry(b"fileid").executable = True
 
989
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
990
        inv.get_entry(b"fileid").text_size = 1
882
991
        chk_bytes = self.get_chk_bytes()
883
992
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
884
 
        bytes = ''.join(chk_inv.to_lines())
885
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
886
 
        fileids = list(new_inv.__iter__())
887
 
        fileids.sort()
888
 
        self.assertEqual([inv.root.file_id, "fileid"], fileids)
 
993
        lines = chk_inv.to_lines()
 
994
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
995
        fileids = sorted(new_inv.iter_all_ids())
 
996
        self.assertEqual([inv.root.file_id, b"fileid"], fileids)
889
997
 
890
998
    def test__len__(self):
891
999
        inv = Inventory()
892
 
        inv.revision_id = "revid"
893
 
        inv.root.revision = "rootrev"
894
 
        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
 
1000
        inv.revision_id = b"revid"
 
1001
        inv.root.revision = b"rootrev"
 
1002
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
1003
        inv.get_entry(b"fileid").revision = b"filerev"
 
1004
        inv.get_entry(b"fileid").executable = True
 
1005
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1006
        inv.get_entry(b"fileid").text_size = 1
899
1007
        chk_bytes = self.get_chk_bytes()
900
1008
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
901
1009
        self.assertEqual(2, len(chk_inv))
902
1010
 
903
 
    def test___getitem__(self):
 
1011
    def test_get_entry(self):
904
1012
        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
 
1013
        inv.revision_id = b"revid"
 
1014
        inv.root.revision = b"rootrev"
 
1015
        inv.add(InventoryFile(b"fileid", u"file", inv.root.file_id))
 
1016
        inv.get_entry(b"fileid").revision = b"filerev"
 
1017
        inv.get_entry(b"fileid").executable = True
 
1018
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1019
        inv.get_entry(b"fileid").text_size = 1
912
1020
        chk_bytes = self.get_chk_bytes()
913
1021
        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"]
 
1022
        lines = chk_inv.to_lines()
 
1023
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
1024
        root_entry = new_inv.get_entry(inv.root.file_id)
 
1025
        file_entry = new_inv.get_entry(b"fileid")
918
1026
        self.assertEqual("directory", root_entry.kind)
919
1027
        self.assertEqual(inv.root.file_id, root_entry.file_id)
920
1028
        self.assertEqual(inv.root.parent_id, root_entry.parent_id)
921
1029
        self.assertEqual(inv.root.name, root_entry.name)
922
 
        self.assertEqual("rootrev", root_entry.revision)
 
1030
        self.assertEqual(b"rootrev", root_entry.revision)
923
1031
        self.assertEqual("file", file_entry.kind)
924
 
        self.assertEqual("fileid", file_entry.file_id)
 
1032
        self.assertEqual(b"fileid", file_entry.file_id)
925
1033
        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)
 
1034
        self.assertEqual(u"file", file_entry.name)
 
1035
        self.assertEqual(b"filerev", file_entry.revision)
 
1036
        self.assertEqual(b"ffff", file_entry.text_sha1)
929
1037
        self.assertEqual(1, file_entry.text_size)
930
1038
        self.assertEqual(True, file_entry.executable)
931
 
        self.assertRaises(errors.NoSuchId, new_inv.__getitem__, 'missing')
 
1039
        self.assertRaises(errors.NoSuchId, new_inv.get_entry, 'missing')
932
1040
 
933
1041
    def test_has_id_true(self):
934
1042
        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
 
1043
        inv.revision_id = b"revid"
 
1044
        inv.root.revision = b"rootrev"
 
1045
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
1046
        inv.get_entry(b"fileid").revision = b"filerev"
 
1047
        inv.get_entry(b"fileid").executable = True
 
1048
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1049
        inv.get_entry(b"fileid").text_size = 1
942
1050
        chk_bytes = self.get_chk_bytes()
943
1051
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
944
 
        self.assertTrue(chk_inv.has_id('fileid'))
 
1052
        self.assertTrue(chk_inv.has_id(b'fileid'))
945
1053
        self.assertTrue(chk_inv.has_id(inv.root.file_id))
946
1054
 
947
1055
    def test_has_id_not(self):
948
1056
        inv = Inventory()
949
 
        inv.revision_id = "revid"
950
 
        inv.root.revision = "rootrev"
 
1057
        inv.revision_id = b"revid"
 
1058
        inv.root.revision = b"rootrev"
951
1059
        chk_bytes = self.get_chk_bytes()
952
1060
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
953
 
        self.assertFalse(chk_inv.has_id('fileid'))
 
1061
        self.assertFalse(chk_inv.has_id(b'fileid'))
954
1062
 
955
1063
    def test_id2path(self):
956
1064
        inv = Inventory()
957
 
        inv.revision_id = "revid"
958
 
        inv.root.revision = "rootrev"
959
 
        direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
960
 
        fileentry = InventoryFile("fileid", "file", "dirid")
 
1065
        inv.revision_id = b"revid"
 
1066
        inv.root.revision = b"rootrev"
 
1067
        direntry = InventoryDirectory(b"dirid", "dir", inv.root.file_id)
 
1068
        fileentry = InventoryFile(b"fileid", "file", b"dirid")
961
1069
        inv.add(direntry)
962
1070
        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"
 
1071
        inv.get_entry(b"fileid").revision = b"filerev"
 
1072
        inv.get_entry(b"fileid").executable = True
 
1073
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1074
        inv.get_entry(b"fileid").text_size = 1
 
1075
        inv.get_entry(b"dirid").revision = b"filerev"
968
1076
        chk_bytes = self.get_chk_bytes()
969
1077
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
970
 
        bytes = ''.join(chk_inv.to_lines())
971
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1078
        lines = chk_inv.to_lines()
 
1079
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
972
1080
        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'))
 
1081
        self.assertEqual('dir', new_inv.id2path(b'dirid'))
 
1082
        self.assertEqual('dir/file', new_inv.id2path(b'fileid'))
975
1083
 
976
1084
    def test_path2id(self):
977
1085
        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")
 
1086
        inv.revision_id = b"revid"
 
1087
        inv.root.revision = b"rootrev"
 
1088
        direntry = InventoryDirectory(b"dirid", "dir", inv.root.file_id)
 
1089
        fileentry = InventoryFile(b"fileid", "file", b"dirid")
982
1090
        inv.add(direntry)
983
1091
        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"
 
1092
        inv.get_entry(b"fileid").revision = b"filerev"
 
1093
        inv.get_entry(b"fileid").executable = True
 
1094
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1095
        inv.get_entry(b"fileid").text_size = 1
 
1096
        inv.get_entry(b"dirid").revision = b"filerev"
989
1097
        chk_bytes = self.get_chk_bytes()
990
1098
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
991
 
        bytes = ''.join(chk_inv.to_lines())
992
 
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1099
        lines = chk_inv.to_lines()
 
1100
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
993
1101
        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'))
 
1102
        self.assertEqual(b'dirid', new_inv.path2id('dir'))
 
1103
        self.assertEqual(b'fileid', new_inv.path2id('dir/file'))
996
1104
 
997
1105
    def test_create_by_apply_delta_sets_root(self):
998
1106
        inv = Inventory()
999
 
        inv.revision_id = "revid"
 
1107
        inv.root.revision = b"myrootrev"
 
1108
        inv.revision_id = b"revid"
1000
1109
        chk_bytes = self.get_chk_bytes()
1001
1110
        base_inv = CHKInventory.from_inventory(chk_bytes, inv)
1002
 
        inv.add_path("", "directory", "myrootid", None)
1003
 
        inv.revision_id = "expectedid"
 
1111
        inv.add_path("", "directory", b"myrootid", None)
 
1112
        inv.revision_id = b"expectedid"
 
1113
        inv.root.revision = b"myrootrev"
1004
1114
        reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
1005
1115
        delta = [("", None, base_inv.root.file_id, None),
1006
 
            (None, "",  "myrootid", inv.root)]
1007
 
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
1008
 
        self.assertEquals(reference_inv.root, new_inv.root)
 
1116
                 (None, "", b"myrootid", inv.root)]
 
1117
        new_inv = base_inv.create_by_apply_delta(delta, b"expectedid")
 
1118
        self.assertEqual(reference_inv.root, new_inv.root)
1009
1119
 
1010
1120
    def test_create_by_apply_delta_empty_add_child(self):
1011
1121
        inv = Inventory()
1012
 
        inv.revision_id = "revid"
1013
 
        inv.root.revision = "rootrev"
 
1122
        inv.revision_id = b"revid"
 
1123
        inv.root.revision = b"rootrev"
1014
1124
        chk_bytes = self.get_chk_bytes()
1015
1125
        base_inv = CHKInventory.from_inventory(chk_bytes, inv)
1016
 
        a_entry = InventoryFile("A-id", "A", inv.root.file_id)
1017
 
        a_entry.revision = "filerev"
 
1126
        a_entry = InventoryFile(b"A-id", "A", inv.root.file_id)
 
1127
        a_entry.revision = b"filerev"
1018
1128
        a_entry.executable = True
1019
 
        a_entry.text_sha1 = "ffff"
 
1129
        a_entry.text_sha1 = b"ffff"
1020
1130
        a_entry.text_size = 1
1021
1131
        inv.add(a_entry)
1022
 
        inv.revision_id = "expectedid"
 
1132
        inv.revision_id = b"expectedid"
1023
1133
        reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
1024
 
        delta = [(None, "A",  "A-id", a_entry)]
1025
 
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
 
1134
        delta = [(None, "A", b"A-id", a_entry)]
 
1135
        new_inv = base_inv.create_by_apply_delta(delta, b"expectedid")
1026
1136
        # new_inv should be the same as reference_inv.
1027
1137
        self.assertEqual(reference_inv.revision_id, new_inv.revision_id)
1028
1138
        self.assertEqual(reference_inv.root_id, new_inv.root_id)
1029
1139
        reference_inv.id_to_entry._ensure_root()
1030
1140
        new_inv.id_to_entry._ensure_root()
1031
1141
        self.assertEqual(reference_inv.id_to_entry._root_node._key,
1032
 
            new_inv.id_to_entry._root_node._key)
 
1142
                         new_inv.id_to_entry._root_node._key)
1033
1143
 
1034
1144
    def test_create_by_apply_delta_empty_add_child_updates_parent_id(self):
1035
1145
        inv = Inventory()
1036
 
        inv.revision_id = "revid"
1037
 
        inv.root.revision = "rootrev"
 
1146
        inv.revision_id = b"revid"
 
1147
        inv.root.revision = b"rootrev"
1038
1148
        chk_bytes = self.get_chk_bytes()
1039
1149
        base_inv = CHKInventory.from_inventory(chk_bytes, inv)
1040
 
        a_entry = InventoryFile("A-id", "A", inv.root.file_id)
1041
 
        a_entry.revision = "filerev"
 
1150
        a_entry = InventoryFile(b"A-id", "A", inv.root.file_id)
 
1151
        a_entry.revision = b"filerev"
1042
1152
        a_entry.executable = True
1043
 
        a_entry.text_sha1 = "ffff"
 
1153
        a_entry.text_sha1 = b"ffff"
1044
1154
        a_entry.text_size = 1
1045
1155
        inv.add(a_entry)
1046
 
        inv.revision_id = "expectedid"
 
1156
        inv.revision_id = b"expectedid"
1047
1157
        reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
1048
 
        delta = [(None, "A",  "A-id", a_entry)]
1049
 
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
 
1158
        delta = [(None, "A", b"A-id", a_entry)]
 
1159
        new_inv = base_inv.create_by_apply_delta(delta, b"expectedid")
1050
1160
        reference_inv.id_to_entry._ensure_root()
1051
1161
        reference_inv.parent_id_basename_to_file_id._ensure_root()
1052
1162
        new_inv.id_to_entry._ensure_root()
1055
1165
        self.assertEqual(reference_inv.revision_id, new_inv.revision_id)
1056
1166
        self.assertEqual(reference_inv.root_id, new_inv.root_id)
1057
1167
        self.assertEqual(reference_inv.id_to_entry._root_node._key,
1058
 
            new_inv.id_to_entry._root_node._key)
 
1168
                         new_inv.id_to_entry._root_node._key)
1059
1169
        self.assertEqual(reference_inv.parent_id_basename_to_file_id._root_node._key,
1060
 
            new_inv.parent_id_basename_to_file_id._root_node._key)
 
1170
                         new_inv.parent_id_basename_to_file_id._root_node._key)
1061
1171
 
1062
1172
    def test_iter_changes(self):
1063
1173
        # Low level bootstrapping smoke test; comprehensive generic tests via
1064
1174
        # InterTree are coming.
1065
1175
        inv = Inventory()
1066
 
        inv.revision_id = "revid"
1067
 
        inv.root.revision = "rootrev"
1068
 
        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
 
1176
        inv.revision_id = b"revid"
 
1177
        inv.root.revision = b"rootrev"
 
1178
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
1179
        inv.get_entry(b"fileid").revision = b"filerev"
 
1180
        inv.get_entry(b"fileid").executable = True
 
1181
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1182
        inv.get_entry(b"fileid").text_size = 1
1073
1183
        inv2 = Inventory()
1074
 
        inv2.revision_id = "revid2"
1075
 
        inv2.root.revision = "rootrev"
1076
 
        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
 
1184
        inv2.revision_id = b"revid2"
 
1185
        inv2.root.revision = b"rootrev"
 
1186
        inv2.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
1187
        inv2.get_entry(b"fileid").revision = b"filerev2"
 
1188
        inv2.get_entry(b"fileid").executable = False
 
1189
        inv2.get_entry(b"fileid").text_sha1 = b"bbbb"
 
1190
        inv2.get_entry(b"fileid").text_size = 2
1081
1191
        # get fresh objects.
1082
1192
        chk_bytes = self.get_chk_bytes()
1083
1193
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
1084
 
        bytes = ''.join(chk_inv.to_lines())
1085
 
        inv_1 = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
 
1194
        lines = chk_inv.to_lines()
 
1195
        inv_1 = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
1086
1196
        chk_inv2 = CHKInventory.from_inventory(chk_bytes, inv2)
1087
 
        bytes = ''.join(chk_inv2.to_lines())
1088
 
        inv_2 = CHKInventory.deserialise(chk_bytes, bytes, ("revid2",))
1089
 
        self.assertEqual([('fileid', (u'file', u'file'), True, (True, True),
1090
 
            ('TREE_ROOT', 'TREE_ROOT'), (u'file', u'file'), ('file', 'file'),
1091
 
            (False, True))],
1092
 
            list(inv_1.iter_changes(inv_2)))
 
1197
        lines = chk_inv2.to_lines()
 
1198
        inv_2 = CHKInventory.deserialise(chk_bytes, lines, (b"revid2",))
 
1199
        self.assertEqual([(b'fileid', (u'file', u'file'), True, (True, True),
 
1200
                           (b'TREE_ROOT', b'TREE_ROOT'), (u'file',
 
1201
                                                          u'file'), ('file', 'file'),
 
1202
                           (False, True))],
 
1203
                         list(inv_1.iter_changes(inv_2)))
1093
1204
 
1094
1205
    def test_parent_id_basename_to_file_id_index_enabled(self):
1095
1206
        inv = Inventory()
1096
 
        inv.revision_id = "revid"
1097
 
        inv.root.revision = "rootrev"
1098
 
        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
 
1207
        inv.revision_id = b"revid"
 
1208
        inv.root.revision = b"rootrev"
 
1209
        inv.add(InventoryFile(b"fileid", "file", inv.root.file_id))
 
1210
        inv.get_entry(b"fileid").revision = b"filerev"
 
1211
        inv.get_entry(b"fileid").executable = True
 
1212
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1213
        inv.get_entry(b"fileid").text_size = 1
1103
1214
        # get fresh objects.
1104
1215
        chk_bytes = self.get_chk_bytes()
1105
1216
        tmp_inv = CHKInventory.from_inventory(chk_bytes, inv)
1106
 
        bytes = ''.join(tmp_inv.to_lines())
1107
 
        chk_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
1108
 
        self.assertIsInstance(chk_inv.parent_id_basename_to_file_id, chk_map.CHKMap)
 
1217
        lines = tmp_inv.to_lines()
 
1218
        chk_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
1219
        self.assertIsInstance(
 
1220
            chk_inv.parent_id_basename_to_file_id, chk_map.CHKMap)
1109
1221
        self.assertEqual(
1110
 
            {('', ''): 'TREE_ROOT', ('TREE_ROOT', 'file'): 'fileid'},
 
1222
            {(b'', b''): b'TREE_ROOT', (b'TREE_ROOT', b'file'): b'fileid'},
1111
1223
            dict(chk_inv.parent_id_basename_to_file_id.iteritems()))
1112
1224
 
1113
1225
    def test_file_entry_to_bytes(self):
1114
1226
        inv = CHKInventory(None)
1115
 
        ie = inventory.InventoryFile('file-id', 'filename', 'parent-id')
 
1227
        ie = inventory.InventoryFile(b'file-id', 'filename', b'parent-id')
1116
1228
        ie.executable = True
1117
 
        ie.revision = 'file-rev-id'
1118
 
        ie.text_sha1 = 'abcdefgh'
 
1229
        ie.revision = b'file-rev-id'
 
1230
        ie.text_sha1 = b'abcdefgh'
1119
1231
        ie.text_size = 100
1120
1232
        bytes = inv._entry_to_bytes(ie)
1121
 
        self.assertEqual('file: file-id\nparent-id\nfilename\n'
1122
 
                         'file-rev-id\nabcdefgh\n100\nY', bytes)
 
1233
        self.assertEqual(b'file: file-id\nparent-id\nfilename\n'
 
1234
                         b'file-rev-id\nabcdefgh\n100\nY', bytes)
1123
1235
        ie2 = inv._bytes_to_entry(bytes)
1124
1236
        self.assertEqual(ie, ie2)
1125
 
        self.assertIsInstance(ie2.name, unicode)
1126
 
        self.assertEqual(('filename', 'file-id', 'file-rev-id'),
 
1237
        self.assertIsInstance(ie2.name, text_type)
 
1238
        self.assertEqual((b'filename', b'file-id', b'file-rev-id'),
1127
1239
                         inv._bytes_to_utf8name_key(bytes))
1128
1240
 
1129
1241
    def test_file2_entry_to_bytes(self):
1130
1242
        inv = CHKInventory(None)
1131
1243
        # \u30a9 == 'omega'
1132
 
        ie = inventory.InventoryFile('file-id', u'\u03a9name', 'parent-id')
 
1244
        ie = inventory.InventoryFile(b'file-id', u'\u03a9name', b'parent-id')
1133
1245
        ie.executable = False
1134
 
        ie.revision = 'file-rev-id'
1135
 
        ie.text_sha1 = '123456'
 
1246
        ie.revision = b'file-rev-id'
 
1247
        ie.text_sha1 = b'123456'
1136
1248
        ie.text_size = 25
1137
1249
        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)
 
1250
        self.assertEqual(b'file: file-id\nparent-id\n\xce\xa9name\n'
 
1251
                         b'file-rev-id\n123456\n25\nN', bytes)
1140
1252
        ie2 = inv._bytes_to_entry(bytes)
1141
1253
        self.assertEqual(ie, ie2)
1142
 
        self.assertIsInstance(ie2.name, unicode)
1143
 
        self.assertEqual(('\xce\xa9name', 'file-id', 'file-rev-id'),
 
1254
        self.assertIsInstance(ie2.name, text_type)
 
1255
        self.assertEqual((b'\xce\xa9name', b'file-id', b'file-rev-id'),
1144
1256
                         inv._bytes_to_utf8name_key(bytes))
1145
1257
 
1146
1258
    def test_dir_entry_to_bytes(self):
1147
1259
        inv = CHKInventory(None)
1148
 
        ie = inventory.InventoryDirectory('dir-id', 'dirname', 'parent-id')
1149
 
        ie.revision = 'dir-rev-id'
 
1260
        ie = inventory.InventoryDirectory(b'dir-id', 'dirname', b'parent-id')
 
1261
        ie.revision = b'dir-rev-id'
1150
1262
        bytes = inv._entry_to_bytes(ie)
1151
 
        self.assertEqual('dir: dir-id\nparent-id\ndirname\ndir-rev-id', bytes)
 
1263
        self.assertEqual(b'dir: dir-id\nparent-id\ndirname\ndir-rev-id', bytes)
1152
1264
        ie2 = inv._bytes_to_entry(bytes)
1153
1265
        self.assertEqual(ie, ie2)
1154
 
        self.assertIsInstance(ie2.name, unicode)
1155
 
        self.assertEqual(('dirname', 'dir-id', 'dir-rev-id'),
 
1266
        self.assertIsInstance(ie2.name, text_type)
 
1267
        self.assertEqual((b'dirname', b'dir-id', b'dir-rev-id'),
1156
1268
                         inv._bytes_to_utf8name_key(bytes))
1157
1269
 
1158
1270
    def test_dir2_entry_to_bytes(self):
1159
1271
        inv = CHKInventory(None)
1160
 
        ie = inventory.InventoryDirectory('dir-id', u'dir\u03a9name',
 
1272
        ie = inventory.InventoryDirectory(b'dir-id', u'dir\u03a9name',
1161
1273
                                          None)
1162
 
        ie.revision = 'dir-rev-id'
 
1274
        ie.revision = b'dir-rev-id'
1163
1275
        bytes = inv._entry_to_bytes(ie)
1164
 
        self.assertEqual('dir: dir-id\n\ndir\xce\xa9name\n'
1165
 
                         'dir-rev-id', bytes)
 
1276
        self.assertEqual(b'dir: dir-id\n\ndir\xce\xa9name\n'
 
1277
                         b'dir-rev-id', bytes)
1166
1278
        ie2 = inv._bytes_to_entry(bytes)
1167
1279
        self.assertEqual(ie, ie2)
1168
 
        self.assertIsInstance(ie2.name, unicode)
 
1280
        self.assertIsInstance(ie2.name, text_type)
1169
1281
        self.assertIs(ie2.parent_id, None)
1170
 
        self.assertEqual(('dir\xce\xa9name', 'dir-id', 'dir-rev-id'),
 
1282
        self.assertEqual((b'dir\xce\xa9name', b'dir-id', b'dir-rev-id'),
1171
1283
                         inv._bytes_to_utf8name_key(bytes))
1172
1284
 
1173
1285
    def test_symlink_entry_to_bytes(self):
1174
1286
        inv = CHKInventory(None)
1175
 
        ie = inventory.InventoryLink('link-id', 'linkname', 'parent-id')
1176
 
        ie.revision = 'link-rev-id'
 
1287
        ie = inventory.InventoryLink(b'link-id', 'linkname', b'parent-id')
 
1288
        ie.revision = b'link-rev-id'
1177
1289
        ie.symlink_target = u'target/path'
1178
1290
        bytes = inv._entry_to_bytes(ie)
1179
 
        self.assertEqual('symlink: link-id\nparent-id\nlinkname\n'
1180
 
                         'link-rev-id\ntarget/path', bytes)
 
1291
        self.assertEqual(b'symlink: link-id\nparent-id\nlinkname\n'
 
1292
                         b'link-rev-id\ntarget/path', bytes)
1181
1293
        ie2 = inv._bytes_to_entry(bytes)
1182
1294
        self.assertEqual(ie, ie2)
1183
 
        self.assertIsInstance(ie2.name, unicode)
1184
 
        self.assertIsInstance(ie2.symlink_target, unicode)
1185
 
        self.assertEqual(('linkname', 'link-id', 'link-rev-id'),
 
1295
        self.assertIsInstance(ie2.name, text_type)
 
1296
        self.assertIsInstance(ie2.symlink_target, text_type)
 
1297
        self.assertEqual((b'linkname', b'link-id', b'link-rev-id'),
1186
1298
                         inv._bytes_to_utf8name_key(bytes))
1187
1299
 
1188
1300
    def test_symlink2_entry_to_bytes(self):
1189
1301
        inv = CHKInventory(None)
1190
 
        ie = inventory.InventoryLink('link-id', u'link\u03a9name', 'parent-id')
1191
 
        ie.revision = 'link-rev-id'
 
1302
        ie = inventory.InventoryLink(
 
1303
            b'link-id', u'link\u03a9name', b'parent-id')
 
1304
        ie.revision = b'link-rev-id'
1192
1305
        ie.symlink_target = u'target/\u03a9path'
1193
1306
        bytes = inv._entry_to_bytes(ie)
1194
 
        self.assertEqual('symlink: link-id\nparent-id\nlink\xce\xa9name\n'
1195
 
                         'link-rev-id\ntarget/\xce\xa9path', bytes)
 
1307
        self.assertEqual(b'symlink: link-id\nparent-id\nlink\xce\xa9name\n'
 
1308
                         b'link-rev-id\ntarget/\xce\xa9path', bytes)
1196
1309
        ie2 = inv._bytes_to_entry(bytes)
1197
1310
        self.assertEqual(ie, ie2)
1198
 
        self.assertIsInstance(ie2.name, unicode)
1199
 
        self.assertIsInstance(ie2.symlink_target, unicode)
1200
 
        self.assertEqual(('link\xce\xa9name', 'link-id', 'link-rev-id'),
 
1311
        self.assertIsInstance(ie2.name, text_type)
 
1312
        self.assertIsInstance(ie2.symlink_target, text_type)
 
1313
        self.assertEqual((b'link\xce\xa9name', b'link-id', b'link-rev-id'),
1201
1314
                         inv._bytes_to_utf8name_key(bytes))
1202
1315
 
1203
1316
    def test_tree_reference_entry_to_bytes(self):
1204
1317
        inv = CHKInventory(None)
1205
 
        ie = inventory.TreeReference('tree-root-id', u'tree\u03a9name',
1206
 
                                     'parent-id')
1207
 
        ie.revision = 'tree-rev-id'
1208
 
        ie.reference_revision = 'ref-rev-id'
 
1318
        ie = inventory.TreeReference(b'tree-root-id', u'tree\u03a9name',
 
1319
                                     b'parent-id')
 
1320
        ie.revision = b'tree-rev-id'
 
1321
        ie.reference_revision = b'ref-rev-id'
1209
1322
        bytes = inv._entry_to_bytes(ie)
1210
 
        self.assertEqual('tree: tree-root-id\nparent-id\ntree\xce\xa9name\n'
1211
 
                         'tree-rev-id\nref-rev-id', bytes)
 
1323
        self.assertEqual(b'tree: tree-root-id\nparent-id\ntree\xce\xa9name\n'
 
1324
                         b'tree-rev-id\nref-rev-id', bytes)
1212
1325
        ie2 = inv._bytes_to_entry(bytes)
1213
1326
        self.assertEqual(ie, ie2)
1214
 
        self.assertIsInstance(ie2.name, unicode)
1215
 
        self.assertEqual(('tree\xce\xa9name', 'tree-root-id', 'tree-rev-id'),
 
1327
        self.assertIsInstance(ie2.name, text_type)
 
1328
        self.assertEqual((b'tree\xce\xa9name', b'tree-root-id', b'tree-rev-id'),
1216
1329
                         inv._bytes_to_utf8name_key(bytes))
1217
1330
 
 
1331
    def make_basic_utf8_inventory(self):
 
1332
        inv = Inventory()
 
1333
        inv.revision_id = b"revid"
 
1334
        inv.root.revision = b"rootrev"
 
1335
        root_id = inv.root.file_id
 
1336
        inv.add(InventoryFile(b"fileid", u'f\xefle', root_id))
 
1337
        inv.get_entry(b"fileid").revision = b"filerev"
 
1338
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1339
        inv.get_entry(b"fileid").text_size = 0
 
1340
        inv.add(InventoryDirectory(b"dirid", u'dir-\N{EURO SIGN}', root_id))
 
1341
        inv.get_entry(b"dirid").revision = b"dirrev"
 
1342
        inv.add(InventoryFile(b"childid", u'ch\xefld', b"dirid"))
 
1343
        inv.get_entry(b"childid").revision = b"filerev"
 
1344
        inv.get_entry(b"childid").text_sha1 = b"ffff"
 
1345
        inv.get_entry(b"childid").text_size = 0
 
1346
        chk_bytes = self.get_chk_bytes()
 
1347
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
 
1348
        lines = chk_inv.to_lines()
 
1349
        return CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
1350
 
 
1351
    def test__preload_handles_utf8(self):
 
1352
        new_inv = self.make_basic_utf8_inventory()
 
1353
        self.assertEqual({}, new_inv._fileid_to_entry_cache)
 
1354
        self.assertFalse(new_inv._fully_cached)
 
1355
        new_inv._preload_cache()
 
1356
        self.assertEqual(
 
1357
            sorted([new_inv.root_id, b"fileid", b"dirid", b"childid"]),
 
1358
            sorted(new_inv._fileid_to_entry_cache.keys()))
 
1359
        ie_root = new_inv._fileid_to_entry_cache[new_inv.root_id]
 
1360
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1361
                         sorted(ie_root._children.keys()))
 
1362
        ie_dir = new_inv._fileid_to_entry_cache[b'dirid']
 
1363
        self.assertEqual([u'ch\xefld'], sorted(ie_dir._children.keys()))
 
1364
 
 
1365
    def test__preload_populates_cache(self):
 
1366
        inv = Inventory()
 
1367
        inv.revision_id = b"revid"
 
1368
        inv.root.revision = b"rootrev"
 
1369
        root_id = inv.root.file_id
 
1370
        inv.add(InventoryFile(b"fileid", "file", root_id))
 
1371
        inv.get_entry(b"fileid").revision = b"filerev"
 
1372
        inv.get_entry(b"fileid").executable = True
 
1373
        inv.get_entry(b"fileid").text_sha1 = b"ffff"
 
1374
        inv.get_entry(b"fileid").text_size = 1
 
1375
        inv.add(InventoryDirectory(b"dirid", "dir", root_id))
 
1376
        inv.get_entry(b"dirid").revision = b"dirrev"
 
1377
        inv.add(InventoryFile(b"childid", "child", b"dirid"))
 
1378
        inv.get_entry(b"childid").revision = b"filerev"
 
1379
        inv.get_entry(b"childid").executable = False
 
1380
        inv.get_entry(b"childid").text_sha1 = b"dddd"
 
1381
        inv.get_entry(b"childid").text_size = 1
 
1382
        chk_bytes = self.get_chk_bytes()
 
1383
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
 
1384
        lines = chk_inv.to_lines()
 
1385
        new_inv = CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
 
1386
        self.assertEqual({}, new_inv._fileid_to_entry_cache)
 
1387
        self.assertFalse(new_inv._fully_cached)
 
1388
        new_inv._preload_cache()
 
1389
        self.assertEqual(
 
1390
            sorted([root_id, b"fileid", b"dirid", b"childid"]),
 
1391
            sorted(new_inv._fileid_to_entry_cache.keys()))
 
1392
        self.assertTrue(new_inv._fully_cached)
 
1393
        ie_root = new_inv._fileid_to_entry_cache[root_id]
 
1394
        self.assertEqual(['dir', 'file'], sorted(ie_root._children.keys()))
 
1395
        ie_dir = new_inv._fileid_to_entry_cache[b'dirid']
 
1396
        self.assertEqual(['child'], sorted(ie_dir._children.keys()))
 
1397
 
 
1398
    def test__preload_handles_partially_evaluated_inventory(self):
 
1399
        new_inv = self.make_basic_utf8_inventory()
 
1400
        ie = new_inv.get_entry(new_inv.root_id)
 
1401
        self.assertIs(None, ie._children)
 
1402
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1403
                         sorted(ie.children.keys()))
 
1404
        # Accessing .children loads _children
 
1405
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1406
                         sorted(ie._children.keys()))
 
1407
        new_inv._preload_cache()
 
1408
        # No change
 
1409
        self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
 
1410
                         sorted(ie._children.keys()))
 
1411
        ie_dir = new_inv.get_entry(b"dirid")
 
1412
        self.assertEqual([u'ch\xefld'],
 
1413
                         sorted(ie_dir._children.keys()))
 
1414
 
 
1415
    def test_filter_change_in_renamed_subfolder(self):
 
1416
        inv = Inventory(b'tree-root')
 
1417
        inv.root.revision = b'rootrev'
 
1418
        src_ie = inv.add_path('src', 'directory', b'src-id')
 
1419
        src_ie.revision = b'srcrev'
 
1420
        sub_ie = inv.add_path('src/sub/', 'directory', b'sub-id')
 
1421
        sub_ie.revision = b'subrev'
 
1422
        a_ie = inv.add_path('src/sub/a', 'file', b'a-id')
 
1423
        a_ie.revision = b'filerev'
 
1424
        a_ie.text_sha1 = osutils.sha_string(b'content\n')
 
1425
        a_ie.text_size = len(b'content\n')
 
1426
        chk_bytes = self.get_chk_bytes()
 
1427
        inv = CHKInventory.from_inventory(chk_bytes, inv)
 
1428
        inv = inv.create_by_apply_delta([
 
1429
            ("src/sub/a", "src/sub/a", b"a-id", a_ie),
 
1430
            ("src", "src2", b"src-id", src_ie),
 
1431
            ], b'new-rev-2')
 
1432
        new_inv = inv.filter([b'a-id', b'src-id'])
 
1433
        self.assertEqual([
 
1434
            ('', b'tree-root'),
 
1435
            ('src', b'src-id'),
 
1436
            ('src/sub', b'sub-id'),
 
1437
            ('src/sub/a', b'a-id'),
 
1438
            ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()])
 
1439
 
1218
1440
 
1219
1441
class TestCHKInventoryExpand(tests.TestCaseWithMemoryTransport):
1220
1442
 
1223
1445
        trans = self.get_transport('')
1224
1446
        return factory(trans)
1225
1447
 
1226
 
    def make_dir(self, inv, name, parent_id):
1227
 
        inv.add(inv.make_entry('directory', name, parent_id, name + '-id'))
 
1448
    def make_dir(self, inv, name, parent_id, revision):
 
1449
        ie = inv.make_entry('directory', name, parent_id,
 
1450
                            name.encode('utf-8') + b'-id')
 
1451
        ie.revision = revision
 
1452
        inv.add(ie)
1228
1453
 
1229
 
    def make_file(self, inv, name, parent_id, content='content\n'):
1230
 
        ie = inv.make_entry('file', name, parent_id, name + '-id')
 
1454
    def make_file(self, inv, name, parent_id, revision, content=b'content\n'):
 
1455
        ie = inv.make_entry('file', name, parent_id,
 
1456
                            name.encode('utf-8') + b'-id')
1231
1457
        ie.text_sha1 = osutils.sha_string(content)
1232
1458
        ie.text_size = len(content)
 
1459
        ie.revision = revision
1233
1460
        inv.add(ie)
1234
1461
 
1235
1462
    def make_simple_inventory(self):
1236
 
        inv = Inventory('TREE_ROOT')
1237
 
        inv.revision_id = "revid"
1238
 
        inv.root.revision = "rootrev"
 
1463
        inv = Inventory(b'TREE_ROOT')
 
1464
        inv.revision_id = b"revid"
 
1465
        inv.root.revision = b"rootrev"
1239
1466
        # /                 TREE_ROOT
1240
1467
        # dir1/             dir1-id
1241
1468
        #   sub-file1       sub-file1-id
1245
1472
        # dir2/             dir2-id
1246
1473
        #   sub2-file1      sub2-file1-id
1247
1474
        # top               top-id
1248
 
        self.make_dir(inv, 'dir1', 'TREE_ROOT')
1249
 
        self.make_dir(inv, 'dir2', 'TREE_ROOT')
1250
 
        self.make_dir(inv, 'sub-dir1', 'dir1-id')
1251
 
        self.make_file(inv, 'top', 'TREE_ROOT')
1252
 
        self.make_file(inv, 'sub-file1', 'dir1-id')
1253
 
        self.make_file(inv, 'sub-file2', 'dir1-id')
1254
 
        self.make_file(inv, 'subsub-file1', 'sub-dir1-id')
1255
 
        self.make_file(inv, 'sub2-file1', 'dir2-id')
 
1475
        self.make_dir(inv, 'dir1', b'TREE_ROOT', b'dirrev')
 
1476
        self.make_dir(inv, 'dir2', b'TREE_ROOT', b'dirrev')
 
1477
        self.make_dir(inv, 'sub-dir1', b'dir1-id', b'dirrev')
 
1478
        self.make_file(inv, 'top', b'TREE_ROOT', b'filerev')
 
1479
        self.make_file(inv, 'sub-file1', b'dir1-id', b'filerev')
 
1480
        self.make_file(inv, 'sub-file2', b'dir1-id', b'filerev')
 
1481
        self.make_file(inv, 'subsub-file1', b'sub-dir1-id', b'filerev')
 
1482
        self.make_file(inv, 'sub2-file1', b'dir2-id', b'filerev')
1256
1483
        chk_bytes = self.get_chk_bytes()
1257
1484
        #  use a small maximum_size to force internal paging structures
1258
1485
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
1259
 
                        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",))
 
1486
                                              maximum_size=100,
 
1487
                                              search_key_name=b'hash-255-way')
 
1488
        lines = chk_inv.to_lines()
 
1489
        return CHKInventory.deserialise(chk_bytes, lines, (b"revid",))
1263
1490
 
1264
1491
    def assert_Getitems(self, expected_fileids, inv, file_ids):
1265
1492
        self.assertEqual(sorted(expected_fileids),
1274
1501
        for entry in entries:
1275
1502
            s = expected_children.setdefault(entry.parent_id, [])
1276
1503
            s.append(entry.file_id)
1277
 
        val_children = dict((k, sorted(v)) for k, v
1278
 
                            in val_children.iteritems())
1279
 
        expected_children = dict((k, sorted(v)) for k, v
1280
 
                            in expected_children.iteritems())
 
1504
        val_children = {
 
1505
            k: sorted(v) for k, v in val_children.items()}
 
1506
        expected_children = {
 
1507
            k: sorted(v) for k, v in expected_children.items()}
1281
1508
        self.assertEqual(expected_children, val_children)
1282
1509
 
1283
1510
    def test_make_simple_inventory(self):
1286
1513
        for path, entry in inv.iter_entries_by_dir():
1287
1514
            layout.append((path, entry.file_id))
1288
1515
        self.assertEqual([
1289
 
            ('', 'TREE_ROOT'),
1290
 
            ('dir1', 'dir1-id'),
1291
 
            ('dir2', 'dir2-id'),
1292
 
            ('top', 'top-id'),
1293
 
            ('dir1/sub-dir1', 'sub-dir1-id'),
1294
 
            ('dir1/sub-file1', 'sub-file1-id'),
1295
 
            ('dir1/sub-file2', 'sub-file2-id'),
1296
 
            ('dir1/sub-dir1/subsub-file1', 'subsub-file1-id'),
1297
 
            ('dir2/sub2-file1', 'sub2-file1-id'),
 
1516
            ('', b'TREE_ROOT'),
 
1517
            ('dir1', b'dir1-id'),
 
1518
            ('dir2', b'dir2-id'),
 
1519
            ('top', b'top-id'),
 
1520
            ('dir1/sub-dir1', b'sub-dir1-id'),
 
1521
            ('dir1/sub-file1', b'sub-file1-id'),
 
1522
            ('dir1/sub-file2', b'sub-file2-id'),
 
1523
            ('dir1/sub-dir1/subsub-file1', b'subsub-file1-id'),
 
1524
            ('dir2/sub2-file1', b'sub2-file1-id'),
1298
1525
            ], layout)
1299
1526
 
1300
1527
    def test__getitems(self):
1301
1528
        inv = self.make_simple_inventory()
1302
1529
        # Reading from disk
1303
 
        self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
1304
 
        self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
1305
 
        self.assertFalse('sub-file2-id' in inv._fileid_to_entry_cache)
 
1530
        self.assert_Getitems([b'dir1-id'], inv, [b'dir1-id'])
 
1531
        self.assertTrue(b'dir1-id' in inv._fileid_to_entry_cache)
 
1532
        self.assertFalse(b'sub-file2-id' in inv._fileid_to_entry_cache)
1306
1533
        # From cache
1307
 
        self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
 
1534
        self.assert_Getitems([b'dir1-id'], inv, [b'dir1-id'])
1308
1535
        # Mixed
1309
 
        self.assert_Getitems(['dir1-id', 'sub-file2-id'], inv,
1310
 
                             ['dir1-id', 'sub-file2-id'])
1311
 
        self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
1312
 
        self.assertTrue('sub-file2-id' in inv._fileid_to_entry_cache)
 
1536
        self.assert_Getitems([b'dir1-id', b'sub-file2-id'], inv,
 
1537
                             [b'dir1-id', b'sub-file2-id'])
 
1538
        self.assertTrue(b'dir1-id' in inv._fileid_to_entry_cache)
 
1539
        self.assertTrue(b'sub-file2-id' in inv._fileid_to_entry_cache)
1313
1540
 
1314
1541
    def test_single_file(self):
1315
1542
        inv = self.make_simple_inventory()
1316
 
        self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
 
1543
        self.assertExpand([b'TREE_ROOT', b'top-id'], inv, [b'top-id'])
1317
1544
 
1318
1545
    def test_get_all_parents(self):
1319
1546
        inv = self.make_simple_inventory()
1320
 
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1321
 
                           'subsub-file1-id',
1322
 
                          ], inv, ['subsub-file1-id'])
 
1547
        self.assertExpand([b'TREE_ROOT', b'dir1-id', b'sub-dir1-id',
 
1548
                           b'subsub-file1-id',
 
1549
                           ], inv, [b'subsub-file1-id'])
1323
1550
 
1324
1551
    def test_get_children(self):
1325
1552
        inv = self.make_simple_inventory()
1326
 
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1327
 
                           'sub-file1-id', 'sub-file2-id', 'subsub-file1-id',
1328
 
                          ], inv, ['dir1-id'])
 
1553
        self.assertExpand([b'TREE_ROOT', b'dir1-id', b'sub-dir1-id',
 
1554
                           b'sub-file1-id', b'sub-file2-id', b'subsub-file1-id',
 
1555
                           ], inv, [b'dir1-id'])
1329
1556
 
1330
1557
    def test_from_root(self):
1331
1558
        inv = self.make_simple_inventory()
1332
 
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'dir2-id', 'sub-dir1-id',
1333
 
                           'sub-file1-id', 'sub-file2-id', 'sub2-file1-id',
1334
 
                           'subsub-file1-id', 'top-id'], inv, ['TREE_ROOT'])
 
1559
        self.assertExpand([b'TREE_ROOT', b'dir1-id', b'dir2-id', b'sub-dir1-id',
 
1560
                           b'sub-file1-id', b'sub-file2-id', b'sub2-file1-id',
 
1561
                           b'subsub-file1-id', b'top-id'], inv, [b'TREE_ROOT'])
1335
1562
 
1336
1563
    def test_top_level_file(self):
1337
1564
        inv = self.make_simple_inventory()
1338
 
        self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
 
1565
        self.assertExpand([b'TREE_ROOT', b'top-id'], inv, [b'top-id'])
1339
1566
 
1340
1567
    def test_subsub_file(self):
1341
1568
        inv = self.make_simple_inventory()
1342
 
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1343
 
                           'subsub-file1-id'], inv, ['subsub-file1-id'])
 
1569
        self.assertExpand([b'TREE_ROOT', b'dir1-id', b'sub-dir1-id',
 
1570
                           b'subsub-file1-id'], inv, [b'subsub-file1-id'])
1344
1571
 
1345
1572
    def test_sub_and_root(self):
1346
1573
        inv = self.make_simple_inventory()
1347
 
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id', 'top-id',
1348
 
                           'subsub-file1-id'], inv, ['top-id', 'subsub-file1-id'])
 
1574
        self.assertExpand([b'TREE_ROOT', b'dir1-id', b'sub-dir1-id', b'top-id',
 
1575
                           b'subsub-file1-id'], inv, [b'top-id', b'subsub-file1-id'])
 
1576
 
 
1577
 
 
1578
class TestMutableInventoryFromTree(TestCaseWithTransport):
 
1579
 
 
1580
    def test_empty(self):
 
1581
        repository = self.make_repository('.')
 
1582
        tree = repository.revision_tree(revision.NULL_REVISION)
 
1583
        inv = mutable_inventory_from_tree(tree)
 
1584
        self.assertEqual(revision.NULL_REVISION, inv.revision_id)
 
1585
        self.assertEqual(0, len(inv))
 
1586
 
 
1587
    def test_some_files(self):
 
1588
        wt = self.make_branch_and_tree('.')
 
1589
        self.build_tree(['a'])
 
1590
        wt.add(['a'], [b'thefileid'])
 
1591
        revid = wt.commit("commit")
 
1592
        tree = wt.branch.repository.revision_tree(revid)
 
1593
        inv = mutable_inventory_from_tree(tree)
 
1594
        self.assertEqual(revid, inv.revision_id)
 
1595
        self.assertEqual(2, len(inv))
 
1596
        self.assertEqual("a", inv.get_entry(b'thefileid').name)
 
1597
        # The inventory should be mutable and independent of
 
1598
        # the original tree
 
1599
        self.assertFalse(tree.root_inventory.get_entry(
 
1600
            b'thefileid').executable)
 
1601
        inv.get_entry(b'thefileid').executable = True
 
1602
        self.assertFalse(tree.root_inventory.get_entry(
 
1603
            b'thefileid').executable)