/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge_core.py

First attempt to merge .dev and resolve the conflicts (but tests are 
failing)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
1
17
import os
2
18
import stat
3
19
import sys
4
20
 
5
21
import bzrlib
6
 
from bzrlib.add import smart_add_tree
7
 
from bzrlib.builtins import merge
 
22
from bzrlib import (
 
23
    generate_ids,
 
24
    merge_directive,
 
25
    osutils,
 
26
    )
8
27
from bzrlib.conflicts import ContentsConflict, TextConflict, PathConflict
 
28
from bzrlib import errors
9
29
from bzrlib.errors import (NotBranchError, NotVersionedError,
10
30
                           WorkingTreeNotRevision, BzrCommandError, NoDiff3)
11
 
import bzrlib.inventory as inventory
12
 
from bzrlib.merge import Merge3Merger, Diff3Merger, WeaveMerger
13
 
from bzrlib.osutils import (file_kind, getcwd, mkdtemp, pathjoin, rename, rmtree,
14
 
                            sha_file, 
 
31
from bzrlib import  inventory
 
32
from bzrlib.merge import (
 
33
    Merge3Merger,
 
34
    Diff3Merger,
 
35
    WeaveMerger,
 
36
    Merger,
 
37
    )
 
38
from bzrlib.osutils import (file_kind, getcwd, pathjoin, rename,
 
39
                            sha_file,
15
40
                            )
 
41
from bzrlib import progress
16
42
from bzrlib.transform import TreeTransform
17
43
from bzrlib.tests import TestCaseWithTransport, TestCase, TestSkipped
18
44
from bzrlib.workingtree import WorkingTree
20
46
 
21
47
class MergeBuilder(object):
22
48
    def __init__(self, dir=None):
23
 
        self.dir = mkdtemp(prefix="merge-test", dir=dir)
 
49
        self.dir = osutils.mkdtemp(prefix="merge-test", dir=dir)
 
50
        self.tree_root = generate_ids.gen_root_id()
24
51
        def wt(name):
25
52
           path = pathjoin(self.dir, name)
26
53
           os.mkdir(path)
27
54
           wt = bzrlib.bzrdir.BzrDir.create_standalone_workingtree(path)
28
55
           # the tests perform pulls, so need a branch that is writeable.
29
56
           wt.lock_write()
 
57
           wt.set_root_id(self.tree_root)
 
58
           wt.flush()
30
59
           tt = TreeTransform(wt)
31
60
           return wt, tt
32
61
        self.base, self.base_tt = wt('base')
35
64
 
36
65
    def get_cset_path(self, parent, name):
37
66
        if name is None:
38
 
            assert (parent is None)
 
67
            if parent is not None:
 
68
                raise AssertionError()
39
69
            return None
40
70
        return pathjoin(self.cset.entries[parent].path, name)
41
71
 
55
85
            # why does this not do wt.pull() ?
56
86
            wt.branch.pull(self.base.branch)
57
87
            wt.set_parent_ids([wt.branch.last_revision()])
 
88
            wt.flush()
 
89
            # We maintain a write lock, so make sure changes are flushed to
 
90
            # disk first
58
91
            tt.apply()
59
92
            wt.commit('branch commit')
60
 
            assert len(wt.branch.revision_history()) == 2
 
93
            wt.flush()
 
94
            if len(wt.branch.revision_history()) != 2:
 
95
                raise AssertionError()
61
96
        self.this.branch.fetch(self.other.branch)
62
97
        other_basis = self.other.branch.basis_tree()
63
98
        merger = merge_type(self.this, self.this, self.base, other_basis, 
164
199
            new_inventory[file_id] = path
165
200
        return new_inventory
166
201
 
167
 
    def cleanup(self):
 
202
    def unlock(self):
168
203
        self.base.unlock()
169
204
        self.this.unlock()
170
205
        self.other.unlock()
171
 
        rmtree(self.dir)
 
206
 
 
207
    def cleanup(self):
 
208
        self.unlock()
 
209
        osutils.rmtree(self.dir)
172
210
 
173
211
 
174
212
class MergeTest(TestCaseWithTransport):
176
214
    def test_change_name(self):
177
215
        """Test renames"""
178
216
        builder = MergeBuilder(getcwd())
179
 
        builder.add_file("1", "TREE_ROOT", "name1", "hello1", True)
 
217
        builder.add_file("1", builder.tree_root, "name1", "hello1", True)
180
218
        builder.change_name("1", other="name2")
181
 
        builder.add_file("2", "TREE_ROOT", "name3", "hello2", True)
 
219
        builder.add_file("2", builder.tree_root, "name3", "hello2", True)
182
220
        builder.change_name("2", base="name4")
183
 
        builder.add_file("3", "TREE_ROOT", "name5", "hello3", True)
 
221
        builder.add_file("3", builder.tree_root, "name5", "hello3", True)
184
222
        builder.change_name("3", this="name6")
185
223
        builder.merge()
186
224
        builder.cleanup()
187
225
        builder = MergeBuilder(getcwd())
188
 
        builder.add_file("1", "TREE_ROOT", "name1", "hello1", False)
 
226
        builder.add_file("1", builder.tree_root, "name1", "hello1", False)
189
227
        builder.change_name("1", other="name2", this="name3")
190
228
        conflicts = builder.merge()
191
229
        self.assertEqual(conflicts, [PathConflict('name3', 'name2', '1')])
193
231
 
194
232
    def test_merge_one(self):
195
233
        builder = MergeBuilder(getcwd())
196
 
        builder.add_file("1", "TREE_ROOT", "name1", "hello1", True)
 
234
        builder.add_file("1", builder.tree_root, "name1", "hello1", True)
197
235
        builder.change_contents("1", other="text4")
198
 
        builder.add_file("2", "TREE_ROOT", "name2", "hello1", True)
 
236
        builder.add_file("2", builder.tree_root, "name2", "hello1", True)
199
237
        builder.change_contents("2", other="text4")
200
238
        builder.merge(interesting_ids=["1"])
201
239
        self.assertEqual(builder.this.get_file("1").read(), "text4" )
205
243
    def test_file_moves(self):
206
244
        """Test moves"""
207
245
        builder = MergeBuilder(getcwd())
208
 
        builder.add_dir("1", "TREE_ROOT", "dir1")
209
 
        builder.add_dir("2", "TREE_ROOT", "dir2")
 
246
        builder.add_dir("1", builder.tree_root, "dir1")
 
247
        builder.add_dir("2", builder.tree_root, "dir2")
210
248
        builder.add_file("3", "1", "file1", "hello1", True)
211
249
        builder.add_file("4", "1", "file2", "hello2", True)
212
250
        builder.add_file("5", "1", "file3", "hello3", True)
217
255
        builder.cleanup()
218
256
 
219
257
        builder = MergeBuilder(getcwd())
220
 
        builder.add_dir("1", "TREE_ROOT", "dir1")
221
 
        builder.add_dir("2", "TREE_ROOT", "dir2")
222
 
        builder.add_dir("3", "TREE_ROOT", "dir3")
 
258
        builder.add_dir("1", builder.tree_root, "dir1")
 
259
        builder.add_dir("2", builder.tree_root, "dir2")
 
260
        builder.add_dir("3", builder.tree_root, "dir3")
223
261
        builder.add_file("4", "1", "file1", "hello1", False)
224
262
        builder.change_parent("4", other="2", this="3")
225
263
        conflicts = builder.merge()
234
272
 
235
273
    def test_contents_merge2(self):
236
274
        """Test diff3 merging"""
 
275
        if sys.platform == 'win32':
 
276
            raise TestSkipped("diff3 does not have --binary flag"
 
277
                              " and therefore always fails on win32")
237
278
        try:
238
279
            self.do_contents_test(Diff3Merger)
239
280
        except NoDiff3:
246
287
    def test_reprocess_weave(self):
247
288
        # Reprocess works on weaves, and behaves as expected
248
289
        builder = MergeBuilder(getcwd())
249
 
        builder.add_file('a', 'TREE_ROOT', 'blah', 'a', False)
 
290
        builder.add_file('a', builder.tree_root, 'blah', 'a', False)
250
291
        builder.change_contents('a', this='b\nc\nd\ne\n', other='z\nc\nd\ny\n')
251
292
        builder.merge(WeaveMerger, reprocess=True)
252
293
        expected = """<<<<<<< TREE
273
314
 
274
315
    def contents_test_success(self, merge_factory):
275
316
        builder = MergeBuilder(getcwd())
276
 
        builder.add_file("1", "TREE_ROOT", "name1", "text1", True)
 
317
        builder.add_file("1", builder.tree_root, "name1", "text1", True)
277
318
        builder.change_contents("1", other="text4")
278
 
        builder.add_file("2", "TREE_ROOT", "name3", "text2", False)
 
319
        builder.add_file("2", builder.tree_root, "name3", "text2", False)
279
320
        builder.change_contents("2", base="text5")
280
 
        builder.add_file("3", "TREE_ROOT", "name5", "text3", True)
281
 
        builder.add_file("4", "TREE_ROOT", "name6", "text4", True)
 
321
        builder.add_file("3", builder.tree_root, "name5", "text3", True)
 
322
        builder.add_file("4", builder.tree_root, "name6", "text4", True)
282
323
        builder.remove_file("4", base=True)
283
 
        builder.add_file("5", "TREE_ROOT", "name7", "a\nb\nc\nd\ne\nf\n", True)
 
324
        builder.add_file("5", builder.tree_root, "name7", "a\nb\nc\nd\ne\nf\n",
 
325
                         True)
284
326
        builder.change_contents("5", other="a\nz\nc\nd\ne\nf\n", 
285
327
                                     this="a\nb\nc\nd\ne\nz\n")
286
 
        builder.merge(merge_factory)
287
 
        self.assertEqual(builder.this.get_file("1").read(), "text4" )
288
 
        self.assertEqual(builder.this.get_file("2").read(), "text2" )
289
 
        self.assertEqual(builder.this.get_file("5").read(), 
290
 
                         "a\nz\nc\nd\ne\nz\n")
291
 
        self.assertIs(builder.this.is_executable("1"), True)
292
 
        self.assertIs(builder.this.is_executable("2"), False)
293
 
        self.assertIs(builder.this.is_executable("3"), True)
 
328
        conflicts = builder.merge(merge_factory)
 
329
        try:
 
330
            self.assertEqual([], conflicts)
 
331
            self.assertEqual("text4", builder.this.get_file("1").read())
 
332
            self.assertEqual("text2", builder.this.get_file("2").read())
 
333
            self.assertEqual("a\nz\nc\nd\ne\nz\n", 
 
334
                             builder.this.get_file("5").read())
 
335
            self.assertTrue(builder.this.is_executable("1"))
 
336
            self.assertFalse(builder.this.is_executable("2"))
 
337
            self.assertTrue(builder.this.is_executable("3"))
 
338
        except:
 
339
            builder.unlock()
 
340
            raise
294
341
        return builder
295
342
 
296
343
    def contents_test_conflicts(self, merge_factory):
297
344
        builder = MergeBuilder(getcwd())
298
 
        builder.add_file("1", "TREE_ROOT", "name1", "text1", True)
 
345
        builder.add_file("1", builder.tree_root, "name1", "text1", True)
299
346
        builder.change_contents("1", other="text4", this="text3")
300
 
        builder.add_file("2", "TREE_ROOT", "name2", "text1", True)
 
347
        builder.add_file("2", builder.tree_root, "name2", "text1", True)
301
348
        builder.change_contents("2", other="\x00", this="text3")
302
 
        builder.add_file("3", "TREE_ROOT", "name3", "text5", False)
 
349
        builder.add_file("3", builder.tree_root, "name3", "text5", False)
303
350
        builder.change_perms("3", this=True)
304
351
        builder.change_contents('3', this='moretext')
305
352
        builder.remove_file('3', other=True)
313
360
    def test_symlink_conflicts(self):
314
361
        if sys.platform != "win32":
315
362
            builder = MergeBuilder(getcwd())
316
 
            builder.add_symlink("2", "TREE_ROOT", "name2", "target1")
 
363
            builder.add_symlink("2", builder.tree_root, "name2", "target1")
317
364
            builder.change_target("2", other="target4", base="text3")
318
365
            conflicts = builder.merge()
319
366
            self.assertEqual(conflicts, [ContentsConflict('name2', 
323
370
    def test_symlink_merge(self):
324
371
        if sys.platform != "win32":
325
372
            builder = MergeBuilder(getcwd())
326
 
            builder.add_symlink("1", "TREE_ROOT", "name1", "target1")
327
 
            builder.add_symlink("2", "TREE_ROOT", "name2", "target1")
328
 
            builder.add_symlink("3", "TREE_ROOT", "name3", "target1")
 
373
            builder.add_symlink("1", builder.tree_root, "name1", "target1")
 
374
            builder.add_symlink("2", builder.tree_root, "name2", "target1")
 
375
            builder.add_symlink("3", builder.tree_root, "name3", "target1")
329
376
            builder.change_target("1", this="target2")
330
377
            builder.change_target("2", base="target2")
331
378
            builder.change_target("3", other="target2")
337
384
 
338
385
    def test_no_passive_add(self):
339
386
        builder = MergeBuilder(getcwd())
340
 
        builder.add_file("1", "TREE_ROOT", "name1", "text1", True)
 
387
        builder.add_file("1", builder.tree_root, "name1", "text1", True)
341
388
        builder.remove_file("1", this=True)
342
389
        builder.merge()
343
390
        builder.cleanup()
344
391
 
345
392
    def test_perms_merge(self):
346
393
        builder = MergeBuilder(getcwd())
347
 
        builder.add_file("1", "TREE_ROOT", "name1", "text1", True)
 
394
        builder.add_file("1", builder.tree_root, "name1", "text1", True)
348
395
        builder.change_perms("1", other=False)
349
 
        builder.add_file("2", "TREE_ROOT", "name2", "text2", True)
 
396
        builder.add_file("2", builder.tree_root, "name2", "text2", True)
350
397
        builder.change_perms("2", base=False)
351
 
        builder.add_file("3", "TREE_ROOT", "name3", "text3", True)
 
398
        builder.add_file("3", builder.tree_root, "name3", "text3", True)
352
399
        builder.change_perms("3", this=False)
353
 
        builder.add_file('4', 'TREE_ROOT', 'name4', 'text4', False)
 
400
        builder.add_file('4', builder.tree_root, 'name4', 'text4', False)
354
401
        builder.change_perms('4', this=True)
355
402
        builder.remove_file('4', base=True)
356
403
        builder.merge()
361
408
 
362
409
    def test_new_suffix(self):
363
410
        builder = MergeBuilder(getcwd())
364
 
        builder.add_file("1", "TREE_ROOT", "name1", "text1", True)
 
411
        builder.add_file("1", builder.tree_root, "name1", "text1", True)
365
412
        builder.change_contents("1", other="text3")
366
 
        builder.add_file("2", "TREE_ROOT", "name1.new", "text2", True)
 
413
        builder.add_file("2", builder.tree_root, "name1.new", "text2", True)
367
414
        builder.merge()
368
415
        os.lstat(builder.this.id2abspath("2"))
369
416
        builder.cleanup()
370
417
 
371
418
    def test_spurious_conflict(self):
372
419
        builder = MergeBuilder(getcwd())
373
 
        builder.add_file("1", "TREE_ROOT", "name1", "text1", False)
 
420
        builder.add_file("1", builder.tree_root, "name1", "text1", False)
374
421
        builder.remove_file("1", other=True)
375
 
        builder.add_file("2", "TREE_ROOT", "name1", "text1", False, this=False, 
376
 
                         base=False)
 
422
        builder.add_file("2", builder.tree_root, "name1", "text1", False, 
 
423
                         this=False, base=False)
377
424
        conflicts = builder.merge()
378
425
        self.assertEqual(conflicts, []) 
379
426
        builder.cleanup()
380
427
 
 
428
    def test_merge_one_renamed(self):
 
429
        builder = MergeBuilder(getcwd())
 
430
        builder.add_file('1', builder.tree_root, 'name1', 'text1a', False)
 
431
        builder.change_name('1', this='name2')
 
432
        builder.change_contents('1', other='text2')
 
433
        builder.merge(interesting_files=['name2'])
 
434
        self.assertEqual('text2', builder.this.get_file('1').read())
 
435
        builder.cleanup()
381
436
 
382
437
class FunctionalMergeTest(TestCaseWithTransport):
383
438
 
387
442
        self.build_tree(("original/", "original/file1", "original/file2"))
388
443
        tree = self.make_branch_and_tree('original')
389
444
        branch = tree.branch
390
 
        smart_add_tree(tree, ["original"])
 
445
        tree.smart_add(["original"])
391
446
        tree.commit("start branch.", verbose=False)
392
447
        # Mary branches it.
393
448
        self.build_tree(("mary/",))
405
460
        file.close()
406
461
        mary_tree.commit("change file2")
407
462
        # john should be able to merge with no conflicts.
408
 
        merge_type = Merge3Merger
409
463
        base = [None, None]
410
464
        other = ("mary", -1)
411
 
        self.assertRaises(BzrCommandError, merge, other, base, check_clean=True,
412
 
                          merge_type=WeaveMerger, this_dir="original",
413
 
                          show_base=True)
414
 
        merge(other, base, check_clean=True, merge_type=merge_type,
415
 
              this_dir="original")
 
465
        tree.merge_from_branch(mary_tree.branch)
416
466
        self.assertEqual("John\n", open("original/file1", "rt").read())
417
467
        self.assertEqual("Mary\n", open("original/file2", "rt").read())
418
468
 
430
480
        file('b/file', 'wb').write('this contents contents\n')
431
481
        wtb = d_b.open_workingtree()
432
482
        wtb.commit('this revision', allow_pointless=False)
433
 
        self.assertEqual(merge(['a', -1], [None, None], this_dir='b'), 1)
 
483
        self.assertEqual(1, wtb.merge_from_branch(wta.branch))
434
484
        self.assert_(os.path.lexists('b/file.THIS'))
435
485
        self.assert_(os.path.lexists('b/file.BASE'))
436
486
        self.assert_(os.path.lexists('b/file.OTHER'))
437
 
        self.assertRaises(WorkingTreeNotRevision, merge, ['a', -1], 
438
 
                          [None, None], this_dir='b', check_clean=False,
439
 
                          merge_type=WeaveMerger)
440
 
        wtb.revert([])
441
 
        self.assertEqual(merge(['a', -1], [None, None], this_dir='b', 
442
 
                               check_clean=False, merge_type=WeaveMerger), 1)
 
487
        wtb.revert()
 
488
        self.assertEqual(1, wtb.merge_from_branch(wta.branch,
 
489
                                                  merge_type=WeaveMerger))
443
490
        self.assert_(os.path.lexists('b/file'))
444
491
        self.assert_(os.path.lexists('b/file.THIS'))
445
492
        self.assert_(not os.path.lexists('b/file.BASE'))
457
504
        file('b/b_file', 'wb').write('contents\n')
458
505
        wtb.add('b_file')
459
506
        b_rev = wtb.commit('b_revision', allow_pointless=False)
460
 
        merge(['b', -1], ['b', 0], this_dir='a')
 
507
        wta.merge_from_branch(wtb.branch, b_rev, 'null:')
461
508
        self.assert_(os.path.lexists('a/b_file'))
462
509
        self.assertEqual([b_rev], wta.get_parent_ids()[1:])
463
510
 
473
520
        file('b/file', 'wb').write('contents\n')
474
521
        wtb.add('file')
475
522
        b_rev = wtb.commit('b_revision', allow_pointless=False)
476
 
        merge(['b', -1], ['b', 0], this_dir='a')
 
523
        wta.merge_from_branch(wtb.branch, b_rev, 'null:')
477
524
        self.assert_(os.path.lexists('a/file'))
478
525
        self.assert_(os.path.lexists('a/file.moved'))
479
526
        self.assertEqual([b_rev], wta.get_parent_ids()[1:])
483
530
        file('a/file', 'wb').write('contents\n')
484
531
        wta.add('file')
485
532
        wta.commit('a_revision', allow_pointless=False)
486
 
        self.run_bzr('branch', 'a', 'b')
 
533
        self.run_bzr('branch a b')
487
534
        os.remove('a/file')
488
535
        wta.commit('removed file', allow_pointless=False)
489
536
        file('b/file', 'wb').write('changed contents\n')
490
537
        wtb = WorkingTree.open('b')
491
538
        wtb.commit('changed file', allow_pointless=False)
492
 
        merge(['a', -1], ['a', 1], this_dir='b')
 
539
        wtb.merge_from_branch(wta.branch, wta.branch.last_revision(),
 
540
                              wta.branch.get_rev_id(1))
493
541
        self.failIf(os.path.lexists('b/file'))
494
542
 
495
543
    def test_merge_metadata_vs_deletion(self):
498
546
        file('a/file', 'wb').write('contents\n')
499
547
        a_wt.add('file')
500
548
        a_wt.commit('r0')
501
 
        self.run_bzr('branch', 'a', 'b')
 
549
        self.run_bzr('branch a b')
502
550
        b_wt = WorkingTree.open('b')
503
551
        os.chmod('b/file', 0755)
504
552
        os.remove('a/file')
506
554
        self.assertEqual(a_wt.branch.revno(), 2)
507
555
        self.assertFalse(os.path.exists('a/file'))
508
556
        b_wt.commit('exec a')
509
 
        merge(['b', -1], ['b', 0], this_dir='a')
 
557
        a_wt.merge_from_branch(b_wt.branch, b_wt.last_revision(), 'null:')
510
558
        self.assert_(os.path.exists('a/file'))
511
559
 
512
560
    def test_merge_swapping_renames(self):
513
561
        a_wt = self.make_branch_and_tree('a')
514
562
        file('a/un','wb').write('UN')
515
563
        file('a/deux','wb').write('DEUX')
516
 
        a_wt.add('un', 'un')
517
 
        a_wt.add('deux', 'deux')
 
564
        a_wt.add('un', 'un-id')
 
565
        a_wt.add('deux', 'deux-id')
518
566
        a_wt.commit('r0', rev_id='r0')
519
 
        self.run_bzr('branch', 'a', 'b')
 
567
        self.run_bzr('branch a b')
520
568
        b_wt = WorkingTree.open('b')
521
569
        b_wt.rename_one('un','tmp')
522
570
        b_wt.rename_one('deux','un')
523
571
        b_wt.rename_one('tmp','deux')
524
572
        b_wt.commit('r1', rev_id='r1')
525
 
        self.assertEqual(0, merge(['b', -1], ['b', 1], this_dir='a'))
 
573
        self.assertEqual(0, a_wt.merge_from_branch(b_wt.branch,
 
574
            b_wt.branch.last_revision(), b_wt.branch.get_rev_id(1)))
526
575
        self.failUnlessExists('a/un')
527
576
        self.failUnless('a/deux')
528
577
        self.assertFalse(os.path.exists('a/tmp'))
534
583
        file('a/file', 'wb').write('THIS')
535
584
        a_wt.add('file')
536
585
        a_wt.commit('r0')
537
 
        self.run_bzr('branch', 'a', 'b')
 
586
        self.run_bzr('branch a b')
538
587
        b_wt = WorkingTree.open('b')
539
588
        os.remove('b/file')
540
589
        b_wt.commit('r1')
541
590
        file('b/file', 'wb').write('THAT')
542
591
        b_wt.add('file')
543
592
        b_wt.commit('r2')
544
 
        merge(['b', -1],['b', 1],this_dir='a')
 
593
        a_wt.merge_from_branch(b_wt.branch, b_wt.branch.last_revision(),
 
594
                               b_wt.branch.get_rev_id(1))
545
595
        self.assert_(os.path.exists('a/file'))
546
596
        self.assertEqual(file('a/file').read(),'THAT')
547
597
 
563
613
        file('a/foo', 'wb').write('A/FOO')
564
614
        a_wt.add('foo')
565
615
        a_wt.commit('added foo')
566
 
        self.run_bzr('branch', 'a', 'b')
 
616
        self.run_bzr('branch a b')
567
617
        b_wt = WorkingTree.open('b')
568
618
        b_wt.rename_one('foo', 'bar')
569
619
        file('b/foo', 'wb').write('B/FOO')
570
620
        b_wt.add('foo')
571
621
        b_wt.commit('moved foo to bar, added new foo')
572
 
        merge(['b', -1],['b', 1],this_dir='a')
 
622
        a_wt.merge_from_branch(b_wt.branch, b_wt.branch.last_revision(),
 
623
                               b_wt.branch.get_rev_id(1))
573
624
 
574
625
    def test_merge_create_before_rename(self):
575
626
        """create before rename, target parents before children
591
642
        file('a/foo', 'wb').write('A/FOO')
592
643
        a_wt.add('foo')
593
644
        a_wt.commit('added foo')
594
 
        self.run_bzr('branch', 'a', 'b')
 
645
        self.run_bzr('branch a b')
595
646
        b_wt = WorkingTree.open('b')
596
647
        os.mkdir('b/bar')
597
648
        b_wt.add('bar')
598
649
        b_wt.rename_one('foo', 'bar/foo')
599
650
        b_wt.commit('created bar dir, moved foo into bar')
600
 
        merge(['b', -1],['b', 1],this_dir='a')
 
651
        a_wt.merge_from_branch(b_wt.branch, b_wt.branch.last_revision(),
 
652
                               b_wt.branch.get_rev_id(1))
601
653
 
602
654
    def test_merge_rename_to_temp_before_delete(self):
603
655
        """rename to temp before delete, source children before parents
620
672
        a_wt.add('foo')
621
673
        a_wt.add('foo/bar')
622
674
        a_wt.commit('added foo/bar')
623
 
        self.run_bzr('branch', 'a', 'b')
 
675
        self.run_bzr('branch a b')
624
676
        b_wt = WorkingTree.open('b')
625
677
        b_wt.rename_one('foo/bar', 'bar')
626
678
        os.rmdir('b/foo')
627
679
        b_wt.remove('foo')
628
680
        b_wt.commit('moved foo/bar to bar, deleted foo')
629
 
        merge(['b', -1],['b', 1],this_dir='a')
 
681
        a_wt.merge_from_branch(b_wt.branch, b_wt.branch.last_revision(),
 
682
                               b_wt.branch.get_rev_id(1))
630
683
 
631
684
    def test_merge_delete_before_rename_to_temp(self):
632
685
        """delete before rename to temp
649
702
        a_wt.add('foo')
650
703
        a_wt.add('bar')
651
704
        a_wt.commit('added foo and bar')
652
 
        self.run_bzr('branch', 'a', 'b')
 
705
        self.run_bzr('branch a b')
653
706
        b_wt = WorkingTree.open('b')
654
707
        os.unlink('b/foo')
655
708
        b_wt.remove('foo')
656
709
        b_wt.rename_one('bar', 'foo')
657
710
        b_wt.commit('deleted foo, renamed bar to foo')
658
 
        merge(['b', -1],['b', 1],this_dir='a')
659
 
 
 
711
        a_wt.merge_from_branch(b_wt.branch, b_wt.branch.last_revision(),
 
712
                               b_wt.branch.get_rev_id(1))
 
713
 
 
714
 
 
715
class TestMerger(TestCaseWithTransport):
 
716
 
 
717
    def set_up_trees(self):
 
718
        this = self.make_branch_and_tree('this')
 
719
        this.commit('rev1', rev_id='rev1')
 
720
        other = this.bzrdir.sprout('other').open_workingtree()
 
721
        this.commit('rev2a', rev_id='rev2a')
 
722
        other.commit('rev2b', rev_id='rev2b')
 
723
        return this, other
 
724
 
 
725
    def test_from_revision_ids(self):
 
726
        this, other = self.set_up_trees()
 
727
        self.assertRaises(errors.NoSuchRevision, Merger.from_revision_ids,
 
728
                          progress.DummyProgress(), this, 'rev2b')
 
729
        this.lock_write()
 
730
        self.addCleanup(this.unlock)
 
731
        merger = Merger.from_revision_ids(progress.DummyProgress(), this,
 
732
            'rev2b', other_branch=other.branch)
 
733
        self.assertEqual('rev2b', merger.other_rev_id)
 
734
        self.assertEqual('rev1', merger.base_rev_id)
 
735
        merger = Merger.from_revision_ids(progress.DummyProgress(), this,
 
736
            'rev2b', 'rev2a', other_branch=other.branch)
 
737
        self.assertEqual('rev2a', merger.base_rev_id)
 
738
 
 
739
    def test_from_uncommitted(self):
 
740
        this, other = self.set_up_trees()
 
741
        merger = Merger.from_uncommitted(this, other, progress.DummyProgress())
 
742
        self.assertIs(other, merger.other_tree)
 
743
        self.assertIs(None, merger.other_rev_id)
 
744
        self.assertEqual('rev2b', merger.base_rev_id)
 
745
 
 
746
    def prepare_for_merging(self):
 
747
        this, other = self.set_up_trees()
 
748
        other.commit('rev3', rev_id='rev3')
 
749
        this.lock_write()
 
750
        self.addCleanup(this.unlock)
 
751
        return this, other
 
752
 
 
753
    def test_from_mergeable(self):
 
754
        this, other = self.prepare_for_merging()
 
755
        md = merge_directive.MergeDirective2.from_objects(
 
756
            other.branch.repository, 'rev3', 0, 0, 'this')
 
757
        other.lock_read()
 
758
        self.addCleanup(other.unlock)
 
759
        merger, verified = Merger.from_mergeable(this, md,
 
760
            progress.DummyProgress())
 
761
        md.patch = None
 
762
        merger, verified = Merger.from_mergeable(this, md,
 
763
            progress.DummyProgress())
 
764
        self.assertEqual('inapplicable', verified)
 
765
        self.assertEqual('rev3', merger.other_rev_id)
 
766
        self.assertEqual('rev1', merger.base_rev_id)
 
767
        md.base_revision_id = 'rev2b'
 
768
        merger, verified = Merger.from_mergeable(this, md,
 
769
            progress.DummyProgress())
 
770
        self.assertEqual('rev2b', merger.base_rev_id)
 
771
 
 
772
    def test_from_mergeable_old_merge_directive(self):
 
773
        this, other = self.prepare_for_merging()
 
774
        other.lock_write()
 
775
        self.addCleanup(other.unlock)
 
776
        md = merge_directive.MergeDirective.from_objects(
 
777
            other.branch.repository, 'rev3', 0, 0, 'this')
 
778
        merger, verified = Merger.from_mergeable(this, md,
 
779
            progress.DummyProgress())
 
780
        self.assertEqual('rev3', merger.other_rev_id)
 
781
        self.assertEqual('rev1', merger.base_rev_id)