1898
1906
builder = self.get_builder()
1899
1907
builder.build_snapshot(None,
1900
[('add', (u'', b'a-root-id', 'directory', None)),
1901
('add', (u'foo', b'foo-id', 'file', b'A content\n'))],
1902
revision_id=b'A-id')
1903
builder.build_snapshot([b'A-id'],
1904
[('modify', ('foo', b'B content\n'))],
1905
revision_id=b'B-id')
1906
builder.build_snapshot([b'A-id'],
1907
[('modify', ('foo', b'C content\n'))],
1908
revision_id=b'C-id')
1908
[('add', (u'', b'a-root-id', 'directory', None)),
1909
('add', (u'foo', b'foo-id', 'file', b'A content\n'))],
1910
revision_id=b'A-id')
1911
builder.build_snapshot([b'A-id'],
1912
[('modify', ('foo', b'B content\n'))],
1913
revision_id=b'B-id')
1914
builder.build_snapshot([b'A-id'],
1915
[('modify', ('foo', b'C content\n'))],
1916
revision_id=b'C-id')
1909
1917
builder.build_snapshot([b'C-id', b'B-id'], [], revision_id=b'E-id')
1910
1918
builder.build_snapshot([b'B-id', b'C-id'],
1911
[('modify', ('foo', b'C content\n'))],
1912
revision_id=b'D-id') # Same as E
1919
[('modify', ('foo', b'C content\n'))],
1920
revision_id=b'D-id') # Same as E
1913
1921
builder.build_snapshot([b'D-id'],
1914
[('modify', ('foo', b'F content\n'))],
1915
revision_id=b'F-id')
1922
[('modify', ('foo', b'F content\n'))],
1923
revision_id=b'F-id')
1916
1924
merge_obj = self.make_merge_obj(builder, b'E-id')
1918
1926
entries = list(merge_obj._entries_lca())
1919
1927
self.expectFailure("We don't detect that LCA resolution was the"
1920
1928
" same on both sides",
1921
self.assertEqual, [], entries)
1929
self.assertEqual, [], entries)
1923
1931
def test_only_path_changed(self):
1924
1932
builder = self.get_builder()
1925
1933
builder.build_snapshot(None,
1926
[('add', (u'', b'a-root-id', 'directory', None)),
1927
('add', (u'a', b'a-id', 'file', b'content\n'))],
1928
revision_id=b'A-id')
1934
[('add', (u'', b'a-root-id', 'directory', None)),
1935
('add', (u'a', b'a-id', 'file', b'content\n'))],
1936
revision_id=b'A-id')
1929
1937
builder.build_snapshot([b'A-id'], [], revision_id=b'B-id')
1930
1938
builder.build_snapshot([b'A-id'], [], revision_id=b'C-id')
1931
1939
builder.build_snapshot([b'C-id', b'B-id'],
1932
[('rename', (u'a', u'b'))],
1933
revision_id=b'E-id')
1940
[('rename', (u'a', u'b'))],
1941
revision_id=b'E-id')
1934
1942
builder.build_snapshot([b'B-id', b'C-id'], [], revision_id=b'D-id')
1935
1943
merge_obj = self.make_merge_obj(builder, b'E-id')
1936
1944
entries = list(merge_obj._entries_lca())
2692
2699
# D E E updates content, renames 'b' => 'c'
2693
2700
builder = self.get_builder()
2694
2701
builder.build_snapshot(None,
2695
[('add', (u'', b'a-root-id', 'directory', None)),
2696
('add', (u'a', b'a-id', 'file', b'base content\n')),
2697
('add', (u'foo', b'foo-id', 'file', b'base content\n'))],
2698
revision_id=b'A-id')
2699
builder.build_snapshot([b'A-id'],
2700
[('modify', ('foo', b'B content\n'))],
2701
revision_id=b'B-id')
2702
builder.build_snapshot([b'A-id'],
2703
[('rename', ('a', 'b'))],
2704
revision_id=b'C-id')
2702
[('add', (u'', b'a-root-id', 'directory', None)),
2703
('add', (u'a', b'a-id', 'file', b'base content\n')),
2704
('add', (u'foo', b'foo-id', 'file', b'base content\n'))],
2705
revision_id=b'A-id')
2706
builder.build_snapshot([b'A-id'],
2707
[('modify', ('foo', b'B content\n'))],
2708
revision_id=b'B-id')
2709
builder.build_snapshot([b'A-id'],
2710
[('rename', ('a', 'b'))],
2711
revision_id=b'C-id')
2705
2712
builder.build_snapshot([b'C-id', b'B-id'],
2706
[('rename', ('b', 'c')),
2707
('modify', ('foo', b'E content\n'))],
2708
revision_id=b'E-id')
2713
[('rename', ('b', 'c')),
2714
('modify', ('foo', b'E content\n'))],
2715
revision_id=b'E-id')
2709
2716
builder.build_snapshot([b'B-id', b'C-id'],
2710
[('rename', ('a', 'b'))], revision_id=b'D-id') # merged change
2717
[('rename', ('a', 'b'))], revision_id=b'D-id') # merged change
2711
2718
wt_this = self.get_wt_from_builder(builder)
2712
2719
wt_base = wt_this.controldir.sprout('base', b'A-id').open_workingtree()
2713
2720
wt_base.lock_read()
2714
2721
self.addCleanup(wt_base.unlock)
2715
wt_lca1 = wt_this.controldir.sprout('b-tree', b'B-id').open_workingtree()
2722
wt_lca1 = wt_this.controldir.sprout(
2723
'b-tree', b'B-id').open_workingtree()
2716
2724
wt_lca1.lock_read()
2717
2725
self.addCleanup(wt_lca1.unlock)
2718
wt_lca2 = wt_this.controldir.sprout('c-tree', b'C-id').open_workingtree()
2726
wt_lca2 = wt_this.controldir.sprout(
2727
'c-tree', b'C-id').open_workingtree()
2719
2728
wt_lca2.lock_read()
2720
2729
self.addCleanup(wt_lca2.unlock)
2721
wt_other = wt_this.controldir.sprout('other', b'E-id').open_workingtree()
2730
wt_other = wt_this.controldir.sprout(
2731
'other', b'E-id').open_workingtree()
2722
2732
wt_other.lock_read()
2723
2733
self.addCleanup(wt_other.unlock)
2724
2734
merge_obj = _mod_merge.Merge3Merger(wt_this, wt_this, wt_base,
2725
wt_other, lca_trees=[wt_lca1, wt_lca2], do_merge=False)
2735
wt_other, lca_trees=[wt_lca1, wt_lca2], do_merge=False)
2726
2736
entries = list(merge_obj._entries_lca())
2727
2737
root_id = b'a-root-id'
2728
2738
self.assertEqual([(b'a-id', False,
2903
2913
def assertLCAMultiWay(self, expected, base, lcas, other, this,
2904
2914
allow_overriding_lca=True):
2905
2915
self.assertEqual(expected, _mod_merge.Merge3Merger._lca_multi_way(
2906
(base, lcas), other, this,
2907
allow_overriding_lca=allow_overriding_lca))
2916
(base, lcas), other, this,
2917
allow_overriding_lca=allow_overriding_lca))
2909
2919
def test_other_equal_equal_lcas(self):
2910
2920
"""Test when OTHER=LCA and all LCAs are identical."""
2911
2921
self.assertLCAMultiWay('this',
2912
'bval', ['bval', 'bval'], 'bval', 'bval')
2913
self.assertLCAMultiWay('this',
2914
'bval', ['lcaval', 'lcaval'], 'lcaval', 'bval')
2915
self.assertLCAMultiWay('this',
2916
'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', 'bval')
2917
self.assertLCAMultiWay('this',
2918
'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', 'tval')
2919
self.assertLCAMultiWay('this',
2920
'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', None)
2922
'bval', ['bval', 'bval'], 'bval', 'bval')
2923
self.assertLCAMultiWay('this',
2924
'bval', ['lcaval', 'lcaval'], 'lcaval', 'bval')
2925
self.assertLCAMultiWay('this',
2926
'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', 'bval')
2927
self.assertLCAMultiWay('this',
2928
'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', 'tval')
2929
self.assertLCAMultiWay('this',
2930
'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', None)
2922
2932
def test_other_equal_this(self):
2923
2933
"""Test when other and this are identical."""
2924
2934
self.assertLCAMultiWay('this',
2925
'bval', ['bval', 'bval'], 'oval', 'oval')
2926
self.assertLCAMultiWay('this',
2927
'bval', ['lcaval', 'lcaval'], 'oval', 'oval')
2928
self.assertLCAMultiWay('this',
2929
'bval', ['cval', 'dval'], 'oval', 'oval')
2930
self.assertLCAMultiWay('this',
2931
'bval', [None, 'lcaval'], 'oval', 'oval')
2932
self.assertLCAMultiWay('this',
2933
None, [None, 'lcaval'], 'oval', 'oval')
2934
self.assertLCAMultiWay('this',
2935
None, ['lcaval', 'lcaval'], 'oval', 'oval')
2936
self.assertLCAMultiWay('this',
2937
None, ['cval', 'dval'], 'oval', 'oval')
2938
self.assertLCAMultiWay('this',
2939
None, ['cval', 'dval'], None, None)
2940
self.assertLCAMultiWay('this',
2941
None, ['cval', 'dval', 'eval', 'fval'], 'oval', 'oval')
2935
'bval', ['bval', 'bval'], 'oval', 'oval')
2936
self.assertLCAMultiWay('this',
2937
'bval', ['lcaval', 'lcaval'], 'oval', 'oval')
2938
self.assertLCAMultiWay('this',
2939
'bval', ['cval', 'dval'], 'oval', 'oval')
2940
self.assertLCAMultiWay('this',
2941
'bval', [None, 'lcaval'], 'oval', 'oval')
2942
self.assertLCAMultiWay('this',
2943
None, [None, 'lcaval'], 'oval', 'oval')
2944
self.assertLCAMultiWay('this',
2945
None, ['lcaval', 'lcaval'], 'oval', 'oval')
2946
self.assertLCAMultiWay('this',
2947
None, ['cval', 'dval'], 'oval', 'oval')
2948
self.assertLCAMultiWay('this',
2949
None, ['cval', 'dval'], None, None)
2950
self.assertLCAMultiWay('this',
2951
None, ['cval', 'dval', 'eval', 'fval'], 'oval', 'oval')
2943
2953
def test_no_lcas(self):
2944
2954
self.assertLCAMultiWay('this',
2945
'bval', [], 'bval', 'tval')
2955
'bval', [], 'bval', 'tval')
2946
2956
self.assertLCAMultiWay('other',
2947
'bval', [], 'oval', 'bval')
2957
'bval', [], 'oval', 'bval')
2948
2958
self.assertLCAMultiWay('conflict',
2949
'bval', [], 'oval', 'tval')
2959
'bval', [], 'oval', 'tval')
2950
2960
self.assertLCAMultiWay('this',
2951
'bval', [], 'oval', 'oval')
2961
'bval', [], 'oval', 'oval')
2953
2963
def test_lca_supersedes_other_lca(self):
2954
2964
"""If one lca == base, the other lca takes precedence"""
2955
2965
self.assertLCAMultiWay('this',
2956
'bval', ['bval', 'lcaval'], 'lcaval', 'tval')
2966
'bval', ['bval', 'lcaval'], 'lcaval', 'tval')
2957
2967
self.assertLCAMultiWay('this',
2958
'bval', ['bval', 'lcaval'], 'lcaval', 'bval')
2968
'bval', ['bval', 'lcaval'], 'lcaval', 'bval')
2959
2969
# This is actually considered a 'revert' because the 'lcaval' in LCAS
2960
2970
# supersedes the BASE val (in the other LCA) but then OTHER reverts it
2961
2971
# back to bval.
2962
2972
self.assertLCAMultiWay('other',
2963
'bval', ['bval', 'lcaval'], 'bval', 'lcaval')
2973
'bval', ['bval', 'lcaval'], 'bval', 'lcaval')
2964
2974
self.assertLCAMultiWay('conflict',
2965
'bval', ['bval', 'lcaval'], 'bval', 'tval')
2975
'bval', ['bval', 'lcaval'], 'bval', 'tval')
2967
2977
def test_other_and_this_pick_different_lca(self):
2968
2978
# OTHER and THIS resolve the lca conflict in different ways
2969
2979
self.assertLCAMultiWay('conflict',
2970
'bval', ['lca1val', 'lca2val'], 'lca1val', 'lca2val')
2971
self.assertLCAMultiWay('conflict',
2972
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'lca2val')
2973
self.assertLCAMultiWay('conflict',
2974
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'lca2val')
2980
'bval', ['lca1val', 'lca2val'], 'lca1val', 'lca2val')
2981
self.assertLCAMultiWay('conflict',
2982
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'lca2val')
2983
self.assertLCAMultiWay('conflict',
2984
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'lca2val')
2976
2986
def test_other_in_lca(self):
2977
2987
# OTHER takes a value of one of the LCAs, THIS takes a new value, which
2978
2988
# theoretically supersedes both LCA values and 'wins'
2979
2989
self.assertLCAMultiWay('this',
2980
'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval')
2990
'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval')
2981
2991
self.assertLCAMultiWay('this',
2982
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval')
2983
self.assertLCAMultiWay('conflict',
2984
'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval',
2985
allow_overriding_lca=False)
2986
self.assertLCAMultiWay('conflict',
2987
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval',
2988
allow_overriding_lca=False)
2992
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval')
2993
self.assertLCAMultiWay('conflict',
2995
'lca2val'], 'lca1val', 'newval',
2996
allow_overriding_lca=False)
2997
self.assertLCAMultiWay('conflict',
2998
'bval', ['lca1val', 'lca2val',
2999
'lca3val'], 'lca1val', 'newval',
3000
allow_overriding_lca=False)
2989
3001
# THIS reverted back to BASE, but that is an explicit supersede of all
2991
3003
self.assertLCAMultiWay('this',
2992
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval')
3004
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval')
2993
3005
self.assertLCAMultiWay('this',
2994
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval')
2995
self.assertLCAMultiWay('conflict',
2996
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval',
2997
allow_overriding_lca=False)
2998
self.assertLCAMultiWay('conflict',
2999
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval',
3000
allow_overriding_lca=False)
3006
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval')
3007
self.assertLCAMultiWay('conflict',
3008
'bval', ['lca1val', 'lca2val',
3009
'lca3val'], 'lca1val', 'bval',
3010
allow_overriding_lca=False)
3011
self.assertLCAMultiWay('conflict',
3012
'bval', ['lca1val', 'lca2val',
3013
'bval'], 'lca1val', 'bval',
3014
allow_overriding_lca=False)
3002
3016
def test_this_in_lca(self):
3003
3017
# THIS takes a value of one of the LCAs, OTHER takes a new value, which
3004
3018
# theoretically supersedes both LCA values and 'wins'
3005
3019
self.assertLCAMultiWay('other',
3006
'bval', ['lca1val', 'lca2val'], 'oval', 'lca1val')
3020
'bval', ['lca1val', 'lca2val'], 'oval', 'lca1val')
3007
3021
self.assertLCAMultiWay('other',
3008
'bval', ['lca1val', 'lca2val'], 'oval', 'lca2val')
3009
self.assertLCAMultiWay('conflict',
3010
'bval', ['lca1val', 'lca2val'], 'oval', 'lca1val',
3011
allow_overriding_lca=False)
3012
self.assertLCAMultiWay('conflict',
3013
'bval', ['lca1val', 'lca2val'], 'oval', 'lca2val',
3014
allow_overriding_lca=False)
3022
'bval', ['lca1val', 'lca2val'], 'oval', 'lca2val')
3023
self.assertLCAMultiWay('conflict',
3025
'lca2val'], 'oval', 'lca1val',
3026
allow_overriding_lca=False)
3027
self.assertLCAMultiWay('conflict',
3029
'lca2val'], 'oval', 'lca2val',
3030
allow_overriding_lca=False)
3015
3031
# OTHER reverted back to BASE, but that is an explicit supersede of all
3017
3033
self.assertLCAMultiWay('other',
3018
'bval', ['lca1val', 'lca2val', 'lca3val'], 'bval', 'lca3val')
3034
'bval', ['lca1val', 'lca2val', 'lca3val'], 'bval', 'lca3val')
3019
3035
self.assertLCAMultiWay('conflict',
3020
'bval', ['lca1val', 'lca2val', 'lca3val'], 'bval', 'lca3val',
3021
allow_overriding_lca=False)
3036
'bval', ['lca1val', 'lca2val',
3037
'lca3val'], 'bval', 'lca3val',
3038
allow_overriding_lca=False)
3023
3040
def test_all_differ(self):
3024
3041
self.assertLCAMultiWay('conflict',
3025
'bval', ['lca1val', 'lca2val'], 'oval', 'tval')
3026
self.assertLCAMultiWay('conflict',
3027
'bval', ['lca1val', 'lca2val', 'lca2val'], 'oval', 'tval')
3028
self.assertLCAMultiWay('conflict',
3029
'bval', ['lca1val', 'lca2val', 'lca3val'], 'oval', 'tval')
3042
'bval', ['lca1val', 'lca2val'], 'oval', 'tval')
3043
self.assertLCAMultiWay('conflict',
3044
'bval', ['lca1val', 'lca2val', 'lca2val'], 'oval', 'tval')
3045
self.assertLCAMultiWay('conflict',
3046
'bval', ['lca1val', 'lca2val', 'lca3val'], 'oval', 'tval')
3032
3049
class TestConfigurableFileMerger(tests.TestCaseWithTransport):