1
# Copyright (C) 2005 by Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
from bzrlib.selftest import TestBase
19
from bzrlib.inventory import Inventory, InventoryEntry
22
class TestIsWithin(TestBase):
24
from bzrlib.osutils import is_inside_any
26
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
27
(['src'], 'src/foo.c'),
30
self.assert_(is_inside_any(dirs, fn))
32
for dirs, fn in [(['src'], 'srccontrol'),
33
(['src'], 'srccontrol/foo')]:
34
self.assertFalse(is_inside_any(dirs, fn))
38
class TestInventoryIds(TestBase):
40
"""Test detection of files within selected directories."""
43
for args in [('src', 'directory', 'src-id'),
44
('doc', 'directory', 'doc-id'),
45
('src/hello.c', 'file'),
46
('src/bye.c', 'file', 'bye-id'),
47
('Makefile', 'file')]:
50
self.assertEqual(inv.path2id('src'), 'src-id')
51
self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
53
self.assert_('src-id' in inv)
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27
from bzrlib.inventory import (CHKInventory, Inventory, ROOT_ID, InventoryFile,
28
InventoryDirectory, InventoryEntry, TreeReference)
29
from bzrlib.tests import (
31
TestCaseWithTransport,
34
split_suite_by_condition,
36
from bzrlib.tests.per_workingtree import workingtree_formats
39
def load_tests(standard_tests, module, loader):
40
"""Parameterise some inventory tests."""
41
to_adapt, result = split_suite_by_condition(standard_tests,
42
condition_isinstance(TestDeltaApplication))
44
('Inventory', {'apply_delta':apply_inventory_Inventory}),
46
# Working tree basis delta application
47
# Repository add_inv_by_delta.
48
# Reduce form of the per_repository test logic - that logic needs to be
49
# be able to get /just/ repositories whereas these tests are fine with
50
# just creating trees.
52
for _, format in repository.format_registry.iteritems():
53
scenarios.append((str(format.__name__), {
54
'apply_delta':apply_inventory_Repository_add_inventory_by_delta,
56
for format in workingtree_formats():
57
scenarios.append((str(format.__class__.__name__), {
58
'apply_delta':apply_inventory_WT_basis,
60
return multiply_tests(to_adapt, scenarios, result)
63
def apply_inventory_Inventory(self, basis, delta):
64
"""Apply delta to basis and return the result.
66
:param basis: An inventory to be used as the basis.
67
:param delta: The inventory delta to apply:
68
:return: An inventory resulting from the application.
70
basis.apply_delta(delta)
74
def apply_inventory_WT_basis(self, basis, delta):
75
"""Apply delta to basis and return the result.
77
This sets the parent and then calls update_basis_by_delta.
78
It also puts the basis in the repository under both 'basis' and 'result' to
79
allow safety checks made by the WT to succeed, and finally ensures that all
80
items in the delta with a new path are present in the WT before calling
81
update_basis_by_delta.
83
:param basis: An inventory to be used as the basis.
84
:param delta: The inventory delta to apply:
85
:return: An inventory resulting from the application.
87
control = self.make_bzrdir('tree', format=self.format._matchingbzrdir)
88
control.create_repository()
89
control.create_branch()
90
tree = self.format.initialize(control)
93
repo = tree.branch.repository
94
repo.start_write_group()
96
rev = revision.Revision('basis', timestamp=0, timezone=None,
97
message="", committer="foo@example.com")
98
basis.revision_id = 'basis'
99
repo.add_revision('basis', rev, basis)
100
# Add a revision for the result, with the basis content -
101
# update_basis_by_delta doesn't check that the delta results in
102
# result, and we want inconsistent deltas to get called on the
103
# tree, or else the code isn't actually checked.
104
rev = revision.Revision('result', timestamp=0, timezone=None,
105
message="", committer="foo@example.com")
106
basis.revision_id = 'result'
107
repo.add_revision('result', rev, basis)
109
repo.abort_write_group()
112
repo.commit_write_group()
113
# Set the basis state as the trees current state
114
tree._write_inventory(basis)
115
# This reads basis from the repo and puts it into the tree's local
116
# cache, if it has one.
117
tree.set_parent_ids(['basis'])
120
for old, new, id, entry in delta:
123
paths[new] = (entry.file_id, entry.kind)
124
parents.add(osutils.dirname(new))
125
parents = osutils.minimum_path_selection(parents)
127
# Put place holders in the tree to permit adding the other entries.
128
for pos, parent in enumerate(parents):
129
if not tree.path2id(parent):
130
# add a synthetic directory in the tree so we can can put the
131
# tree0 entries in place for dirstate.
132
tree.add([parent], ["id%d" % pos], ["directory"])
134
# Many deltas may cause this mini-apply to fail, but we want to see what
135
# the delta application code says, not the prep that we do to deal with
136
# limitations of dirstate's update_basis code.
137
for path, (file_id, kind) in sorted(paths.items()):
139
tree.add([path], [file_id], [kind])
140
except (KeyboardInterrupt, SystemExit):
146
# Fresh lock, reads disk again.
149
tree.update_basis_by_delta('result', delta)
152
# reload tree - ensure we get what was written.
153
tree = tree.bzrdir.open_workingtree()
154
basis_tree = tree.basis_tree()
155
basis_tree.lock_read()
156
self.addCleanup(basis_tree.unlock)
157
# Note, that if the tree does not have a local cache, the trick above of
158
# setting the result as the basis, will come back to bite us. That said,
159
# all the implementations in bzr do have a local cache.
160
return basis_tree.inventory
163
def apply_inventory_Repository_add_inventory_by_delta(self, basis, delta):
164
"""Apply delta to basis and return the result.
166
This inserts basis as a whole inventory and then uses
167
add_inventory_by_delta to add delta.
169
:param basis: An inventory to be used as the basis.
170
:param delta: The inventory delta to apply:
171
:return: An inventory resulting from the application.
173
format = self.format()
174
control = self.make_bzrdir('tree', format=format._matchingbzrdir)
175
repo = format.initialize(control)
178
repo.start_write_group()
180
rev = revision.Revision('basis', timestamp=0, timezone=None,
181
message="", committer="foo@example.com")
182
basis.revision_id = 'basis'
183
repo.add_revision('basis', rev, basis)
185
repo.abort_write_group()
188
repo.commit_write_group()
193
repo.start_write_group()
195
inv_sha1 = repo.add_inventory_by_delta('basis', delta,
198
repo.abort_write_group()
201
repo.commit_write_group()
204
# Fresh lock, reads disk again.
205
repo = repo.bzrdir.open_repository()
207
self.addCleanup(repo.unlock)
208
return repo.get_inventory('result')
211
class TestDeltaApplication(TestCaseWithTransport):
213
def get_empty_inventory(self, reference_inv=None):
214
"""Get an empty inventory.
216
Note that tests should not depend on the revision of the root for
217
setting up test conditions, as it has to be flexible to accomodate non
218
rich root repositories.
220
:param reference_inv: If not None, get the revision for the root from
221
this inventory. This is useful for dealing with older repositories
222
that routinely discarded the root entry data. If None, the root's
223
revision is set to 'basis'.
225
inv = inventory.Inventory()
226
if reference_inv is not None:
227
inv.root.revision = reference_inv.root.revision
229
inv.root.revision = 'basis'
232
def test_empty_delta(self):
233
inv = self.get_empty_inventory()
235
inv = self.apply_delta(self, inv, delta)
236
inv2 = self.get_empty_inventory(inv)
237
self.assertEqual([], inv2._make_delta(inv))
239
def test_repeated_file_id(self):
240
inv = self.get_empty_inventory()
241
file1 = inventory.InventoryFile('id', 'path1', inv.root.file_id)
242
file1.revision = 'result'
245
file2 = inventory.InventoryFile('id', 'path2', inv.root.file_id)
246
file2.revision = 'result'
249
delta = [(None, u'path1', 'id', file1), (None, u'path2', 'id', file2)]
250
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
253
def test_repeated_new_path(self):
254
inv = self.get_empty_inventory()
255
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
256
file1.revision = 'result'
259
file2 = inventory.InventoryFile('id2', 'path', inv.root.file_id)
260
file2.revision = 'result'
263
delta = [(None, u'path', 'id1', file1), (None, u'path', 'id2', file2)]
264
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
267
def test_repeated_old_path(self):
268
inv = self.get_empty_inventory()
269
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
270
file1.revision = 'result'
273
# We can't *create* a source inventory with the same path, but
274
# a badly generated partial delta might claim the same source twice.
275
# This would be buggy in two ways: the path is repeated in the delta,
276
# And the path for one of the file ids doesn't match the source
277
# location. Alternatively, we could have a repeated fileid, but that
278
# is separately checked for.
279
file2 = inventory.InventoryFile('id2', 'path2', inv.root.file_id)
280
file2.revision = 'result'
285
delta = [(u'path', None, 'id1', None), (u'path', None, 'id2', None)]
286
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
289
def test_mismatched_id_entry_id(self):
290
inv = self.get_empty_inventory()
291
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
292
file1.revision = 'result'
295
delta = [(None, u'path', 'id', file1)]
296
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
299
def test_parent_is_not_directory(self):
300
inv = self.get_empty_inventory()
301
file1 = inventory.InventoryFile('id1', 'path', inv.root.file_id)
302
file1.revision = 'result'
305
file2 = inventory.InventoryFile('id2', 'path2', 'id1')
306
file2.revision = 'result'
310
delta = [(None, u'path/path2', 'id2', file2)]
311
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
314
def test_parent_is_missing(self):
315
inv = self.get_empty_inventory()
316
file2 = inventory.InventoryFile('id2', 'path2', 'missingparent')
317
file2.revision = 'result'
320
delta = [(None, u'path/path2', 'id2', file2)]
321
self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
325
class TestInventoryEntry(TestCase):
327
def test_file_kind_character(self):
328
file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
329
self.assertEqual(file.kind_character(), '')
331
def test_dir_kind_character(self):
332
dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
333
self.assertEqual(dir.kind_character(), '/')
335
def test_link_kind_character(self):
336
dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
337
self.assertEqual(dir.kind_character(), '')
339
def test_dir_detect_changes(self):
340
left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
342
left.executable = True
343
left.symlink_target='foo'
344
right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
345
right.text_sha1 = 321
346
right.symlink_target='bar'
347
self.assertEqual((False, False), left.detect_changes(right))
348
self.assertEqual((False, False), right.detect_changes(left))
350
def test_file_detect_changes(self):
351
left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
353
right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
354
right.text_sha1 = 123
355
self.assertEqual((False, False), left.detect_changes(right))
356
self.assertEqual((False, False), right.detect_changes(left))
357
left.executable = True
358
self.assertEqual((False, True), left.detect_changes(right))
359
self.assertEqual((False, True), right.detect_changes(left))
360
right.text_sha1 = 321
361
self.assertEqual((True, True), left.detect_changes(right))
362
self.assertEqual((True, True), right.detect_changes(left))
364
def test_symlink_detect_changes(self):
365
left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
367
left.executable = True
368
left.symlink_target='foo'
369
right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
370
right.text_sha1 = 321
371
right.symlink_target='foo'
372
self.assertEqual((False, False), left.detect_changes(right))
373
self.assertEqual((False, False), right.detect_changes(left))
374
left.symlink_target = 'different'
375
self.assertEqual((True, False), left.detect_changes(right))
376
self.assertEqual((True, False), right.detect_changes(left))
378
def test_file_has_text(self):
379
file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
380
self.failUnless(file.has_text())
382
def test_directory_has_text(self):
383
dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
384
self.failIf(dir.has_text())
386
def test_link_has_text(self):
387
link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
388
self.failIf(link.has_text())
390
def test_make_entry(self):
391
self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
392
inventory.InventoryFile)
393
self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
394
inventory.InventoryLink)
395
self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
396
inventory.InventoryDirectory)
398
def test_make_entry_non_normalized(self):
399
orig_normalized_filename = osutils.normalized_filename
402
osutils.normalized_filename = osutils._accessible_normalized_filename
403
entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
404
self.assertEqual(u'\xe5', entry.name)
405
self.assertIsInstance(entry, inventory.InventoryFile)
407
osutils.normalized_filename = osutils._inaccessible_normalized_filename
408
self.assertRaises(errors.InvalidNormalization,
409
inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
411
osutils.normalized_filename = orig_normalized_filename
414
class TestDescribeChanges(TestCase):
416
def test_describe_change(self):
417
# we need to test the following change combinations:
423
# renamed/reparented and modified
424
# change kind (perhaps can't be done yet?)
425
# also, merged in combination with all of these?
426
old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
427
old_a.text_sha1 = '123132'
429
new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
430
new_a.text_sha1 = '123132'
433
self.assertChangeDescription('unchanged', old_a, new_a)
436
new_a.text_sha1 = 'abcabc'
437
self.assertChangeDescription('modified', old_a, new_a)
439
self.assertChangeDescription('added', None, new_a)
440
self.assertChangeDescription('removed', old_a, None)
441
# perhaps a bit questionable but seems like the most reasonable thing...
442
self.assertChangeDescription('unchanged', None, None)
444
# in this case it's both renamed and modified; show a rename and
446
new_a.name = 'newfilename'
447
self.assertChangeDescription('modified and renamed', old_a, new_a)
449
# reparenting is 'renaming'
450
new_a.name = old_a.name
451
new_a.parent_id = 'somedir-id'
452
self.assertChangeDescription('modified and renamed', old_a, new_a)
454
# reset the content values so its not modified
455
new_a.text_size = old_a.text_size
456
new_a.text_sha1 = old_a.text_sha1
457
new_a.name = old_a.name
459
new_a.name = 'newfilename'
460
self.assertChangeDescription('renamed', old_a, new_a)
462
# reparenting is 'renaming'
463
new_a.name = old_a.name
464
new_a.parent_id = 'somedir-id'
465
self.assertChangeDescription('renamed', old_a, new_a)
467
def assertChangeDescription(self, expected_change, old_ie, new_ie):
468
change = InventoryEntry.describe_change(old_ie, new_ie)
469
self.assertEqual(expected_change, change)
472
class TestCHKInventory(TestCaseWithTransport):
474
def get_chk_bytes(self):
475
# The easiest way to get a CHK store is a development6 repository and
476
# then work with the chk_bytes attribute directly.
477
repo = self.make_repository(".", format="development6-rich-root")
479
self.addCleanup(repo.unlock)
480
repo.start_write_group()
481
self.addCleanup(repo.abort_write_group)
482
return repo.chk_bytes
484
def read_bytes(self, chk_bytes, key):
485
stream = chk_bytes.get_record_stream([key], 'unordered', True)
486
return stream.next().get_bytes_as("fulltext")
488
def test_deserialise_gives_CHKInventory(self):
490
inv.revision_id = "revid"
491
inv.root.revision = "rootrev"
492
chk_bytes = self.get_chk_bytes()
493
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
494
bytes = ''.join(chk_inv.to_lines())
495
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
496
self.assertEqual("revid", new_inv.revision_id)
497
self.assertEqual("directory", new_inv.root.kind)
498
self.assertEqual(inv.root.file_id, new_inv.root.file_id)
499
self.assertEqual(inv.root.parent_id, new_inv.root.parent_id)
500
self.assertEqual(inv.root.name, new_inv.root.name)
501
self.assertEqual("rootrev", new_inv.root.revision)
502
self.assertEqual('plain', new_inv._search_key_name)
504
def test_deserialise_wrong_revid(self):
506
inv.revision_id = "revid"
507
inv.root.revision = "rootrev"
508
chk_bytes = self.get_chk_bytes()
509
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
510
bytes = ''.join(chk_inv.to_lines())
511
self.assertRaises(ValueError, CHKInventory.deserialise, chk_bytes,
514
def test_captures_rev_root_byid(self):
516
inv.revision_id = "foo"
517
inv.root.revision = "bar"
518
chk_bytes = self.get_chk_bytes()
519
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
520
lines = chk_inv.to_lines()
523
'revision_id: foo\n',
524
'root_id: TREE_ROOT\n',
525
'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
526
'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
528
chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
529
self.assertEqual('plain', chk_inv._search_key_name)
531
def test_captures_parent_id_basename_index(self):
533
inv.revision_id = "foo"
534
inv.root.revision = "bar"
535
chk_bytes = self.get_chk_bytes()
536
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
537
lines = chk_inv.to_lines()
540
'revision_id: foo\n',
541
'root_id: TREE_ROOT\n',
542
'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
543
'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
545
chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
546
self.assertEqual('plain', chk_inv._search_key_name)
548
def test_captures_search_key_name(self):
550
inv.revision_id = "foo"
551
inv.root.revision = "bar"
552
chk_bytes = self.get_chk_bytes()
553
chk_inv = CHKInventory.from_inventory(chk_bytes, inv,
554
search_key_name='hash-16-way')
555
lines = chk_inv.to_lines()
558
'search_key_name: hash-16-way\n',
559
'root_id: TREE_ROOT\n',
560
'parent_id_basename_to_file_id: sha1:eb23f0ad4b07f48e88c76d4c94292be57fb2785f\n',
561
'revision_id: foo\n',
562
'id_to_entry: sha1:debfe920f1f10e7929260f0534ac9a24d7aabbb4\n',
564
chk_inv = CHKInventory.deserialise(chk_bytes, ''.join(lines), ('foo',))
565
self.assertEqual('hash-16-way', chk_inv._search_key_name)
567
def test_directory_children_on_demand(self):
569
inv.revision_id = "revid"
570
inv.root.revision = "rootrev"
571
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
572
inv["fileid"].revision = "filerev"
573
inv["fileid"].executable = True
574
inv["fileid"].text_sha1 = "ffff"
575
inv["fileid"].text_size = 1
576
chk_bytes = self.get_chk_bytes()
577
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
578
bytes = ''.join(chk_inv.to_lines())
579
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
580
root_entry = new_inv[inv.root.file_id]
581
self.assertEqual(None, root_entry._children)
582
self.assertEqual(['file'], root_entry.children.keys())
583
file_direct = new_inv["fileid"]
584
file_found = root_entry.children['file']
585
self.assertEqual(file_direct.kind, file_found.kind)
586
self.assertEqual(file_direct.file_id, file_found.file_id)
587
self.assertEqual(file_direct.parent_id, file_found.parent_id)
588
self.assertEqual(file_direct.name, file_found.name)
589
self.assertEqual(file_direct.revision, file_found.revision)
590
self.assertEqual(file_direct.text_sha1, file_found.text_sha1)
591
self.assertEqual(file_direct.text_size, file_found.text_size)
592
self.assertEqual(file_direct.executable, file_found.executable)
594
def test_from_inventory_maximum_size(self):
595
# from_inventory supports the maximum_size parameter.
597
inv.revision_id = "revid"
598
inv.root.revision = "rootrev"
599
chk_bytes = self.get_chk_bytes()
600
chk_inv = CHKInventory.from_inventory(chk_bytes, inv, 120)
601
chk_inv.id_to_entry._ensure_root()
602
self.assertEqual(120, chk_inv.id_to_entry._root_node.maximum_size)
603
self.assertEqual(1, chk_inv.id_to_entry._root_node._key_width)
604
p_id_basename = chk_inv.parent_id_basename_to_file_id
605
p_id_basename._ensure_root()
606
self.assertEqual(120, p_id_basename._root_node.maximum_size)
607
self.assertEqual(2, p_id_basename._root_node._key_width)
609
def test___iter__(self):
611
inv.revision_id = "revid"
612
inv.root.revision = "rootrev"
613
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
614
inv["fileid"].revision = "filerev"
615
inv["fileid"].executable = True
616
inv["fileid"].text_sha1 = "ffff"
617
inv["fileid"].text_size = 1
618
chk_bytes = self.get_chk_bytes()
619
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
620
bytes = ''.join(chk_inv.to_lines())
621
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
622
fileids = list(new_inv.__iter__())
624
self.assertEqual([inv.root.file_id, "fileid"], fileids)
626
def test__len__(self):
628
inv.revision_id = "revid"
629
inv.root.revision = "rootrev"
630
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
631
inv["fileid"].revision = "filerev"
632
inv["fileid"].executable = True
633
inv["fileid"].text_sha1 = "ffff"
634
inv["fileid"].text_size = 1
635
chk_bytes = self.get_chk_bytes()
636
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
637
self.assertEqual(2, len(chk_inv))
639
def test___getitem__(self):
641
inv.revision_id = "revid"
642
inv.root.revision = "rootrev"
643
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
644
inv["fileid"].revision = "filerev"
645
inv["fileid"].executable = True
646
inv["fileid"].text_sha1 = "ffff"
647
inv["fileid"].text_size = 1
648
chk_bytes = self.get_chk_bytes()
649
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
650
bytes = ''.join(chk_inv.to_lines())
651
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
652
root_entry = new_inv[inv.root.file_id]
653
file_entry = new_inv["fileid"]
654
self.assertEqual("directory", root_entry.kind)
655
self.assertEqual(inv.root.file_id, root_entry.file_id)
656
self.assertEqual(inv.root.parent_id, root_entry.parent_id)
657
self.assertEqual(inv.root.name, root_entry.name)
658
self.assertEqual("rootrev", root_entry.revision)
659
self.assertEqual("file", file_entry.kind)
660
self.assertEqual("fileid", file_entry.file_id)
661
self.assertEqual(inv.root.file_id, file_entry.parent_id)
662
self.assertEqual("file", file_entry.name)
663
self.assertEqual("filerev", file_entry.revision)
664
self.assertEqual("ffff", file_entry.text_sha1)
665
self.assertEqual(1, file_entry.text_size)
666
self.assertEqual(True, file_entry.executable)
667
self.assertRaises(errors.NoSuchId, new_inv.__getitem__, 'missing')
669
def test_has_id_true(self):
671
inv.revision_id = "revid"
672
inv.root.revision = "rootrev"
673
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
674
inv["fileid"].revision = "filerev"
675
inv["fileid"].executable = True
676
inv["fileid"].text_sha1 = "ffff"
677
inv["fileid"].text_size = 1
678
chk_bytes = self.get_chk_bytes()
679
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
680
self.assertTrue(chk_inv.has_id('fileid'))
681
self.assertTrue(chk_inv.has_id(inv.root.file_id))
683
def test_has_id_not(self):
685
inv.revision_id = "revid"
686
inv.root.revision = "rootrev"
687
chk_bytes = self.get_chk_bytes()
688
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
689
self.assertFalse(chk_inv.has_id('fileid'))
691
def test_id2path(self):
693
inv.revision_id = "revid"
694
inv.root.revision = "rootrev"
695
direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
696
fileentry = InventoryFile("fileid", "file", "dirid")
699
inv["fileid"].revision = "filerev"
700
inv["fileid"].executable = True
701
inv["fileid"].text_sha1 = "ffff"
702
inv["fileid"].text_size = 1
703
inv["dirid"].revision = "filerev"
704
chk_bytes = self.get_chk_bytes()
705
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
706
bytes = ''.join(chk_inv.to_lines())
707
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
708
self.assertEqual('', new_inv.id2path(inv.root.file_id))
709
self.assertEqual('dir', new_inv.id2path('dirid'))
710
self.assertEqual('dir/file', new_inv.id2path('fileid'))
712
def test_path2id(self):
714
inv.revision_id = "revid"
715
inv.root.revision = "rootrev"
716
direntry = InventoryDirectory("dirid", "dir", inv.root.file_id)
717
fileentry = InventoryFile("fileid", "file", "dirid")
720
inv["fileid"].revision = "filerev"
721
inv["fileid"].executable = True
722
inv["fileid"].text_sha1 = "ffff"
723
inv["fileid"].text_size = 1
724
inv["dirid"].revision = "filerev"
725
chk_bytes = self.get_chk_bytes()
726
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
727
bytes = ''.join(chk_inv.to_lines())
728
new_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
729
self.assertEqual(inv.root.file_id, new_inv.path2id(''))
730
self.assertEqual('dirid', new_inv.path2id('dir'))
731
self.assertEqual('fileid', new_inv.path2id('dir/file'))
733
def test_create_by_apply_delta_sets_root(self):
735
inv.revision_id = "revid"
736
chk_bytes = self.get_chk_bytes()
737
base_inv = CHKInventory.from_inventory(chk_bytes, inv)
738
inv.add_path("", "directory", "myrootid", None)
739
inv.revision_id = "expectedid"
740
reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
741
delta = [(None, "", "myrootid", inv.root)]
742
new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
743
self.assertEquals(reference_inv.root, new_inv.root)
745
def test_create_by_apply_delta_empty_add_child(self):
747
inv.revision_id = "revid"
748
inv.root.revision = "rootrev"
749
chk_bytes = self.get_chk_bytes()
750
base_inv = CHKInventory.from_inventory(chk_bytes, inv)
751
a_entry = InventoryFile("A-id", "A", inv.root.file_id)
752
a_entry.revision = "filerev"
753
a_entry.executable = True
754
a_entry.text_sha1 = "ffff"
755
a_entry.text_size = 1
757
inv.revision_id = "expectedid"
758
reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
759
delta = [(None, "A", "A-id", a_entry)]
760
new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
761
# new_inv should be the same as reference_inv.
762
self.assertEqual(reference_inv.revision_id, new_inv.revision_id)
763
self.assertEqual(reference_inv.root_id, new_inv.root_id)
764
reference_inv.id_to_entry._ensure_root()
765
new_inv.id_to_entry._ensure_root()
766
self.assertEqual(reference_inv.id_to_entry._root_node._key,
767
new_inv.id_to_entry._root_node._key)
769
def test_create_by_apply_delta_empty_add_child_updates_parent_id(self):
771
inv.revision_id = "revid"
772
inv.root.revision = "rootrev"
773
chk_bytes = self.get_chk_bytes()
774
base_inv = CHKInventory.from_inventory(chk_bytes, inv)
775
a_entry = InventoryFile("A-id", "A", inv.root.file_id)
776
a_entry.revision = "filerev"
777
a_entry.executable = True
778
a_entry.text_sha1 = "ffff"
779
a_entry.text_size = 1
781
inv.revision_id = "expectedid"
782
reference_inv = CHKInventory.from_inventory(chk_bytes, inv)
783
delta = [(None, "A", "A-id", a_entry)]
784
new_inv = base_inv.create_by_apply_delta(delta, "expectedid")
785
reference_inv.id_to_entry._ensure_root()
786
reference_inv.parent_id_basename_to_file_id._ensure_root()
787
new_inv.id_to_entry._ensure_root()
788
new_inv.parent_id_basename_to_file_id._ensure_root()
789
# new_inv should be the same as reference_inv.
790
self.assertEqual(reference_inv.revision_id, new_inv.revision_id)
791
self.assertEqual(reference_inv.root_id, new_inv.root_id)
792
self.assertEqual(reference_inv.id_to_entry._root_node._key,
793
new_inv.id_to_entry._root_node._key)
794
self.assertEqual(reference_inv.parent_id_basename_to_file_id._root_node._key,
795
new_inv.parent_id_basename_to_file_id._root_node._key)
797
def test_iter_changes(self):
798
# Low level bootstrapping smoke test; comprehensive generic tests via
799
# InterTree are coming.
801
inv.revision_id = "revid"
802
inv.root.revision = "rootrev"
803
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
804
inv["fileid"].revision = "filerev"
805
inv["fileid"].executable = True
806
inv["fileid"].text_sha1 = "ffff"
807
inv["fileid"].text_size = 1
809
inv2.revision_id = "revid2"
810
inv2.root.revision = "rootrev"
811
inv2.add(InventoryFile("fileid", "file", inv.root.file_id))
812
inv2["fileid"].revision = "filerev2"
813
inv2["fileid"].executable = False
814
inv2["fileid"].text_sha1 = "bbbb"
815
inv2["fileid"].text_size = 2
817
chk_bytes = self.get_chk_bytes()
818
chk_inv = CHKInventory.from_inventory(chk_bytes, inv)
819
bytes = ''.join(chk_inv.to_lines())
820
inv_1 = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
821
chk_inv2 = CHKInventory.from_inventory(chk_bytes, inv2)
822
bytes = ''.join(chk_inv2.to_lines())
823
inv_2 = CHKInventory.deserialise(chk_bytes, bytes, ("revid2",))
824
self.assertEqual([('fileid', (u'file', u'file'), True, (True, True),
825
('TREE_ROOT', 'TREE_ROOT'), (u'file', u'file'), ('file', 'file'),
827
list(inv_1.iter_changes(inv_2)))
829
def test_parent_id_basename_to_file_id_index_enabled(self):
831
inv.revision_id = "revid"
832
inv.root.revision = "rootrev"
833
inv.add(InventoryFile("fileid", "file", inv.root.file_id))
834
inv["fileid"].revision = "filerev"
835
inv["fileid"].executable = True
836
inv["fileid"].text_sha1 = "ffff"
837
inv["fileid"].text_size = 1
839
chk_bytes = self.get_chk_bytes()
840
tmp_inv = CHKInventory.from_inventory(chk_bytes, inv)
841
bytes = ''.join(tmp_inv.to_lines())
842
chk_inv = CHKInventory.deserialise(chk_bytes, bytes, ("revid",))
843
self.assertIsInstance(chk_inv.parent_id_basename_to_file_id, chk_map.CHKMap)
845
{('', ''): 'TREE_ROOT', ('TREE_ROOT', 'file'): 'fileid'},
846
dict(chk_inv.parent_id_basename_to_file_id.iteritems()))
848
def test_file_entry_to_bytes(self):
849
inv = CHKInventory(None)
850
ie = inventory.InventoryFile('file-id', 'filename', 'parent-id')
852
ie.revision = 'file-rev-id'
853
ie.text_sha1 = 'abcdefgh'
855
bytes = inv._entry_to_bytes(ie)
856
self.assertEqual('file: file-id\nparent-id\nfilename\n'
857
'file-rev-id\nabcdefgh\n100\nY', bytes)
858
ie2 = inv._bytes_to_entry(bytes)
859
self.assertEqual(ie, ie2)
860
self.assertIsInstance(ie2.name, unicode)
861
self.assertEqual(('filename', 'file-id', 'file-rev-id'),
862
inv._bytes_to_utf8name_key(bytes))
864
def test_file2_entry_to_bytes(self):
865
inv = CHKInventory(None)
867
ie = inventory.InventoryFile('file-id', u'\u03a9name', 'parent-id')
868
ie.executable = False
869
ie.revision = 'file-rev-id'
870
ie.text_sha1 = '123456'
872
bytes = inv._entry_to_bytes(ie)
873
self.assertEqual('file: file-id\nparent-id\n\xce\xa9name\n'
874
'file-rev-id\n123456\n25\nN', bytes)
875
ie2 = inv._bytes_to_entry(bytes)
876
self.assertEqual(ie, ie2)
877
self.assertIsInstance(ie2.name, unicode)
878
self.assertEqual(('\xce\xa9name', 'file-id', 'file-rev-id'),
879
inv._bytes_to_utf8name_key(bytes))
881
def test_dir_entry_to_bytes(self):
882
inv = CHKInventory(None)
883
ie = inventory.InventoryDirectory('dir-id', 'dirname', 'parent-id')
884
ie.revision = 'dir-rev-id'
885
bytes = inv._entry_to_bytes(ie)
886
self.assertEqual('dir: dir-id\nparent-id\ndirname\ndir-rev-id', bytes)
887
ie2 = inv._bytes_to_entry(bytes)
888
self.assertEqual(ie, ie2)
889
self.assertIsInstance(ie2.name, unicode)
890
self.assertEqual(('dirname', 'dir-id', 'dir-rev-id'),
891
inv._bytes_to_utf8name_key(bytes))
893
def test_dir2_entry_to_bytes(self):
894
inv = CHKInventory(None)
895
ie = inventory.InventoryDirectory('dir-id', u'dir\u03a9name',
897
ie.revision = 'dir-rev-id'
898
bytes = inv._entry_to_bytes(ie)
899
self.assertEqual('dir: dir-id\n\ndir\xce\xa9name\n'
901
ie2 = inv._bytes_to_entry(bytes)
902
self.assertEqual(ie, ie2)
903
self.assertIsInstance(ie2.name, unicode)
904
self.assertIs(ie2.parent_id, None)
905
self.assertEqual(('dir\xce\xa9name', 'dir-id', 'dir-rev-id'),
906
inv._bytes_to_utf8name_key(bytes))
908
def test_symlink_entry_to_bytes(self):
909
inv = CHKInventory(None)
910
ie = inventory.InventoryLink('link-id', 'linkname', 'parent-id')
911
ie.revision = 'link-rev-id'
912
ie.symlink_target = u'target/path'
913
bytes = inv._entry_to_bytes(ie)
914
self.assertEqual('symlink: link-id\nparent-id\nlinkname\n'
915
'link-rev-id\ntarget/path', bytes)
916
ie2 = inv._bytes_to_entry(bytes)
917
self.assertEqual(ie, ie2)
918
self.assertIsInstance(ie2.name, unicode)
919
self.assertIsInstance(ie2.symlink_target, unicode)
920
self.assertEqual(('linkname', 'link-id', 'link-rev-id'),
921
inv._bytes_to_utf8name_key(bytes))
923
def test_symlink2_entry_to_bytes(self):
924
inv = CHKInventory(None)
925
ie = inventory.InventoryLink('link-id', u'link\u03a9name', 'parent-id')
926
ie.revision = 'link-rev-id'
927
ie.symlink_target = u'target/\u03a9path'
928
bytes = inv._entry_to_bytes(ie)
929
self.assertEqual('symlink: link-id\nparent-id\nlink\xce\xa9name\n'
930
'link-rev-id\ntarget/\xce\xa9path', bytes)
931
ie2 = inv._bytes_to_entry(bytes)
932
self.assertEqual(ie, ie2)
933
self.assertIsInstance(ie2.name, unicode)
934
self.assertIsInstance(ie2.symlink_target, unicode)
935
self.assertEqual(('link\xce\xa9name', 'link-id', 'link-rev-id'),
936
inv._bytes_to_utf8name_key(bytes))
938
def test_tree_reference_entry_to_bytes(self):
939
inv = CHKInventory(None)
940
ie = inventory.TreeReference('tree-root-id', u'tree\u03a9name',
942
ie.revision = 'tree-rev-id'
943
ie.reference_revision = 'ref-rev-id'
944
bytes = inv._entry_to_bytes(ie)
945
self.assertEqual('tree: tree-root-id\nparent-id\ntree\xce\xa9name\n'
946
'tree-rev-id\nref-rev-id', bytes)
947
ie2 = inv._bytes_to_entry(bytes)
948
self.assertEqual(ie, ie2)
949
self.assertIsInstance(ie2.name, unicode)
950
self.assertEqual(('tree\xce\xa9name', 'tree-root-id', 'tree-rev-id'),
951
inv._bytes_to_utf8name_key(bytes))