~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_conflicts.py

  • Committer: Andrew Bennetts
  • Date: 2010-03-11 04:33:41 UTC
  • mfrom: (4797.33.4 2.1)
  • mto: This revision was merged to the branch mainline in revision 5082.
  • Revision ID: andrew.bennetts@canonical.com-20100311043341-rzdik83fnactjsxs
Merge lp:bzr/2.1, including fixes for #496813, #526211, #526353.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
18
import os
19
19
 
20
 
from bzrlib import bzrdir
21
 
from bzrlib.tests import TestCaseWithTransport, TestCase
22
 
from bzrlib.branch import Branch
23
 
from bzrlib.conflicts import (
24
 
    ConflictList,
25
 
    ContentsConflict,
26
 
    DuplicateID,
27
 
    DuplicateEntry,
28
 
    MissingParent,
29
 
    NonDirectoryParent,
30
 
    ParentLoop,
31
 
    PathConflict,
32
 
    TextConflict,
33
 
    UnversionedParent,
34
 
    resolve,
35
 
    restore,
 
20
from bzrlib import (
 
21
    branchbuilder,
 
22
    bzrdir,
 
23
    conflicts,
 
24
    errors,
 
25
    option,
 
26
    tests,
 
27
    workingtree,
36
28
    )
37
 
from bzrlib.errors import NotConflicted
 
29
from bzrlib.tests import script
 
30
 
 
31
 
 
32
def load_tests(standard_tests, module, loader):
 
33
    result = loader.suiteClass()
 
34
 
 
35
    sp_tests, remaining_tests = tests.split_suite_by_condition(
 
36
        standard_tests, tests.condition_isinstance((
 
37
                TestResolveContentConflicts,
 
38
                )))
 
39
    tests.multiply_tests(sp_tests, content_conflict_scenarios(), result)
 
40
 
 
41
    # No parametrization for the remaining tests
 
42
    result.addTests(remaining_tests)
 
43
 
 
44
    return result
38
45
 
39
46
 
40
47
# TODO: Test commit with some added, and added-but-missing files
44
51
# be a sorted list.
45
52
# u'\xe5' == a with circle
46
53
# '\xc3\xae' == u'\xee' == i with hat
47
 
# So these are u'pathg' and 'idg' only with a circle and a hat. (shappo?)
48
 
example_conflicts = ConflictList([ 
49
 
    MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
50
 
    ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'), 
51
 
    TextConflict(u'p\xe5tha'),
52
 
    PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
53
 
    DuplicateID('Unversioned existing file', u'p\xe5thc', u'p\xe5thc2',
54
 
                '\xc3\xaedc', '\xc3\xaedc'),
55
 
    DuplicateEntry('Moved existing file to',  u'p\xe5thdd.moved', u'p\xe5thd',
56
 
                   '\xc3\xaedd', None),
57
 
    ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
58
 
               None, '\xc3\xaed2e'),
59
 
    UnversionedParent('Versioned directory', u'p\xe5thf', '\xc3\xaedf'),
60
 
    NonDirectoryParent('Created directory', u'p\xe5thg', '\xc3\xaedg'),
 
54
# So these are u'path' and 'id' only with a circle and a hat. (shappo?)
 
55
example_conflicts = conflicts.ConflictList(
 
56
    [conflicts.MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
 
57
     conflicts.ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
 
58
     conflicts.TextConflict(u'p\xe5tha'),
 
59
     conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
 
60
     conflicts.DuplicateID('Unversioned existing file',
 
61
                           u'p\xe5thc', u'p\xe5thc2',
 
62
                           '\xc3\xaedc', '\xc3\xaedc'),
 
63
    conflicts.DuplicateEntry('Moved existing file to',
 
64
                             u'p\xe5thdd.moved', u'p\xe5thd',
 
65
                             '\xc3\xaedd', None),
 
66
    conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
 
67
                         None, '\xc3\xaed2e'),
 
68
    conflicts.UnversionedParent('Versioned directory',
 
69
                                u'p\xe5thf', '\xc3\xaedf'),
 
70
    conflicts.NonDirectoryParent('Created directory',
 
71
                                 u'p\xe5thg', '\xc3\xaedg'),
61
72
])
62
73
 
63
74
 
64
 
class TestConflicts(TestCaseWithTransport):
 
75
class TestConflicts(tests.TestCaseWithTransport):
65
76
 
66
77
    def test_conflicts(self):
67
78
        """Conflicts are detected properly"""
68
 
        tree = self.make_branch_and_tree('.',
69
 
            format=bzrdir.BzrDirFormat6())
70
 
        b = tree.branch
71
 
        file('hello', 'w').write('hello world4')
72
 
        file('hello.THIS', 'w').write('hello world2')
73
 
        file('hello.BASE', 'w').write('hello world1')
74
 
        file('hello.OTHER', 'w').write('hello world3')
75
 
        file('hello.sploo.BASE', 'w').write('yellow world')
76
 
        file('hello.sploo.OTHER', 'w').write('yellow world2')
 
79
        # Use BzrDirFormat6 so we can fake conflicts
 
80
        tree = self.make_branch_and_tree('.', format=bzrdir.BzrDirFormat6())
 
81
        self.build_tree_contents([('hello', 'hello world4'),
 
82
                                  ('hello.THIS', 'hello world2'),
 
83
                                  ('hello.BASE', 'hello world1'),
 
84
                                  ('hello.OTHER', 'hello world3'),
 
85
                                  ('hello.sploo.BASE', 'yellowworld'),
 
86
                                  ('hello.sploo.OTHER', 'yellowworld2'),
 
87
                                  ])
77
88
        tree.lock_read()
78
 
        self.assertEqual(len(list(tree.list_files())), 6)
 
89
        self.assertLength(6, list(tree.list_files()))
79
90
        tree.unlock()
80
 
        conflicts = tree.conflicts()
81
 
        self.assertEqual(len(conflicts), 2)
82
 
        self.assert_('hello' in conflicts[0].path)
83
 
        self.assert_('hello.sploo' in conflicts[1].path)
84
 
        restore('hello')
85
 
        restore('hello.sploo')
86
 
        self.assertEqual(len(tree.conflicts()), 0)
 
91
        tree_conflicts = tree.conflicts()
 
92
        self.assertLength(2, tree_conflicts)
 
93
        self.assertTrue('hello' in tree_conflicts[0].path)
 
94
        self.assertTrue('hello.sploo' in tree_conflicts[1].path)
 
95
        conflicts.restore('hello')
 
96
        conflicts.restore('hello.sploo')
 
97
        self.assertLength(0, tree.conflicts())
87
98
        self.assertFileEqual('hello world2', 'hello')
88
99
        self.assertFalse(os.path.lexists('hello.sploo'))
89
 
        self.assertRaises(NotConflicted, restore, 'hello')
90
 
        self.assertRaises(NotConflicted, restore, 'hello.sploo')
 
100
        self.assertRaises(errors.NotConflicted, conflicts.restore, 'hello')
 
101
        self.assertRaises(errors.NotConflicted,
 
102
                          conflicts.restore, 'hello.sploo')
91
103
 
92
104
    def test_resolve_conflict_dir(self):
93
105
        tree = self.make_branch_and_tree('.')
94
 
        b = tree.branch
95
 
        file('hello', 'w').write('hello world4')
 
106
        self.build_tree_contents([('hello', 'hello world4'),
 
107
                                  ('hello.THIS', 'hello world2'),
 
108
                                  ('hello.BASE', 'hello world1'),
 
109
                                  ])
 
110
        os.mkdir('hello.OTHER')
96
111
        tree.add('hello', 'q')
97
 
        file('hello.THIS', 'w').write('hello world2')
98
 
        file('hello.BASE', 'w').write('hello world1')
99
 
        os.mkdir('hello.OTHER')
100
 
        l = ConflictList([TextConflict('hello')])
 
112
        l = conflicts.ConflictList([conflicts.TextConflict('hello')])
101
113
        l.remove_files(tree)
102
114
 
103
115
    def test_select_conflicts(self):
104
116
        tree = self.make_branch_and_tree('.')
105
 
        tree_conflicts = ConflictList([ContentsConflict('foo'),
106
 
                                       ContentsConflict('bar')])
107
 
        self.assertEqual((ConflictList([ContentsConflict('bar')]),
108
 
                          ConflictList([ContentsConflict('foo')])),
109
 
                         tree_conflicts.select_conflicts(tree, ['foo']))
110
 
        self.assertEqual((ConflictList(), tree_conflicts),
111
 
                         tree_conflicts.select_conflicts(tree, [''],
112
 
                         ignore_misses=True, recurse=True))
113
 
        tree_conflicts = ConflictList([ContentsConflict('foo/baz'),
114
 
                                       ContentsConflict('bar')])
115
 
        self.assertEqual((ConflictList([ContentsConflict('bar')]),
116
 
                          ConflictList([ContentsConflict('foo/baz')])),
117
 
                         tree_conflicts.select_conflicts(tree, ['foo'],
118
 
                                                         recurse=True,
119
 
                                                         ignore_misses=True))
120
 
        tree_conflicts = ConflictList([PathConflict('qux', 'foo/baz')])
121
 
        self.assertEqual((ConflictList(), tree_conflicts),
122
 
                         tree_conflicts.select_conflicts(tree, ['foo'],
123
 
                                                         recurse=True,
124
 
                                                         ignore_misses=True))
125
 
        self.assertEqual((tree_conflicts, ConflictList()),
126
 
                         tree_conflicts.select_conflicts(tree, ['foo'],
127
 
                                                         ignore_misses=True))
 
117
        clist = conflicts.ConflictList
 
118
 
 
119
        def check_select(not_selected, selected, paths, **kwargs):
 
120
            self.assertEqual(
 
121
                (not_selected, selected),
 
122
                tree_conflicts.select_conflicts(tree, paths, **kwargs))
 
123
 
 
124
        foo = conflicts.ContentsConflict('foo')
 
125
        bar = conflicts.ContentsConflict('bar')
 
126
        tree_conflicts = clist([foo, bar])
 
127
 
 
128
        check_select(clist([bar]), clist([foo]), ['foo'])
 
129
        check_select(clist(), tree_conflicts,
 
130
                     [''], ignore_misses=True, recurse=True)
 
131
 
 
132
        foobaz  = conflicts.ContentsConflict('foo/baz')
 
133
        tree_conflicts = clist([foobaz, bar])
 
134
 
 
135
        check_select(clist([bar]), clist([foobaz]),
 
136
                     ['foo'], ignore_misses=True, recurse=True)
 
137
 
 
138
        qux = conflicts.PathConflict('qux', 'foo/baz')
 
139
        tree_conflicts = clist([qux])
 
140
 
 
141
        check_select(clist(), tree_conflicts,
 
142
                     ['foo'], ignore_misses=True, recurse=True)
 
143
        check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
128
144
 
129
145
    def test_resolve_conflicts_recursive(self):
130
146
        tree = self.make_branch_and_tree('.')
131
147
        self.build_tree(['dir/', 'dir/hello'])
132
148
        tree.add(['dir', 'dir/hello'])
133
 
        tree.set_conflicts(ConflictList([TextConflict('dir/hello')]))
134
 
        resolve(tree, ['dir'], recursive=False, ignore_misses=True)
135
 
        self.assertEqual(ConflictList([TextConflict('dir/hello')]),
136
 
                         tree.conflicts())
137
 
        resolve(tree, ['dir'], recursive=True, ignore_misses=True)
138
 
        self.assertEqual(ConflictList([]),
139
 
                         tree.conflicts())
140
 
 
141
 
 
142
 
class TestConflictStanzas(TestCase):
 
149
 
 
150
        dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
 
151
        tree.set_conflicts(dirhello)
 
152
 
 
153
        conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
 
154
        self.assertEqual(dirhello, tree.conflicts())
 
155
 
 
156
        conflicts.resolve(tree, ['dir'], recursive=True, ignore_misses=True)
 
157
        self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
 
158
 
 
159
 
 
160
class TestConflictStanzas(tests.TestCase):
143
161
 
144
162
    def test_stanza_roundtrip(self):
145
163
        # write and read our example stanza.
146
164
        stanza_iter = example_conflicts.to_stanzas()
147
 
        processed = ConflictList.from_stanzas(stanza_iter)
 
165
        processed = conflicts.ConflictList.from_stanzas(stanza_iter)
148
166
        for o, p in zip(processed, example_conflicts):
149
167
            self.assertEqual(o, p)
150
168
 
171
189
                self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
172
190
            if 'conflict_file_id' in stanza:
173
191
                self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
 
192
 
 
193
 
 
194
# FIXME: The shell-like tests should be converted to real whitebox tests... or
 
195
# moved to a blackbox module -- vila 20100205
 
196
 
 
197
# FIXME: Tests missing for DuplicateID conflict type
 
198
class TestResolveConflicts(script.TestCaseWithTransportAndScript):
 
199
 
 
200
    preamble = None # The setup script set by daughter classes
 
201
 
 
202
    def setUp(self):
 
203
        super(TestResolveConflicts, self).setUp()
 
204
        self.run_script(self.preamble)
 
205
 
 
206
 
 
207
class TestResolveTextConflicts(TestResolveConflicts):
 
208
    # TBC
 
209
    pass
 
210
 
 
211
 
 
212
def content_conflict_scenarios():
 
213
    return [('file,None', dict(_this_actions='modify_file',
 
214
                               _check_this='file_has_more_content',
 
215
                               _other_actions='delete_file',
 
216
                               _check_other='file_doesnt_exist',
 
217
                               )),
 
218
            ('None,file', dict(_this_actions='delete_file',
 
219
                               _check_this='file_doesnt_exist',
 
220
                               _other_actions='modify_file',
 
221
                               _check_other='file_has_more_content',
 
222
                               )),
 
223
            ]
 
224
 
 
225
 
 
226
class TestResolveContentConflicts(tests.TestCaseWithTransport):
 
227
 
 
228
    # Set by load_tests
 
229
    this_actions = None
 
230
    other_actions = None
 
231
 
 
232
    def setUp(self):
 
233
        super(TestResolveContentConflicts, self).setUp()
 
234
        builder = self.make_branch_builder('trunk')
 
235
        builder.start_series()
 
236
        # Create an empty trunk
 
237
        builder.build_snapshot('start', None, [
 
238
                ('add', ('', 'root-id', 'directory', ''))])
 
239
        # Add a minimal base content
 
240
        builder.build_snapshot('base', ['start'], [
 
241
                ('add', ('file', 'file-id', 'file', 'trunk content\n'))])
 
242
        # Modify the base content in branch
 
243
        other_actions = self._get_actions(self._other_actions)
 
244
        builder.build_snapshot('other', ['base'], other_actions())
 
245
        # Modify the base content in trunk
 
246
        this_actions = self._get_actions(self._this_actions)
 
247
        builder.build_snapshot('this', ['base'], this_actions())
 
248
        builder.finish_series()
 
249
        self.builder = builder
 
250
 
 
251
    def _get_actions(self, name):
 
252
        return getattr(self, 'do_%s' % name)
 
253
 
 
254
    def _get_check(self, name):
 
255
        return getattr(self, 'check_%s' % name)
 
256
 
 
257
    def do_modify_file(self):
 
258
        return [('modify', ('file-id', 'trunk content\nmore content\n'))]
 
259
 
 
260
    def check_file_has_more_content(self):
 
261
        self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
 
262
 
 
263
    def do_delete_file(self):
 
264
        return [('unversion', 'file-id')]
 
265
 
 
266
    def check_file_doesnt_exist(self):
 
267
        self.failIfExists('branch/file')
 
268
 
 
269
    def _merge_other_into_this(self):
 
270
        b = self.builder.get_branch()
 
271
        wt = b.bzrdir.sprout('branch').open_workingtree()
 
272
        wt.merge_from_branch(b, 'other')
 
273
        return wt
 
274
 
 
275
    def assertConflict(self, wt, ctype, **kwargs):
 
276
        confs = wt.conflicts()
 
277
        self.assertLength(1, confs)
 
278
        c = confs[0]
 
279
        self.assertIsInstance(c, ctype)
 
280
        sentinel = object() # An impossible value
 
281
        for k, v in kwargs.iteritems():
 
282
            self.assertEqual(v, getattr(c, k, sentinel))
 
283
 
 
284
    def check_resolved(self, wt, item, action):
 
285
        conflicts.resolve(wt, [item], action=action)
 
286
        # Check that we don't have any conflicts nor unknown left
 
287
        self.assertLength(0, wt.conflicts())
 
288
        self.assertLength(0, list(wt.unknowns()))
 
289
 
 
290
    def test_resolve_taking_this(self):
 
291
        wt = self._merge_other_into_this()
 
292
        self.assertConflict(wt, conflicts.ContentsConflict,
 
293
                            path='file', file_id='file-id',)
 
294
        self.check_resolved(wt, 'file', 'take_this')
 
295
        check_this = self._get_check(self._check_this)
 
296
        check_this()
 
297
 
 
298
    def test_resolve_taking_other(self):
 
299
        wt = self._merge_other_into_this()
 
300
        self.assertConflict(wt, conflicts.ContentsConflict,
 
301
                            path='file', file_id='file-id',)
 
302
        self.check_resolved(wt, 'file', 'take_other')
 
303
        check_other = self._get_check(self._check_other)
 
304
        check_other()
 
305
 
 
306
 
 
307
class TestResolveDuplicateEntry(TestResolveConflicts):
 
308
 
 
309
    preamble = """
 
310
$ bzr init trunk
 
311
$ cd trunk
 
312
$ echo 'trunk content' >file
 
313
$ bzr add file
 
314
$ bzr commit -m 'Create trunk'
 
315
 
 
316
$ echo 'trunk content too' >file2
 
317
$ bzr add file2
 
318
$ bzr commit -m 'Add file2 in trunk'
 
319
 
 
320
$ bzr branch . -r 1 ../branch
 
321
$ cd ../branch
 
322
$ echo 'branch content' >file2
 
323
$ bzr add file2
 
324
$ bzr commit -m 'Add file2 in branch'
 
325
 
 
326
$ bzr merge ../trunk
 
327
2>+N  file2
 
328
2>R   file2 => file2.moved
 
329
2>Conflict adding file file2.  Moved existing file to file2.moved.
 
330
2>1 conflicts encountered.
 
331
"""
 
332
 
 
333
    def test_keep_this(self):
 
334
        self.run_script("""
 
335
$ bzr rm file2  --force
 
336
$ bzr mv file2.moved file2
 
337
$ bzr resolve file2
 
338
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
339
""")
 
340
 
 
341
    def test_keep_other(self):
 
342
        self.failIfExists('branch/file2.moved')
 
343
        self.run_script("""
 
344
$ bzr rm file2.moved --force
 
345
$ bzr resolve file2
 
346
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
347
""")
 
348
        self.failIfExists('branch/file2.moved')
 
349
 
 
350
    def test_resolve_taking_this(self):
 
351
        self.run_script("""
 
352
$ bzr resolve --take-this file2
 
353
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
354
""")
 
355
 
 
356
    def test_resolve_taking_other(self):
 
357
        self.run_script("""
 
358
$ bzr resolve --take-other file2
 
359
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
360
""")
 
361
 
 
362
 
 
363
class TestResolveUnversionedParent(TestResolveConflicts):
 
364
 
 
365
    # FIXME: Add the reverse tests: dir deleted in trunk, file added in branch
 
366
 
 
367
    # FIXME: While this *creates* UnversionedParent conflicts, this really only
 
368
    # tests MissingParent resolution :-/
 
369
    preamble = """
 
370
$ bzr init trunk
 
371
$ cd trunk
 
372
$ mkdir dir
 
373
$ bzr add dir
 
374
$ bzr commit -m 'Create trunk'
 
375
 
 
376
$ echo 'trunk content' >dir/file
 
377
$ bzr add dir/file
 
378
$ bzr commit -m 'Add dir/file in trunk'
 
379
 
 
380
$ bzr branch . -r 1 ../branch
 
381
$ cd ../branch
 
382
$ bzr rm dir
 
383
$ bzr commit -m 'Remove dir in branch'
 
384
 
 
385
$ bzr merge ../trunk
 
386
2>+N  dir/
 
387
2>+N  dir/file
 
388
2>Conflict adding files to dir.  Created directory.
 
389
2>Conflict because dir is not versioned, but has versioned children.  Versioned directory.
 
390
2>2 conflicts encountered.
 
391
"""
 
392
 
 
393
    def test_take_this(self):
 
394
        self.run_script("""
 
395
$ bzr rm dir  --force
 
396
$ bzr resolve dir
 
397
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
398
""")
 
399
 
 
400
    def test_take_other(self):
 
401
        self.run_script("""
 
402
$ bzr resolve dir
 
403
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
404
""")
 
405
 
 
406
 
 
407
class TestResolveMissingParent(TestResolveConflicts):
 
408
 
 
409
    preamble = """
 
410
$ bzr init trunk
 
411
$ cd trunk
 
412
$ mkdir dir
 
413
$ echo 'trunk content' >dir/file
 
414
$ bzr add
 
415
$ bzr commit -m 'Create trunk'
 
416
 
 
417
$ echo 'trunk content' >dir/file2
 
418
$ bzr add dir/file2
 
419
$ bzr commit -m 'Add dir/file2 in branch'
 
420
 
 
421
$ bzr branch . -r 1 ../branch
 
422
$ cd ../branch
 
423
$ bzr rm dir/file --force
 
424
$ bzr rm dir
 
425
$ bzr commit -m 'Remove dir/file'
 
426
 
 
427
$ bzr merge ../trunk
 
428
2>+N  dir/
 
429
2>+N  dir/file2
 
430
2>Conflict adding files to dir.  Created directory.
 
431
2>Conflict because dir is not versioned, but has versioned children.  Versioned directory.
 
432
2>2 conflicts encountered.
 
433
"""
 
434
 
 
435
    def test_keep_them_all(self):
 
436
        self.run_script("""
 
437
$ bzr resolve dir
 
438
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
439
""")
 
440
 
 
441
    def test_adopt_child(self):
 
442
        self.run_script("""
 
443
$ bzr mv dir/file2 file2
 
444
$ bzr rm dir --force
 
445
$ bzr resolve dir
 
446
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
447
""")
 
448
 
 
449
    def test_kill_them_all(self):
 
450
        self.run_script("""
 
451
$ bzr rm dir --force
 
452
$ bzr resolve dir
 
453
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
454
""")
 
455
 
 
456
    def test_resolve_taking_this(self):
 
457
        self.run_script("""
 
458
$ bzr resolve --take-this dir
 
459
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
460
""")
 
461
 
 
462
    def test_resolve_taking_other(self):
 
463
        self.run_script("""
 
464
$ bzr resolve --take-other dir
 
465
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
466
""")
 
467
 
 
468
 
 
469
class TestResolveDeletingParent(TestResolveConflicts):
 
470
 
 
471
    preamble = """
 
472
$ bzr init trunk
 
473
$ cd trunk
 
474
$ mkdir dir
 
475
$ echo 'trunk content' >dir/file
 
476
$ bzr add
 
477
$ bzr commit -m 'Create trunk'
 
478
 
 
479
$ bzr rm dir/file --force
 
480
$ bzr rm dir --force
 
481
$ bzr commit -m 'Remove dir/file'
 
482
 
 
483
$ bzr branch . -r 1 ../branch
 
484
$ cd ../branch
 
485
$ echo 'branch content' >dir/file2
 
486
$ bzr add dir/file2
 
487
$ bzr commit -m 'Add dir/file2 in branch'
 
488
 
 
489
$ bzr merge ../trunk
 
490
2>-D  dir/file
 
491
2>Conflict: can't delete dir because it is not empty.  Not deleting.
 
492
2>Conflict because dir is not versioned, but has versioned children.  Versioned directory.
 
493
2>2 conflicts encountered.
 
494
"""
 
495
 
 
496
    def test_keep_them_all(self):
 
497
        self.run_script("""
 
498
$ bzr resolve dir
 
499
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
500
""")
 
501
 
 
502
    def test_adopt_child(self):
 
503
        self.run_script("""
 
504
$ bzr mv dir/file2 file2
 
505
$ bzr rm dir --force
 
506
$ bzr resolve dir
 
507
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
508
""")
 
509
 
 
510
    def test_kill_them_all(self):
 
511
        self.run_script("""
 
512
$ bzr rm dir --force
 
513
$ bzr resolve dir
 
514
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
515
""")
 
516
 
 
517
    def test_resolve_taking_this(self):
 
518
        self.run_script("""
 
519
$ bzr resolve --take-this dir
 
520
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
521
""")
 
522
 
 
523
    def test_resolve_taking_other(self):
 
524
        self.run_script("""
 
525
$ bzr resolve --take-other dir
 
526
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
527
""")
 
528
 
 
529
 
 
530
class TestResolvePathConflict(TestResolveConflicts):
 
531
 
 
532
    preamble = """
 
533
$ bzr init trunk
 
534
$ cd trunk
 
535
$ echo 'Boo!' >file
 
536
$ bzr add
 
537
$ bzr commit -m 'Create trunk'
 
538
 
 
539
$ bzr mv file file-in-trunk
 
540
$ bzr commit -m 'Renamed to file-in-trunk'
 
541
 
 
542
$ bzr branch . -r 1 ../branch
 
543
$ cd ../branch
 
544
$ bzr mv file file-in-branch
 
545
$ bzr commit -m 'Renamed to file-in-branch'
 
546
 
 
547
$ bzr merge ../trunk
 
548
2>R   file-in-branch => file-in-trunk
 
549
2>Path conflict: file-in-branch / file-in-trunk
 
550
2>1 conflicts encountered.
 
551
"""
 
552
 
 
553
    def test_keep_source(self):
 
554
        self.run_script("""
 
555
$ bzr resolve file-in-trunk
 
556
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
557
""")
 
558
 
 
559
    def test_keep_target(self):
 
560
        self.run_script("""
 
561
$ bzr mv file-in-trunk file-in-branch
 
562
$ bzr resolve file-in-branch
 
563
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
564
""")
 
565
 
 
566
    def test_resolve_taking_this(self):
 
567
        self.run_script("""
 
568
$ bzr resolve --take-this file-in-branch
 
569
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
570
""")
 
571
 
 
572
    def test_resolve_taking_other(self):
 
573
        self.run_script("""
 
574
$ bzr resolve --take-other file-in-branch
 
575
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
576
""")
 
577
 
 
578
 
 
579
class TestResolveParentLoop(TestResolveConflicts):
 
580
 
 
581
    preamble = """
 
582
$ bzr init trunk
 
583
$ cd trunk
 
584
$ bzr mkdir dir1
 
585
$ bzr mkdir dir2
 
586
$ bzr commit -m 'Create trunk'
 
587
 
 
588
$ bzr mv dir2 dir1
 
589
$ bzr commit -m 'Moved dir2 into dir1'
 
590
 
 
591
$ bzr branch . -r 1 ../branch
 
592
$ cd ../branch
 
593
$ bzr mv dir1 dir2
 
594
$ bzr commit -m 'Moved dir1 into dir2'
 
595
 
 
596
$ bzr merge ../trunk
 
597
2>Conflict moving dir2/dir1 into dir2.  Cancelled move.
 
598
2>1 conflicts encountered.
 
599
"""
 
600
 
 
601
    def test_take_this(self):
 
602
        self.run_script("""
 
603
$ bzr resolve dir2
 
604
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
605
""")
 
606
 
 
607
    def test_take_other(self):
 
608
        self.run_script("""
 
609
$ bzr mv dir2/dir1 dir1
 
610
$ bzr mv dir2 dir1
 
611
$ bzr resolve dir2
 
612
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
613
""")
 
614
 
 
615
    def test_resolve_taking_this(self):
 
616
        self.run_script("""
 
617
$ bzr resolve --take-this dir2
 
618
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
619
""")
 
620
        self.failUnlessExists('dir2')
 
621
 
 
622
    def test_resolve_taking_other(self):
 
623
        self.run_script("""
 
624
$ bzr resolve --take-other dir2
 
625
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
626
""")
 
627
        self.failUnlessExists('dir1')
 
628
 
 
629
 
 
630
class TestResolveNonDirectoryParent(TestResolveConflicts):
 
631
 
 
632
    preamble = """
 
633
$ bzr init trunk
 
634
$ cd trunk
 
635
$ bzr mkdir foo
 
636
$ bzr commit -m 'Create trunk'
 
637
$ echo "Boing" >foo/bar
 
638
$ bzr add foo/bar
 
639
$ bzr commit -m 'Add foo/bar'
 
640
 
 
641
$ bzr branch . -r 1 ../branch
 
642
$ cd ../branch
 
643
$ rm -r foo
 
644
$ echo "Boo!" >foo
 
645
$ bzr commit -m 'foo is now a file'
 
646
 
 
647
$ bzr merge ../trunk
 
648
2>+N  foo.new/bar
 
649
2>RK  foo => foo.new/
 
650
# FIXME: The message is misleading, foo.new *is* a directory when the message
 
651
# is displayed -- vila 090916
 
652
2>Conflict: foo.new is not a directory, but has files in it.  Created directory.
 
653
2>1 conflicts encountered.
 
654
"""
 
655
 
 
656
    def test_take_this(self):
 
657
        self.run_script("""
 
658
$ bzr rm foo.new --force
 
659
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
 
660
# aside ? -- vila 090916
 
661
$ bzr add foo
 
662
$ bzr resolve foo.new
 
663
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
664
""")
 
665
 
 
666
    def test_take_other(self):
 
667
        self.run_script("""
 
668
$ bzr rm foo --force
 
669
$ bzr mv foo.new foo
 
670
$ bzr resolve foo
 
671
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
672
""")
 
673
 
 
674
    def test_resolve_taking_this(self):
 
675
        self.run_script("""
 
676
$ bzr resolve --take-this foo.new
 
677
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
678
""")
 
679
 
 
680
    def test_resolve_taking_other(self):
 
681
        self.run_script("""
 
682
$ bzr resolve --take-other foo.new
 
683
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
684
""")
 
685
 
 
686
 
 
687
class TestMalformedTransform(script.TestCaseWithTransportAndScript):
 
688
 
 
689
    def test_bug_430129(self):
 
690
        # This is nearly like TestResolveNonDirectoryParent but with branch and
 
691
        # trunk switched. As such it should certainly produce the same
 
692
        # conflict.
 
693
        self.run_script("""
 
694
$ bzr init trunk
 
695
$ cd trunk
 
696
$ bzr mkdir foo
 
697
$ bzr commit -m 'Create trunk'
 
698
$ rm -r foo
 
699
$ echo "Boo!" >foo
 
700
$ bzr commit -m 'foo is now a file'
 
701
 
 
702
$ bzr branch . -r 1 ../branch
 
703
$ cd ../branch
 
704
$ echo "Boing" >foo/bar
 
705
$ bzr add foo/bar
 
706
$ bzr commit -m 'Add foo/bar'
 
707
 
 
708
$ bzr merge ../trunk
 
709
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
 
710
""")
 
711
 
 
712
 
 
713
class TestResolveActionOption(tests.TestCase):
 
714
 
 
715
    def setUp(self):
 
716
        super(TestResolveActionOption, self).setUp()
 
717
        self.options = [conflicts.ResolveActionOption()]
 
718
        self.parser = option.get_optparser(dict((o.name, o)
 
719
                                                for o in self.options))
 
720
 
 
721
    def parse(self, args):
 
722
        return self.parser.parse_args(args)
 
723
 
 
724
    def test_unknown_action(self):
 
725
        self.assertRaises(errors.BadOptionValue,
 
726
                          self.parse, ['--action', 'take-me-to-the-moon'])
 
727
 
 
728
    def test_done(self):
 
729
        opts, args = self.parse(['--action', 'done'])
 
730
        self.assertEqual({'action':'done'}, opts)
 
731
 
 
732
    def test_take_this(self):
 
733
        opts, args = self.parse(['--action', 'take-this'])
 
734
        self.assertEqual({'action': 'take_this'}, opts)
 
735
        opts, args = self.parse(['--take-this'])
 
736
        self.assertEqual({'action': 'take_this'}, opts)
 
737
 
 
738
    def test_take_other(self):
 
739
        opts, args = self.parse(['--action', 'take-other'])
 
740
        self.assertEqual({'action': 'take_other'}, opts)
 
741
        opts, args = self.parse(['--take-other'])
 
742
        self.assertEqual({'action': 'take_other'}, opts)