1
# Copyright (C) 2006 Canonical Ltd
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.
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.
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
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests of the parent related functions of WorkingTrees."""
19
from errno import EEXIST
25
revision as _mod_revision,
29
from bzrlib.inventory import (
35
from bzrlib.revision import Revision
36
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
37
from bzrlib.uncommit import uncommit
40
class TestParents(TestCaseWithWorkingTree):
42
def assertConsistentParents(self, expected, tree):
43
"""Check that the parents found are as expected.
45
This test helper also checks that they are consistent with
46
the pre-get_parent_ids() api - which is now deprecated.
48
self.assertEqual(expected, tree.get_parent_ids())
50
self.assertEqual(_mod_revision.NULL_REVISION,
51
_mod_revision.ensure_null(tree.last_revision()))
53
self.assertEqual(expected[0], tree.last_revision())
56
class TestGetParents(TestParents):
58
def test_get_parents(self):
59
t = self.make_branch_and_tree('.')
60
self.assertEqual([], t.get_parent_ids())
63
class TestSetParents(TestParents):
65
def test_set_no_parents(self):
66
t = self.make_branch_and_tree('.')
67
t.set_parent_trees([])
68
self.assertEqual([], t.get_parent_ids())
69
# now give it a real parent, and then set it to no parents again.
70
t.commit('first post')
71
t.set_parent_trees([])
72
self.assertConsistentParents([], t)
74
def test_set_null_parent(self):
75
t = self.make_branch_and_tree('.')
76
self.assertRaises(errors.ReservedId, t.set_parent_ids, ['null:'],
77
allow_leftmost_as_ghost=True)
78
self.assertRaises(errors.ReservedId, t.set_parent_trees,
79
[('null:', None)], allow_leftmost_as_ghost=True)
81
def test_set_one_ghost_parent_rejects(self):
82
t = self.make_branch_and_tree('.')
83
self.assertRaises(errors.GhostRevisionUnusableHere,
84
t.set_parent_trees, [('missing-revision-id', None)])
86
def test_set_one_ghost_parent_force(self):
87
t = self.make_branch_and_tree('.')
88
t.set_parent_trees([('missing-revision-id', None)],
89
allow_leftmost_as_ghost=True)
90
self.assertConsistentParents(['missing-revision-id'], t)
92
def test_set_two_parents_one_ghost(self):
93
t = self.make_branch_and_tree('.')
94
revision_in_repo = t.commit('first post')
95
# remove the tree's history
96
uncommit(t.branch, tree=t)
97
rev_tree = t.branch.repository.revision_tree(revision_in_repo)
98
t.set_parent_trees([(revision_in_repo, rev_tree),
99
('another-missing', None)])
100
self.assertConsistentParents([revision_in_repo, 'another-missing'], t)
102
def test_set_three_parents(self):
103
t = self.make_branch_and_tree('.')
104
first_revision = t.commit('first post')
105
uncommit(t.branch, tree=t)
106
second_revision = t.commit('second post')
107
uncommit(t.branch, tree=t)
108
third_revision = t.commit('third post')
109
uncommit(t.branch, tree=t)
110
rev_tree1 = t.branch.repository.revision_tree(first_revision)
111
rev_tree2 = t.branch.repository.revision_tree(second_revision)
112
rev_tree3 = t.branch.repository.revision_tree(third_revision)
113
t.set_parent_trees([(first_revision, rev_tree1),
114
(second_revision, rev_tree2),
115
(third_revision, rev_tree3)])
116
self.assertConsistentParents(
117
[first_revision, second_revision, third_revision], t)
119
def test_set_no_parents_ids(self):
120
t = self.make_branch_and_tree('.')
122
self.assertEqual([], t.get_parent_ids())
123
# now give it a real parent, and then set it to no parents again.
124
t.commit('first post')
126
self.assertConsistentParents([], t)
128
def test_set_one_ghost_parent_ids_rejects(self):
129
t = self.make_branch_and_tree('.')
130
self.assertRaises(errors.GhostRevisionUnusableHere,
131
t.set_parent_ids, ['missing-revision-id'])
133
def test_set_one_ghost_parent_ids_force(self):
134
t = self.make_branch_and_tree('.')
135
t.set_parent_ids(['missing-revision-id'],
136
allow_leftmost_as_ghost=True)
137
self.assertConsistentParents(['missing-revision-id'], t)
139
def test_set_two_parents_one_ghost_ids(self):
140
t = self.make_branch_and_tree('.')
141
revision_in_repo = t.commit('first post')
142
# remove the tree's history
143
uncommit(t.branch, tree=t)
144
rev_tree = t.branch.repository.revision_tree(revision_in_repo)
145
t.set_parent_ids([revision_in_repo, 'another-missing'])
146
self.assertConsistentParents([revision_in_repo, 'another-missing'], t)
148
def test_set_three_parents_ids(self):
149
t = self.make_branch_and_tree('.')
150
first_revision = t.commit('first post')
151
uncommit(t.branch, tree=t)
152
second_revision = t.commit('second post')
153
uncommit(t.branch, tree=t)
154
third_revision = t.commit('third post')
155
uncommit(t.branch, tree=t)
156
rev_tree1 = t.branch.repository.revision_tree(first_revision)
157
rev_tree2 = t.branch.repository.revision_tree(second_revision)
158
rev_tree3 = t.branch.repository.revision_tree(third_revision)
159
t.set_parent_ids([first_revision, second_revision, third_revision])
160
self.assertConsistentParents(
161
[first_revision, second_revision, third_revision], t)
163
def test_set_duplicate_parent_ids(self):
164
t = self.make_branch_and_tree('.')
165
rev1 = t.commit('first post')
166
uncommit(t.branch, tree=t)
167
rev2 = t.commit('second post')
168
uncommit(t.branch, tree=t)
169
rev3 = t.commit('third post')
170
uncommit(t.branch, tree=t)
171
t.set_parent_ids([rev1, rev2, rev2, rev3])
172
# We strip the duplicate, but preserve the ordering
173
self.assertConsistentParents([rev1, rev2, rev3], t)
175
def test_set_duplicate_parent_trees(self):
176
t = self.make_branch_and_tree('.')
177
rev1 = t.commit('first post')
178
uncommit(t.branch, tree=t)
179
rev2 = t.commit('second post')
180
uncommit(t.branch, tree=t)
181
rev3 = t.commit('third post')
182
uncommit(t.branch, tree=t)
183
rev_tree1 = t.branch.repository.revision_tree(rev1)
184
rev_tree2 = t.branch.repository.revision_tree(rev2)
185
rev_tree3 = t.branch.repository.revision_tree(rev3)
186
t.set_parent_trees([(rev1, rev_tree1), (rev2, rev_tree2),
187
(rev2, rev_tree2), (rev3, rev_tree3)])
188
# We strip the duplicate, but preserve the ordering
189
self.assertConsistentParents([rev1, rev2, rev3], t)
191
def test_set_parent_ids_in_ancestry(self):
192
t = self.make_branch_and_tree('.')
193
rev1 = t.commit('first post')
194
rev2 = t.commit('second post')
195
rev3 = t.commit('third post')
196
# Reset the tree, back to rev1
197
t.set_parent_ids([rev1])
198
t.branch.set_last_revision_info(1, rev1)
199
self.assertConsistentParents([rev1], t)
200
t.set_parent_ids([rev1, rev2, rev3])
201
# rev2 is in the ancestry of rev3, so it will be filtered out
202
self.assertConsistentParents([rev1, rev3], t)
203
# Order should be preserved, and the first revision should always be
205
t.set_parent_ids([rev2, rev3, rev1])
206
self.assertConsistentParents([rev2, rev3], t)
208
def test_set_parent_trees_in_ancestry(self):
209
t = self.make_branch_and_tree('.')
210
rev1 = t.commit('first post')
211
rev2 = t.commit('second post')
212
rev3 = t.commit('third post')
213
# Reset the tree, back to rev1
214
t.set_parent_ids([rev1])
215
t.branch.set_last_revision_info(1, rev1)
216
self.assertConsistentParents([rev1], t)
217
rev_tree1 = t.branch.repository.revision_tree(rev1)
218
rev_tree2 = t.branch.repository.revision_tree(rev2)
219
rev_tree3 = t.branch.repository.revision_tree(rev3)
220
t.set_parent_trees([(rev1, rev_tree1), (rev2, rev_tree2),
222
# rev2 is in the ancestry of rev3, so it will be filtered out
223
self.assertConsistentParents([rev1, rev3], t)
224
# Order should be preserved, and the first revision should always be
226
t.set_parent_trees([(rev2, rev_tree2), (rev1, rev_tree1),
228
self.assertConsistentParents([rev2, rev3], t)
230
def test_unicode_symlink(self):
231
# this tests bug #272444
232
self.requireFeature(tests.SymlinkFeature)
233
self.requireFeature(tests.UnicodeFilenameFeature)
235
tree = self.make_branch_and_tree('tree1')
237
# The link points to a file whose name is an omega
238
# U+03A9 GREEK CAPITAL LETTER OMEGA
239
# UTF-8: ce a9 UTF-16BE: 03a9 Decimal: Ω
241
link_name = u'\N{Euro Sign}link'
242
os.symlink(target, 'tree1/' + link_name)
243
tree.add([link_name],['link-id'])
245
revision1 = tree.commit('added a link to a Unicode target')
246
revision2 = tree.commit('this revision will be discarded')
247
tree.set_parent_ids([revision1])
249
self.addCleanup(tree.unlock)
250
# Check that the symlink target is safely round-tripped in the trees.
251
self.assertEqual(target, tree.get_symlink_target('link-id'))
252
basis = tree.basis_tree()
253
self.assertEqual(target, basis.get_symlink_target('link-id'))
256
class TestAddParent(TestParents):
258
def test_add_first_parent_id(self):
259
"""Test adding the first parent id"""
260
tree = self.make_branch_and_tree('.')
261
first_revision = tree.commit('first post')
262
uncommit(tree.branch, tree=tree)
263
tree.add_parent_tree_id(first_revision)
264
self.assertConsistentParents([first_revision], tree)
266
def test_add_first_parent_id_ghost_rejects(self):
267
"""Test adding the first parent id - as a ghost"""
268
tree = self.make_branch_and_tree('.')
269
self.assertRaises(errors.GhostRevisionUnusableHere,
270
tree.add_parent_tree_id, 'first-revision')
272
def test_add_first_parent_id_ghost_force(self):
273
"""Test adding the first parent id - as a ghost"""
274
tree = self.make_branch_and_tree('.')
275
tree.add_parent_tree_id('first-revision', allow_leftmost_as_ghost=True)
276
self.assertConsistentParents(['first-revision'], tree)
278
def test_add_second_parent_id_with_ghost_first(self):
279
"""Test adding the second parent when the first is a ghost."""
280
tree = self.make_branch_and_tree('.')
281
tree.add_parent_tree_id('first-revision', allow_leftmost_as_ghost=True)
282
tree.add_parent_tree_id('second')
283
self.assertConsistentParents(['first-revision', 'second'], tree)
285
def test_add_second_parent_id(self):
286
"""Test adding the second parent id"""
287
tree = self.make_branch_and_tree('.')
288
first_revision = tree.commit('first post')
289
uncommit(tree.branch, tree=tree)
290
second_revision = tree.commit('second post')
291
tree.add_parent_tree_id(first_revision)
292
self.assertConsistentParents([second_revision, first_revision], tree)
294
def test_add_second_parent_id_ghost(self):
295
"""Test adding the second parent id - as a ghost"""
296
tree = self.make_branch_and_tree('.')
297
first_revision = tree.commit('first post')
298
tree.add_parent_tree_id('second')
299
self.assertConsistentParents([first_revision, 'second'], tree)
301
def test_add_first_parent_tree(self):
302
"""Test adding the first parent id"""
303
tree = self.make_branch_and_tree('.')
304
first_revision = tree.commit('first post')
305
uncommit(tree.branch, tree=tree)
306
tree.add_parent_tree((first_revision,
307
tree.branch.repository.revision_tree(first_revision)))
308
self.assertConsistentParents([first_revision], tree)
310
def test_add_first_parent_tree_ghost_rejects(self):
311
"""Test adding the first parent id - as a ghost"""
312
tree = self.make_branch_and_tree('.')
313
self.assertRaises(errors.GhostRevisionUnusableHere,
314
tree.add_parent_tree, ('first-revision', None))
316
def test_add_first_parent_tree_ghost_force(self):
317
"""Test adding the first parent id - as a ghost"""
318
tree = self.make_branch_and_tree('.')
319
tree.add_parent_tree(('first-revision', None),
320
allow_leftmost_as_ghost=True)
321
self.assertConsistentParents(['first-revision'], tree)
323
def test_add_second_parent_tree(self):
324
"""Test adding the second parent id"""
325
tree = self.make_branch_and_tree('.')
326
first_revision = tree.commit('first post')
327
uncommit(tree.branch, tree=tree)
328
second_revision = tree.commit('second post')
329
tree.add_parent_tree((first_revision,
330
tree.branch.repository.revision_tree(first_revision)))
331
self.assertConsistentParents([second_revision, first_revision], tree)
333
def test_add_second_parent_tree_ghost(self):
334
"""Test adding the second parent id - as a ghost"""
335
tree = self.make_branch_and_tree('.')
336
first_revision = tree.commit('first post')
337
tree.add_parent_tree(('second', None))
338
self.assertConsistentParents([first_revision, 'second'], tree)
341
class UpdateToOneParentViaDeltaTests(TestCaseWithWorkingTree):
342
"""Tests for the update_basis_by_delta call.
344
This is intuitively defined as 'apply an inventory delta to the basis and
345
discard other parents', but for trees that have an inventory that is not
346
managed as a tree-by-id, the implementation requires roughly duplicated
347
tests with those for apply_inventory_delta on the main tree.
350
def assertDeltaApplicationResultsInExpectedBasis(self, tree, revid, delta,
354
tree.update_basis_by_delta(revid, delta)
357
# check the last revision was adjusted to rev_id
358
self.assertEqual(revid, tree.last_revision())
359
# check the parents are what we expect
360
self.assertEqual([revid], tree.get_parent_ids())
361
# check that the basis tree has the inventory we expect from applying
363
result_basis = tree.basis_tree()
364
result_basis.lock_read()
366
self.assertEqual(expected_inventory, result_basis.inventory)
368
result_basis.unlock()
370
def make_inv_delta(self, old, new):
371
"""Make an inventory delta from two inventories."""
372
old_ids = set(old._byid.iterkeys())
373
new_ids = set(new._byid.iterkeys())
374
adds = new_ids - old_ids
375
deletes = old_ids - new_ids
376
common = old_ids.intersection(new_ids)
378
for file_id in deletes:
379
delta.append((old.id2path(file_id), None, file_id, None))
381
delta.append((None, new.id2path(file_id), file_id, new[file_id]))
382
for file_id in common:
383
if old[file_id] != new[file_id]:
384
delta.append((old.id2path(file_id), new.id2path(file_id),
385
file_id, new[file_id]))
388
def fake_up_revision(self, tree, revid, shape):
391
tree.branch.repository.start_write_group()
393
if shape.root.revision is None:
394
shape.root.revision = revid
395
# Create the text records for this inventory.
396
for path, ie in shape.iter_entries():
398
lines = ['a' * ie.text_size]
401
tree.branch.repository.texts.add_lines(
402
(ie.file_id, ie.revision), [], lines)
403
sha1 = tree.branch.repository.add_inventory(revid, shape, [])
404
rev = Revision(timestamp=0,
406
committer="Foo Bar <foo@example.com>",
410
tree.branch.repository.add_revision(revid, rev)
411
tree.branch.repository.commit_write_group()
413
tree.branch.repository.abort_write_group()
418
def add_entry(self, inv, rev_id, entry):
419
entry.revision = rev_id
422
def add_dir(self, inv, rev_id, file_id, parent_id, name):
423
new_dir = InventoryDirectory(file_id, name, parent_id)
424
self.add_entry(inv, rev_id, new_dir)
426
def add_file(self, inv, rev_id, file_id, parent_id, name, sha, size):
427
new_file = InventoryFile(file_id, name, parent_id)
428
new_file.text_sha1 = sha
429
new_file.text_size = size
430
self.add_entry(inv, rev_id, new_file)
432
def add_link(self, inv, rev_id, file_id, parent_id, name, target):
433
new_link = InventoryLink(file_id, name, parent_id)
434
new_link.symlink_target = target
435
self.add_entry(inv, rev_id, new_link)
437
def add_new_root(self, new_shape, old_revid, new_revid):
438
if self.bzrdir_format.repository_format.rich_root_data:
439
self.add_dir(new_shape, old_revid, 'root-id', None, '')
441
self.add_dir(new_shape, new_revid, 'root-id', None, '')
443
def assertTransitionFromBasisToShape(self, basis_shape, basis_revid,
444
new_shape, new_revid, extra_parent=None):
445
# set the inventory revision ids.
446
basis_shape.revision_id = basis_revid
447
new_shape.revision_id = new_revid
448
delta = self.make_inv_delta(basis_shape, new_shape)
449
tree = self.make_branch_and_tree('tree')
450
# the shapes need to be in the tree's repository to be able to set them
451
# as a parent, but the file content is not needed.
452
if basis_revid is not None:
453
self.fake_up_revision(tree, basis_revid, basis_shape)
454
parents = [basis_revid]
455
if extra_parent is not None:
456
parents.append(extra_parent)
457
tree.set_parent_ids(parents)
458
self.fake_up_revision(tree, new_revid, new_shape)
459
# give tree an inventory of new_shape
460
tree._write_inventory(new_shape)
461
self.assertDeltaApplicationResultsInExpectedBasis(tree, new_revid,
463
# The tree should be internally consistent; while this is a moderately
464
# large hammer, this is a particularly sensitive area of code, so the
465
# extra assurance is well worth it.
467
osutils.rmtree('tree')
469
def test_no_parents_just_root(self):
470
"""Test doing an empty commit - no parent, set a root only."""
471
basis_shape = Inventory(root_id=None) # empty tree
472
new_shape = Inventory() # tree with a root
473
self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
476
def test_no_parents_full_tree(self):
477
"""Test doing a regular initial commit with files and dirs."""
478
basis_shape = Inventory(root_id=None) # empty tree
480
new_shape = Inventory(root_id=None)
481
self.add_dir(new_shape, revid, 'root-id', None, '')
482
self.add_link(new_shape, revid, 'link-id', 'root-id', 'link', 'target')
483
self.add_file(new_shape, revid, 'file-id', 'root-id', 'file', '1' * 32,
485
self.add_dir(new_shape, revid, 'dir-id', 'root-id', 'dir')
486
self.add_file(new_shape, revid, 'subfile-id', 'dir-id', 'subfile',
488
self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
491
def test_file_content_change(self):
492
old_revid = 'old-parent'
493
basis_shape = Inventory(root_id=None)
494
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
495
self.add_file(basis_shape, old_revid, 'file-id', 'root-id', 'file',
497
new_revid = 'new-parent'
498
new_shape = Inventory(root_id=None)
499
self.add_new_root(new_shape, old_revid, new_revid)
500
self.add_file(new_shape, new_revid, 'file-id', 'root-id', 'file',
502
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
503
new_shape, new_revid)
505
def test_link_content_change(self):
506
old_revid = 'old-parent'
507
basis_shape = Inventory(root_id=None)
508
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
509
self.add_link(basis_shape, old_revid, 'link-id', 'root-id', 'link',
511
new_revid = 'new-parent'
512
new_shape = Inventory(root_id=None)
513
self.add_new_root(new_shape, old_revid, new_revid)
514
self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
516
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
517
new_shape, new_revid)
519
def test_kind_changes(self):
520
def do_file(inv, revid):
521
self.add_file(inv, revid, 'path-id', 'root-id', 'path', '1' * 32,
523
def do_link(inv, revid):
524
self.add_link(inv, revid, 'path-id', 'root-id', 'path', 'target')
525
def do_dir(inv, revid):
526
self.add_dir(inv, revid, 'path-id', 'root-id', 'path')
527
for old_factory in (do_file, do_link, do_dir):
528
for new_factory in (do_file, do_link, do_dir):
529
if old_factory == new_factory:
531
old_revid = 'old-parent'
532
basis_shape = Inventory(root_id=None)
533
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
534
old_factory(basis_shape, old_revid)
535
new_revid = 'new-parent'
536
new_shape = Inventory(root_id=None)
537
self.add_new_root(new_shape, old_revid, new_revid)
538
new_factory(new_shape, new_revid)
539
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
540
new_shape, new_revid)
542
def test_content_from_second_parent_is_dropped(self):
543
left_revid = 'left-parent'
544
basis_shape = Inventory(root_id=None)
545
self.add_dir(basis_shape, left_revid, 'root-id', None, '')
546
self.add_link(basis_shape, left_revid, 'link-id', 'root-id', 'link',
548
# the right shape has content - file, link, subdir with a child,
549
# that should all be discarded by the call.
550
right_revid = 'right-parent'
551
right_shape = Inventory(root_id=None)
552
self.add_dir(right_shape, left_revid, 'root-id', None, '')
553
self.add_link(right_shape, right_revid, 'link-id', 'root-id', 'link',
555
self.add_dir(right_shape, right_revid, 'subdir-id', 'root-id', 'dir')
556
self.add_file(right_shape, right_revid, 'file-id', 'subdir-id', 'file',
558
new_revid = 'new-parent'
559
new_shape = Inventory(root_id=None)
560
self.add_new_root(new_shape, left_revid, new_revid)
561
self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
563
self.assertTransitionFromBasisToShape(basis_shape, left_revid,
564
new_shape, new_revid, right_revid)
566
def test_parent_id_changed(self):
567
# test that when the only change to an entry is its parent id changing
568
# that it is handled correctly (that is it keeps the same path)
569
old_revid = 'old-parent'
570
basis_shape = Inventory(root_id=None)
571
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
572
self.add_dir(basis_shape, old_revid, 'orig-parent-id', 'root-id', 'dir')
573
self.add_dir(basis_shape, old_revid, 'dir-id', 'orig-parent-id', 'dir')
574
new_revid = 'new-parent'
575
new_shape = Inventory(root_id=None)
576
self.add_new_root(new_shape, old_revid, new_revid)
577
self.add_dir(new_shape, new_revid, 'new-parent-id', 'root-id', 'dir')
578
self.add_dir(new_shape, new_revid, 'dir-id', 'new-parent-id', 'dir')
579
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
580
new_shape, new_revid)
582
def test_name_changed(self):
583
# test that when the only change to an entry is its name changing that
584
# it is handled correctly (that is it keeps the same parent id)
585
old_revid = 'old-parent'
586
basis_shape = Inventory(root_id=None)
587
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
588
self.add_dir(basis_shape, old_revid, 'parent-id', 'root-id', 'origdir')
589
self.add_dir(basis_shape, old_revid, 'dir-id', 'parent-id', 'olddir')
590
new_revid = 'new-parent'
591
new_shape = Inventory(root_id=None)
592
self.add_new_root(new_shape, old_revid, new_revid)
593
self.add_dir(new_shape, new_revid, 'parent-id', 'root-id', 'newdir')
594
self.add_dir(new_shape, new_revid, 'dir-id', 'parent-id', 'newdir')
595
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
596
new_shape, new_revid)
598
def test_parent_child_swap(self):
599
# test a A->A/B and A/B->A path swap.
600
old_revid = 'old-parent'
601
basis_shape = Inventory(root_id=None)
602
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
603
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
604
self.add_dir(basis_shape, old_revid, 'dir-id-B', 'dir-id-A', 'B')
605
self.add_link(basis_shape, old_revid, 'link-id-C', 'dir-id-B', 'C', 'C')
606
new_revid = 'new-parent'
607
new_shape = Inventory(root_id=None)
608
self.add_new_root(new_shape, old_revid, new_revid)
609
self.add_dir(new_shape, new_revid, 'dir-id-B', 'root-id', 'A')
610
self.add_dir(new_shape, new_revid, 'dir-id-A', 'dir-id-B', 'B')
611
self.add_link(new_shape, new_revid, 'link-id-C', 'dir-id-A', 'C', 'C')
612
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
613
new_shape, new_revid)
615
def test_parent_deleted_child_renamed(self):
616
# test a A->None and A/B->A.
617
old_revid = 'old-parent'
618
basis_shape = Inventory(root_id=None)
619
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
620
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
621
self.add_dir(basis_shape, old_revid, 'dir-id-B', 'dir-id-A', 'B')
622
self.add_link(basis_shape, old_revid, 'link-id-C', 'dir-id-B', 'C', 'C')
623
new_revid = 'new-parent'
624
new_shape = Inventory(root_id=None)
625
self.add_new_root(new_shape, old_revid, new_revid)
626
self.add_dir(new_shape, new_revid, 'dir-id-B', 'root-id', 'A')
627
self.add_link(new_shape, old_revid, 'link-id-C', 'dir-id-B', 'C', 'C')
628
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
629
new_shape, new_revid)
631
def test_dir_to_root(self):
633
old_revid = 'old-parent'
634
basis_shape = Inventory(root_id=None)
635
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
636
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
637
self.add_link(basis_shape, old_revid, 'link-id-B', 'dir-id-A', 'B', 'B')
638
new_revid = 'new-parent'
639
new_shape = Inventory(root_id=None)
640
self.add_dir(new_shape, new_revid, 'dir-id-A', None, '')
641
self.add_link(new_shape, old_revid, 'link-id-B', 'dir-id-A', 'B', 'B')
642
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
643
new_shape, new_revid)
645
def test_path_swap(self):
646
# test a A->B and B->A path swap.
647
old_revid = 'old-parent'
648
basis_shape = Inventory(root_id=None)
649
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
650
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
651
self.add_dir(basis_shape, old_revid, 'dir-id-B', 'root-id', 'B')
652
self.add_link(basis_shape, old_revid, 'link-id-C', 'root-id', 'C', 'C')
653
self.add_link(basis_shape, old_revid, 'link-id-D', 'root-id', 'D', 'D')
654
self.add_file(basis_shape, old_revid, 'file-id-E', 'root-id', 'E',
656
self.add_file(basis_shape, old_revid, 'file-id-F', 'root-id', 'F',
658
new_revid = 'new-parent'
659
new_shape = Inventory(root_id=None)
660
self.add_new_root(new_shape, old_revid, new_revid)
661
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'B')
662
self.add_dir(new_shape, new_revid, 'dir-id-B', 'root-id', 'A')
663
self.add_link(new_shape, new_revid, 'link-id-C', 'root-id', 'D', 'C')
664
self.add_link(new_shape, new_revid, 'link-id-D', 'root-id', 'C', 'D')
665
self.add_file(new_shape, new_revid, 'file-id-E', 'root-id', 'F',
667
self.add_file(new_shape, new_revid, 'file-id-F', 'root-id', 'E',
669
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
670
new_shape, new_revid)
673
# test adding paths and dirs, including adding to a newly added dir.
674
old_revid = 'old-parent'
675
basis_shape = Inventory(root_id=None)
676
# with a root, so its a commit after the first.
677
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
678
new_revid = 'new-parent'
679
new_shape = Inventory(root_id=None)
680
self.add_new_root(new_shape, old_revid, new_revid)
681
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
682
self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
683
self.add_file(new_shape, new_revid, 'file-id-C', 'root-id', 'C',
685
self.add_file(new_shape, new_revid, 'file-id-D', 'dir-id-A', 'D',
687
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
688
new_shape, new_revid)
690
def test_removes(self):
691
# test removing paths, including paths that are within other also
693
old_revid = 'old-parent'
694
basis_shape = Inventory(root_id=None)
695
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
696
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
697
self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
698
self.add_file(basis_shape, old_revid, 'file-id-C', 'root-id', 'C',
700
self.add_file(basis_shape, old_revid, 'file-id-D', 'dir-id-A', 'D',
702
new_revid = 'new-parent'
703
new_shape = Inventory(root_id=None)
704
self.add_new_root(new_shape, old_revid, new_revid)
705
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
706
new_shape, new_revid)
708
def test_move_to_added_dir(self):
709
old_revid = 'old-parent'
710
basis_shape = Inventory(root_id=None)
711
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
712
self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
713
new_revid = 'new-parent'
714
new_shape = Inventory(root_id=None)
715
self.add_new_root(new_shape, old_revid, new_revid)
716
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
717
self.add_link(new_shape, new_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
718
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
719
new_shape, new_revid)
721
def test_move_from_removed_dir(self):
722
old_revid = 'old-parent'
723
basis_shape = Inventory(root_id=None)
724
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
725
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
726
self.add_link(basis_shape, old_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
727
new_revid = 'new-parent'
728
new_shape = Inventory(root_id=None)
729
self.add_new_root(new_shape, old_revid, new_revid)
730
self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
731
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
732
new_shape, new_revid)
734
def test_move_moves_children_recursively(self):
735
old_revid = 'old-parent'
736
basis_shape = Inventory(root_id=None)
737
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
738
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
739
self.add_dir(basis_shape, old_revid, 'dir-id-B', 'dir-id-A', 'B')
740
self.add_link(basis_shape, old_revid, 'link-id-C', 'dir-id-B', 'C', 'D')
741
new_revid = 'new-parent'
742
new_shape = Inventory(root_id=None)
743
self.add_new_root(new_shape, old_revid, new_revid)
745
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'B')
747
self.add_dir(new_shape, old_revid, 'dir-id-B', 'dir-id-A', 'B')
748
self.add_link(new_shape, old_revid, 'link-id-C', 'dir-id-B', 'C', 'D')
749
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
750
new_shape, new_revid)