~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge.py

  • Committer: Vincent Ladeuil
  • Date: 2008-01-03 08:49:38 UTC
  • mfrom: (3111.1.31 175524)
  • mto: This revision was merged to the branch mainline in revision 3158.
  • Revision ID: v.ladeuil+lp@free.fr-20080103084938-7kvurk5uvde2ui54
Fix bug #175524, http test servers are 1.1 compliant

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