20
20
from bzrlib import (
28
from bzrlib.tests import (
34
load_tests = scenarios.load_tests_apply_scenarios
29
from bzrlib.tests import script
32
def load_tests(standard_tests, module, loader):
33
result = loader.suiteClass()
35
sp_tests, remaining_tests = tests.split_suite_by_condition(
36
standard_tests, tests.condition_isinstance((
37
TestParametrizedResolveConflicts,
39
# Each test class defines its own scenarios. This is needed for
40
# TestResolvePathConflictBefore531967 that verifies that the same tests as
41
# TestResolvePathConflict still pass.
42
for test in tests.iter_suite_tests(sp_tests):
43
tests.apply_scenarios(test, test.scenarios(), result)
45
# No parametrization for the remaining tests
46
result.addTests(remaining_tests)
37
51
# TODO: Test commit with some added, and added-but-missing files
65
79
class TestConflicts(tests.TestCaseWithTransport):
81
def test_conflicts(self):
82
"""Conflicts are detected properly"""
83
# Use BzrDirFormat6 so we can fake conflicts
84
tree = self.make_branch_and_tree('.', format=bzrdir.BzrDirFormat6())
85
self.build_tree_contents([('hello', 'hello world4'),
86
('hello.THIS', 'hello world2'),
87
('hello.BASE', 'hello world1'),
88
('hello.OTHER', 'hello world3'),
89
('hello.sploo.BASE', 'yellowworld'),
90
('hello.sploo.OTHER', 'yellowworld2'),
93
self.assertLength(6, list(tree.list_files()))
95
tree_conflicts = tree.conflicts()
96
self.assertLength(2, tree_conflicts)
97
self.assertTrue('hello' in tree_conflicts[0].path)
98
self.assertTrue('hello.sploo' in tree_conflicts[1].path)
99
conflicts.restore('hello')
100
conflicts.restore('hello.sploo')
101
self.assertLength(0, tree.conflicts())
102
self.assertFileEqual('hello world2', 'hello')
103
self.assertFalse(os.path.lexists('hello.sploo'))
104
self.assertRaises(errors.NotConflicted, conflicts.restore, 'hello')
105
self.assertRaises(errors.NotConflicted,
106
conflicts.restore, 'hello.sploo')
67
108
def test_resolve_conflict_dir(self):
68
109
tree = self.make_branch_and_tree('.')
69
110
self.build_tree_contents([('hello', 'hello world4'),
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.
298
"""Return the scenario list for the conflict type defined by the class.
300
Each scenario is of the form:
301
(common, (left_name, left_dict), (right_name, right_dict))
305
* left_name and right_name are the scenario names that will be combined
307
* left_dict and right_dict are the attributes specific to each half of
308
the scenario. They should include at least 'actions' and 'check' and
309
will be available as '_this' and '_other' test instance attributes.
311
Daughters classes are free to add their specific attributes as they see
312
fit in any of the three dicts.
314
This is a class method so that load_tests can find it.
316
'_base_actions' in the common dict, 'actions' and 'check' in the left
317
and right dicts use names that map to methods in the test classes. Some
318
prefixes are added to these names to get the correspong methods (see
319
_get_actions() and _get_check()). The motivation here is to avoid
320
collisions in the class namespace.
322
# Only concrete classes return actual scenarios
277
326
super(TestParametrizedResolveConflicts, self).setUp()
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
391
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
409
_conflict_type = conflicts.ContentsConflict
393
_conflict_type = conflicts.ContentsConflict,
411
# Set by the scenarios
395
# Set by load_tests from scenarios()
412
396
# path and file-id for the file involved in the conflict
416
scenarios = mirror_scenarios(
418
403
# File modified/deleted
419
404
(dict(_base_actions='create_file',
420
405
_path='file', _file_id='file-id'),
422
407
dict(actions='modify_file', check='file_has_more_content')),
424
409
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')),),
411
return mirror_scenarios(base_scenarios)
436
413
def do_create_file(self):
437
414
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
446
423
return [('unversion', 'file-id')]
448
425
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')
426
self.failIfExists('branch/file')
464
428
def _get_resolve_path_arg(self, wt, action):
465
429
return self._path
492
457
# PathConflicts deletion handling requires a special
493
458
# hard-coded value
494
459
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
460
# File renamed/renamed differently
506
461
(dict(_base_actions='create_file'),
540
496
return [('rename', ('file', 'new-file'))]
542
498
def check_file_renamed(self):
543
self.assertPathDoesNotExist('branch/file')
544
self.assertPathExists('branch/new-file')
499
self.failIfExists('branch/file')
500
self.failUnlessExists('branch/new-file')
546
502
def do_rename_file2(self):
547
503
return [('rename', ('file', 'new-file2'))]
549
505
def check_file_renamed2(self):
550
self.assertPathDoesNotExist('branch/file')
551
self.assertPathExists('branch/new-file2')
506
self.failIfExists('branch/file')
507
self.failUnlessExists('branch/new-file2')
553
509
def do_rename_dir(self):
554
510
return [('rename', ('dir', 'new-dir'))]
556
512
def check_dir_renamed(self):
557
self.assertPathDoesNotExist('branch/dir')
558
self.assertPathExists('branch/new-dir')
513
self.failIfExists('branch/dir')
514
self.failUnlessExists('branch/new-dir')
560
516
def do_rename_dir2(self):
561
517
return [('rename', ('dir', 'new-dir2'))]
563
519
def check_dir_renamed2(self):
564
self.assertPathDoesNotExist('branch/dir')
565
self.assertPathExists('branch/new-dir2')
520
self.failIfExists('branch/dir')
521
self.failUnlessExists('branch/new-dir2')
567
523
def do_delete_file(self):
568
524
return [('unversion', 'file-id')]
570
526
def check_file_doesnt_exist(self):
571
self.assertPathDoesNotExist('branch/file')
527
self.failIfExists('branch/file')
573
529
def do_delete_dir(self):
574
530
return [('unversion', 'dir-id')]
576
532
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')
533
self.failIfExists('branch/dir')
593
535
def _get_resolve_path_arg(self, wt, action):
594
536
tpath = self._this['path']
724
670
$ echo 'trunk content' >dir/file
726
$ bzr commit -m 'Create trunk' -q
672
$ bzr commit -m 'Create trunk'
727
674
$ echo 'trunk content' >dir/file2
728
$ bzr add -q dir/file2
729
$ bzr commit -q -m 'Add dir/file2 in branch'
730
$ bzr branch -q . -r 1 ../branch
676
$ bzr commit -m 'Add dir/file2 in branch'
678
$ bzr branch . -r 1 ../branch
732
$ bzr rm -q dir/file --force
734
$ bzr commit -q -m 'Remove dir/file'
680
$ bzr rm dir/file --force
682
$ bzr commit -m 'Remove dir/file'
735
684
$ bzr merge ../trunk
743
692
def test_keep_them_all(self):
744
693
self.run_script("""
745
694
$ bzr resolve dir
746
2>2 conflict(s) resolved, 0 remaining
747
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
695
$ bzr commit --strict -m 'No more conflicts nor unknown files'
750
698
def test_adopt_child(self):
751
699
self.run_script("""
752
$ bzr mv -q dir/file2 file2
753
$ bzr rm -q dir --force
700
$ bzr mv dir/file2 file2
754
702
$ bzr resolve dir
755
2>2 conflict(s) resolved, 0 remaining
756
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
703
$ bzr commit --strict -m 'No more conflicts nor unknown files'
759
706
def test_kill_them_all(self):
760
707
self.run_script("""
761
$ bzr rm -q dir --force
762
709
$ bzr resolve dir
763
2>2 conflict(s) resolved, 0 remaining
764
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
710
$ bzr commit --strict -m 'No more conflicts nor unknown files'
767
713
def test_resolve_taking_this(self):
768
714
self.run_script("""
769
715
$ bzr resolve --take-this dir
771
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
716
$ bzr commit --strict -m 'No more conflicts nor unknown files'
774
719
def test_resolve_taking_other(self):
775
720
self.run_script("""
776
721
$ bzr resolve --take-other dir
778
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
722
$ bzr commit --strict -m 'No more conflicts nor unknown files'
789
732
$ echo 'trunk content' >dir/file
791
$ bzr commit -m 'Create trunk' -q
792
$ bzr rm -q dir/file --force
793
$ bzr rm -q dir --force
794
$ bzr commit -q -m 'Remove dir/file'
795
$ bzr branch -q . -r 1 ../branch
734
$ bzr commit -m 'Create trunk'
736
$ bzr rm dir/file --force
738
$ bzr commit -m 'Remove dir/file'
740
$ bzr branch . -r 1 ../branch
797
742
$ echo 'branch content' >dir/file2
798
$ bzr add -q dir/file2
799
$ bzr commit -q -m 'Add dir/file2 in branch'
744
$ bzr commit -m 'Add dir/file2 in branch'
800
746
$ bzr merge ../trunk
802
748
2>Conflict: can't delete dir because it is not empty. Not deleting.
807
753
def test_keep_them_all(self):
808
754
self.run_script("""
809
755
$ bzr resolve dir
810
2>2 conflict(s) resolved, 0 remaining
811
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
756
$ bzr commit --strict -m 'No more conflicts nor unknown files'
814
759
def test_adopt_child(self):
815
760
self.run_script("""
816
$ bzr mv -q dir/file2 file2
817
$ bzr rm -q dir --force
761
$ bzr mv dir/file2 file2
818
763
$ bzr resolve dir
819
2>2 conflict(s) resolved, 0 remaining
820
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
764
$ bzr commit --strict -m 'No more conflicts nor unknown files'
823
767
def test_kill_them_all(self):
824
768
self.run_script("""
825
$ bzr rm -q dir --force
826
770
$ bzr resolve dir
827
2>2 conflict(s) resolved, 0 remaining
828
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
771
$ bzr commit --strict -m 'No more conflicts nor unknown files'
831
774
def test_resolve_taking_this(self):
832
775
self.run_script("""
833
776
$ bzr resolve --take-this dir
834
2>2 conflict(s) resolved, 0 remaining
835
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
777
$ bzr commit --strict -m 'No more conflicts nor unknown files'
838
780
def test_resolve_taking_other(self):
839
781
self.run_script("""
840
782
$ bzr resolve --take-other dir
843
2>2 conflict(s) resolved, 0 remaining
844
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
783
$ bzr commit --strict -m 'No more conflicts nor unknown files'
848
787
class TestResolveParentLoop(TestParametrizedResolveConflicts):
850
_conflict_type = conflicts.ParentLoop
789
_conflict_type = conflicts.ParentLoop,
852
791
_this_args = None
853
792
_other_args = None
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(
796
# Each side dict additionally defines:
797
# - dir_id: the directory being moved
798
# - target_id: The target directory
799
# - xfail: whether the test is expected to fail if the action is
800
# involved as 'other'
862
802
# Dirs moved into each other
863
803
(dict(_base_actions='create_dir1_dir2'),
864
804
('dir1_into_dir2',
885
826
return [('rename', ('dir1', 'dir2/dir1'))]
887
828
def check_dir1_moved(self):
888
self.assertPathDoesNotExist('branch/dir1')
889
self.assertPathExists('branch/dir2/dir1')
829
self.failIfExists('branch/dir1')
830
self.failUnlessExists('branch/dir2/dir1')
891
832
def do_move_dir2_into_dir1(self):
892
833
return [('rename', ('dir2', 'dir1/dir2'))]
894
835
def check_dir2_moved(self):
895
self.assertPathDoesNotExist('branch/dir2')
896
self.assertPathExists('branch/dir1/dir2')
836
self.failIfExists('branch/dir2')
837
self.failUnlessExists('branch/dir1/dir2')
898
839
def do_create_dir1_4(self):
899
840
return [('add', ('dir1', 'dir1-id', 'directory', '')),
905
846
return [('rename', ('dir1', 'dir3/dir4/dir1'))]
907
848
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')
849
self.failIfExists('branch/dir1')
850
self.failUnlessExists('branch/dir3/dir4/dir1')
851
self.failUnlessExists('branch/dir3/dir4/dir1/dir2')
912
853
def do_move_dir3_into_dir2(self):
913
854
return [('rename', ('dir3', 'dir1/dir2/dir3'))]
915
856
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')
857
self.failIfExists('branch/dir3')
858
self.failUnlessExists('branch/dir1/dir2/dir3')
859
self.failUnlessExists('branch/dir1/dir2/dir3/dir4')
920
861
def _get_resolve_path_arg(self, wt, action):
921
862
# ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
966
907
def test_take_this(self):
967
908
self.run_script("""
968
$ bzr rm -q foo.new --force
909
$ bzr rm foo.new --force
969
910
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
970
911
# aside ? -- vila 090916
972
913
$ bzr resolve foo.new
973
2>1 conflict(s) resolved, 0 remaining
974
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
914
$ bzr commit --strict -m 'No more conflicts nor unknown files'
977
917
def test_take_other(self):
978
918
self.run_script("""
979
$ bzr rm -q foo --force
980
$ bzr mv -q foo.new foo
981
921
$ bzr resolve foo
982
2>1 conflict(s) resolved, 0 remaining
983
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
922
$ bzr commit --strict -m 'No more conflicts nor unknown files'
986
925
def test_resolve_taking_this(self):
987
926
self.run_script("""
988
927
$ bzr resolve --take-this foo.new
990
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
928
$ bzr commit --strict -m 'No more conflicts nor unknown files'
993
931
def test_resolve_taking_other(self):
994
932
self.run_script("""
995
933
$ bzr resolve --take-other foo.new
997
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
934
$ bzr commit --strict -m 'No more conflicts nor unknown files'