1383
1421
((False, [False, False]), None, False)),
1424
def test_not_in_other_or_lca(self):
1425
# A base, introduces 'foo'
1427
# B C B nothing, C deletes foo
1429
# D E D restores foo (same as B), E leaves it deleted
1430
# We should emit an entry for this
1431
builder = self.get_builder()
1432
builder.build_snapshot('A-id', None,
1433
[('add', (u'', 'a-root-id', 'directory', None)),
1434
('add', (u'foo', 'foo-id', 'file', 'content\n'))])
1435
builder.build_snapshot('B-id', ['A-id'], [])
1436
builder.build_snapshot('C-id', ['A-id'],
1437
[('unversion', 'foo-id')])
1438
builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1439
builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1440
merge_obj = self.make_merge_obj(builder, 'E-id')
1442
entries = list(merge_obj._entries_lca())
1443
root_id = 'a-root-id'
1444
self.assertEqual([('foo-id', True,
1445
((root_id, [root_id, None]), None, root_id),
1446
((u'foo', [u'foo', None]), None, 'foo'),
1447
((False, [False, None]), None, False)),
1386
1450
def test_only_in_one_lca(self):
1387
1451
builder = self.get_builder()
1388
1452
builder.build_snapshot('A-id', None,
1422
1486
((None, [None, None]), False, None)),
1489
def test_one_lca_supersedes(self):
1490
# One LCA supersede's the other LCA's last modified value, but the
1491
# value is not the same as BASE.
1492
# A base, introduces 'foo', last mod A
1494
# B C B modifies 'foo' (mod B), C does nothing (mod A)
1496
# D E D does nothing (mod B), E updates 'foo' (mod E)
1498
# F G F updates 'foo' (mod F). G does nothing (mod E)
1500
# At this point, G should not be considered to modify 'foo', even
1501
# though its LCAs disagree. This is because the modification in E
1502
# completely supersedes the value in D.
1503
builder = self.get_builder()
1504
builder.build_snapshot('A-id', None,
1505
[('add', (u'', 'a-root-id', 'directory', None)),
1506
('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
1507
builder.build_snapshot('C-id', ['A-id'], [])
1508
builder.build_snapshot('B-id', ['A-id'],
1509
[('modify', ('foo-id', 'B content\n'))])
1510
builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1511
builder.build_snapshot('E-id', ['C-id', 'B-id'],
1512
[('modify', ('foo-id', 'E content\n'))])
1513
builder.build_snapshot('G-id', ['E-id', 'D-id'], [])
1514
builder.build_snapshot('F-id', ['D-id', 'E-id'],
1515
[('modify', ('foo-id', 'F content\n'))])
1516
merge_obj = self.make_merge_obj(builder, 'G-id')
1518
self.assertEqual([], list(merge_obj._entries_lca()))
1520
def test_both_sides_revert(self):
1521
# Both sides of a criss-cross revert the text to the lca
1522
# A base, introduces 'foo'
1524
# B C B modifies 'foo', C modifies 'foo'
1526
# D E D reverts to B, E reverts to C
1527
# This should conflict
1528
builder = self.get_builder()
1529
builder.build_snapshot('A-id', None,
1530
[('add', (u'', 'a-root-id', 'directory', None)),
1531
('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
1532
builder.build_snapshot('B-id', ['A-id'],
1533
[('modify', ('foo-id', 'B content\n'))])
1534
builder.build_snapshot('C-id', ['A-id'],
1535
[('modify', ('foo-id', 'C content\n'))])
1536
builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1537
builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1538
merge_obj = self.make_merge_obj(builder, 'E-id')
1540
entries = list(merge_obj._entries_lca())
1541
root_id = 'a-root-id'
1542
self.assertEqual([('foo-id', True,
1543
((root_id, [root_id, root_id]), root_id, root_id),
1544
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1545
((False, [False, False]), False, False)),
1548
def test_different_lca_resolve_one_side_updates_content(self):
1549
# Both sides converge, but then one side updates the text.
1550
# A base, introduces 'foo'
1552
# B C B modifies 'foo', C modifies 'foo'
1554
# D E D reverts to B, E reverts to C
1556
# F F updates to a new value
1557
# We need to emit an entry for 'foo', because D & E differed on the
1559
builder = self.get_builder()
1560
builder.build_snapshot('A-id', None,
1561
[('add', (u'', 'a-root-id', 'directory', None)),
1562
('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
1563
builder.build_snapshot('B-id', ['A-id'],
1564
[('modify', ('foo-id', 'B content\n'))])
1565
builder.build_snapshot('C-id', ['A-id'],
1566
[('modify', ('foo-id', 'C content\n'))])
1567
builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1568
builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1569
builder.build_snapshot('F-id', ['D-id'],
1570
[('modify', ('foo-id', 'F content\n'))])
1571
merge_obj = self.make_merge_obj(builder, 'E-id')
1573
entries = list(merge_obj._entries_lca())
1574
root_id = 'a-root-id'
1575
self.assertEqual([('foo-id', True,
1576
((root_id, [root_id, root_id]), root_id, root_id),
1577
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1578
((False, [False, False]), False, False)),
1581
def test_same_lca_resolution_one_side_updates_content(self):
1582
# Both sides converge, but then one side updates the text.
1583
# A base, introduces 'foo'
1585
# B C B modifies 'foo', C modifies 'foo'
1587
# D E D and E use C's value
1589
# F F updates to a new value
1590
# I think it is a bug that this conflicts, but we don't have a way to
1591
# detect otherwise. And because of:
1592
# test_different_lca_resolve_one_side_updates_content
1593
# We need to conflict.
1595
builder = self.get_builder()
1596
builder.build_snapshot('A-id', None,
1597
[('add', (u'', 'a-root-id', 'directory', None)),
1598
('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
1599
builder.build_snapshot('B-id', ['A-id'],
1600
[('modify', ('foo-id', 'B content\n'))])
1601
builder.build_snapshot('C-id', ['A-id'],
1602
[('modify', ('foo-id', 'C content\n'))])
1603
builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1604
builder.build_snapshot('D-id', ['B-id', 'C-id'],
1605
[('modify', ('foo-id', 'C content\n'))]) # Same as E
1606
builder.build_snapshot('F-id', ['D-id'],
1607
[('modify', ('foo-id', 'F content\n'))])
1608
merge_obj = self.make_merge_obj(builder, 'E-id')
1610
entries = list(merge_obj._entries_lca())
1611
root_id = 'a-root-id'
1612
self.expectFailure("We don't detect that LCA resolution was the"
1613
" same on both sides",
1614
self.assertEqual, [], entries)
1425
1616
def test_only_path_changed(self):
1426
1617
builder = self.get_builder()
1427
1618
builder.build_snapshot('A-id', None,
1761
1952
self.assertEqual('foo-id', wt.path2id('foo'))
1762
1953
self.assertEqual('bar', wt.get_symlink_target('foo-id'))
1955
def test_both_sides_revert(self):
1956
# Both sides of a criss-cross revert the text to the lca
1957
# A base, introduces 'foo'
1959
# B C B modifies 'foo', C modifies 'foo'
1961
# D E D reverts to B, E reverts to C
1962
# This should conflict
1963
# This must be done with a real WorkingTree, because normally their
1964
# inventory contains "None" rather than a real sha1
1965
builder = self.get_builder()
1966
builder.build_snapshot('A-id', None,
1967
[('add', (u'', 'a-root-id', 'directory', None)),
1968
('add', (u'foo', 'foo-id', 'file', 'A content\n'))])
1969
builder.build_snapshot('B-id', ['A-id'],
1970
[('modify', ('foo-id', 'B content\n'))])
1971
builder.build_snapshot('C-id', ['A-id'],
1972
[('modify', ('foo-id', 'C content\n'))])
1973
builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1974
builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1975
wt, conflicts = self.do_merge(builder, 'E-id')
1976
self.assertEqual(1, conflicts)
1977
self.assertEqualDiff('<<<<<<< TREE\n'
1981
'>>>>>>> MERGE-SOURCE\n',
1982
wt.get_file_text('foo-id'))
1764
1984
def test_modified_symlink(self):
1765
1985
self.requireFeature(tests.SymlinkFeature)
1766
1986
# A Create symlink foo => bar
2061
2283
'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval')
2062
2284
self.assertLCAMultiWay('this',
2063
2285
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval')
2286
self.assertLCAMultiWay('conflict',
2287
'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval',
2288
allow_overriding_lca=False)
2289
self.assertLCAMultiWay('conflict',
2290
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval',
2291
allow_overriding_lca=False)
2064
2292
# THIS reverted back to BASE, but that is an explicit supersede of all
2066
2294
self.assertLCAMultiWay('this',
2067
2295
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval')
2068
2296
self.assertLCAMultiWay('this',
2069
2297
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval')
2298
self.assertLCAMultiWay('conflict',
2299
'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval',
2300
allow_overriding_lca=False)
2301
self.assertLCAMultiWay('conflict',
2302
'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval',
2303
allow_overriding_lca=False)
2071
2305
def test_this_in_lca(self):
2072
2306
# THIS takes a value of one of the LCAs, OTHER takes a new value, which