~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge.py

  • Committer: Aaron Bentley
  • Date: 2007-07-11 19:44:51 UTC
  • mto: This revision was merged to the branch mainline in revision 2606.
  • Revision ID: abentley@panoramicfeedback.com-20070711194451-3jqhye1nnd02a9uv
Restore original Branch.last_revision behavior, fix bits that care

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
from bzrlib import (
21
21
    conflicts,
22
 
    errors,
23
 
    knit,
24
22
    merge as _mod_merge,
25
23
    option,
26
 
    progress,
27
 
    versionedfile,
28
24
    )
29
25
from bzrlib.branch import Branch
 
26
from bzrlib.builtins import _merge_helper
30
27
from bzrlib.conflicts import ConflictList, TextConflict
31
28
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
32
 
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
 
29
from bzrlib.merge import transform_tree, merge_inner
33
30
from bzrlib.osutils import pathjoin, file_kind
34
31
from bzrlib.revision import common_ancestor
35
 
from bzrlib.tests import TestCaseWithTransport, TestCaseWithMemoryTransport
 
32
from bzrlib.tests import TestCaseWithTransport
36
33
from bzrlib.trace import (enable_test_log, disable_test_log)
37
34
from bzrlib.workingtree import WorkingTree
38
35
 
44
41
        wt = self.make_branch_and_tree('.')
45
42
        rev_a = wt.commit("lala!")
46
43
        self.assertEqual([rev_a], wt.get_parent_ids())
47
 
        self.assertRaises(errors.PointlessMerge, wt.merge_from_branch,
48
 
                          wt.branch)
 
44
        _merge_helper([u'.', -1], [None, None])
49
45
        self.assertEqual([rev_a], wt.get_parent_ids())
50
 
        return wt
51
46
 
52
47
    def test_undo(self):
53
48
        wt = self.make_branch_and_tree('.')
54
49
        wt.commit("lala!")
55
50
        wt.commit("haha!")
56
51
        wt.commit("blabla!")
57
 
        wt.merge_from_branch(wt.branch, wt.branch.get_rev_id(2),
58
 
                             wt.branch.get_rev_id(1))
 
52
        _merge_helper([u'.', 2], [u'.', 1])
59
53
 
60
54
    def test_nocommits(self):
61
 
        wt = self.test_pending()
 
55
        self.test_pending()
62
56
        wt2 = self.make_branch_and_tree('branch2')
63
 
        self.assertRaises(NoCommits, wt.merge_from_branch, wt2.branch)
64
 
        return wt, wt2
 
57
        self.assertRaises(NoCommits, _merge_helper, ['branch2', -1], 
 
58
                          [None, None])
 
59
        return wt2
65
60
 
66
61
    def test_unrelated(self):
67
 
        wt, wt2 = self.test_nocommits()
 
62
        wt2 = self.test_nocommits()
68
63
        wt2.commit("blah")
69
 
        self.assertRaises(UnrelatedBranches, wt.merge_from_branch, wt2.branch)
 
64
        self.assertRaises(UnrelatedBranches, _merge_helper, ['branch2', -1], 
 
65
                          [None, None])
70
66
        return wt2
71
67
 
72
68
    def test_merge_one_file(self):
96
92
        br1.fetch(wt2.branch)
97
93
        # merge all of branch 2 into branch 1 even though they 
98
94
        # are not related.
99
 
        wt1.merge_from_branch(wt2.branch, wt2.last_revision(), 'null:')
 
95
        self.assertRaises(BzrCommandError, _merge_helper, ['branch2', -1],
 
96
                          ['branch2', 0], reprocess=True, show_base=True)
 
97
        _merge_helper(['branch2', -1], ['branch2', 0], reprocess=True)
100
98
        self.assertEqual([br1.last_revision(), wt2.branch.last_revision()],
101
99
            wt1.get_parent_ids())
102
100
        return (wt1, wt2.branch)
138
136
        tree_a.commit(message="hello")
139
137
        dir_b = tree_a.bzrdir.sprout('b')
140
138
        tree_b = dir_b.open_workingtree()
141
 
        tree_b.lock_write()
142
 
        self.addCleanup(tree_b.unlock)
143
139
        tree_a.commit(message="hello again")
144
140
        log = StringIO()
145
141
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
146
142
                    this_tree=tree_b, ignore_zero=True)
147
143
        log = self._get_log(keep_log_file=True)
148
144
        self.failUnless('All changes applied successfully.\n' not in log)
149
 
        tree_b.revert()
 
145
        tree_b.revert([])
150
146
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
151
147
                    this_tree=tree_b, ignore_zero=False)
152
148
        log = self._get_log(keep_log_file=True)
232
228
        tree_a.commit('changed file to directory')
233
229
        tree_b.merge_from_branch(tree_a.branch)
234
230
        self.assertEqual('directory', file_kind('tree_b/file'))
235
 
        tree_b.revert()
 
231
        tree_b.revert([])
236
232
        self.assertEqual('file', file_kind('tree_b/file'))
237
233
        self.build_tree_contents([('tree_b/file', 'content_2')])
238
234
        tree_b.commit('content change')
274
270
            tree_b.merge_from_branch(tree_a.branch)
275
271
        except AttributeError:
276
272
            self.fail('tried to join a path when name was None')
277
 
 
278
 
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis(self):
279
 
        tree_a = self.make_branch_and_tree('a')
280
 
        self.build_tree(['a/file_1', 'a/file_2'])
281
 
        tree_a.add(['file_1'])
282
 
        tree_a.commit('commit 1')
283
 
        tree_a.add(['file_2'])
284
 
        tree_a.commit('commit 2')
285
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
286
 
        tree_b.rename_one('file_1', 'renamed')
287
 
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
288
 
                                                    progress.DummyProgress())
289
 
        merger.merge_type = _mod_merge.Merge3Merger
290
 
        merger.do_merge()
291
 
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
292
 
 
293
 
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis_weave(self):
294
 
        tree_a = self.make_branch_and_tree('a')
295
 
        self.build_tree(['a/file_1', 'a/file_2'])
296
 
        tree_a.add(['file_1'])
297
 
        tree_a.commit('commit 1')
298
 
        tree_a.add(['file_2'])
299
 
        tree_a.commit('commit 2')
300
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
301
 
        tree_b.rename_one('file_1', 'renamed')
302
 
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
303
 
                                                    progress.DummyProgress())
304
 
        merger.merge_type = _mod_merge.WeaveMerger
305
 
        merger.do_merge()
306
 
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
307
 
 
308
 
    def prepare_cherrypick(self):
309
 
        """Prepare a pair of trees for cherrypicking tests.
310
 
 
311
 
        Both trees have a file, 'file'.
312
 
        rev1 sets content to 'a'.
313
 
        rev2b adds 'b'.
314
 
        rev3b adds 'c'.
315
 
        A full merge of rev2b and rev3b into this_tree would add both 'b' and
316
 
        'c'.  A successful cherrypick of rev2b-rev3b into this_tree will add
317
 
        'c', but not 'b'.
318
 
        """
319
 
        this_tree = self.make_branch_and_tree('this')
320
 
        self.build_tree_contents([('this/file', "a\n")])
321
 
        this_tree.add('file')
322
 
        this_tree.commit('rev1')
323
 
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
324
 
        self.build_tree_contents([('other/file', "a\nb\n")])
325
 
        other_tree.commit('rev2b', rev_id='rev2b')
326
 
        self.build_tree_contents([('other/file', "c\na\nb\n")])
327
 
        other_tree.commit('rev3b', rev_id='rev3b')
328
 
        this_tree.lock_write()
329
 
        self.addCleanup(this_tree.unlock)
330
 
        return this_tree, other_tree
331
 
 
332
 
    def test_weave_cherrypick(self):
333
 
        this_tree, other_tree = self.prepare_cherrypick()
334
 
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
335
 
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
336
 
        merger.merge_type = _mod_merge.WeaveMerger
337
 
        merger.do_merge()
338
 
        self.assertFileEqual('c\na\n', 'this/file')
339
 
 
340
 
    def test_weave_cannot_reverse_cherrypick(self):
341
 
        this_tree, other_tree = self.prepare_cherrypick()
342
 
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
343
 
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
344
 
        merger.merge_type = _mod_merge.WeaveMerger
345
 
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
346
 
 
347
 
    def test_merge3_can_reverse_cherrypick(self):
348
 
        this_tree, other_tree = self.prepare_cherrypick()
349
 
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
350
 
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
351
 
        merger.merge_type = _mod_merge.Merge3Merger
352
 
        merger.do_merge()
353
 
 
354
 
 
355
 
class TestPlanMerge(TestCaseWithMemoryTransport):
356
 
 
357
 
    def setUp(self):
358
 
        TestCaseWithMemoryTransport.setUp(self)
359
 
        self.vf = knit.KnitVersionedFile('root', self.get_transport(),
360
 
                                         create=True)
361
 
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
362
 
                                                                   [self.vf])
363
 
 
364
 
    def add_version(self, version_id, parents, text):
365
 
        self.vf.add_lines(version_id, parents, [c+'\n' for c in text])
366
 
 
367
 
    def add_uncommitted_version(self, version_id, parents, text):
368
 
        self.plan_merge_vf.add_lines(version_id, parents,
369
 
                                     [c+'\n' for c in text])
370
 
 
371
 
    def setup_plan_merge(self):
372
 
        self.add_version('A', [], 'abc')
373
 
        self.add_version('B', ['A'], 'acehg')
374
 
        self.add_version('C', ['A'], 'fabg')
375
 
        return _PlanMerge('B', 'C', self.plan_merge_vf)
376
 
 
377
 
    def setup_plan_merge_uncommitted(self):
378
 
        self.add_version('A', [], 'abc')
379
 
        self.add_uncommitted_version('B:', ['A'], 'acehg')
380
 
        self.add_uncommitted_version('C:', ['A'], 'fabg')
381
 
        return _PlanMerge('B:', 'C:', self.plan_merge_vf)
382
 
 
383
 
    def test_unique_lines(self):
384
 
        plan = self.setup_plan_merge()
385
 
        self.assertEqual(plan._unique_lines(
386
 
            plan._get_matching_blocks('B', 'C')),
387
 
            ([1, 2, 3], [0, 2]))
388
 
 
389
 
    def test_find_new(self):
390
 
        plan = self.setup_plan_merge()
391
 
        self.assertEqual(set([2, 3, 4]), plan._find_new('B'))
392
 
        self.assertEqual(set([0, 3]), plan._find_new('C'))
393
 
 
394
 
    def test_find_new2(self):
395
 
        self.add_version('A', [], 'abc')
396
 
        self.add_version('B', ['A'], 'abcde')
397
 
        self.add_version('C', ['A'], 'abcefg')
398
 
        self.add_version('D', ['A', 'B', 'C'], 'abcdegh')
399
 
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf)
400
 
        self.assertEqual(set([5, 6]), my_plan._find_new('D'))
401
 
        self.assertEqual(set(), my_plan._find_new('A'))
402
 
 
403
 
    def test_find_new_no_ancestors(self):
404
 
        self.add_version('A', [], 'abc')
405
 
        self.add_version('B', [], 'xyz')
406
 
        my_plan = _PlanMerge('A', 'B', self.vf)
407
 
        self.assertEqual(set([0, 1, 2]), my_plan._find_new('A'))
408
 
 
409
 
    def test_plan_merge(self):
410
 
        self.setup_plan_merge()
411
 
        plan = self.plan_merge_vf.plan_merge('B', 'C')
412
 
        self.assertEqual([
413
 
                          ('new-b', 'f\n'),
414
 
                          ('unchanged', 'a\n'),
415
 
                          ('killed-b', 'c\n'),
416
 
                          ('new-a', 'e\n'),
417
 
                          ('new-a', 'h\n'),
418
 
                          ('killed-a', 'b\n'),
419
 
                          ('unchanged', 'g\n')],
420
 
                         list(plan))
421
 
 
422
 
    def test_plan_merge_uncommitted_files(self):
423
 
        self.setup_plan_merge_uncommitted()
424
 
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
425
 
        self.assertEqual([
426
 
                          ('new-b', 'f\n'),
427
 
                          ('unchanged', 'a\n'),
428
 
                          ('killed-b', 'c\n'),
429
 
                          ('new-a', 'e\n'),
430
 
                          ('new-a', 'h\n'),
431
 
                          ('killed-a', 'b\n'),
432
 
                          ('unchanged', 'g\n')],
433
 
                         list(plan))
434
 
 
435
 
    def test_subtract_plans(self):
436
 
        old_plan = [
437
 
        ('unchanged', 'a\n'),
438
 
        ('new-a', 'b\n'),
439
 
        ('killed-a', 'c\n'),
440
 
        ('new-b', 'd\n'),
441
 
        ('new-b', 'e\n'),
442
 
        ('killed-b', 'f\n'),
443
 
        ('killed-b', 'g\n'),
444
 
        ]
445
 
        new_plan = [
446
 
        ('unchanged', 'a\n'),
447
 
        ('new-a', 'b\n'),
448
 
        ('killed-a', 'c\n'),
449
 
        ('new-b', 'd\n'),
450
 
        ('new-b', 'h\n'),
451
 
        ('killed-b', 'f\n'),
452
 
        ('killed-b', 'i\n'),
453
 
        ]
454
 
        subtracted_plan = [
455
 
        ('unchanged', 'a\n'),
456
 
        ('new-a', 'b\n'),
457
 
        ('killed-a', 'c\n'),
458
 
        ('new-b', 'h\n'),
459
 
        ('unchanged', 'f\n'),
460
 
        ('killed-b', 'i\n'),
461
 
        ]
462
 
        self.assertEqual(subtracted_plan,
463
 
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
464
 
 
465
 
    def setup_merge_with_base(self):
466
 
        self.add_version('COMMON', [], 'abc')
467
 
        self.add_version('THIS', ['COMMON'], 'abcd')
468
 
        self.add_version('BASE', ['COMMON'], 'eabc')
469
 
        self.add_version('OTHER', ['BASE'], 'eafb')
470
 
 
471
 
    def test_plan_merge_with_base(self):
472
 
        self.setup_merge_with_base()
473
 
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
474
 
        self.assertEqual([('unchanged', 'a\n'),
475
 
                          ('new-b', 'f\n'),
476
 
                          ('unchanged', 'b\n'),
477
 
                          ('killed-b', 'c\n'),
478
 
                          ('new-a', 'd\n')
479
 
                         ], list(plan))
480
 
 
481
 
    def test_plan_lca_merge(self):
482
 
        self.setup_plan_merge()
483
 
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
484
 
        self.assertEqual([
485
 
                          ('new-b', 'f\n'),
486
 
                          ('unchanged', 'a\n'),
487
 
                          ('killed-b', 'c\n'),
488
 
                          ('new-a', 'e\n'),
489
 
                          ('new-a', 'h\n'),
490
 
                          ('killed-a', 'b\n'),
491
 
                          ('unchanged', 'g\n')],
492
 
                         list(plan))
493
 
 
494
 
    def test_plan_lca_merge_uncommitted_files(self):
495
 
        self.setup_plan_merge_uncommitted()
496
 
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
497
 
        self.assertEqual([
498
 
                          ('new-b', 'f\n'),
499
 
                          ('unchanged', 'a\n'),
500
 
                          ('killed-b', 'c\n'),
501
 
                          ('new-a', 'e\n'),
502
 
                          ('new-a', 'h\n'),
503
 
                          ('killed-a', 'b\n'),
504
 
                          ('unchanged', 'g\n')],
505
 
                         list(plan))
506
 
 
507
 
    def test_plan_lca_merge_with_base(self):
508
 
        self.setup_merge_with_base()
509
 
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
510
 
        self.assertEqual([('unchanged', 'a\n'),
511
 
                          ('new-b', 'f\n'),
512
 
                          ('unchanged', 'b\n'),
513
 
                          ('killed-b', 'c\n'),
514
 
                          ('new-a', 'd\n')
515
 
                         ], list(plan))
516
 
 
517
 
    def test_plan_lca_merge_with_criss_cross(self):
518
 
        self.add_version('ROOT', [], 'abc')
519
 
        # each side makes a change
520
 
        self.add_version('REV1', ['ROOT'], 'abcd')
521
 
        self.add_version('REV2', ['ROOT'], 'abce')
522
 
        # both sides merge, discarding others' changes
523
 
        self.add_version('LCA1', ['REV1', 'REV2'], 'abcd')
524
 
        self.add_version('LCA2', ['REV1', 'REV2'], 'abce')
525
 
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
526
 
        self.assertEqual([('unchanged', 'a\n'),
527
 
                          ('unchanged', 'b\n'),
528
 
                          ('unchanged', 'c\n'),
529
 
                          ('conflicted-a', 'd\n'),
530
 
                          ('conflicted-b', 'e\n'),
531
 
                         ], list(plan))