/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5365.5.25 by John Arbash Meinel
Merge bzr.dev 5387 in prep for NEWS
1
# Copyright (C) 2005-2010 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
963 by Martin Pool
- add the start of a test for inventory file-id matching
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
963 by Martin Pool
- add the start of a test for inventory file-id matching
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
963 by Martin Pool
- add the start of a test for inventory file-id matching
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
963 by Martin Pool
- add the start of a test for inventory file-id matching
16
2729.2.5 by Martin Pool
Move per-inventory tests from test_inv to tests.inventory_implementations
17
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
18
from bzrlib import (
19
    chk_map,
4634.51.1 by John Arbash Meinel
Switch away from creating a whole repository just to get a VF.
20
    groupcompress,
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
21
    errors,
22
    inventory,
23
    osutils,
24
    repository,
25
    revision,
4634.51.1 by John Arbash Meinel
Switch away from creating a whole repository just to get a VF.
26
    tests,
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
27
    )
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
28
from bzrlib.inventory import (CHKInventory, Inventory, ROOT_ID, InventoryFile,
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
29
    InventoryDirectory, InventoryEntry, TreeReference)
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
30
from bzrlib.tests import (
31
    TestCase,
32
    TestCaseWithTransport,
33
    condition_isinstance,
34
    multiply_tests,
35
    )
4525.1.1 by Vincent Ladeuil
Finish the *_implementation to per_* test renaming
36
from bzrlib.tests.per_workingtree import workingtree_formats
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
37
from bzrlib.tests.scenarios import load_tests_apply_scenarios
38
39
40
load_tests = load_tests_apply_scenarios
41
42
43
def delta_application_scenarios():
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
44
    scenarios = [
45
        ('Inventory', {'apply_delta':apply_inventory_Inventory}),
46
        ]
47
    # Working tree basis delta application
48
    # Repository add_inv_by_delta.
49
    # Reduce form of the per_repository test logic - that logic needs to be
50
    # be able to get /just/ repositories whereas these tests are fine with
51
    # just creating trees.
52
    formats = set()
53
    for _, format in repository.format_registry.iteritems():
54
        scenarios.append((str(format.__name__), {
55
            'apply_delta':apply_inventory_Repository_add_inventory_by_delta,
56
            'format':format}))
57
    for format in workingtree_formats():
4526.9.2 by Robert Collins
Handle deltas with new paths not matching the actual path.
58
        scenarios.append(
59
            (str(format.__class__.__name__) + ".update_basis_by_delta", {
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
60
            'apply_delta':apply_inventory_WT_basis,
61
            'format':format}))
4526.9.2 by Robert Collins
Handle deltas with new paths not matching the actual path.
62
        scenarios.append(
63
            (str(format.__class__.__name__) + ".apply_inventory_delta", {
4526.9.1 by Robert Collins
Add WorkingTree.apply_inventory_delta to the set of delta implementations interface tested.
64
            'apply_delta':apply_inventory_WT,
65
            'format':format}))
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
66
    return scenarios
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
67
68
4634.35.19 by Andrew Bennetts
Fix test_inv.
69
def create_texts_for_inv(repo, inv):
70
    for path, ie in inv.iter_entries():
71
        if ie.text_size:
72
            lines = ['a' * ie.text_size]
73
        else:
74
            lines = []
75
        repo.texts.add_lines((ie.file_id, ie.revision), [], lines)
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
76
4634.35.19 by Andrew Bennetts
Fix test_inv.
77
    
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
78
def apply_inventory_Inventory(self, basis, delta):
79
    """Apply delta to basis and return the result.
80
    
81
    :param basis: An inventory to be used as the basis.
82
    :param delta: The inventory delta to apply:
83
    :return: An inventory resulting from the application.
84
    """
85
    basis.apply_delta(delta)
86
    return basis
87
88
4526.9.1 by Robert Collins
Add WorkingTree.apply_inventory_delta to the set of delta implementations interface tested.
89
def apply_inventory_WT(self, basis, delta):
90
    """Apply delta to basis and return the result.
91
92
    This sets the tree state to be basis, and then calls apply_inventory_delta.
93
    
94
    :param basis: An inventory to be used as the basis.
95
    :param delta: The inventory delta to apply:
96
    :return: An inventory resulting from the application.
97
    """
98
    control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
99
    control.create_repository()
100
    control.create_branch()
101
    tree = self.format.initialize(control)
102
    tree.lock_write()
103
    try:
104
        tree._write_inventory(basis)
105
    finally:
106
        tree.unlock()
107
    # Fresh object, reads disk again.
108
    tree = tree.bzrdir.open_workingtree()
109
    tree.lock_write()
110
    try:
111
        tree.apply_inventory_delta(delta)
112
    finally:
113
        tree.unlock()
114
    # reload tree - ensure we get what was written.
115
    tree = tree.bzrdir.open_workingtree()
116
    tree.lock_read()
117
    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
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
125
def apply_inventory_WT_basis(self, basis, delta):
126
    """Apply delta to basis and return the result.
127
128
    This sets the parent and then calls update_basis_by_delta.
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
129
    It also puts the basis in the repository under both 'basis' and 'result' to
130
    allow safety checks made by the WT to succeed, and finally ensures that all
131
    items in the delta with a new path are present in the WT before calling
132
    update_basis_by_delta.
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
133
    
134
    :param basis: An inventory to be used as the basis.
135
    :param delta: The inventory delta to apply:
136
    :return: An inventory resulting from the application.
137
    """
138
    control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
139
    control.create_repository()
140
    control.create_branch()
141
    tree = self.format.initialize(control)
142
    tree.lock_write()
143
    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'
4634.35.19 by Andrew Bennetts
Fix test_inv.
150
            create_texts_for_inv(tree.branch.repository, basis)
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
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)
4634.35.19 by Andrew Bennetts
Fix test_inv.
160
            repo.commit_write_group()
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
161
        except:
162
            repo.abort_write_group()
163
            raise
4505.5.5 by Robert Collins
Parents used in a delta must be directories.
164
        # Set the basis state as the trees current state
165
        tree._write_inventory(basis)
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
166
        # This reads basis from the repo and puts it into the tree's local
167
        # cache, if it has one.
168
        tree.set_parent_ids(['basis'])
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
169
        paths = {}
170
        parents = set()
171
        for old, new, id, entry in delta:
4526.9.4 by Robert Collins
Look for trivial issues with new_path and entry being out of sync in deltas.
172
            if None in (new, entry):
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
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('')
4505.5.5 by Robert Collins
Parents used in a delta must be directories.
178
        # Put place holders in the tree to permit adding the other entries.
4505.5.6 by Robert Collins
Check for missing parents in deltas.
179
        for pos, parent in enumerate(parents):
4505.5.5 by Robert Collins
Parents used in a delta must be directories.
180
            if not tree.path2id(parent):
4505.5.6 by Robert Collins
Check for missing parents in deltas.
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"])
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
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
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
195
    finally:
196
        tree.unlock()
197
    # Fresh lock, reads disk again.
198
    tree.lock_write()
199
    try:
200
        tree.update_basis_by_delta('result', delta)
201
    finally:
202
        tree.unlock()
203
    # reload tree - ensure we get what was written.
204
    tree = tree.bzrdir.open_workingtree()
205
    basis_tree = tree.basis_tree()
206
    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):
215
    """Apply delta to basis and return the result.
216
    
217
    This inserts basis as a whole inventory and then uses
218
    add_inventory_by_delta to add delta.
219
220
    :param basis: An inventory to be used as the basis.
221
    :param delta: The inventory delta to apply:
222
    :return: An inventory resulting from the application.
223
    """
224
    format = self.format()
225
    control = self.make_bzrdir('tree', format=format._matchingbzrdir)
226
    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'
4634.35.19 by Andrew Bennetts
Fix test_inv.
234
            create_texts_for_inv(repo, basis)
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
235
            repo.add_revision('basis', rev, basis)
4634.35.19 by Andrew Bennetts
Fix test_inv.
236
            repo.commit_write_group()
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
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()
255
    # Fresh lock, reads disk again.
256
    repo = repo.bzrdir.open_repository()
257
    repo.lock_read()
258
    self.addCleanup(repo.unlock)
259
    return repo.get_inventory('result')
260
261
4634.51.7 by John Arbash Meinel
Finish adding CHKInventory as a permutation in per_inventory.
262
class TestInventoryUpdates(TestCase):
263
264
    def test_creation_from_root_id(self):
265
        # iff a root id is passed to the constructor, a root directory is made
266
        inv = inventory.Inventory(root_id='tree-root')
267
        self.assertNotEqual(None, inv.root)
268
        self.assertEqual('tree-root', inv.root.file_id)
269
270
    def test_add_path_of_root(self):
271
        # if no root id is given at creation time, there is no root directory
272
        inv = inventory.Inventory(root_id=None)
273
        self.assertIs(None, inv.root)
274
        # 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)
278
        self.assertIs(ie, inv.root)
279
280
    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)
284
        self.assertEqual('file', ie.kind)
285
286
    def test_copy(self):
287
        """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')
290
        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
296
    def test_copy_empty(self):
297
        """Make sure an empty inventory can be copied."""
298
        inv = inventory.Inventory(root_id=None)
299
        inv2 = inv.copy()
300
        self.assertIs(None, inv2.root)
301
302
    def test_copy_copies_root_revision(self):
303
        """Make sure the revision of the root gets copied."""
304
        inv = inventory.Inventory(root_id='someroot')
305
        inv.root.revision = 'therev'
306
        inv2 = inv.copy()
307
        self.assertEquals('someroot', inv2.root.file_id)
308
        self.assertEquals('therev', inv2.root.revision)
309
310
    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'))
314
315
    def test_error_encoding(self):
316
        inv = inventory.Inventory('tree-root')
317
        inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
318
        e = self.assertRaises(errors.InconsistentDelta, inv.add,
319
            InventoryFile('b-id', u'\u1234', 'tree-root'))
320
        self.assertContainsRe(str(e), r'\\u1234')
321
322
    def test_add_recursive(self):
323
        parent = InventoryDirectory('src-id', 'src', 'tree-root')
324
        child = InventoryFile('hello-id', 'hello.c', 'src-id')
325
        parent.children[child.file_id] = child
326
        inv = inventory.Inventory('tree-root')
327
        inv.add(parent)
328
        self.assertEqual('src/hello.c', inv.id2path('hello-id'))
329
330
331
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
332
class TestDeltaApplication(TestCaseWithTransport):
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
333
334
    scenarios = delta_application_scenarios()
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
335
 
336
    def get_empty_inventory(self, reference_inv=None):
337
        """Get an empty inventory.
338
339
        Note that tests should not depend on the revision of the root for
340
        setting up test conditions, as it has to be flexible to accomodate non
341
        rich root repositories.
342
343
        :param reference_inv: If not None, get the revision for the root from
344
            this inventory. This is useful for dealing with older repositories
345
            that routinely discarded the root entry data. If None, the root's
346
            revision is set to 'basis'.
347
        """
348
        inv = inventory.Inventory()
349
        if reference_inv is not None:
350
            inv.root.revision = reference_inv.root.revision
351
        else:
352
            inv.root.revision = 'basis'
353
        return inv
354
355
    def test_empty_delta(self):
356
        inv = self.get_empty_inventory()
357
        delta = []
358
        inv = self.apply_delta(self, inv, delta)
359
        inv2 = self.get_empty_inventory(inv)
360
        self.assertEqual([], inv2._make_delta(inv))
361
4526.9.22 by Robert Collins
Check fileids in inventory deltas are not None and are strings.
362
    def test_None_file_id(self):
363
        inv = self.get_empty_inventory()
364
        dir1 = inventory.InventoryDirectory(None, 'dir1', inv.root.file_id)
365
        dir1.revision = 'result'
366
        delta = [(None, u'dir1', None, dir1)]
367
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
368
            inv, delta)
369
370
    def test_unicode_file_id(self):
371
        inv = self.get_empty_inventory()
372
        dir1 = inventory.InventoryDirectory(u'dirid', 'dir1', inv.root.file_id)
373
        dir1.revision = 'result'
374
        delta = [(None, u'dir1', dir1.file_id, dir1)]
375
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
376
            inv, delta)
377
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
378
    def test_repeated_file_id(self):
379
        inv = self.get_empty_inventory()
380
        file1 = inventory.InventoryFile('id', 'path1', inv.root.file_id)
381
        file1.revision = 'result'
382
        file1.text_size = 0
383
        file1.text_sha1 = ""
384
        file2 = inventory.InventoryFile('id', 'path2', inv.root.file_id)
385
        file2.revision = 'result'
386
        file2.text_size = 0
387
        file2.text_sha1 = ""
4505.5.7 by Robert Collins
Handle unicode parents correctly in dirstate parent checking.
388
        delta = [(None, u'path1', 'id', file1), (None, u'path2', 'id', file2)]
4505.5.3 by Robert Collins
Test infrastructure for testing all inventory delta applications and fix CHK inventories to reject repeated file ids in deltas.
389
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
390
            inv, delta)
963 by Martin Pool
- add the start of a test for inventory file-id matching
391
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
392
    def test_repeated_new_path(self):
393
        inv = self.get_empty_inventory()
394
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
395
        file1.revision = 'result'
396
        file1.text_size = 0
397
        file1.text_sha1 = ""
398
        file2 = inventory.InventoryFile('id2', 'path', inv.root.file_id)
399
        file2.revision = 'result'
400
        file2.text_size = 0
401
        file2.text_sha1 = ""
4505.5.7 by Robert Collins
Handle unicode parents correctly in dirstate parent checking.
402
        delta = [(None, u'path', 'id1', file1), (None, u'path', 'id2', file2)]
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
403
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
404
            inv, delta)
405
406
    def test_repeated_old_path(self):
407
        inv = self.get_empty_inventory()
408
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
409
        file1.revision = 'result'
410
        file1.text_size = 0
411
        file1.text_sha1 = ""
412
        # We can't *create* a source inventory with the same path, but
413
        # a badly generated partial delta might claim the same source twice.
414
        # This would be buggy in two ways: the path is repeated in the delta,
415
        # And the path for one of the file ids doesn't match the source
416
        # location. Alternatively, we could have a repeated fileid, but that
417
        # is separately checked for.
418
        file2 = inventory.InventoryFile('id2', 'path2', inv.root.file_id)
419
        file2.revision = 'result'
420
        file2.text_size = 0
421
        file2.text_sha1 = ""
422
        inv.add(file1)
423
        inv.add(file2)
4505.5.7 by Robert Collins
Handle unicode parents correctly in dirstate parent checking.
424
        delta = [(u'path', None, 'id1', None), (u'path', None, 'id2', None)]
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
425
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
426
            inv, delta)
427
428
    def test_mismatched_id_entry_id(self):
429
        inv = self.get_empty_inventory()
430
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
431
        file1.revision = 'result'
432
        file1.text_size = 0
433
        file1.text_sha1 = ""
4505.5.7 by Robert Collins
Handle unicode parents correctly in dirstate parent checking.
434
        delta = [(None, u'path', 'id', file1)]
4505.5.4 by Robert Collins
Repeated path/id corruption detected.
435
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
436
            inv, delta)
437
4526.9.4 by Robert Collins
Look for trivial issues with new_path and entry being out of sync in deltas.
438
    def test_mismatched_new_path_entry_None(self):
439
        inv = self.get_empty_inventory()
440
        delta = [(None, u'path', 'id', None)]
441
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
442
            inv, delta)
443
444
    def test_mismatched_new_path_None_entry(self):
445
        inv = self.get_empty_inventory()
446
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
447
        file1.revision = 'result'
448
        file1.text_size = 0
449
        file1.text_sha1 = ""
450
        delta = [(u"path", None, 'id1', file1)]
451
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
452
            inv, delta)
453
4505.5.5 by Robert Collins
Parents used in a delta must be directories.
454
    def test_parent_is_not_directory(self):
455
        inv = self.get_empty_inventory()
456
        file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
457
        file1.revision = 'result'
458
        file1.text_size = 0
459
        file1.text_sha1 = ""
460
        file2 = inventory.InventoryFile('id2', 'path2', 'id1')
461
        file2.revision = 'result'
462
        file2.text_size = 0
463
        file2.text_sha1 = ""
464
        inv.add(file1)
4505.5.7 by Robert Collins
Handle unicode parents correctly in dirstate parent checking.
465
        delta = [(None, u'path/path2', 'id2', file2)]
4505.5.5 by Robert Collins
Parents used in a delta must be directories.
466
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
467
            inv, delta)
468
4505.5.6 by Robert Collins
Check for missing parents in deltas.
469
    def test_parent_is_missing(self):
470
        inv = self.get_empty_inventory()
471
        file2 = inventory.InventoryFile('id2', 'path2', 'missingparent')
472
        file2.revision = 'result'
473
        file2.text_size = 0
474
        file2.text_sha1 = ""
4505.5.7 by Robert Collins
Handle unicode parents correctly in dirstate parent checking.
475
        delta = [(None, u'path/path2', 'id2', file2)]
4505.5.6 by Robert Collins
Check for missing parents in deltas.
476
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
477
            inv, delta)
478
4526.9.2 by Robert Collins
Handle deltas with new paths not matching the actual path.
479
    def test_new_parent_path_has_wrong_id(self):
480
        inv = self.get_empty_inventory()
481
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
482
        parent1.revision = 'result'
483
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
484
        parent2.revision = 'result'
485
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
486
        file1.revision = 'result'
487
        file1.text_size = 0
488
        file1.text_sha1 = ""
489
        inv.add(parent1)
490
        inv.add(parent2)
491
        # This delta claims that file1 is at dir/path, but actually its at
492
        # dir2/path if you follow the inventory parent structure.
493
        delta = [(None, u'dir/path', 'id', file1)]
494
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
495
            inv, delta)
496
4526.9.3 by Robert Collins
Handle mismatches between inventory delta paths and actual paths found by traversing parent pointers.
497
    def test_old_parent_path_is_wrong(self):
498
        inv = self.get_empty_inventory()
499
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
500
        parent1.revision = 'result'
501
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
502
        parent2.revision = 'result'
503
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
504
        file1.revision = 'result'
505
        file1.text_size = 0
506
        file1.text_sha1 = ""
507
        inv.add(parent1)
508
        inv.add(parent2)
509
        inv.add(file1)
510
        # This delta claims that file1 was at dir/path, but actually it was at
511
        # dir2/path if you follow the inventory parent structure.
512
        delta = [(u'dir/path', None, 'id', None)]
513
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
514
            inv, delta)
515
516
    def test_old_parent_path_is_for_other_id(self):
517
        inv = self.get_empty_inventory()
518
        parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
519
        parent1.revision = 'result'
520
        parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
521
        parent2.revision = 'result'
522
        file1 = inventory.InventoryFile('id', 'path', 'p-2')
523
        file1.revision = 'result'
524
        file1.text_size = 0
525
        file1.text_sha1 = ""
526
        file2 = inventory.InventoryFile('id2', 'path', 'p-1')
527
        file2.revision = 'result'
528
        file2.text_size = 0
529
        file2.text_sha1 = ""
530
        inv.add(parent1)
531
        inv.add(parent2)
532
        inv.add(file1)
533
        inv.add(file2)
534
        # This delta claims that file1 was at dir/path, but actually it was at
535
        # dir2/path if you follow the inventory parent structure. At dir/path
536
        # is another entry we should not delete.
537
        delta = [(u'dir/path', None, 'id', None)]
538
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
539
            inv, delta)
540
4526.9.5 by Robert Collins
Require that added ids in inventory deltas be new.
541
    def test_add_existing_id_new_path(self):
542
        inv = self.get_empty_inventory()
543
        parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
544
        parent1.revision = 'result'
545
        parent2 = inventory.InventoryDirectory('p-1', 'dir2', inv.root.file_id)
546
        parent2.revision = 'result'
547
        inv.add(parent1)
548
        delta = [(None, u'dir2', 'p-1', parent2)]
549
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
550
            inv, delta)
551
4526.9.8 by Robert Collins
Check that the paths deltas put entries into are not in use already.
552
    def test_add_new_id_existing_path(self):
553
        inv = self.get_empty_inventory()
554
        parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
555
        parent1.revision = 'result'
556
        parent2 = inventory.InventoryDirectory('p-2', 'dir1', inv.root.file_id)
557
        parent2.revision = 'result'
558
        inv.add(parent1)
559
        delta = [(None, u'dir1', 'p-2', parent2)]
560
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
561
            inv, delta)
562
4526.9.9 by Robert Collins
Add interface tests for dangling children in inventory deltas.
563
    def test_remove_dir_leaving_dangling_child(self):
564
        inv = self.get_empty_inventory()
565
        dir1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
566
        dir1.revision = 'result'
567
        dir2 = inventory.InventoryDirectory('p-2', 'child1', 'p-1')
568
        dir2.revision = 'result'
569
        dir3 = inventory.InventoryDirectory('p-3', 'child2', 'p-1')
570
        dir3.revision = 'result'
571
        inv.add(dir1)
572
        inv.add(dir2)
573
        inv.add(dir3)
574
        delta = [(u'dir1', None, 'p-1', None),
575
            (u'dir1/child2', None, 'p-3', None)]
576
        self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
577
            inv, delta)
578
969 by Martin Pool
- Add less-sucky is_within_any
579
4634.51.7 by John Arbash Meinel
Finish adding CHKInventory as a permutation in per_inventory.
580
class TestInventory(TestCase):
581
582
    def test_is_root(self):
583
        """Ensure our root-checking code is accurate."""
584
        inv = inventory.Inventory('TREE_ROOT')
585
        self.assertTrue(inv.is_root('TREE_ROOT'))
586
        self.assertFalse(inv.is_root('booga'))
587
        inv.root.file_id = 'booga'
588
        self.assertFalse(inv.is_root('TREE_ROOT'))
589
        self.assertTrue(inv.is_root('booga'))
590
        # works properly even if no root is set
591
        inv.root = None
592
        self.assertFalse(inv.is_root('TREE_ROOT'))
593
        self.assertFalse(inv.is_root('booga'))
594
5410.1.2 by Daniel Knittl-Frank
Add a test case for `entries()` on empty inventory
595
    def test_entries_for_empty_inventory(self):
596
        """Test that entries() will not fail for an empty inventory"""
5410.1.3 by Daniel Knittl-Frank
fix whitespace (only use spaces)
597
        inv = Inventory(root_id=None)
598
        self.assertEqual([], inv.entries())
5410.1.2 by Daniel Knittl-Frank
Add a test case for `entries()` on empty inventory
599
4634.51.7 by John Arbash Meinel
Finish adding CHKInventory as a permutation in per_inventory.
600
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
601
class TestInventoryEntry(TestCase):
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
602
603
    def test_file_kind_character(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
604
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
605
        self.assertEqual(file.kind_character(), '')
606
607
    def test_dir_kind_character(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
608
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
609
        self.assertEqual(dir.kind_character(), '/')
610
611
    def test_link_kind_character(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
612
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
613
        self.assertEqual(dir.kind_character(), '')
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
614
615
    def test_dir_detect_changes(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
616
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
617
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
618
        self.assertEqual((False, False), left.detect_changes(right))
619
        self.assertEqual((False, False), right.detect_changes(left))
620
621
    def test_file_detect_changes(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
622
        left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
623
        left.text_sha1 = 123
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
624
        right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
625
        right.text_sha1 = 123
626
        self.assertEqual((False, False), left.detect_changes(right))
627
        self.assertEqual((False, False), right.detect_changes(left))
628
        left.executable = True
629
        self.assertEqual((False, True), left.detect_changes(right))
630
        self.assertEqual((False, True), right.detect_changes(left))
631
        right.text_sha1 = 321
632
        self.assertEqual((True, True), left.detect_changes(right))
633
        self.assertEqual((True, True), right.detect_changes(left))
634
635
    def test_symlink_detect_changes(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
636
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
637
        left.symlink_target='foo'
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
638
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
639
        right.symlink_target='foo'
640
        self.assertEqual((False, False), left.detect_changes(right))
641
        self.assertEqual((False, False), right.detect_changes(left))
642
        left.symlink_target = 'different'
643
        self.assertEqual((True, False), left.detect_changes(right))
644
        self.assertEqual((True, False), right.detect_changes(left))
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
645
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
646
    def test_file_has_text(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
647
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
648
        self.failUnless(file.has_text())
649
650
    def test_directory_has_text(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
651
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
652
        self.failIf(dir.has_text())
653
654
    def test_link_has_text(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
655
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
656
        self.failIf(link.has_text())
657
1713.1.11 by Robert Collins
refactor smart_add to pass around the parent inventory entry and use that, resulting in another 100bzrlib/inventory.py performance improvement, and making inventory writing the dominating factory in add. (Robert Collins)
658
    def test_make_entry(self):
659
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
660
            inventory.InventoryFile)
661
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
662
            inventory.InventoryLink)
663
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
664
            inventory.InventoryDirectory)
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
665
1830.3.5 by John Arbash Meinel
make_entry refuses to create non-normalized entries.
666
    def test_make_entry_non_normalized(self):
667
        orig_normalized_filename = osutils.normalized_filename
668
669
        try:
670
            osutils.normalized_filename = osutils._accessible_normalized_filename
671
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
672
            self.assertEqual(u'\xe5', entry.name)
673
            self.assertIsInstance(entry, inventory.InventoryFile)
674
675
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
676
            self.assertRaises(errors.InvalidNormalization,
677
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
678
        finally:
679
            osutils.normalized_filename = orig_normalized_filename
680
681
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
682
class TestDescribeChanges(TestCase):
683
684
    def test_describe_change(self):
685
        # we need to test the following change combinations:
686
        # rename
687
        # reparent
688
        # modify
689
        # gone
690
        # added
691
        # renamed/reparented and modified
692
        # change kind (perhaps can't be done yet?)
693
        # also, merged in combination with all of these?
694
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
695
        old_a.text_sha1 = '123132'
696
        old_a.text_size = 0
697
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
698
        new_a.text_sha1 = '123132'
699
        new_a.text_size = 0
700
701
        self.assertChangeDescription('unchanged', old_a, new_a)
702
703
        new_a.text_size = 10
704
        new_a.text_sha1 = 'abcabc'
705
        self.assertChangeDescription('modified', old_a, new_a)
706
707
        self.assertChangeDescription('added', None, new_a)
708
        self.assertChangeDescription('removed', old_a, None)
709
        # perhaps a bit questionable but seems like the most reasonable thing...
710
        self.assertChangeDescription('unchanged', None, None)
711
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
712
        # in this case it's both renamed and modified; show a rename and
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
713
        # modification:
714
        new_a.name = 'newfilename'
715
        self.assertChangeDescription('modified and renamed', old_a, new_a)
716
717
        # reparenting is 'renaming'
718
        new_a.name = old_a.name
719
        new_a.parent_id = 'somedir-id'
720
        self.assertChangeDescription('modified and renamed', old_a, new_a)
721
722
        # reset the content values so its not modified
723
        new_a.text_size = old_a.text_size
724
        new_a.text_sha1 = old_a.text_sha1
725
        new_a.name = old_a.name
726
727
        new_a.name = 'newfilename'
728
        self.assertChangeDescription('renamed', old_a, new_a)
729
730
        # reparenting is 'renaming'
731
        new_a.name = old_a.name
732
        new_a.parent_id = 'somedir-id'
733
        self.assertChangeDescription('renamed', old_a, new_a)
734
735
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
736
        change = InventoryEntry.describe_change(old_ie, new_ie)
737
        self.assertEqual(expected_change, change)
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
738
739
4634.51.1 by John Arbash Meinel
Switch away from creating a whole repository just to get a VF.
740
class TestCHKInventory(tests.TestCaseWithMemoryTransport):
3735.2.99 by John Arbash Meinel
Merge bzr.dev 4034. Whitespace cleanup
741
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
742
    def get_chk_bytes(self):
4634.51.1 by John Arbash Meinel
Switch away from creating a whole repository just to get a VF.
743
        factory = groupcompress.make_pack_factory(True, True, 1)
744
        trans = self.get_transport('')
745
        return factory(trans)
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
746
747
    def read_bytes(self, chk_bytes, key):
748
        stream = chk_bytes.get_record_stream([key], 'unordered', True)
749
        return stream.next().get_bytes_as("fulltext")
750
751
    def test_deserialise_gives_CHKInventory(self):
752
        inv = Inventory()
753
        inv.revision_id = "revid"
754
        inv.root.revision = "rootrev"
755
        chk_bytes = self.get_chk_bytes()
756
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
757
        bytes = ''.join(chk_inv.to_lines())
758
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
759
        self.assertEqual("revid", new_inv.revision_id)
760
        self.assertEqual("directory", new_inv.root.kind)
761
        self.assertEqual(inv.root.file_id, new_inv.root.file_id)
762
        self.assertEqual(inv.root.parent_id, new_inv.root.parent_id)
763
        self.assertEqual(inv.root.name, new_inv.root.name)
764
        self.assertEqual("rootrev", new_inv.root.revision)
3735.16.7 by John Arbash Meinel
Start parameterizing CHKInventory and CHKSerializer so that we can
765
        self.assertEqual('plain', new_inv._search_key_name)
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
766
767
    def test_deserialise_wrong_revid(self):
768
        inv = Inventory()
769
        inv.revision_id = "revid"
770
        inv.root.revision = "rootrev"
771
        chk_bytes = self.get_chk_bytes()
772
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
773
        bytes = ''.join(chk_inv.to_lines())
774
        self.assertRaises(ValueError, CHKInventory.deserialise, chk_bytes,
775
            bytes, ("revid2",))
776
777
    def test_captures_rev_root_byid(self):
778
        inv = Inventory()
779
        inv.revision_id = "foo"
780
        inv.root.revision = "bar"
781
        chk_bytes = self.get_chk_bytes()
782
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
3735.16.7 by John Arbash Meinel
Start parameterizing CHKInventory and CHKSerializer so that we can
783
        lines = chk_inv.to_lines()
784
        self.assertEqual([
785
            'chkinventory:\n',
786
            'revision_id: foo\n',
787
            'root_id: TREE_ROOT\n',
3735.2.132 by John Arbash Meinel
Remove references to parent_id_basename_index, now that we know we want it.
788
            'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
3735.17.11 by John Arbash Meinel
Actually format the inventories using line-based separation.
789
            'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
3735.16.7 by John Arbash Meinel
Start parameterizing CHKInventory and CHKSerializer so that we can
790
            ], lines)
791
        chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
792
        self.assertEqual('plain', chk_inv._search_key_name)
793
794
    def test_captures_parent_id_basename_index(self):
795
        inv = Inventory()
796
        inv.revision_id = "foo"
797
        inv.root.revision = "bar"
798
        chk_bytes = self.get_chk_bytes()
3735.2.132 by John Arbash Meinel
Remove references to parent_id_basename_index, now that we know we want it.
799
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
3735.16.7 by John Arbash Meinel
Start parameterizing CHKInventory and CHKSerializer so that we can
800
        lines = chk_inv.to_lines()
801
        self.assertEqual([
802
            'chkinventory:\n',
803
            'revision_id: foo\n',
804
            'root_id: TREE_ROOT\n',
3735.17.8 by John Arbash Meinel
Most direct tests are now passing.
805
            'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
3735.17.11 by John Arbash Meinel
Actually format the inventories using line-based separation.
806
            'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
3735.16.7 by John Arbash Meinel
Start parameterizing CHKInventory and CHKSerializer so that we can
807
            ], lines)
808
        chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
809
        self.assertEqual('plain', chk_inv._search_key_name)
810
811
    def test_captures_search_key_name(self):
812
        inv = Inventory()
813
        inv.revision_id = "foo"
814
        inv.root.revision = "bar"
815
        chk_bytes = self.get_chk_bytes()
816
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
817
                                              search_key_name='hash-16-way')
818
        lines = chk_inv.to_lines()
819
        self.assertEqual([
820
            'chkinventory:\n',
821
            'search_key_name: hash-16-way\n',
3735.24.2 by John Arbash Meinel
Add a bit more strictness to the formatting, update the test case.
822
            'root_id: TREE_ROOT\n',
3735.17.8 by John Arbash Meinel
Most direct tests are now passing.
823
            'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
3735.24.2 by John Arbash Meinel
Add a bit more strictness to the formatting, update the test case.
824
            'revision_id: foo\n',
3735.17.11 by John Arbash Meinel
Actually format the inventories using line-based separation.
825
            'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
3735.16.7 by John Arbash Meinel
Start parameterizing CHKInventory and CHKSerializer so that we can
826
            ], lines)
827
        chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
828
        self.assertEqual('hash-16-way', chk_inv._search_key_name)
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
829
830
    def test_directory_children_on_demand(self):
831
        inv = Inventory()
832
        inv.revision_id = "revid"
833
        inv.root.revision = "rootrev"
834
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
835
        inv["fileid"].revision = "filerev"
836
        inv["fileid"].executable = True
837
        inv["fileid"].text_sha1 = "ffff"
838
        inv["fileid"].text_size = 1
839
        chk_bytes = self.get_chk_bytes()
840
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
841
        bytes = ''.join(chk_inv.to_lines())
842
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
843
        root_entry = new_inv[inv.root.file_id]
844
        self.assertEqual(None, root_entry._children)
845
        self.assertEqual(['file'], root_entry.children.keys())
846
        file_direct = new_inv["fileid"]
847
        file_found = root_entry.children['file']
848
        self.assertEqual(file_direct.kind, file_found.kind)
849
        self.assertEqual(file_direct.file_id, file_found.file_id)
850
        self.assertEqual(file_direct.parent_id, file_found.parent_id)
851
        self.assertEqual(file_direct.name, file_found.name)
852
        self.assertEqual(file_direct.revision, file_found.revision)
853
        self.assertEqual(file_direct.text_sha1, file_found.text_sha1)
854
        self.assertEqual(file_direct.text_size, file_found.text_size)
855
        self.assertEqual(file_direct.executable, file_found.executable)
856
3735.2.27 by Robert Collins
Use 4K pages for development3 repositories.
857
    def test_from_inventory_maximum_size(self):
858
        # from_inventory supports the maximum_size parameter.
859
        inv = Inventory()
860
        inv.revision_id = "revid"
861
        inv.root.revision = "rootrev"
862
        chk_bytes = self.get_chk_bytes()
863
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv, 120)
4413.5.10 by John Arbash Meinel
Clean upt the test_inv tests that assumed _root_node was real and not just a key.
864
        chk_inv.id_to_entry._ensure_root()
3735.2.27 by Robert Collins
Use 4K pages for development3 repositories.
865
        self.assertEqual(120, chk_inv.id_to_entry._root_node.maximum_size)
4413.5.10 by John Arbash Meinel
Clean upt the test_inv tests that assumed _root_node was real and not just a key.
866
        self.assertEqual(1, chk_inv.id_to_entry._root_node._key_width)
867
        p_id_basename = chk_inv.parent_id_basename_to_file_id
868
        p_id_basename._ensure_root()
869
        self.assertEqual(120, p_id_basename._root_node.maximum_size)
870
        self.assertEqual(2, p_id_basename._root_node._key_width)
3735.2.27 by Robert Collins
Use 4K pages for development3 repositories.
871
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
872
    def test___iter__(self):
873
        inv = Inventory()
874
        inv.revision_id = "revid"
875
        inv.root.revision = "rootrev"
876
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
877
        inv["fileid"].revision = "filerev"
878
        inv["fileid"].executable = True
879
        inv["fileid"].text_sha1 = "ffff"
880
        inv["fileid"].text_size = 1
881
        chk_bytes = self.get_chk_bytes()
882
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
883
        bytes = ''.join(chk_inv.to_lines())
884
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
885
        fileids = list(new_inv.__iter__())
886
        fileids.sort()
887
        self.assertEqual([inv.root.file_id, "fileid"], fileids)
888
889
    def test__len__(self):
890
        inv = Inventory()
891
        inv.revision_id = "revid"
892
        inv.root.revision = "rootrev"
893
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
894
        inv["fileid"].revision = "filerev"
895
        inv["fileid"].executable = True
896
        inv["fileid"].text_sha1 = "ffff"
897
        inv["fileid"].text_size = 1
898
        chk_bytes = self.get_chk_bytes()
899
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
900
        self.assertEqual(2, len(chk_inv))
901
902
    def test___getitem__(self):
903
        inv = Inventory()
904
        inv.revision_id = "revid"
905
        inv.root.revision = "rootrev"
906
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
907
        inv["fileid"].revision = "filerev"
908
        inv["fileid"].executable = True
909
        inv["fileid"].text_sha1 = "ffff"
910
        inv["fileid"].text_size = 1
911
        chk_bytes = self.get_chk_bytes()
912
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
913
        bytes = ''.join(chk_inv.to_lines())
914
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
915
        root_entry = new_inv[inv.root.file_id]
916
        file_entry = new_inv["fileid"]
917
        self.assertEqual("directory", root_entry.kind)
918
        self.assertEqual(inv.root.file_id, root_entry.file_id)
919
        self.assertEqual(inv.root.parent_id, root_entry.parent_id)
920
        self.assertEqual(inv.root.name, root_entry.name)
921
        self.assertEqual("rootrev", root_entry.revision)
922
        self.assertEqual("file", file_entry.kind)
923
        self.assertEqual("fileid", file_entry.file_id)
924
        self.assertEqual(inv.root.file_id, file_entry.parent_id)
925
        self.assertEqual("file", file_entry.name)
926
        self.assertEqual("filerev", file_entry.revision)
927
        self.assertEqual("ffff", file_entry.text_sha1)
928
        self.assertEqual(1, file_entry.text_size)
929
        self.assertEqual(True, file_entry.executable)
3735.2.53 by Robert Collins
Support Inventory.__getitem__ more consistently.
930
        self.assertRaises(errors.NoSuchId, new_inv.__getitem__, 'missing')
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
931
932
    def test_has_id_true(self):
933
        inv = Inventory()
934
        inv.revision_id = "revid"
935
        inv.root.revision = "rootrev"
936
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
937
        inv["fileid"].revision = "filerev"
938
        inv["fileid"].executable = True
939
        inv["fileid"].text_sha1 = "ffff"
940
        inv["fileid"].text_size = 1
941
        chk_bytes = self.get_chk_bytes()
942
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
943
        self.assertTrue(chk_inv.has_id('fileid'))
944
        self.assertTrue(chk_inv.has_id(inv.root.file_id))
945
946
    def test_has_id_not(self):
947
        inv = Inventory()
948
        inv.revision_id = "revid"
949
        inv.root.revision = "rootrev"
950
        chk_bytes = self.get_chk_bytes()
951
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
952
        self.assertFalse(chk_inv.has_id('fileid'))
3735.2.10 by Robert Collins
Teach CHKInventory how to make a new inventory from an inventory delta.
953
3735.2.12 by Robert Collins
Implement commit-via-deltas for split inventory repositories.
954
    def test_id2path(self):
955
        inv = Inventory()
956
        inv.revision_id = "revid"
957
        inv.root.revision = "rootrev"
958
        direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
959
        fileentry = InventoryFile("fileid", "file", "dirid")
960
        inv.add(direntry)
961
        inv.add(fileentry)
962
        inv["fileid"].revision = "filerev"
963
        inv["fileid"].executable = True
964
        inv["fileid"].text_sha1 = "ffff"
965
        inv["fileid"].text_size = 1
966
        inv["dirid"].revision = "filerev"
967
        chk_bytes = self.get_chk_bytes()
968
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
969
        bytes = ''.join(chk_inv.to_lines())
970
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
971
        self.assertEqual('', new_inv.id2path(inv.root.file_id))
972
        self.assertEqual('dir', new_inv.id2path('dirid'))
973
        self.assertEqual('dir/file', new_inv.id2path('fileid'))
974
975
    def test_path2id(self):
976
        inv = Inventory()
977
        inv.revision_id = "revid"
978
        inv.root.revision = "rootrev"
979
        direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
980
        fileentry = InventoryFile("fileid", "file", "dirid")
981
        inv.add(direntry)
982
        inv.add(fileentry)
983
        inv["fileid"].revision = "filerev"
984
        inv["fileid"].executable = True
985
        inv["fileid"].text_sha1 = "ffff"
986
        inv["fileid"].text_size = 1
987
        inv["dirid"].revision = "filerev"
988
        chk_bytes = self.get_chk_bytes()
989
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
990
        bytes = ''.join(chk_inv.to_lines())
991
        new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
992
        self.assertEqual(inv.root.file_id, new_inv.path2id(''))
993
        self.assertEqual('dirid', new_inv.path2id('dir'))
994
        self.assertEqual('fileid', new_inv.path2id('dir/file'))
995
3735.2.57 by Jelmer Vernooij
Make sure CHKInventory._entry_cache gets initialized in create_by_apply_delta.
996
    def test_create_by_apply_delta_sets_root(self):
997
        inv = Inventory()
998
        inv.revision_id = "revid"
999
        chk_bytes = self.get_chk_bytes()
1000
        base_inv = CHKInventory.from_inventory(chk_bytes, inv)
1001
        inv.add_path("", "directory", "myrootid", None)
1002
        inv.revision_id = "expectedid"
1003
        reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
4526.9.15 by Robert Collins
Fix broken CHK inventory test that was applying an inconsistend delta.
1004
        delta = [("", None, base_inv.root.file_id, None),
1005
            (None, "",  "myrootid", inv.root)]
3735.2.57 by Jelmer Vernooij
Make sure CHKInventory._entry_cache gets initialized in create_by_apply_delta.
1006
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
1007
        self.assertEquals(reference_inv.root, new_inv.root)
1008
3735.2.10 by Robert Collins
Teach CHKInventory how to make a new inventory from an inventory delta.
1009
    def test_create_by_apply_delta_empty_add_child(self):
1010
        inv = Inventory()
1011
        inv.revision_id = "revid"
1012
        inv.root.revision = "rootrev"
1013
        chk_bytes = self.get_chk_bytes()
1014
        base_inv = CHKInventory.from_inventory(chk_bytes, inv)
1015
        a_entry = InventoryFile("A-id", "A", inv.root.file_id)
1016
        a_entry.revision = "filerev"
1017
        a_entry.executable = True
1018
        a_entry.text_sha1 = "ffff"
1019
        a_entry.text_size = 1
1020
        inv.add(a_entry)
1021
        inv.revision_id = "expectedid"
1022
        reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
1023
        delta = [(None, "A",  "A-id", a_entry)]
1024
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
1025
        # new_inv should be the same as reference_inv.
1026
        self.assertEqual(reference_inv.revision_id, new_inv.revision_id)
1027
        self.assertEqual(reference_inv.root_id, new_inv.root_id)
4413.5.10 by John Arbash Meinel
Clean upt the test_inv tests that assumed _root_node was real and not just a key.
1028
        reference_inv.id_to_entry._ensure_root()
1029
        new_inv.id_to_entry._ensure_root()
3735.2.10 by Robert Collins
Teach CHKInventory how to make a new inventory from an inventory delta.
1030
        self.assertEqual(reference_inv.id_to_entry._root_node._key,
1031
            new_inv.id_to_entry._root_node._key)
3735.2.33 by Robert Collins
Create a smoke-tested CHKInventory.iter_changes(CHKInventory) - incomplete in general but enough to start working with.
1032
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1033
    def test_create_by_apply_delta_empty_add_child_updates_parent_id(self):
1034
        inv = Inventory()
1035
        inv.revision_id = "revid"
1036
        inv.root.revision = "rootrev"
1037
        chk_bytes = self.get_chk_bytes()
3735.2.132 by John Arbash Meinel
Remove references to parent_id_basename_index, now that we know we want it.
1038
        base_inv = CHKInventory.from_inventory(chk_bytes, inv)
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1039
        a_entry = InventoryFile("A-id", "A", inv.root.file_id)
1040
        a_entry.revision = "filerev"
1041
        a_entry.executable = True
1042
        a_entry.text_sha1 = "ffff"
1043
        a_entry.text_size = 1
1044
        inv.add(a_entry)
1045
        inv.revision_id = "expectedid"
3735.2.132 by John Arbash Meinel
Remove references to parent_id_basename_index, now that we know we want it.
1046
        reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1047
        delta = [(None, "A",  "A-id", a_entry)]
1048
        new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
4413.5.10 by John Arbash Meinel
Clean upt the test_inv tests that assumed _root_node was real and not just a key.
1049
        reference_inv.id_to_entry._ensure_root()
1050
        reference_inv.parent_id_basename_to_file_id._ensure_root()
1051
        new_inv.id_to_entry._ensure_root()
1052
        new_inv.parent_id_basename_to_file_id._ensure_root()
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1053
        # new_inv should be the same as reference_inv.
1054
        self.assertEqual(reference_inv.revision_id, new_inv.revision_id)
1055
        self.assertEqual(reference_inv.root_id, new_inv.root_id)
1056
        self.assertEqual(reference_inv.id_to_entry._root_node._key,
1057
            new_inv.id_to_entry._root_node._key)
1058
        self.assertEqual(reference_inv.parent_id_basename_to_file_id._root_node._key,
1059
            new_inv.parent_id_basename_to_file_id._root_node._key)
1060
3735.2.33 by Robert Collins
Create a smoke-tested CHKInventory.iter_changes(CHKInventory) - incomplete in general but enough to start working with.
1061
    def test_iter_changes(self):
1062
        # Low level bootstrapping smoke test; comprehensive generic tests via
1063
        # InterTree are coming.
1064
        inv = Inventory()
1065
        inv.revision_id = "revid"
1066
        inv.root.revision = "rootrev"
1067
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
1068
        inv["fileid"].revision = "filerev"
1069
        inv["fileid"].executable = True
1070
        inv["fileid"].text_sha1 = "ffff"
1071
        inv["fileid"].text_size = 1
1072
        inv2 = Inventory()
1073
        inv2.revision_id = "revid2"
1074
        inv2.root.revision = "rootrev"
1075
        inv2.add(InventoryFile("fileid", "file", inv.root.file_id))
1076
        inv2["fileid"].revision = "filerev2"
1077
        inv2["fileid"].executable = False
1078
        inv2["fileid"].text_sha1 = "bbbb"
1079
        inv2["fileid"].text_size = 2
1080
        # get fresh objects.
1081
        chk_bytes = self.get_chk_bytes()
1082
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
1083
        bytes = ''.join(chk_inv.to_lines())
1084
        inv_1 = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
1085
        chk_inv2 = CHKInventory.from_inventory(chk_bytes, inv2)
1086
        bytes = ''.join(chk_inv2.to_lines())
1087
        inv_2 = CHKInventory.deserialise(chk_bytes, bytes, ("revid2",))
1088
        self.assertEqual([('fileid', (u'file', u'file'), True, (True, True),
1089
            ('TREE_ROOT', 'TREE_ROOT'), (u'file', u'file'), ('file', 'file'),
1090
            (False, True))],
1091
            list(inv_1.iter_changes(inv_2)))
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
1092
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1093
    def test_parent_id_basename_to_file_id_index_enabled(self):
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
1094
        inv = Inventory()
1095
        inv.revision_id = "revid"
1096
        inv.root.revision = "rootrev"
1097
        inv.add(InventoryFile("fileid", "file", inv.root.file_id))
1098
        inv["fileid"].revision = "filerev"
1099
        inv["fileid"].executable = True
1100
        inv["fileid"].text_sha1 = "ffff"
1101
        inv["fileid"].text_size = 1
1102
        # get fresh objects.
1103
        chk_bytes = self.get_chk_bytes()
3735.2.132 by John Arbash Meinel
Remove references to parent_id_basename_index, now that we know we want it.
1104
        tmp_inv = CHKInventory.from_inventory(chk_bytes, inv)
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
1105
        bytes = ''.join(tmp_inv.to_lines())
1106
        chk_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1107
        self.assertIsInstance(chk_inv.parent_id_basename_to_file_id, chk_map.CHKMap)
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
1108
        self.assertEqual(
1109
            {('', ''): 'TREE_ROOT', ('TREE_ROOT', 'file'): 'fileid'},
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
1110
            dict(chk_inv.parent_id_basename_to_file_id.iteritems()))
3735.36.12 by John Arbash Meinel
Add some direct tests for CHKInventory._entry_to_bytes
1111
1112
    def test_file_entry_to_bytes(self):
1113
        inv = CHKInventory(None)
1114
        ie = inventory.InventoryFile('file-id', 'filename', 'parent-id')
1115
        ie.executable = True
1116
        ie.revision = 'file-rev-id'
1117
        ie.text_sha1 = 'abcdefgh'
1118
        ie.text_size = 100
1119
        bytes = inv._entry_to_bytes(ie)
1120
        self.assertEqual('file: file-id\nparent-id\nfilename\n'
1121
                         'file-rev-id\nabcdefgh\n100\nY', bytes)
1122
        ie2 = inv._bytes_to_entry(bytes)
1123
        self.assertEqual(ie, ie2)
1124
        self.assertIsInstance(ie2.name, unicode)
1125
        self.assertEqual(('filename', 'file-id', 'file-rev-id'),
1126
                         inv._bytes_to_utf8name_key(bytes))
1127
1128
    def test_file2_entry_to_bytes(self):
1129
        inv = CHKInventory(None)
1130
        # \u30a9 == 'omega'
1131
        ie = inventory.InventoryFile('file-id', u'\u03a9name', 'parent-id')
1132
        ie.executable = False
1133
        ie.revision = 'file-rev-id'
1134
        ie.text_sha1 = '123456'
1135
        ie.text_size = 25
1136
        bytes = inv._entry_to_bytes(ie)
1137
        self.assertEqual('file: file-id\nparent-id\n\xce\xa9name\n'
1138
                         'file-rev-id\n123456\n25\nN', bytes)
1139
        ie2 = inv._bytes_to_entry(bytes)
1140
        self.assertEqual(ie, ie2)
1141
        self.assertIsInstance(ie2.name, unicode)
1142
        self.assertEqual(('\xce\xa9name', 'file-id', 'file-rev-id'),
1143
                         inv._bytes_to_utf8name_key(bytes))
1144
1145
    def test_dir_entry_to_bytes(self):
1146
        inv = CHKInventory(None)
1147
        ie = inventory.InventoryDirectory('dir-id', 'dirname', 'parent-id')
1148
        ie.revision = 'dir-rev-id'
1149
        bytes = inv._entry_to_bytes(ie)
1150
        self.assertEqual('dir: dir-id\nparent-id\ndirname\ndir-rev-id', bytes)
1151
        ie2 = inv._bytes_to_entry(bytes)
1152
        self.assertEqual(ie, ie2)
1153
        self.assertIsInstance(ie2.name, unicode)
1154
        self.assertEqual(('dirname', 'dir-id', 'dir-rev-id'),
1155
                         inv._bytes_to_utf8name_key(bytes))
1156
1157
    def test_dir2_entry_to_bytes(self):
1158
        inv = CHKInventory(None)
1159
        ie = inventory.InventoryDirectory('dir-id', u'dir\u03a9name',
1160
                                          None)
1161
        ie.revision = 'dir-rev-id'
1162
        bytes = inv._entry_to_bytes(ie)
1163
        self.assertEqual('dir: dir-id\n\ndir\xce\xa9name\n'
1164
                         'dir-rev-id', bytes)
1165
        ie2 = inv._bytes_to_entry(bytes)
1166
        self.assertEqual(ie, ie2)
1167
        self.assertIsInstance(ie2.name, unicode)
1168
        self.assertIs(ie2.parent_id, None)
1169
        self.assertEqual(('dir\xce\xa9name', 'dir-id', 'dir-rev-id'),
1170
                         inv._bytes_to_utf8name_key(bytes))
1171
1172
    def test_symlink_entry_to_bytes(self):
1173
        inv = CHKInventory(None)
1174
        ie = inventory.InventoryLink('link-id', 'linkname', 'parent-id')
1175
        ie.revision = 'link-rev-id'
1176
        ie.symlink_target = u'target/path'
1177
        bytes = inv._entry_to_bytes(ie)
1178
        self.assertEqual('symlink: link-id\nparent-id\nlinkname\n'
1179
                         'link-rev-id\ntarget/path', bytes)
1180
        ie2 = inv._bytes_to_entry(bytes)
1181
        self.assertEqual(ie, ie2)
1182
        self.assertIsInstance(ie2.name, unicode)
1183
        self.assertIsInstance(ie2.symlink_target, unicode)
1184
        self.assertEqual(('linkname', 'link-id', 'link-rev-id'),
1185
                         inv._bytes_to_utf8name_key(bytes))
1186
1187
    def test_symlink2_entry_to_bytes(self):
1188
        inv = CHKInventory(None)
1189
        ie = inventory.InventoryLink('link-id', u'link\u03a9name', 'parent-id')
1190
        ie.revision = 'link-rev-id'
1191
        ie.symlink_target = u'target/\u03a9path'
1192
        bytes = inv._entry_to_bytes(ie)
1193
        self.assertEqual('symlink: link-id\nparent-id\nlink\xce\xa9name\n'
1194
                         'link-rev-id\ntarget/\xce\xa9path', bytes)
1195
        ie2 = inv._bytes_to_entry(bytes)
1196
        self.assertEqual(ie, ie2)
1197
        self.assertIsInstance(ie2.name, unicode)
1198
        self.assertIsInstance(ie2.symlink_target, unicode)
1199
        self.assertEqual(('link\xce\xa9name', 'link-id', 'link-rev-id'),
1200
                         inv._bytes_to_utf8name_key(bytes))
1201
1202
    def test_tree_reference_entry_to_bytes(self):
1203
        inv = CHKInventory(None)
1204
        ie = inventory.TreeReference('tree-root-id', u'tree\u03a9name',
1205
                                     'parent-id')
1206
        ie.revision = 'tree-rev-id'
1207
        ie.reference_revision = 'ref-rev-id'
1208
        bytes = inv._entry_to_bytes(ie)
1209
        self.assertEqual('tree: tree-root-id\nparent-id\ntree\xce\xa9name\n'
1210
                         'tree-rev-id\nref-rev-id', bytes)
1211
        ie2 = inv._bytes_to_entry(bytes)
1212
        self.assertEqual(ie, ie2)
1213
        self.assertIsInstance(ie2.name, unicode)
1214
        self.assertEqual(('tree\xce\xa9name', 'tree-root-id', 'tree-rev-id'),
1215
                         inv._bytes_to_utf8name_key(bytes))
4634.51.2 by John Arbash Meinel
Start laying the groundwork for testing the expansion code
1216
1217
1218
class TestCHKInventoryExpand(tests.TestCaseWithMemoryTransport):
1219
1220
    def get_chk_bytes(self):
1221
        factory = groupcompress.make_pack_factory(True, True, 1)
1222
        trans = self.get_transport('')
1223
        return factory(trans)
1224
1225
    def make_dir(self, inv, name, parent_id):
1226
        inv.add(inv.make_entry('directory', name, parent_id, name + '-id'))
1227
1228
    def make_file(self, inv, name, parent_id, content='content\n'):
4634.51.3 by John Arbash Meinel
We have iteration to parents working, need to find children now.
1229
        ie = inv.make_entry('file', name, parent_id, name + '-id')
4634.51.2 by John Arbash Meinel
Start laying the groundwork for testing the expansion code
1230
        ie.text_sha1 = osutils.sha_string(content)
1231
        ie.text_size = len(content)
1232
        inv.add(ie)
1233
1234
    def make_simple_inventory(self):
1235
        inv = Inventory('TREE_ROOT')
1236
        inv.revision_id = "revid"
1237
        inv.root.revision = "rootrev"
1238
        # /                 TREE_ROOT
1239
        # dir1/             dir1-id
1240
        #   sub-file1       sub-file1-id
1241
        #   sub-file2       sub-file2-id
1242
        #   sub-dir1/       sub-dir1-id
1243
        #     subsub-file1  subsub-file1-id
1244
        # dir2/             dir2-id
1245
        #   sub2-file1      sub2-file1-id
1246
        # top               top-id
1247
        self.make_dir(inv, 'dir1', 'TREE_ROOT')
1248
        self.make_dir(inv, 'dir2', 'TREE_ROOT')
1249
        self.make_dir(inv, 'sub-dir1', 'dir1-id')
1250
        self.make_file(inv, 'top', 'TREE_ROOT')
1251
        self.make_file(inv, 'sub-file1', 'dir1-id')
1252
        self.make_file(inv, 'sub-file2', 'dir1-id')
1253
        self.make_file(inv, 'subsub-file1', 'sub-dir1-id')
1254
        self.make_file(inv, 'sub2-file1', 'dir2-id')
1255
        chk_bytes = self.get_chk_bytes()
4634.51.8 by John Arbash Meinel
Catch a corner case that we were missing.
1256
        #  use a small maximum_size to force internal paging structures
1257
        chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
1258
                        maximum_size=100,
1259
                        search_key_name='hash-255-way')
4634.51.3 by John Arbash Meinel
We have iteration to parents working, need to find children now.
1260
        bytes = ''.join(chk_inv.to_lines())
1261
        return CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
1262
1263
    def assert_Getitems(self, expected_fileids, inv, file_ids):
1264
        self.assertEqual(sorted(expected_fileids),
1265
                         sorted([ie.file_id for ie in inv._getitems(file_ids)]))
1266
4634.51.5 by John Arbash Meinel
Change the api a bit.
1267
    def assertExpand(self, all_ids, inv, file_ids):
1268
        (val_all_ids,
1269
         val_children) = inv._expand_fileids_to_parents_and_children(file_ids)
1270
        self.assertEqual(set(all_ids), val_all_ids)
1271
        entries = inv._getitems(val_all_ids)
1272
        expected_children = {}
1273
        for entry in entries:
1274
            s = expected_children.setdefault(entry.parent_id, [])
1275
            s.append(entry.file_id)
1276
        val_children = dict((k, sorted(v)) for k, v
1277
                            in val_children.iteritems())
1278
        expected_children = dict((k, sorted(v)) for k, v
1279
                            in expected_children.iteritems())
1280
        self.assertEqual(expected_children, val_children)
4634.51.3 by John Arbash Meinel
We have iteration to parents working, need to find children now.
1281
1282
    def test_make_simple_inventory(self):
4634.51.2 by John Arbash Meinel
Start laying the groundwork for testing the expansion code
1283
        inv = self.make_simple_inventory()
1284
        layout = []
1285
        for path, entry in inv.iter_entries_by_dir():
1286
            layout.append((path, entry.file_id))
1287
        self.assertEqual([
1288
            ('', 'TREE_ROOT'),
1289
            ('dir1', 'dir1-id'),
1290
            ('dir2', 'dir2-id'),
1291
            ('top', 'top-id'),
1292
            ('dir1/sub-dir1', 'sub-dir1-id'),
1293
            ('dir1/sub-file1', 'sub-file1-id'),
1294
            ('dir1/sub-file2', 'sub-file2-id'),
1295
            ('dir1/sub-dir1/subsub-file1', 'subsub-file1-id'),
1296
            ('dir2/sub2-file1', 'sub2-file1-id'),
1297
            ], layout)
4634.51.3 by John Arbash Meinel
We have iteration to parents working, need to find children now.
1298
1299
    def test__getitems(self):
1300
        inv = self.make_simple_inventory()
1301
        # Reading from disk
1302
        self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
1303
        self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
1304
        self.assertFalse('sub-file2-id' in inv._fileid_to_entry_cache)
1305
        # From cache
1306
        self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
1307
        # Mixed
1308
        self.assert_Getitems(['dir1-id', 'sub-file2-id'], inv,
1309
                             ['dir1-id', 'sub-file2-id'])
1310
        self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
1311
        self.assertTrue('sub-file2-id' in inv._fileid_to_entry_cache)
1312
1313
    def test_single_file(self):
1314
        inv = self.make_simple_inventory()
4634.51.5 by John Arbash Meinel
Change the api a bit.
1315
        self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
4634.51.3 by John Arbash Meinel
We have iteration to parents working, need to find children now.
1316
1317
    def test_get_all_parents(self):
1318
        inv = self.make_simple_inventory()
4634.51.5 by John Arbash Meinel
Change the api a bit.
1319
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1320
                           'subsub-file1-id',
1321
                          ], inv, ['subsub-file1-id'])
4634.51.4 by John Arbash Meinel
Implement an expansion function that works directly on the chk maps.
1322
1323
    def test_get_children(self):
1324
        inv = self.make_simple_inventory()
4634.51.5 by John Arbash Meinel
Change the api a bit.
1325
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1326
                           'sub-file1-id', 'sub-file2-id', 'subsub-file1-id',
4634.51.4 by John Arbash Meinel
Implement an expansion function that works directly on the chk maps.
1327
                          ], inv, ['dir1-id'])
4634.51.8 by John Arbash Meinel
Catch a corner case that we were missing.
1328
1329
    def test_from_root(self):
1330
        inv = self.make_simple_inventory()
1331
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'dir2-id', 'sub-dir1-id',
1332
                           'sub-file1-id', 'sub-file2-id', 'sub2-file1-id',
1333
                           'subsub-file1-id', 'top-id'], inv, ['TREE_ROOT'])
1334
1335
    def test_top_level_file(self):
1336
        inv = self.make_simple_inventory()
1337
        self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
1338
1339
    def test_subsub_file(self):
1340
        inv = self.make_simple_inventory()
1341
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1342
                           'subsub-file1-id'], inv, ['subsub-file1-id'])
1343
1344
    def test_sub_and_root(self):
1345
        inv = self.make_simple_inventory()
1346
        self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id', 'top-id',
1347
                           'subsub-file1-id'], inv, ['top-id', 'subsub-file1-id'])