187
169
self.run_script(self.preamble)
190
class TestResolveTextConflicts(TestResolveConflicts):
195
class TestResolveContentConflicts(TestResolveConflicts):
197
# FIXME: We need to add the reverse case (delete in trunk, modify in
198
# branch) but that could wait until the resolution mechanism is implemented.
203
$ echo 'trunk content' >file
205
$ bzr commit -m 'Create trunk'
207
$ bzr branch . ../branch
210
$ bzr commit -m 'Delete file'
213
$ echo 'more content' >>file
214
$ bzr commit -m 'Modify file'
219
2>Contents conflict in file
220
2>1 conflicts encountered.
223
def test_take_this(self):
225
$ bzr rm file.OTHER --force # a simple rm file.OTHER is valid too
227
$ bzr commit --strict -m 'No more conflicts nor unknown files'
230
def test_take_other(self):
232
$ bzr mv file.OTHER file
234
$ bzr commit --strict -m 'No more conflicts nor unknown files'
237
def test_resolve_taking_this(self):
239
$ bzr resolve --take-this file
240
$ bzr commit --strict -m 'No more conflicts nor unknown files'
243
def test_resolve_taking_other(self):
245
$ bzr resolve --take-other file
246
$ bzr commit --strict -m 'No more conflicts nor unknown files'
250
class TestResolveDuplicateEntry(TestResolveConflicts):
255
$ echo 'trunk content' >file
257
$ bzr commit -m 'Create trunk'
258
$ echo 'trunk content too' >file2
260
$ bzr commit -m 'Add file2 in trunk'
262
$ bzr branch . -r 1 ../branch
264
$ echo 'branch content' >file2
266
$ bzr commit -m 'Add file2 in branch'
270
2>R file2 => file2.moved
271
2>Conflict adding file file2. Moved existing file to file2.moved.
272
2>1 conflicts encountered.
275
def test_keep_this(self):
277
$ bzr rm file2 --force
278
$ bzr mv file2.moved file2
280
$ bzr commit --strict -m 'No more conflicts nor unknown files'
283
def test_keep_other(self):
284
self.failIfExists('branch/file2.moved')
286
$ bzr rm file2.moved --force
288
$ bzr commit --strict -m 'No more conflicts nor unknown files'
290
self.failIfExists('branch/file2.moved')
292
def test_resolve_taking_this(self):
294
$ bzr resolve --take-this file2
295
$ bzr commit --strict -m 'No more conflicts nor unknown files'
298
def test_resolve_taking_other(self):
300
$ bzr resolve --take-other file2
301
$ bzr commit --strict -m 'No more conflicts nor unknown files'
172
def mirror_scenarios(base_scenarios):
173
"""Return a list of mirrored scenarios.
175
Each scenario in base_scenarios is duplicated switching the roles of 'this'
179
for common, (lname, ldict), (rname, rdict) in base_scenarios:
180
a = tests.multiply_scenarios([(lname, dict(_this=ldict))],
181
[(rname, dict(_other=rdict))])
182
b = tests.multiply_scenarios([(rname, dict(_this=rdict))],
183
[(lname, dict(_other=ldict))])
184
# Inject the common parameters in all scenarios
185
for name, d in a + b:
187
scenarios.extend(a + b)
191
# FIXME: Get rid of parametrized (in the class name) once we delete
192
# TestResolveConflicts -- vila 20100308
193
class TestParametrizedResolveConflicts(tests.TestCaseWithTransport):
194
"""This class provides a base to test single conflict resolution.
196
Since all conflict objects are created with specific semantics for their
197
attributes, each class should implement the necessary functions and
198
attributes described below.
200
Each class should define the scenarios that create the expected (single)
203
Each scenario describes:
204
* how to create 'base' tree (and revision)
205
* how to create 'left' tree (and revision, parent rev 'base')
206
* how to create 'right' tree (and revision, parent rev 'base')
207
* how to check that changes in 'base'->'left' have been taken
208
* how to check that changes in 'base'->'right' have been taken
210
From each base scenario, we generate two concrete scenarios where:
211
* this=left, other=right
212
* this=right, other=left
214
Then the test case verifies each concrete scenario by:
215
* creating a branch containing the 'base', 'this' and 'other' revisions
216
* creating a working tree for the 'this' revision
217
* performing the merge of 'other' into 'this'
218
* verifying the expected conflict was generated
219
* resolving with --take-this or --take-other, and running the corresponding
220
checks (for either 'base'->'this', or 'base'->'other')
222
:cvar _conflict_type: The expected class of the generated conflict.
224
:cvar _assert_conflict: A method receiving the working tree and the
225
conflict object and checking its attributes.
227
:cvar _base_actions: The branchbuilder actions to create the 'base'
230
:cvar _this: The dict related to 'base' -> 'this'. It contains at least:
231
* 'actions': The branchbuilder actions to create the 'this'
233
* 'check': how to check the changes after resolution with --take-this.
235
:cvar _other: The dict related to 'base' -> 'other'. It contains at least:
236
* 'actions': The branchbuilder actions to create the 'other'
238
* 'check': how to check the changes after resolution with --take-other.
241
# Set by daughter classes
242
_conflict_type = None
243
_assert_conflict = None
251
"""The scenario list for the conflict type defined by the class.
253
Each scenario is of the form:
254
(common, (left_name, left_dict), (right_name, right_dict))
258
* left_name and right_name are the scenario names that will be combined
260
* left_dict and right_dict are the attributes specific to each half of
261
the scenario. They should include at least 'actions' and 'check' and
262
will be available as '_this' and '_other' test instance attributes.
264
Daughters classes are free to add their specific attributes as they see
265
fit in any of the three dicts.
267
This is a class method so that load_tests can find it.
269
'_base_actions' in the common dict, 'actions' and 'check' in the left
270
and right dicts use names that map to methods in the test classes. Some
271
prefixes are added to these names to get the correspong methods (see
272
_get_actions() and _get_check()). The motivation here is to avoid
273
collisions in the class namespace.
277
super(TestParametrizedResolveConflicts, self).setUp()
278
builder = self.make_branch_builder('trunk')
279
builder.start_series()
281
# Create an empty trunk
282
builder.build_snapshot('start', None, [
283
('add', ('', 'root-id', 'directory', ''))])
284
# Add a minimal base content
285
base_actions = self._get_actions(self._base_actions)()
286
builder.build_snapshot('base', ['start'], base_actions)
287
# Modify the base content in branch
288
actions_other = self._get_actions(self._other['actions'])()
289
builder.build_snapshot('other', ['base'], actions_other)
290
# Modify the base content in trunk
291
actions_this = self._get_actions(self._this['actions'])()
292
builder.build_snapshot('this', ['base'], actions_this)
293
# builder.get_branch() tip is now 'this'
295
builder.finish_series()
296
self.builder = builder
298
def _get_actions(self, name):
299
return getattr(self, 'do_%s' % name)
301
def _get_check(self, name):
302
return getattr(self, 'check_%s' % name)
304
def _merge_other_into_this(self):
305
b = self.builder.get_branch()
306
wt = b.bzrdir.sprout('branch').open_workingtree()
307
wt.merge_from_branch(b, 'other')
310
def assertConflict(self, wt):
311
confs = wt.conflicts()
312
self.assertLength(1, confs)
314
self.assertIsInstance(c, self._conflict_type)
315
self._assert_conflict(wt, c)
317
def _get_resolve_path_arg(self, wt, action):
318
raise NotImplementedError(self._get_resolve_path_arg)
320
def check_resolved(self, wt, action):
321
path = self._get_resolve_path_arg(wt, action)
322
conflicts.resolve(wt, [path], action=action)
323
# Check that we don't have any conflicts nor unknown left
324
self.assertLength(0, wt.conflicts())
325
self.assertLength(0, list(wt.unknowns()))
327
def test_resolve_taking_this(self):
328
wt = self._merge_other_into_this()
329
self.assertConflict(wt)
330
self.check_resolved(wt, 'take_this')
331
check_this = self._get_check(self._this['check'])
334
def test_resolve_taking_other(self):
335
wt = self._merge_other_into_this()
336
self.assertConflict(wt)
337
self.check_resolved(wt, 'take_other')
338
check_other = self._get_check(self._other['check'])
342
class TestResolveTextConflicts(TestParametrizedResolveConflicts):
344
_conflict_type = conflicts.TextConflict
346
# Set by the scenarios
347
# path and file-id for the file involved in the conflict
351
scenarios = mirror_scenarios(
353
# File modified on both sides
354
(dict(_base_actions='create_file',
355
_path='file', _file_id='file-id'),
357
dict(actions='modify_file_A', check='file_has_content_A')),
359
dict(actions='modify_file_B', check='file_has_content_B')),),
360
# File modified on both sides in dir
361
(dict(_base_actions='create_file_in_dir',
362
_path='dir/file', _file_id='file-id'),
363
('filed_modified_A_in_dir',
364
dict(actions='modify_file_A',
365
check='file_in_dir_has_content_A')),
367
dict(actions='modify_file_B',
368
check='file_in_dir_has_content_B')),),
371
def do_create_file(self, path='file'):
372
return [('add', (path, 'file-id', 'file', 'trunk content\n'))]
374
def do_modify_file_A(self):
375
return [('modify', ('file-id', 'trunk content\nfeature A\n'))]
377
def do_modify_file_B(self):
378
return [('modify', ('file-id', 'trunk content\nfeature B\n'))]
380
def check_file_has_content_A(self, path='file'):
381
self.assertFileEqual('trunk content\nfeature A\n',
382
osutils.pathjoin('branch', path))
384
def check_file_has_content_B(self, path='file'):
385
self.assertFileEqual('trunk content\nfeature B\n',
386
osutils.pathjoin('branch', path))
388
def do_create_file_in_dir(self):
389
return [('add', ('dir', 'dir-id', 'directory', '')),
390
] + self.do_create_file('dir/file')
392
def check_file_in_dir_has_content_A(self):
393
self.check_file_has_content_A('dir/file')
395
def check_file_in_dir_has_content_B(self):
396
self.check_file_has_content_B('dir/file')
398
def _get_resolve_path_arg(self, wt, action):
401
def assertTextConflict(self, wt, c):
402
self.assertEqual(self._file_id, c.file_id)
403
self.assertEqual(self._path, c.path)
404
_assert_conflict = assertTextConflict
407
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
409
_conflict_type = conflicts.ContentsConflict
411
# Set by the scenarios
412
# path and file-id for the file involved in the conflict
416
scenarios = mirror_scenarios(
418
# File modified/deleted
419
(dict(_base_actions='create_file',
420
_path='file', _file_id='file-id'),
422
dict(actions='modify_file', check='file_has_more_content')),
424
dict(actions='delete_file', check='file_doesnt_exist')),),
425
# File modified/deleted in dir
426
(dict(_base_actions='create_file_in_dir',
427
_path='dir/file', _file_id='file-id'),
428
('file_modified_in_dir',
429
dict(actions='modify_file_in_dir',
430
check='file_in_dir_has_more_content')),
431
('file_deleted_in_dir',
432
dict(actions='delete_file',
433
check='file_in_dir_doesnt_exist')),),
436
def do_create_file(self):
437
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
439
def do_modify_file(self):
440
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
442
def check_file_has_more_content(self):
443
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
445
def do_delete_file(self):
446
return [('unversion', 'file-id')]
448
def check_file_doesnt_exist(self):
449
self.assertPathDoesNotExist('branch/file')
451
def do_create_file_in_dir(self):
452
return [('add', ('dir', 'dir-id', 'directory', '')),
453
('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
455
def do_modify_file_in_dir(self):
456
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
458
def check_file_in_dir_has_more_content(self):
459
self.assertFileEqual('trunk content\nmore content\n', 'branch/dir/file')
461
def check_file_in_dir_doesnt_exist(self):
462
self.assertPathDoesNotExist('branch/dir/file')
464
def _get_resolve_path_arg(self, wt, action):
467
def assertContentsConflict(self, wt, c):
468
self.assertEqual(self._file_id, c.file_id)
469
self.assertEqual(self._path, c.path)
470
_assert_conflict = assertContentsConflict
473
class TestResolvePathConflict(TestParametrizedResolveConflicts):
475
_conflict_type = conflicts.PathConflict
477
def do_nothing(self):
480
# Each side dict additionally defines:
481
# - path path involved (can be '<deleted>')
483
scenarios = mirror_scenarios(
485
# File renamed/deleted
486
(dict(_base_actions='create_file'),
488
dict(actions='rename_file', check='file_renamed',
489
path='new-file', file_id='file-id')),
491
dict(actions='delete_file', check='file_doesnt_exist',
492
# PathConflicts deletion handling requires a special
494
path='<deleted>', file_id='file-id')),),
495
# File renamed/deleted in dir
496
(dict(_base_actions='create_file_in_dir'),
497
('file_renamed_in_dir',
498
dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
499
path='dir/new-file', file_id='file-id')),
501
dict(actions='delete_file', check='file_in_dir_doesnt_exist',
502
# PathConflicts deletion handling requires a special
504
path='<deleted>', file_id='file-id')),),
505
# File renamed/renamed differently
506
(dict(_base_actions='create_file'),
508
dict(actions='rename_file', check='file_renamed',
509
path='new-file', file_id='file-id')),
511
dict(actions='rename_file2', check='file_renamed2',
512
path='new-file2', file_id='file-id')),),
513
# Dir renamed/deleted
514
(dict(_base_actions='create_dir'),
516
dict(actions='rename_dir', check='dir_renamed',
517
path='new-dir', file_id='dir-id')),
519
dict(actions='delete_dir', check='dir_doesnt_exist',
520
# PathConflicts deletion handling requires a special
522
path='<deleted>', file_id='dir-id')),),
523
# Dir renamed/renamed differently
524
(dict(_base_actions='create_dir'),
526
dict(actions='rename_dir', check='dir_renamed',
527
path='new-dir', file_id='dir-id')),
529
dict(actions='rename_dir2', check='dir_renamed2',
530
path='new-dir2', file_id='dir-id')),),
533
def do_create_file(self):
534
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
536
def do_create_dir(self):
537
return [('add', ('dir', 'dir-id', 'directory', ''))]
539
def do_rename_file(self):
540
return [('rename', ('file', 'new-file'))]
542
def check_file_renamed(self):
543
self.assertPathDoesNotExist('branch/file')
544
self.assertPathExists('branch/new-file')
546
def do_rename_file2(self):
547
return [('rename', ('file', 'new-file2'))]
549
def check_file_renamed2(self):
550
self.assertPathDoesNotExist('branch/file')
551
self.assertPathExists('branch/new-file2')
553
def do_rename_dir(self):
554
return [('rename', ('dir', 'new-dir'))]
556
def check_dir_renamed(self):
557
self.assertPathDoesNotExist('branch/dir')
558
self.assertPathExists('branch/new-dir')
560
def do_rename_dir2(self):
561
return [('rename', ('dir', 'new-dir2'))]
563
def check_dir_renamed2(self):
564
self.assertPathDoesNotExist('branch/dir')
565
self.assertPathExists('branch/new-dir2')
567
def do_delete_file(self):
568
return [('unversion', 'file-id')]
570
def check_file_doesnt_exist(self):
571
self.assertPathDoesNotExist('branch/file')
573
def do_delete_dir(self):
574
return [('unversion', 'dir-id')]
576
def check_dir_doesnt_exist(self):
577
self.assertPathDoesNotExist('branch/dir')
579
def do_create_file_in_dir(self):
580
return [('add', ('dir', 'dir-id', 'directory', '')),
581
('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
583
def do_rename_file_in_dir(self):
584
return [('rename', ('dir/file', 'dir/new-file'))]
586
def check_file_in_dir_renamed(self):
587
self.assertPathDoesNotExist('branch/dir/file')
588
self.assertPathExists('branch/dir/new-file')
590
def check_file_in_dir_doesnt_exist(self):
591
self.assertPathDoesNotExist('branch/dir/file')
593
def _get_resolve_path_arg(self, wt, action):
594
tpath = self._this['path']
595
opath = self._other['path']
596
if tpath == '<deleted>':
602
def assertPathConflict(self, wt, c):
603
tpath = self._this['path']
604
tfile_id = self._this['file_id']
605
opath = self._other['path']
606
ofile_id = self._other['file_id']
607
self.assertEqual(tfile_id, ofile_id) # Sanity check
608
self.assertEqual(tfile_id, c.file_id)
609
self.assertEqual(tpath, c.path)
610
self.assertEqual(opath, c.conflict_path)
611
_assert_conflict = assertPathConflict
614
class TestResolvePathConflictBefore531967(TestResolvePathConflict):
615
"""Same as TestResolvePathConflict but a specific conflict object.
618
def assertPathConflict(self, c):
619
# We create a conflict object as it was created before the fix and
620
# inject it into the working tree, the test will exercise the
621
# compatibility code.
622
old_c = conflicts.PathConflict('<deleted>', self._item_path,
624
wt.set_conflicts(conflicts.ConflictList([old_c]))
627
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
629
_conflict_type = conflicts.DuplicateEntry
631
scenarios = mirror_scenarios(
633
# File created with different file-ids
634
(dict(_base_actions='nothing'),
636
dict(actions='create_file_a', check='file_content_a',
637
path='file', file_id='file-a-id')),
639
dict(actions='create_file_b', check='file_content_b',
640
path='file', file_id='file-b-id')),),
643
def do_nothing(self):
646
def do_create_file_a(self):
647
return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
649
def check_file_content_a(self):
650
self.assertFileEqual('file a content\n', 'branch/file')
652
def do_create_file_b(self):
653
return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
655
def check_file_content_b(self):
656
self.assertFileEqual('file b content\n', 'branch/file')
658
def _get_resolve_path_arg(self, wt, action):
659
return self._this['path']
661
def assertDuplicateEntry(self, wt, c):
662
tpath = self._this['path']
663
tfile_id = self._this['file_id']
664
opath = self._other['path']
665
ofile_id = self._other['file_id']
666
self.assertEqual(tpath, opath) # Sanity check
667
self.assertEqual(tfile_id, c.file_id)
668
self.assertEqual(tpath + '.moved', c.path)
669
self.assertEqual(tpath, c.conflict_path)
670
_assert_conflict = assertDuplicateEntry
305
673
class TestResolveUnversionedParent(TestResolveConflicts):
435
807
def test_keep_them_all(self):
436
808
self.run_script("""
437
809
$ bzr resolve dir
438
$ bzr commit --strict -m 'No more conflicts nor unknown files'
810
2>2 conflict(s) resolved, 0 remaining
811
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
441
814
def test_adopt_child(self):
442
815
self.run_script("""
443
$ bzr mv dir/file2 file2
816
$ bzr mv -q dir/file2 file2
817
$ bzr rm -q dir --force
445
818
$ bzr resolve dir
446
$ bzr commit --strict -m 'No more conflicts nor unknown files'
819
2>2 conflict(s) resolved, 0 remaining
820
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
449
823
def test_kill_them_all(self):
450
824
self.run_script("""
825
$ bzr rm -q dir --force
452
826
$ bzr resolve dir
453
$ bzr commit --strict -m 'No more conflicts nor unknown files'
827
2>2 conflict(s) resolved, 0 remaining
828
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
456
831
def test_resolve_taking_this(self):
457
832
self.run_script("""
458
833
$ bzr resolve --take-this dir
459
$ bzr commit --strict -m 'No more conflicts nor unknown files'
834
2>2 conflict(s) resolved, 0 remaining
835
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
462
838
def test_resolve_taking_other(self):
463
839
self.run_script("""
464
840
$ bzr resolve --take-other dir
465
$ bzr commit --strict -m 'No more conflicts nor unknown files'
469
class TestResolvePathConflict(TestResolveConflicts):
476
$ bzr commit -m 'Create trunk'
477
$ bzr mv file file-in-trunk
478
$ bzr commit -m 'Renamed to file-in-trunk'
480
$ bzr branch . -r 1 ../branch
482
$ bzr mv file file-in-branch
483
$ bzr commit -m 'Renamed to file-in-branch'
486
2>R file-in-branch => file-in-trunk
487
2>Path conflict: file-in-branch / file-in-trunk
488
2>1 conflicts encountered.
491
def test_keep_source(self):
493
$ bzr resolve file-in-trunk
494
$ bzr commit --strict -m 'No more conflicts nor unknown files'
497
def test_keep_target(self):
499
$ bzr mv file-in-trunk file-in-branch
500
$ bzr resolve file-in-branch
501
$ bzr commit --strict -m 'No more conflicts nor unknown files'
504
def test_resolve_taking_this(self):
506
$ bzr resolve --take-this file-in-branch
507
$ bzr commit --strict -m 'No more conflicts nor unknown files'
510
def test_resolve_taking_other(self):
512
$ bzr resolve --take-other file-in-branch
513
$ bzr commit --strict -m 'No more conflicts nor unknown files'
517
class TestResolveParentLoop(TestResolveConflicts):
524
$ bzr commit -m 'Create trunk'
526
$ bzr commit -m 'Moved dir2 into dir1'
528
$ bzr branch . -r 1 ../branch
531
$ bzr commit -m 'Moved dir1 into dir2'
534
2>Conflict moving dir2/dir1 into dir2. Cancelled move.
535
2>1 conflicts encountered.
538
def test_take_this(self):
541
$ bzr commit --strict -m 'No more conflicts nor unknown files'
544
def test_take_other(self):
546
$ bzr mv dir2/dir1 dir1
549
$ bzr commit --strict -m 'No more conflicts nor unknown files'
552
def test_resolve_taking_this(self):
554
$ bzr resolve --take-this dir2
555
$ bzr commit --strict -m 'No more conflicts nor unknown files'
557
self.failUnlessExists('dir2')
559
def test_resolve_taking_other(self):
561
$ bzr resolve --take-other dir2
562
$ bzr commit --strict -m 'No more conflicts nor unknown files'
564
self.failUnlessExists('dir1')
843
2>2 conflict(s) resolved, 0 remaining
844
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
848
class TestResolveParentLoop(TestParametrizedResolveConflicts):
850
_conflict_type = conflicts.ParentLoop
855
# Each side dict additionally defines:
856
# - dir_id: the directory being moved
857
# - target_id: The target directory
858
# - xfail: whether the test is expected to fail if the action is
859
# involved as 'other'
860
scenarios = mirror_scenarios(
862
# Dirs moved into each other
863
(dict(_base_actions='create_dir1_dir2'),
865
dict(actions='move_dir1_into_dir2', check='dir1_moved',
866
dir_id='dir1-id', target_id='dir2-id', xfail=False)),
868
dict(actions='move_dir2_into_dir1', check='dir2_moved',
869
dir_id='dir2-id', target_id='dir1-id', xfail=False))),
870
# Subdirs moved into each other
871
(dict(_base_actions='create_dir1_4'),
873
dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
874
dir_id='dir1-id', target_id='dir4-id', xfail=True)),
876
dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
877
dir_id='dir3-id', target_id='dir2-id', xfail=True))),
880
def do_create_dir1_dir2(self):
881
return [('add', ('dir1', 'dir1-id', 'directory', '')),
882
('add', ('dir2', 'dir2-id', 'directory', '')),]
884
def do_move_dir1_into_dir2(self):
885
return [('rename', ('dir1', 'dir2/dir1'))]
887
def check_dir1_moved(self):
888
self.assertPathDoesNotExist('branch/dir1')
889
self.assertPathExists('branch/dir2/dir1')
891
def do_move_dir2_into_dir1(self):
892
return [('rename', ('dir2', 'dir1/dir2'))]
894
def check_dir2_moved(self):
895
self.assertPathDoesNotExist('branch/dir2')
896
self.assertPathExists('branch/dir1/dir2')
898
def do_create_dir1_4(self):
899
return [('add', ('dir1', 'dir1-id', 'directory', '')),
900
('add', ('dir1/dir2', 'dir2-id', 'directory', '')),
901
('add', ('dir3', 'dir3-id', 'directory', '')),
902
('add', ('dir3/dir4', 'dir4-id', 'directory', '')),]
904
def do_move_dir1_into_dir4(self):
905
return [('rename', ('dir1', 'dir3/dir4/dir1'))]
907
def check_dir1_2_moved(self):
908
self.assertPathDoesNotExist('branch/dir1')
909
self.assertPathExists('branch/dir3/dir4/dir1')
910
self.assertPathExists('branch/dir3/dir4/dir1/dir2')
912
def do_move_dir3_into_dir2(self):
913
return [('rename', ('dir3', 'dir1/dir2/dir3'))]
915
def check_dir3_4_moved(self):
916
self.assertPathDoesNotExist('branch/dir3')
917
self.assertPathExists('branch/dir1/dir2/dir3')
918
self.assertPathExists('branch/dir1/dir2/dir3/dir4')
920
def _get_resolve_path_arg(self, wt, action):
921
# ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
922
# But since <path> doesn't exist in the working tree, we need to use
923
# <conflict_path> instead, and that, in turn, is given by dir_id. Pfew.
924
return wt.id2path(self._other['dir_id'])
926
def assertParentLoop(self, wt, c):
927
self.assertEqual(self._other['dir_id'], c.file_id)
928
self.assertEqual(self._other['target_id'], c.conflict_file_id)
929
# The conflict paths are irrelevant (they are deterministic but not
930
# worth checking since they don't provide the needed information
932
if self._other['xfail']:
933
# It's a bit hackish to raise from here relying on being called for
934
# both tests but this avoid overriding test_resolve_taking_other
935
raise tests.KnownFailure(
936
"ParentLoop doesn't carry enough info to resolve --take-other")
937
_assert_conflict = assertParentLoop
567
940
class TestResolveNonDirectoryParent(TestResolveConflicts):
573
$ bzr commit -m 'Create trunk'
948
$ bzr commit -m 'Create trunk' -q
574
949
$ echo "Boing" >foo/bar
576
$ bzr commit -m 'Add foo/bar'
578
$ bzr branch . -r 1 ../branch
951
$ bzr commit -q -m 'Add foo/bar'
952
$ bzr branch -q . -r 1 ../branch
581
955
$ echo "Boo!" >foo
582
$ bzr commit -m 'foo is now a file'
956
$ bzr commit -q -m 'foo is now a file'
584
957
$ bzr merge ../trunk
586
959
2>RK foo => foo.new/