15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29
from bzrlib.inventory import (
37
mutable_inventory_from_tree,
39
from bzrlib.tests import (
41
TestCaseWithTransport,
43
from bzrlib.tests.scenarios import load_tests_apply_scenarios
46
load_tests = load_tests_apply_scenarios
49
def delta_application_scenarios():
51
('Inventory', {'apply_delta':apply_inventory_Inventory}),
53
# Working tree basis delta application
54
# Repository add_inv_by_delta.
55
# Reduce form of the per_repository test logic - that logic needs to be
56
# be able to get /just/ repositories whereas these tests are fine with
57
# just creating trees.
59
for _, format in repository.format_registry.iteritems():
60
if format.supports_full_versioned_files:
61
scenarios.append((str(format.__name__), {
62
'apply_delta':apply_inventory_Repository_add_inventory_by_delta,
64
for format in workingtree.format_registry._get_all():
65
repo_fmt = format._matchingbzrdir.repository_format
66
if not repo_fmt.supports_full_versioned_files:
69
(str(format.__class__.__name__) + ".update_basis_by_delta", {
70
'apply_delta':apply_inventory_WT_basis,
73
(str(format.__class__.__name__) + ".apply_inventory_delta", {
74
'apply_delta':apply_inventory_WT,
79
def create_texts_for_inv(repo, inv):
80
for path, ie in inv.iter_entries():
82
lines = ['a' * ie.text_size]
85
repo.texts.add_lines((ie.file_id, ie.revision), [], lines)
88
def apply_inventory_Inventory(self, basis, delta, invalid_delta=True):
89
"""Apply delta to basis and return the result.
91
:param basis: An inventory to be used as the basis.
92
:param delta: The inventory delta to apply:
93
:return: An inventory resulting from the application.
95
basis.apply_delta(delta)
99
def apply_inventory_WT(self, basis, delta, invalid_delta=True):
100
"""Apply delta to basis and return the result.
102
This sets the tree state to be basis, and then calls apply_inventory_delta.
104
:param basis: An inventory to be used as the basis.
105
:param delta: The inventory delta to apply:
106
:return: An inventory resulting from the application.
108
control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
109
control.create_repository()
110
control.create_branch()
111
tree = self.format.initialize(control)
114
tree._write_inventory(basis)
117
# Fresh object, reads disk again.
118
tree = tree.bzrdir.open_workingtree()
121
tree.apply_inventory_delta(delta)
124
# reload tree - ensure we get what was written.
125
tree = tree.bzrdir.open_workingtree()
127
self.addCleanup(tree.unlock)
128
if not invalid_delta:
130
return tree.inventory
133
def _create_repo_revisions(repo, basis, delta, invalid_delta):
134
repo.start_write_group()
136
rev = revision.Revision('basis', timestamp=0, timezone=None,
137
message="", committer="foo@example.com")
138
basis.revision_id = 'basis'
139
create_texts_for_inv(repo, basis)
140
repo.add_revision('basis', rev, basis)
142
# We don't want to apply the delta to the basis, because we expect
143
# the delta is invalid.
145
result_inv.revision_id = 'result'
146
target_entries = None
148
result_inv = basis.create_by_apply_delta(delta, 'result')
149
create_texts_for_inv(repo, result_inv)
150
target_entries = list(result_inv.iter_entries_by_dir())
151
rev = revision.Revision('result', timestamp=0, timezone=None,
152
message="", committer="foo@example.com")
153
repo.add_revision('result', rev, result_inv)
154
repo.commit_write_group()
156
repo.abort_write_group()
158
return target_entries
161
def _get_basis_entries(tree):
162
basis_tree = tree.basis_tree()
163
basis_tree.lock_read()
164
basis_tree_entries = list(basis_tree.inventory.iter_entries_by_dir())
166
return basis_tree_entries
169
def _populate_different_tree(tree, basis, delta):
170
"""Put all entries into tree, but at a unique location."""
173
tree.add(['unique-dir'], ['unique-dir-id'], ['directory'])
174
for path, ie in basis.iter_entries_by_dir():
175
if ie.file_id in added_ids:
177
# We want a unique path for each of these, we use the file-id
178
tree.add(['unique-dir/' + ie.file_id], [ie.file_id], [ie.kind])
179
added_ids.add(ie.file_id)
180
for old_path, new_path, file_id, ie in delta:
181
if file_id in added_ids:
183
tree.add(['unique-dir/' + file_id], [file_id], [ie.kind])
186
def apply_inventory_WT_basis(test, basis, delta, invalid_delta=True):
187
"""Apply delta to basis and return the result.
189
This sets the parent and then calls update_basis_by_delta.
190
It also puts the basis in the repository under both 'basis' and 'result' to
191
allow safety checks made by the WT to succeed, and finally ensures that all
192
items in the delta with a new path are present in the WT before calling
193
update_basis_by_delta.
195
:param basis: An inventory to be used as the basis.
196
:param delta: The inventory delta to apply:
197
:return: An inventory resulting from the application.
199
control = test.make_bzrdir('tree', format=test.format._matchingbzrdir)
200
control.create_repository()
201
control.create_branch()
202
tree = test.format.initialize(control)
205
target_entries = _create_repo_revisions(tree.branch.repository, basis,
206
delta, invalid_delta)
207
# Set the basis state as the trees current state
208
tree._write_inventory(basis)
209
# This reads basis from the repo and puts it into the tree's local
210
# cache, if it has one.
211
tree.set_parent_ids(['basis'])
214
# Fresh lock, reads disk again.
217
tree.update_basis_by_delta('result', delta)
218
if not invalid_delta:
222
# reload tree - ensure we get what was written.
223
tree = tree.bzrdir.open_workingtree()
224
basis_tree = tree.basis_tree()
225
basis_tree.lock_read()
226
test.addCleanup(basis_tree.unlock)
227
basis_inv = basis_tree.inventory
229
basis_entries = list(basis_inv.iter_entries_by_dir())
230
test.assertEqual(target_entries, basis_entries)
234
def apply_inventory_Repository_add_inventory_by_delta(self, basis, delta,
236
"""Apply delta to basis and return the result.
238
This inserts basis as a whole inventory and then uses
239
add_inventory_by_delta to add delta.
241
:param basis: An inventory to be used as the basis.
242
:param delta: The inventory delta to apply:
243
:return: An inventory resulting from the application.
245
format = self.format()
246
control = self.make_bzrdir('tree', format=format._matchingbzrdir)
247
repo = format.initialize(control)
250
repo.start_write_group()
252
rev = revision.Revision('basis', timestamp=0, timezone=None,
253
message="", committer="foo@example.com")
254
basis.revision_id = 'basis'
255
create_texts_for_inv(repo, basis)
256
repo.add_revision('basis', rev, basis)
257
repo.commit_write_group()
259
repo.abort_write_group()
265
repo.start_write_group()
267
inv_sha1 = repo.add_inventory_by_delta('basis', delta,
270
repo.abort_write_group()
273
repo.commit_write_group()
276
# Fresh lock, reads disk again.
277
repo = repo.bzrdir.open_repository()
279
self.addCleanup(repo.unlock)
280
return repo.get_inventory('result')
283
class TestInventoryUpdates(TestCase):
285
def test_creation_from_root_id(self):
286
# iff a root id is passed to the constructor, a root directory is made
287
inv = inventory.Inventory(root_id='tree-root')
288
self.assertNotEqual(None, inv.root)
289
self.assertEqual('tree-root', inv.root.file_id)
291
def test_add_path_of_root(self):
292
# if no root id is given at creation time, there is no root directory
293
inv = inventory.Inventory(root_id=None)
294
self.assertIs(None, inv.root)
295
# add a root entry by adding its path
296
ie = inv.add_path("", "directory", "my-root")
297
ie.revision = 'test-rev'
298
self.assertEqual("my-root", ie.file_id)
299
self.assertIs(ie, inv.root)
301
def test_add_path(self):
302
inv = inventory.Inventory(root_id='tree_root')
303
ie = inv.add_path('hello', 'file', 'hello-id')
304
self.assertEqual('hello-id', ie.file_id)
305
self.assertEqual('file', ie.kind)
308
"""Make sure copy() works and creates a deep copy."""
309
inv = inventory.Inventory(root_id='some-tree-root')
310
ie = inv.add_path('hello', 'file', 'hello-id')
312
inv.root.file_id = 'some-new-root'
314
self.assertEqual('some-tree-root', inv2.root.file_id)
315
self.assertEqual('hello', inv2['hello-id'].name)
317
def test_copy_empty(self):
318
"""Make sure an empty inventory can be copied."""
319
inv = inventory.Inventory(root_id=None)
321
self.assertIs(None, inv2.root)
323
def test_copy_copies_root_revision(self):
324
"""Make sure the revision of the root gets copied."""
325
inv = inventory.Inventory(root_id='someroot')
326
inv.root.revision = 'therev'
328
self.assertEquals('someroot', inv2.root.file_id)
329
self.assertEquals('therev', inv2.root.revision)
331
def test_create_tree_reference(self):
332
inv = inventory.Inventory('tree-root-123')
333
inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
334
revision='rev', reference_revision='rev2'))
336
def test_error_encoding(self):
337
inv = inventory.Inventory('tree-root')
338
inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
339
e = self.assertRaises(errors.InconsistentDelta, inv.add,
340
InventoryFile('b-id', u'\u1234', 'tree-root'))
341
self.assertContainsRe(str(e), r'\\u1234')
343
def test_add_recursive(self):
344
parent = InventoryDirectory('src-id', 'src', 'tree-root')
345
child = InventoryFile('hello-id', 'hello.c', 'src-id')
346
parent.children[child.file_id] = child
347
inv = inventory.Inventory('tree-root')
349
self.assertEqual('src/hello.c', inv.id2path('hello-id'))
353
class TestDeltaApplication(TestCaseWithTransport):
355
scenarios = delta_application_scenarios()
357
def get_empty_inventory(self, reference_inv=None):
358
"""Get an empty inventory.
360
Note that tests should not depend on the revision of the root for
361
setting up test conditions, as it has to be flexible to accomodate non
362
rich root repositories.
364
:param reference_inv: If not None, get the revision for the root from
365
this inventory. This is useful for dealing with older repositories
366
that routinely discarded the root entry data. If None, the root's
367
revision is set to 'basis'.
369
inv = inventory.Inventory()
370
if reference_inv is not None:
371
inv.root.revision = reference_inv.root.revision
373
inv.root.revision = 'basis'
376
def make_file_ie(self, file_id='file-id', name='name', parent_id=None):
377
ie_file = inventory.InventoryFile(file_id, name, parent_id)
378
ie_file.revision = 'result'
379
ie_file.text_size = 0
380
ie_file.text_sha1 = ''
383
def test_empty_delta(self):
384
inv = self.get_empty_inventory()
386
inv = self.apply_delta(self, inv, delta)
387
inv2 = self.get_empty_inventory(inv)
388
self.assertEqual([], inv2._make_delta(inv))
390
def test_None_file_id(self):
391
inv = self.get_empty_inventory()
392
dir1 = inventory.InventoryDirectory(None, 'dir1', inv.root.file_id)
393
dir1.revision = 'result'
394
delta = [(None, u'dir1', None, dir1)]
395
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
398
def test_unicode_file_id(self):
399
inv = self.get_empty_inventory()
400
dir1 = inventory.InventoryDirectory(u'dirid', 'dir1', inv.root.file_id)
401
dir1.revision = 'result'
402
delta = [(None, u'dir1', dir1.file_id, dir1)]
403
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
406
def test_repeated_file_id(self):
407
inv = self.get_empty_inventory()
408
file1 = inventory.InventoryFile('id', 'path1', inv.root.file_id)
409
file1.revision = 'result'
414
delta = [(None, u'path1', 'id', file1), (None, u'path2', 'id', file2)]
415
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
418
def test_repeated_new_path(self):
419
inv = self.get_empty_inventory()
420
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
421
file1.revision = 'result'
425
file2.file_id = 'id2'
426
delta = [(None, u'path', 'id1', file1), (None, u'path', 'id2', file2)]
427
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
430
def test_repeated_old_path(self):
431
inv = self.get_empty_inventory()
432
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
433
file1.revision = 'result'
436
# We can't *create* a source inventory with the same path, but
437
# a badly generated partial delta might claim the same source twice.
438
# This would be buggy in two ways: the path is repeated in the delta,
439
# And the path for one of the file ids doesn't match the source
440
# location. Alternatively, we could have a repeated fileid, but that
441
# is separately checked for.
442
file2 = inventory.InventoryFile('id2', 'path2', inv.root.file_id)
443
file2.revision = 'result'
448
delta = [(u'path', None, 'id1', None), (u'path', None, 'id2', None)]
449
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
452
def test_mismatched_id_entry_id(self):
453
inv = self.get_empty_inventory()
454
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
455
file1.revision = 'result'
458
delta = [(None, u'path', 'id', file1)]
459
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
462
def test_mismatched_new_path_entry_None(self):
463
inv = self.get_empty_inventory()
464
delta = [(None, u'path', 'id', None)]
465
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
468
def test_mismatched_new_path_None_entry(self):
469
inv = self.get_empty_inventory()
470
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
471
file1.revision = 'result'
474
delta = [(u"path", None, 'id1', file1)]
475
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
478
def test_parent_is_not_directory(self):
479
inv = self.get_empty_inventory()
480
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
481
file1.revision = 'result'
484
file2 = inventory.InventoryFile('id2', 'path2', 'id1')
485
file2.revision = 'result'
489
delta = [(None, u'path/path2', 'id2', file2)]
490
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
493
def test_parent_is_missing(self):
494
inv = self.get_empty_inventory()
495
file2 = inventory.InventoryFile('id2', 'path2', 'missingparent')
496
file2.revision = 'result'
499
delta = [(None, u'path/path2', 'id2', file2)]
500
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
503
def test_new_parent_path_has_wrong_id(self):
504
inv = self.get_empty_inventory()
505
parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
506
parent1.revision = 'result'
507
parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
508
parent2.revision = 'result'
509
file1 = inventory.InventoryFile('id', 'path', 'p-2')
510
file1.revision = 'result'
515
# This delta claims that file1 is at dir/path, but actually its at
516
# dir2/path if you follow the inventory parent structure.
517
delta = [(None, u'dir/path', 'id', file1)]
518
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
521
def test_old_parent_path_is_wrong(self):
522
inv = self.get_empty_inventory()
523
parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
524
parent1.revision = 'result'
525
parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
526
parent2.revision = 'result'
527
file1 = inventory.InventoryFile('id', 'path', 'p-2')
528
file1.revision = 'result'
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.
536
delta = [(u'dir/path', None, 'id', None)]
537
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
540
def test_old_parent_path_is_for_other_id(self):
541
inv = self.get_empty_inventory()
542
parent1 = inventory.InventoryDirectory('p-1', 'dir', inv.root.file_id)
543
parent1.revision = 'result'
544
parent2 = inventory.InventoryDirectory('p-2', 'dir2', inv.root.file_id)
545
parent2.revision = 'result'
546
file1 = inventory.InventoryFile('id', 'path', 'p-2')
547
file1.revision = 'result'
550
file2 = inventory.InventoryFile('id2', 'path', 'p-1')
551
file2.revision = 'result'
558
# This delta claims that file1 was at dir/path, but actually it was at
559
# dir2/path if you follow the inventory parent structure. At dir/path
560
# is another entry we should not delete.
561
delta = [(u'dir/path', None, 'id', None)]
562
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
565
def test_add_existing_id_new_path(self):
566
inv = self.get_empty_inventory()
567
parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
568
parent1.revision = 'result'
569
parent2 = inventory.InventoryDirectory('p-1', 'dir2', inv.root.file_id)
570
parent2.revision = 'result'
572
delta = [(None, u'dir2', 'p-1', parent2)]
573
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
576
def test_add_new_id_existing_path(self):
577
inv = self.get_empty_inventory()
578
parent1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
579
parent1.revision = 'result'
580
parent2 = inventory.InventoryDirectory('p-2', 'dir1', inv.root.file_id)
581
parent2.revision = 'result'
583
delta = [(None, u'dir1', 'p-2', parent2)]
584
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
587
def test_remove_dir_leaving_dangling_child(self):
588
inv = self.get_empty_inventory()
589
dir1 = inventory.InventoryDirectory('p-1', 'dir1', inv.root.file_id)
590
dir1.revision = 'result'
591
dir2 = inventory.InventoryDirectory('p-2', 'child1', 'p-1')
592
dir2.revision = 'result'
593
dir3 = inventory.InventoryDirectory('p-3', 'child2', 'p-1')
594
dir3.revision = 'result'
598
delta = [(u'dir1', None, 'p-1', None),
599
(u'dir1/child2', None, 'p-3', None)]
600
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
603
def test_add_file(self):
604
inv = self.get_empty_inventory()
605
file1 = inventory.InventoryFile('file-id', 'path', inv.root.file_id)
606
file1.revision = 'result'
609
delta = [(None, u'path', 'file-id', file1)]
610
res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
611
self.assertEqual('file-id', res_inv['file-id'].file_id)
613
def test_remove_file(self):
614
inv = self.get_empty_inventory()
615
file1 = inventory.InventoryFile('file-id', 'path', inv.root.file_id)
616
file1.revision = 'result'
620
delta = [(u'path', None, 'file-id', None)]
621
res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
622
self.assertEqual(None, res_inv.path2id('path'))
623
self.assertRaises(errors.NoSuchId, res_inv.id2path, 'file-id')
625
def test_rename_file(self):
626
inv = self.get_empty_inventory()
627
file1 = self.make_file_ie(name='path', parent_id=inv.root.file_id)
629
file2 = self.make_file_ie(name='path2', parent_id=inv.root.file_id)
630
delta = [(u'path', 'path2', 'file-id', file2)]
631
res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
632
self.assertEqual(None, res_inv.path2id('path'))
633
self.assertEqual('file-id', res_inv.path2id('path2'))
635
def test_replaced_at_new_path(self):
636
inv = self.get_empty_inventory()
637
file1 = self.make_file_ie(file_id='id1', parent_id=inv.root.file_id)
639
file2 = self.make_file_ie(file_id='id2', parent_id=inv.root.file_id)
640
delta = [(u'name', None, 'id1', None),
641
(None, u'name', 'id2', file2)]
642
res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
643
self.assertEqual('id2', res_inv.path2id('name'))
645
def test_rename_dir(self):
646
inv = self.get_empty_inventory()
647
dir1 = inventory.InventoryDirectory('dir-id', 'dir1', inv.root.file_id)
648
dir1.revision = 'basis'
649
file1 = self.make_file_ie(parent_id='dir-id')
652
dir2 = inventory.InventoryDirectory('dir-id', 'dir2', inv.root.file_id)
653
dir2.revision = 'result'
654
delta = [('dir1', 'dir2', 'dir-id', dir2)]
655
res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
656
# The file should be accessible under the new path
657
self.assertEqual('file-id', res_inv.path2id('dir2/name'))
659
def test_renamed_dir_with_renamed_child(self):
660
inv = self.get_empty_inventory()
661
dir1 = inventory.InventoryDirectory('dir-id', 'dir1', inv.root.file_id)
662
dir1.revision = 'basis'
663
file1 = self.make_file_ie('file-id-1', 'name1', parent_id='dir-id')
664
file2 = self.make_file_ie('file-id-2', 'name2', parent_id='dir-id')
668
dir2 = inventory.InventoryDirectory('dir-id', 'dir2', inv.root.file_id)
669
dir2.revision = 'result'
670
file2b = self.make_file_ie('file-id-2', 'name2', inv.root.file_id)
671
delta = [('dir1', 'dir2', 'dir-id', dir2),
672
('dir1/name2', 'name2', 'file-id-2', file2b)]
673
res_inv = self.apply_delta(self, inv, delta, invalid_delta=False)
674
# The file should be accessible under the new path
675
self.assertEqual('file-id-1', res_inv.path2id('dir2/name1'))
676
self.assertEqual(None, res_inv.path2id('dir2/name2'))
677
self.assertEqual('file-id-2', res_inv.path2id('name2'))
679
def test_is_root(self):
680
"""Ensure our root-checking code is accurate."""
681
inv = inventory.Inventory('TREE_ROOT')
682
self.assertTrue(inv.is_root('TREE_ROOT'))
683
self.assertFalse(inv.is_root('booga'))
684
inv.root.file_id = 'booga'
685
self.assertFalse(inv.is_root('TREE_ROOT'))
686
self.assertTrue(inv.is_root('booga'))
687
# works properly even if no root is set
689
self.assertFalse(inv.is_root('TREE_ROOT'))
690
self.assertFalse(inv.is_root('booga'))
692
def test_entries_for_empty_inventory(self):
693
"""Test that entries() will not fail for an empty inventory"""
694
inv = Inventory(root_id=None)
695
self.assertEqual([], inv.entries())
18
from bzrlib import errors, chk_map, inventory, osutils
19
from bzrlib.inventory import (CHKInventory, Inventory, ROOT_ID, InventoryFile,
20
InventoryDirectory, InventoryEntry, TreeReference)
21
from bzrlib.tests import TestCase, TestCaseWithTransport
698
24
class TestInventoryEntry(TestCase):
1310
636
self.assertIsInstance(ie2.name, unicode)
1311
637
self.assertEqual(('tree\xce\xa9name', 'tree-root-id', 'tree-rev-id'),
1312
638
inv._bytes_to_utf8name_key(bytes))
1314
def make_basic_utf8_inventory(self):
1316
inv.revision_id = "revid"
1317
inv.root.revision = "rootrev"
1318
root_id = inv.root.file_id
1319
inv.add(InventoryFile("fileid", u'f\xefle', root_id))
1320
inv["fileid"].revision = "filerev"
1321
inv["fileid"].text_sha1 = "ffff"
1322
inv["fileid"].text_size = 0
1323
inv.add(InventoryDirectory("dirid", u'dir-\N{EURO SIGN}', root_id))
1324
inv.add(InventoryFile("childid", u'ch\xefld', "dirid"))
1325
inv["childid"].revision = "filerev"
1326
inv["childid"].text_sha1 = "ffff"
1327
inv["childid"].text_size = 0
1328
chk_bytes = self.get_chk_bytes()
1329
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
1330
bytes = ''.join(chk_inv.to_lines())
1331
return CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
1333
def test__preload_handles_utf8(self):
1334
new_inv = self.make_basic_utf8_inventory()
1335
self.assertEqual({}, new_inv._fileid_to_entry_cache)
1336
self.assertFalse(new_inv._fully_cached)
1337
new_inv._preload_cache()
1339
sorted([new_inv.root_id, "fileid", "dirid", "childid"]),
1340
sorted(new_inv._fileid_to_entry_cache.keys()))
1341
ie_root = new_inv._fileid_to_entry_cache[new_inv.root_id]
1342
self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
1343
sorted(ie_root._children.keys()))
1344
ie_dir = new_inv._fileid_to_entry_cache['dirid']
1345
self.assertEqual([u'ch\xefld'], sorted(ie_dir._children.keys()))
1347
def test__preload_populates_cache(self):
1349
inv.revision_id = "revid"
1350
inv.root.revision = "rootrev"
1351
root_id = inv.root.file_id
1352
inv.add(InventoryFile("fileid", "file", root_id))
1353
inv["fileid"].revision = "filerev"
1354
inv["fileid"].executable = True
1355
inv["fileid"].text_sha1 = "ffff"
1356
inv["fileid"].text_size = 1
1357
inv.add(InventoryDirectory("dirid", "dir", root_id))
1358
inv.add(InventoryFile("childid", "child", "dirid"))
1359
inv["childid"].revision = "filerev"
1360
inv["childid"].executable = False
1361
inv["childid"].text_sha1 = "dddd"
1362
inv["childid"].text_size = 1
1363
chk_bytes = self.get_chk_bytes()
1364
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
1365
bytes = ''.join(chk_inv.to_lines())
1366
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
1367
self.assertEqual({}, new_inv._fileid_to_entry_cache)
1368
self.assertFalse(new_inv._fully_cached)
1369
new_inv._preload_cache()
1371
sorted([root_id, "fileid", "dirid", "childid"]),
1372
sorted(new_inv._fileid_to_entry_cache.keys()))
1373
self.assertTrue(new_inv._fully_cached)
1374
ie_root = new_inv._fileid_to_entry_cache[root_id]
1375
self.assertEqual(['dir', 'file'], sorted(ie_root._children.keys()))
1376
ie_dir = new_inv._fileid_to_entry_cache['dirid']
1377
self.assertEqual(['child'], sorted(ie_dir._children.keys()))
1379
def test__preload_handles_partially_evaluated_inventory(self):
1380
new_inv = self.make_basic_utf8_inventory()
1381
ie = new_inv[new_inv.root_id]
1382
self.assertIs(None, ie._children)
1383
self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
1384
sorted(ie.children.keys()))
1385
# Accessing .children loads _children
1386
self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
1387
sorted(ie._children.keys()))
1388
new_inv._preload_cache()
1390
self.assertEqual([u'dir-\N{EURO SIGN}', u'f\xefle'],
1391
sorted(ie._children.keys()))
1392
ie_dir = new_inv["dirid"]
1393
self.assertEqual([u'ch\xefld'],
1394
sorted(ie_dir._children.keys()))
1396
def test_filter_change_in_renamed_subfolder(self):
1397
inv = Inventory('tree-root')
1398
src_ie = inv.add_path('src', 'directory', 'src-id')
1399
inv.add_path('src/sub/', 'directory', 'sub-id')
1400
a_ie = inv.add_path('src/sub/a', 'file', 'a-id')
1401
a_ie.text_sha1 = osutils.sha_string('content\n')
1402
a_ie.text_size = len('content\n')
1403
chk_bytes = self.get_chk_bytes()
1404
inv = CHKInventory.from_inventory(chk_bytes, inv)
1405
inv = inv.create_by_apply_delta([
1406
("src/sub/a", "src/sub/a", "a-id", a_ie),
1407
("src", "src2", "src-id", src_ie),
1409
new_inv = inv.filter(['a-id', 'src-id'])
1413
('src/sub', 'sub-id'),
1414
('src/sub/a', 'a-id'),
1415
], [(path, ie.file_id) for path, ie in new_inv.iter_entries()])
1417
class TestCHKInventoryExpand(tests.TestCaseWithMemoryTransport):
1419
def get_chk_bytes(self):
1420
factory = groupcompress.make_pack_factory(True, True, 1)
1421
trans = self.get_transport('')
1422
return factory(trans)
1424
def make_dir(self, inv, name, parent_id):
1425
inv.add(inv.make_entry('directory', name, parent_id, name + '-id'))
1427
def make_file(self, inv, name, parent_id, content='content\n'):
1428
ie = inv.make_entry('file', name, parent_id, name + '-id')
1429
ie.text_sha1 = osutils.sha_string(content)
1430
ie.text_size = len(content)
1433
def make_simple_inventory(self):
1434
inv = Inventory('TREE_ROOT')
1435
inv.revision_id = "revid"
1436
inv.root.revision = "rootrev"
1439
# sub-file1 sub-file1-id
1440
# sub-file2 sub-file2-id
1441
# sub-dir1/ sub-dir1-id
1442
# subsub-file1 subsub-file1-id
1444
# sub2-file1 sub2-file1-id
1446
self.make_dir(inv, 'dir1', 'TREE_ROOT')
1447
self.make_dir(inv, 'dir2', 'TREE_ROOT')
1448
self.make_dir(inv, 'sub-dir1', 'dir1-id')
1449
self.make_file(inv, 'top', 'TREE_ROOT')
1450
self.make_file(inv, 'sub-file1', 'dir1-id')
1451
self.make_file(inv, 'sub-file2', 'dir1-id')
1452
self.make_file(inv, 'subsub-file1', 'sub-dir1-id')
1453
self.make_file(inv, 'sub2-file1', 'dir2-id')
1454
chk_bytes = self.get_chk_bytes()
1455
# use a small maximum_size to force internal paging structures
1456
chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
1458
search_key_name='hash-255-way')
1459
bytes = ''.join(chk_inv.to_lines())
1460
return CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
1462
def assert_Getitems(self, expected_fileids, inv, file_ids):
1463
self.assertEqual(sorted(expected_fileids),
1464
sorted([ie.file_id for ie in inv._getitems(file_ids)]))
1466
def assertExpand(self, all_ids, inv, file_ids):
1468
val_children) = inv._expand_fileids_to_parents_and_children(file_ids)
1469
self.assertEqual(set(all_ids), val_all_ids)
1470
entries = inv._getitems(val_all_ids)
1471
expected_children = {}
1472
for entry in entries:
1473
s = expected_children.setdefault(entry.parent_id, [])
1474
s.append(entry.file_id)
1475
val_children = dict((k, sorted(v)) for k, v
1476
in val_children.iteritems())
1477
expected_children = dict((k, sorted(v)) for k, v
1478
in expected_children.iteritems())
1479
self.assertEqual(expected_children, val_children)
1481
def test_make_simple_inventory(self):
1482
inv = self.make_simple_inventory()
1484
for path, entry in inv.iter_entries_by_dir():
1485
layout.append((path, entry.file_id))
1488
('dir1', 'dir1-id'),
1489
('dir2', 'dir2-id'),
1491
('dir1/sub-dir1', 'sub-dir1-id'),
1492
('dir1/sub-file1', 'sub-file1-id'),
1493
('dir1/sub-file2', 'sub-file2-id'),
1494
('dir1/sub-dir1/subsub-file1', 'subsub-file1-id'),
1495
('dir2/sub2-file1', 'sub2-file1-id'),
1498
def test__getitems(self):
1499
inv = self.make_simple_inventory()
1501
self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
1502
self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
1503
self.assertFalse('sub-file2-id' in inv._fileid_to_entry_cache)
1505
self.assert_Getitems(['dir1-id'], inv, ['dir1-id'])
1507
self.assert_Getitems(['dir1-id', 'sub-file2-id'], inv,
1508
['dir1-id', 'sub-file2-id'])
1509
self.assertTrue('dir1-id' in inv._fileid_to_entry_cache)
1510
self.assertTrue('sub-file2-id' in inv._fileid_to_entry_cache)
1512
def test_single_file(self):
1513
inv = self.make_simple_inventory()
1514
self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
1516
def test_get_all_parents(self):
1517
inv = self.make_simple_inventory()
1518
self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1520
], inv, ['subsub-file1-id'])
1522
def test_get_children(self):
1523
inv = self.make_simple_inventory()
1524
self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1525
'sub-file1-id', 'sub-file2-id', 'subsub-file1-id',
1526
], inv, ['dir1-id'])
1528
def test_from_root(self):
1529
inv = self.make_simple_inventory()
1530
self.assertExpand(['TREE_ROOT', 'dir1-id', 'dir2-id', 'sub-dir1-id',
1531
'sub-file1-id', 'sub-file2-id', 'sub2-file1-id',
1532
'subsub-file1-id', 'top-id'], inv, ['TREE_ROOT'])
1534
def test_top_level_file(self):
1535
inv = self.make_simple_inventory()
1536
self.assertExpand(['TREE_ROOT', 'top-id'], inv, ['top-id'])
1538
def test_subsub_file(self):
1539
inv = self.make_simple_inventory()
1540
self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id',
1541
'subsub-file1-id'], inv, ['subsub-file1-id'])
1543
def test_sub_and_root(self):
1544
inv = self.make_simple_inventory()
1545
self.assertExpand(['TREE_ROOT', 'dir1-id', 'sub-dir1-id', 'top-id',
1546
'subsub-file1-id'], inv, ['top-id', 'subsub-file1-id'])
1549
class TestMutableInventoryFromTree(TestCaseWithTransport):
1551
def test_empty(self):
1552
repository = self.make_repository('.')
1553
tree = repository.revision_tree(revision.NULL_REVISION)
1554
inv = mutable_inventory_from_tree(tree)
1555
self.assertEquals(revision.NULL_REVISION, inv.revision_id)
1556
self.assertEquals(0, len(inv))
1558
def test_some_files(self):
1559
wt = self.make_branch_and_tree('.')
1560
self.build_tree(['a'])
1561
wt.add(['a'], ['thefileid'])
1562
revid = wt.commit("commit")
1563
tree = wt.branch.repository.revision_tree(revid)
1564
inv = mutable_inventory_from_tree(tree)
1565
self.assertEquals(revid, inv.revision_id)
1566
self.assertEquals(2, len(inv))
1567
self.assertEquals("a", inv['thefileid'].name)
1568
# The inventory should be mutable and independent of
1570
self.assertFalse(tree.inventory['thefileid'].executable)
1571
inv['thefileid'].executable = True
1572
self.assertFalse(tree.inventory['thefileid'].executable)