/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 breezy/tests/test_conflicts.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-09 23:53:11 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180509235311-k1zk8mwcb09b8vm0
Update TODO.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
17
17
 
18
18
import os
19
19
 
20
 
from bzrlib import (
21
 
    branchbuilder,
22
 
    bzrdir,
 
20
from .. import (
23
21
    conflicts,
24
22
    errors,
25
23
    option,
 
24
    osutils,
26
25
    tests,
27
 
    workingtree,
28
 
    )
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
 
                TestParametrizedResolveConflicts,
38
 
                )))
39
 
    # Each test class defines its own scenarios. This is needed for
40
 
    # TestResolvePathConflictBefore531967 that verifies that the same tests as
41
 
    # TestResolvePathConflict still pass.
42
 
    for test in tests.iter_suite_tests(sp_tests):
43
 
        tests.apply_scenarios(test, test.scenarios(), result)
44
 
 
45
 
    # No parametrization for the remaining tests
46
 
    result.addTests(remaining_tests)
47
 
 
48
 
    return result
 
26
    )
 
27
from . import (
 
28
    script,
 
29
    scenarios,
 
30
    )
 
31
 
 
32
 
 
33
load_tests = scenarios.load_tests_apply_scenarios
49
34
 
50
35
 
51
36
# TODO: Test commit with some added, and added-but-missing files
76
61
])
77
62
 
78
63
 
 
64
def vary_by_conflicts():
 
65
    for conflict in example_conflicts:
 
66
        yield (conflict.__class__.__name__, {"conflict": conflict})
 
67
 
 
68
 
79
69
class TestConflicts(tests.TestCaseWithTransport):
80
70
 
81
 
    def test_conflicts(self):
82
 
        """Conflicts are detected properly"""
83
 
        # Use BzrDirFormat6 so we can fake conflicts
84
 
        tree = self.make_branch_and_tree('.', format=bzrdir.BzrDirFormat6())
85
 
        self.build_tree_contents([('hello', 'hello world4'),
86
 
                                  ('hello.THIS', 'hello world2'),
87
 
                                  ('hello.BASE', 'hello world1'),
88
 
                                  ('hello.OTHER', 'hello world3'),
89
 
                                  ('hello.sploo.BASE', 'yellowworld'),
90
 
                                  ('hello.sploo.OTHER', 'yellowworld2'),
91
 
                                  ])
92
 
        tree.lock_read()
93
 
        self.assertLength(6, list(tree.list_files()))
94
 
        tree.unlock()
95
 
        tree_conflicts = tree.conflicts()
96
 
        self.assertLength(2, tree_conflicts)
97
 
        self.assertTrue('hello' in tree_conflicts[0].path)
98
 
        self.assertTrue('hello.sploo' in tree_conflicts[1].path)
99
 
        conflicts.restore('hello')
100
 
        conflicts.restore('hello.sploo')
101
 
        self.assertLength(0, tree.conflicts())
102
 
        self.assertFileEqual('hello world2', 'hello')
103
 
        self.assertFalse(os.path.lexists('hello.sploo'))
104
 
        self.assertRaises(errors.NotConflicted, conflicts.restore, 'hello')
105
 
        self.assertRaises(errors.NotConflicted,
106
 
                          conflicts.restore, 'hello.sploo')
107
 
 
108
71
    def test_resolve_conflict_dir(self):
109
72
        tree = self.make_branch_and_tree('.')
110
 
        self.build_tree_contents([('hello', 'hello world4'),
111
 
                                  ('hello.THIS', 'hello world2'),
112
 
                                  ('hello.BASE', 'hello world1'),
 
73
        self.build_tree_contents([('hello', b'hello world4'),
 
74
                                  ('hello.THIS', b'hello world2'),
 
75
                                  ('hello.BASE', b'hello world1'),
113
76
                                  ])
114
77
        os.mkdir('hello.OTHER')
115
78
        tree.add('hello', 'q')
161
124
        self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
162
125
 
163
126
 
164
 
class TestConflictStanzas(tests.TestCase):
 
127
class TestPerConflict(tests.TestCase):
 
128
 
 
129
    scenarios = scenarios.multiply_scenarios(vary_by_conflicts())
 
130
 
 
131
    def test_stringification(self):
 
132
        text = unicode(self.conflict)
 
133
        self.assertContainsString(text, self.conflict.path)
 
134
        self.assertContainsString(text.lower(), "conflict")
 
135
        self.assertContainsString(repr(self.conflict),
 
136
            self.conflict.__class__.__name__)
165
137
 
166
138
    def test_stanza_roundtrip(self):
167
 
        # write and read our example stanza.
168
 
        stanza_iter = example_conflicts.to_stanzas()
169
 
        processed = conflicts.ConflictList.from_stanzas(stanza_iter)
170
 
        for o, p in zip(processed, example_conflicts):
171
 
            self.assertEqual(o, p)
172
 
 
173
 
            self.assertIsInstance(o.path, unicode)
174
 
 
175
 
            if o.file_id is not None:
176
 
                self.assertIsInstance(o.file_id, str)
177
 
 
178
 
            conflict_path = getattr(o, 'conflict_path', None)
179
 
            if conflict_path is not None:
180
 
                self.assertIsInstance(conflict_path, unicode)
181
 
 
182
 
            conflict_file_id = getattr(o, 'conflict_file_id', None)
183
 
            if conflict_file_id is not None:
184
 
                self.assertIsInstance(conflict_file_id, str)
 
139
        p = self.conflict
 
140
        o = conflicts.Conflict.factory(**p.as_stanza().as_dict())
 
141
        self.assertEqual(o, p)
 
142
 
 
143
        self.assertIsInstance(o.path, unicode)
 
144
 
 
145
        if o.file_id is not None:
 
146
            self.assertIsInstance(o.file_id, str)
 
147
 
 
148
        conflict_path = getattr(o, 'conflict_path', None)
 
149
        if conflict_path is not None:
 
150
            self.assertIsInstance(conflict_path, unicode)
 
151
 
 
152
        conflict_file_id = getattr(o, 'conflict_file_id', None)
 
153
        if conflict_file_id is not None:
 
154
            self.assertIsInstance(conflict_file_id, str)
185
155
 
186
156
    def test_stanzification(self):
187
 
        for stanza in example_conflicts.to_stanzas():
188
 
            if 'file_id' in stanza:
189
 
                # In Stanza form, the file_id has to be unicode.
190
 
                self.assertStartsWith(stanza['file_id'], u'\xeed')
191
 
            self.assertStartsWith(stanza['path'], u'p\xe5th')
192
 
            if 'conflict_path' in stanza:
193
 
                self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
194
 
            if 'conflict_file_id' in stanza:
195
 
                self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
 
157
        stanza = self.conflict.as_stanza()
 
158
        if 'file_id' in stanza:
 
159
            # In Stanza form, the file_id has to be unicode.
 
160
            self.assertStartsWith(stanza['file_id'], u'\xeed')
 
161
        self.assertStartsWith(stanza['path'], u'p\xe5th')
 
162
        if 'conflict_path' in stanza:
 
163
            self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
 
164
        if 'conflict_file_id' in stanza:
 
165
            self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
 
166
 
 
167
 
 
168
class TestConflictList(tests.TestCase):
 
169
 
 
170
    def test_stanzas_roundtrip(self):
 
171
        stanzas_iter = example_conflicts.to_stanzas()
 
172
        processed = conflicts.ConflictList.from_stanzas(stanzas_iter)
 
173
        self.assertEqual(example_conflicts, processed)
 
174
 
 
175
    def test_stringification(self):
 
176
        for text, o in zip(example_conflicts.to_strings(), example_conflicts):
 
177
            self.assertEqual(text, unicode(o))
196
178
 
197
179
 
198
180
# FIXME: The shell-like tests should be converted to real whitebox tests... or
210
192
        self.run_script(self.preamble)
211
193
 
212
194
 
213
 
class TestResolveTextConflicts(TestResolveConflicts):
214
 
    # TBC
215
 
    pass
216
 
 
217
 
 
218
195
def mirror_scenarios(base_scenarios):
219
196
    """Return a list of mirrored scenarios.
220
197
 
293
270
    _this = None
294
271
    _other = None
295
272
 
296
 
    @staticmethod
297
 
    def scenarios():
298
 
        """Return the scenario list for the conflict type defined by the class.
299
 
 
300
 
        Each scenario is of the form:
301
 
        (common, (left_name, left_dict), (right_name, right_dict))
302
 
 
303
 
        * common is a dict
304
 
 
305
 
        * left_name and right_name are the scenario names that will be combined
306
 
 
307
 
        * left_dict and right_dict are the attributes specific to each half of
308
 
          the scenario. They should include at least 'actions' and 'check' and
309
 
          will be available as '_this' and '_other' test instance attributes.
310
 
 
311
 
        Daughters classes are free to add their specific attributes as they see
312
 
        fit in any of the three dicts.
313
 
 
314
 
        This is a class method so that load_tests can find it.
315
 
 
316
 
        '_base_actions' in the common dict, 'actions' and 'check' in the left
317
 
        and right dicts use names that map to methods in the test classes. Some
318
 
        prefixes are added to these names to get the correspong methods (see
319
 
        _get_actions() and _get_check()). The motivation here is to avoid
320
 
        collisions in the class namespace.
321
 
        """
322
 
        # Only concrete classes return actual scenarios
323
 
        return []
 
273
    scenarios = []
 
274
    """The scenario list for the conflict type defined by the class.
 
275
 
 
276
    Each scenario is of the form:
 
277
    (common, (left_name, left_dict), (right_name, right_dict))
 
278
 
 
279
    * common is a dict
 
280
 
 
281
    * left_name and right_name are the scenario names that will be combined
 
282
 
 
283
    * left_dict and right_dict are the attributes specific to each half of
 
284
      the scenario. They should include at least 'actions' and 'check' and
 
285
      will be available as '_this' and '_other' test instance attributes.
 
286
 
 
287
    Daughters classes are free to add their specific attributes as they see
 
288
    fit in any of the three dicts.
 
289
 
 
290
    This is a class method so that load_tests can find it.
 
291
 
 
292
    '_base_actions' in the common dict, 'actions' and 'check' in the left
 
293
    and right dicts use names that map to methods in the test classes. Some
 
294
    prefixes are added to these names to get the correspong methods (see
 
295
    _get_actions() and _get_check()). The motivation here is to avoid
 
296
    collisions in the class namespace.
 
297
    """
324
298
 
325
299
    def setUp(self):
326
300
        super(TestParametrizedResolveConflicts, self).setUp()
328
302
        builder.start_series()
329
303
 
330
304
        # Create an empty trunk
331
 
        builder.build_snapshot('start', None, [
332
 
                ('add', ('', 'root-id', 'directory', ''))])
 
305
        builder.build_snapshot(None, [
 
306
                ('add', ('', 'root-id', 'directory', ''))],
 
307
                revision_id='start')
333
308
        # Add a minimal base content
334
309
        base_actions = self._get_actions(self._base_actions)()
335
 
        builder.build_snapshot('base', ['start'], base_actions)
 
310
        builder.build_snapshot(['start'], base_actions, revision_id='base')
336
311
        # Modify the base content in branch
337
312
        actions_other = self._get_actions(self._other['actions'])()
338
 
        builder.build_snapshot('other', ['base'], actions_other)
 
313
        builder.build_snapshot(['base'], actions_other, revision_id='other')
339
314
        # Modify the base content in trunk
340
315
        actions_this = self._get_actions(self._this['actions'])()
341
 
        builder.build_snapshot('this', ['base'], actions_this)
 
316
        builder.build_snapshot(['base'], actions_this, revision_id='this')
342
317
        # builder.get_branch() tip is now 'this'
343
318
 
344
319
        builder.finish_series()
352
327
 
353
328
    def _merge_other_into_this(self):
354
329
        b = self.builder.get_branch()
355
 
        wt = b.bzrdir.sprout('branch').open_workingtree()
 
330
        wt = b.controldir.sprout('branch').open_workingtree()
356
331
        wt.merge_from_branch(b, 'other')
357
332
        return wt
358
333
 
388
363
        check_other()
389
364
 
390
365
 
 
366
class TestResolveTextConflicts(TestParametrizedResolveConflicts):
 
367
 
 
368
    _conflict_type = conflicts.TextConflict
 
369
 
 
370
    # Set by the scenarios
 
371
    # path and file-id for the file involved in the conflict
 
372
    _path = None
 
373
    _file_id = None
 
374
 
 
375
    scenarios = mirror_scenarios(
 
376
        [
 
377
            # File modified on both sides
 
378
            (dict(_base_actions='create_file',
 
379
                  _path='file', _file_id='file-id'),
 
380
             ('filed_modified_A',
 
381
              dict(actions='modify_file_A', check='file_has_content_A')),
 
382
             ('file_modified_B',
 
383
              dict(actions='modify_file_B', check='file_has_content_B')),),
 
384
            # File modified on both sides in dir
 
385
            (dict(_base_actions='create_file_in_dir',
 
386
                  _path='dir/file', _file_id='file-id'),
 
387
             ('filed_modified_A_in_dir',
 
388
              dict(actions='modify_file_A_in_dir',
 
389
                   check='file_in_dir_has_content_A')),
 
390
             ('file_modified_B',
 
391
              dict(actions='modify_file_B_in_dir',
 
392
                   check='file_in_dir_has_content_B')),),
 
393
            ])
 
394
 
 
395
    def do_create_file(self, path='file'):
 
396
        return [('add', (path, 'file-id', 'file', 'trunk content\n'))]
 
397
 
 
398
    def do_modify_file_A(self):
 
399
        return [('modify', ('file', 'trunk content\nfeature A\n'))]
 
400
 
 
401
    def do_modify_file_B(self):
 
402
        return [('modify', ('file', 'trunk content\nfeature B\n'))]
 
403
 
 
404
    def do_modify_file_A_in_dir(self):
 
405
        return [('modify', ('dir/file', 'trunk content\nfeature A\n'))]
 
406
 
 
407
    def do_modify_file_B_in_dir(self):
 
408
        return [('modify', ('dir/file', 'trunk content\nfeature B\n'))]
 
409
 
 
410
    def check_file_has_content_A(self, path='file'):
 
411
        self.assertFileEqual('trunk content\nfeature A\n',
 
412
                             osutils.pathjoin('branch', path))
 
413
 
 
414
    def check_file_has_content_B(self, path='file'):
 
415
        self.assertFileEqual('trunk content\nfeature B\n',
 
416
                             osutils.pathjoin('branch', path))
 
417
 
 
418
    def do_create_file_in_dir(self):
 
419
        return [('add', ('dir', 'dir-id', 'directory', '')),
 
420
            ] + self.do_create_file('dir/file')
 
421
 
 
422
    def check_file_in_dir_has_content_A(self):
 
423
        self.check_file_has_content_A('dir/file')
 
424
 
 
425
    def check_file_in_dir_has_content_B(self):
 
426
        self.check_file_has_content_B('dir/file')
 
427
 
 
428
    def _get_resolve_path_arg(self, wt, action):
 
429
        return self._path
 
430
 
 
431
    def assertTextConflict(self, wt, c):
 
432
        self.assertEqual(self._file_id, c.file_id)
 
433
        self.assertEqual(self._path, c.path)
 
434
    _assert_conflict = assertTextConflict
 
435
 
 
436
 
391
437
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
392
438
 
393
 
    _conflict_type = conflicts.ContentsConflict,
 
439
    _conflict_type = conflicts.ContentsConflict
394
440
 
395
 
    # Set by load_tests from scenarios()
 
441
    # Set by the scenarios
396
442
    # path and file-id for the file involved in the conflict
397
443
    _path = None
398
444
    _file_id = None
399
445
 
400
 
    @staticmethod
401
 
    def scenarios():
402
 
        base_scenarios = [
 
446
    scenarios = mirror_scenarios(
 
447
        [
403
448
            # File modified/deleted
404
449
            (dict(_base_actions='create_file',
405
450
                  _path='file', _file_id='file-id'),
407
452
              dict(actions='modify_file', check='file_has_more_content')),
408
453
             ('file_deleted',
409
454
              dict(actions='delete_file', check='file_doesnt_exist')),),
410
 
            ]
411
 
        return mirror_scenarios(base_scenarios)
 
455
            # File renamed-modified/deleted
 
456
            (dict(_base_actions='create_file',
 
457
                  _path='new-file', _file_id='file-id'),
 
458
             ('file_renamed_and_modified',
 
459
              dict(actions='modify_and_rename_file',
 
460
                   check='file_renamed_and_more_content')),
 
461
             ('file_deleted',
 
462
              dict(actions='delete_file', check='file_doesnt_exist')),),
 
463
            # File modified/deleted in dir
 
464
            (dict(_base_actions='create_file_in_dir',
 
465
                  _path='dir/file', _file_id='file-id'),
 
466
             ('file_modified_in_dir',
 
467
              dict(actions='modify_file_in_dir',
 
468
                   check='file_in_dir_has_more_content')),
 
469
             ('file_deleted_in_dir',
 
470
              dict(actions='delete_file_in_dir',
 
471
                   check='file_in_dir_doesnt_exist')),),
 
472
            ])
412
473
 
413
474
    def do_create_file(self):
414
475
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
415
476
 
416
477
    def do_modify_file(self):
417
 
        return [('modify', ('file-id', 'trunk content\nmore content\n'))]
 
478
        return [('modify', ('file', 'trunk content\nmore content\n'))]
 
479
 
 
480
    def do_modify_and_rename_file(self):
 
481
        return [('modify', ('new-file', 'trunk content\nmore content\n')),
 
482
                ('rename', ('file', 'new-file'))]
418
483
 
419
484
    def check_file_has_more_content(self):
420
485
        self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
421
486
 
 
487
    def check_file_renamed_and_more_content(self):
 
488
        self.assertFileEqual('trunk content\nmore content\n', 'branch/new-file')
 
489
 
422
490
    def do_delete_file(self):
423
 
        return [('unversion', 'file-id')]
 
491
        return [('unversion', 'file')]
 
492
 
 
493
    def do_delete_file_in_dir(self):
 
494
        return [('unversion', 'dir/file')]
424
495
 
425
496
    def check_file_doesnt_exist(self):
426
 
        self.failIfExists('branch/file')
 
497
        self.assertPathDoesNotExist('branch/file')
 
498
 
 
499
    def do_create_file_in_dir(self):
 
500
        return [('add', ('dir', 'dir-id', 'directory', '')),
 
501
                ('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
 
502
 
 
503
    def do_modify_file_in_dir(self):
 
504
        return [('modify', ('dir/file', 'trunk content\nmore content\n'))]
 
505
 
 
506
    def check_file_in_dir_has_more_content(self):
 
507
        self.assertFileEqual('trunk content\nmore content\n', 'branch/dir/file')
 
508
 
 
509
    def check_file_in_dir_doesnt_exist(self):
 
510
        self.assertPathDoesNotExist('branch/dir/file')
427
511
 
428
512
    def _get_resolve_path_arg(self, wt, action):
429
513
        return self._path
436
520
 
437
521
class TestResolvePathConflict(TestParametrizedResolveConflicts):
438
522
 
439
 
    _conflict_type = conflicts.PathConflict,
 
523
    _conflict_type = conflicts.PathConflict
440
524
 
441
525
    def do_nothing(self):
442
526
        return []
443
527
 
444
 
    @staticmethod
445
 
    def scenarios():
446
 
        # Each side dict additionally defines:
447
 
        # - path path involved (can be '<deleted>')
448
 
        # - file-id involved
449
 
        base_scenarios = [
 
528
    # Each side dict additionally defines:
 
529
    # - path path involved (can be '<deleted>')
 
530
    # - file-id involved
 
531
    scenarios = mirror_scenarios(
 
532
        [
450
533
            # File renamed/deleted
451
534
            (dict(_base_actions='create_file'),
452
535
             ('file_renamed',
457
540
                   # PathConflicts deletion handling requires a special
458
541
                   # hard-coded value
459
542
                   path='<deleted>', file_id='file-id')),),
 
543
            # File renamed/deleted in dir
 
544
            (dict(_base_actions='create_file_in_dir'),
 
545
             ('file_renamed_in_dir',
 
546
              dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
 
547
                   path='dir/new-file', file_id='file-id')),
 
548
             ('file_deleted',
 
549
              dict(actions='delete_file_in_dir', check='file_in_dir_doesnt_exist',
 
550
                   # PathConflicts deletion handling requires a special
 
551
                   # hard-coded value
 
552
                   path='<deleted>', file_id='file-id')),),
460
553
            # File renamed/renamed differently
461
554
            (dict(_base_actions='create_file'),
462
555
             ('file_renamed',
483
576
             ('dir_renamed2',
484
577
              dict(actions='rename_dir2', check='dir_renamed2',
485
578
                   path='new-dir2', file_id='dir-id')),),
486
 
        ]
487
 
        return mirror_scenarios(base_scenarios)
 
579
            ])
488
580
 
489
581
    def do_create_file(self):
490
582
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
496
588
        return [('rename', ('file', 'new-file'))]
497
589
 
498
590
    def check_file_renamed(self):
499
 
        self.failIfExists('branch/file')
500
 
        self.failUnlessExists('branch/new-file')
 
591
        self.assertPathDoesNotExist('branch/file')
 
592
        self.assertPathExists('branch/new-file')
501
593
 
502
594
    def do_rename_file2(self):
503
595
        return [('rename', ('file', 'new-file2'))]
504
596
 
505
597
    def check_file_renamed2(self):
506
 
        self.failIfExists('branch/file')
507
 
        self.failUnlessExists('branch/new-file2')
 
598
        self.assertPathDoesNotExist('branch/file')
 
599
        self.assertPathExists('branch/new-file2')
508
600
 
509
601
    def do_rename_dir(self):
510
602
        return [('rename', ('dir', 'new-dir'))]
511
603
 
512
604
    def check_dir_renamed(self):
513
 
        self.failIfExists('branch/dir')
514
 
        self.failUnlessExists('branch/new-dir')
 
605
        self.assertPathDoesNotExist('branch/dir')
 
606
        self.assertPathExists('branch/new-dir')
515
607
 
516
608
    def do_rename_dir2(self):
517
609
        return [('rename', ('dir', 'new-dir2'))]
518
610
 
519
611
    def check_dir_renamed2(self):
520
 
        self.failIfExists('branch/dir')
521
 
        self.failUnlessExists('branch/new-dir2')
 
612
        self.assertPathDoesNotExist('branch/dir')
 
613
        self.assertPathExists('branch/new-dir2')
522
614
 
523
615
    def do_delete_file(self):
524
 
        return [('unversion', 'file-id')]
 
616
        return [('unversion', 'file')]
 
617
 
 
618
    def do_delete_file_in_dir(self):
 
619
        return [('unversion', 'dir/file')]
525
620
 
526
621
    def check_file_doesnt_exist(self):
527
 
        self.failIfExists('branch/file')
 
622
        self.assertPathDoesNotExist('branch/file')
528
623
 
529
624
    def do_delete_dir(self):
530
 
        return [('unversion', 'dir-id')]
 
625
        return [('unversion', 'dir')]
531
626
 
532
627
    def check_dir_doesnt_exist(self):
533
 
        self.failIfExists('branch/dir')
 
628
        self.assertPathDoesNotExist('branch/dir')
 
629
 
 
630
    def do_create_file_in_dir(self):
 
631
        return [('add', ('dir', 'dir-id', 'directory', '')),
 
632
                ('add', ('dir/file', 'file-id', 'file', 'trunk content\n'))]
 
633
 
 
634
    def do_rename_file_in_dir(self):
 
635
        return [('rename', ('dir/file', 'dir/new-file'))]
 
636
 
 
637
    def check_file_in_dir_renamed(self):
 
638
        self.assertPathDoesNotExist('branch/dir/file')
 
639
        self.assertPathExists('branch/dir/new-file')
 
640
 
 
641
    def check_file_in_dir_doesnt_exist(self):
 
642
        self.assertPathDoesNotExist('branch/dir/file')
534
643
 
535
644
    def _get_resolve_path_arg(self, wt, action):
536
645
        tpath = self._this['path']
568
677
 
569
678
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
570
679
 
571
 
    _conflict_type = conflicts.DuplicateEntry,
 
680
    _conflict_type = conflicts.DuplicateEntry
572
681
 
573
 
    @staticmethod
574
 
    def scenarios():
575
 
        # Each side dict additionally defines:
576
 
        # - path involved
577
 
        # - file-id involved
578
 
        base_scenarios = [
 
682
    scenarios = mirror_scenarios(
 
683
        [
579
684
            # File created with different file-ids
580
685
            (dict(_base_actions='nothing'),
581
686
             ('filea_created',
584
689
             ('fileb_created',
585
690
              dict(actions='create_file_b', check='file_content_b',
586
691
                   path='file', file_id='file-b-id')),),
587
 
            ]
588
 
        return mirror_scenarios(base_scenarios)
 
692
            # File created with different file-ids but deleted on one side
 
693
            (dict(_base_actions='create_file_a'),
 
694
             ('filea_replaced',
 
695
              dict(actions='replace_file_a_by_b', check='file_content_b',
 
696
                   path='file', file_id='file-b-id')),
 
697
             ('filea_modified',
 
698
              dict(actions='modify_file_a', check='file_new_content',
 
699
                   path='file', file_id='file-a-id')),),
 
700
            ])
589
701
 
590
702
    def do_nothing(self):
591
703
        return []
602
714
    def check_file_content_b(self):
603
715
        self.assertFileEqual('file b content\n', 'branch/file')
604
716
 
 
717
    def do_replace_file_a_by_b(self):
 
718
        return [('unversion', 'file'),
 
719
                ('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
 
720
 
 
721
    def do_modify_file_a(self):
 
722
        return [('modify', ('file', 'new content\n'))]
 
723
 
 
724
    def check_file_new_content(self):
 
725
        self.assertFileEqual('new content\n', 'branch/file')
 
726
 
605
727
    def _get_resolve_path_arg(self, wt, action):
606
728
        return self._this['path']
607
729
 
624
746
    # FIXME: While this *creates* UnversionedParent conflicts, this really only
625
747
    # tests MissingParent resolution :-/
626
748
    preamble = """
627
 
$ bzr init trunk
 
749
$ brz init trunk
 
750
...
628
751
$ cd trunk
629
752
$ mkdir dir
630
 
$ bzr add dir
631
 
$ bzr commit -m 'Create trunk'
632
 
 
 
753
$ brz add -q dir
 
754
$ brz commit -m 'Create trunk' -q
633
755
$ echo 'trunk content' >dir/file
634
 
$ bzr add dir/file
635
 
$ bzr commit -m 'Add dir/file in trunk'
636
 
 
637
 
$ bzr branch . -r 1 ../branch
 
756
$ brz add -q dir/file
 
757
$ brz commit -q -m 'Add dir/file in trunk'
 
758
$ brz branch -q . -r 1 ../branch
638
759
$ cd ../branch
639
 
$ bzr rm dir
640
 
$ bzr commit -m 'Remove dir in branch'
641
 
 
642
 
$ bzr merge ../trunk
 
760
$ brz rm dir -q
 
761
$ brz commit -q -m 'Remove dir in branch'
 
762
$ brz merge ../trunk
643
763
2>+N  dir/
644
764
2>+N  dir/file
645
765
2>Conflict adding files to dir.  Created directory.
649
769
 
650
770
    def test_take_this(self):
651
771
        self.run_script("""
652
 
$ bzr rm dir  --force
653
 
$ bzr resolve dir
654
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
772
$ brz rm -q dir --no-backup
 
773
$ brz resolve dir
 
774
2>2 conflicts resolved, 0 remaining
 
775
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
655
776
""")
656
777
 
657
778
    def test_take_other(self):
658
779
        self.run_script("""
659
 
$ bzr resolve dir
660
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
780
$ brz resolve dir
 
781
2>2 conflicts resolved, 0 remaining
 
782
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
661
783
""")
662
784
 
663
785
 
664
786
class TestResolveMissingParent(TestResolveConflicts):
665
787
 
666
788
    preamble = """
667
 
$ bzr init trunk
 
789
$ brz init trunk
 
790
...
668
791
$ cd trunk
669
792
$ mkdir dir
670
793
$ echo 'trunk content' >dir/file
671
 
$ bzr add
672
 
$ bzr commit -m 'Create trunk'
673
 
 
 
794
$ brz add -q
 
795
$ brz commit -m 'Create trunk' -q
674
796
$ echo 'trunk content' >dir/file2
675
 
$ bzr add dir/file2
676
 
$ bzr commit -m 'Add dir/file2 in branch'
677
 
 
678
 
$ bzr branch . -r 1 ../branch
 
797
$ brz add -q dir/file2
 
798
$ brz commit -q -m 'Add dir/file2 in branch'
 
799
$ brz branch -q . -r 1 ../branch
679
800
$ cd ../branch
680
 
$ bzr rm dir/file --force
681
 
$ bzr rm dir
682
 
$ bzr commit -m 'Remove dir/file'
683
 
 
684
 
$ bzr merge ../trunk
 
801
$ brz rm -q dir/file --no-backup
 
802
$ brz rm -q dir
 
803
$ brz commit -q -m 'Remove dir/file'
 
804
$ brz merge ../trunk
685
805
2>+N  dir/
686
806
2>+N  dir/file2
687
807
2>Conflict adding files to dir.  Created directory.
691
811
 
692
812
    def test_keep_them_all(self):
693
813
        self.run_script("""
694
 
$ bzr resolve dir
695
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
814
$ brz resolve dir
 
815
2>2 conflicts resolved, 0 remaining
 
816
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
696
817
""")
697
818
 
698
819
    def test_adopt_child(self):
699
820
        self.run_script("""
700
 
$ bzr mv dir/file2 file2
701
 
$ bzr rm dir --force
702
 
$ bzr resolve dir
703
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
821
$ brz mv -q dir/file2 file2
 
822
$ brz rm -q dir --no-backup
 
823
$ brz resolve dir
 
824
2>2 conflicts resolved, 0 remaining
 
825
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
704
826
""")
705
827
 
706
828
    def test_kill_them_all(self):
707
829
        self.run_script("""
708
 
$ bzr rm dir --force
709
 
$ bzr resolve dir
710
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
830
$ brz rm -q dir --no-backup
 
831
$ brz resolve dir
 
832
2>2 conflicts resolved, 0 remaining
 
833
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
711
834
""")
712
835
 
713
836
    def test_resolve_taking_this(self):
714
837
        self.run_script("""
715
 
$ bzr resolve --take-this dir
716
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
838
$ brz resolve --take-this dir
 
839
2>...
 
840
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
717
841
""")
718
842
 
719
843
    def test_resolve_taking_other(self):
720
844
        self.run_script("""
721
 
$ bzr resolve --take-other dir
722
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
845
$ brz resolve --take-other dir
 
846
2>...
 
847
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
723
848
""")
724
849
 
725
850
 
726
851
class TestResolveDeletingParent(TestResolveConflicts):
727
852
 
728
853
    preamble = """
729
 
$ bzr init trunk
 
854
$ brz init trunk
 
855
...
730
856
$ cd trunk
731
857
$ mkdir dir
732
858
$ echo 'trunk content' >dir/file
733
 
$ bzr add
734
 
$ bzr commit -m 'Create trunk'
735
 
 
736
 
$ bzr rm dir/file --force
737
 
$ bzr rm dir --force
738
 
$ bzr commit -m 'Remove dir/file'
739
 
 
740
 
$ bzr branch . -r 1 ../branch
 
859
$ brz add -q
 
860
$ brz commit -m 'Create trunk' -q
 
861
$ brz rm -q dir/file --no-backup
 
862
$ brz rm -q dir --no-backup
 
863
$ brz commit -q -m 'Remove dir/file'
 
864
$ brz branch -q . -r 1 ../branch
741
865
$ cd ../branch
742
866
$ echo 'branch content' >dir/file2
743
 
$ bzr add dir/file2
744
 
$ bzr commit -m 'Add dir/file2 in branch'
745
 
 
746
 
$ bzr merge ../trunk
 
867
$ brz add -q dir/file2
 
868
$ brz commit -q -m 'Add dir/file2 in branch'
 
869
$ brz merge ../trunk
747
870
2>-D  dir/file
748
871
2>Conflict: can't delete dir because it is not empty.  Not deleting.
749
872
2>Conflict because dir is not versioned, but has versioned children.  Versioned directory.
752
875
 
753
876
    def test_keep_them_all(self):
754
877
        self.run_script("""
755
 
$ bzr resolve dir
756
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
878
$ brz resolve dir
 
879
2>2 conflicts resolved, 0 remaining
 
880
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
757
881
""")
758
882
 
759
883
    def test_adopt_child(self):
760
884
        self.run_script("""
761
 
$ bzr mv dir/file2 file2
762
 
$ bzr rm dir --force
763
 
$ bzr resolve dir
764
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
885
$ brz mv -q dir/file2 file2
 
886
$ brz rm -q dir --no-backup
 
887
$ brz resolve dir
 
888
2>2 conflicts resolved, 0 remaining
 
889
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
765
890
""")
766
891
 
767
892
    def test_kill_them_all(self):
768
893
        self.run_script("""
769
 
$ bzr rm dir --force
770
 
$ bzr resolve dir
771
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
894
$ brz rm -q dir --no-backup
 
895
$ brz resolve dir
 
896
2>2 conflicts resolved, 0 remaining
 
897
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
772
898
""")
773
899
 
774
900
    def test_resolve_taking_this(self):
775
901
        self.run_script("""
776
 
$ bzr resolve --take-this dir
777
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
902
$ brz resolve --take-this dir
 
903
2>2 conflicts resolved, 0 remaining
 
904
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
778
905
""")
779
906
 
780
907
    def test_resolve_taking_other(self):
781
908
        self.run_script("""
782
 
$ bzr resolve --take-other dir
783
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
909
$ brz resolve --take-other dir
 
910
2>deleted dir/file2
 
911
2>deleted dir
 
912
2>2 conflicts resolved, 0 remaining
 
913
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
784
914
""")
785
915
 
786
916
 
787
917
class TestResolveParentLoop(TestParametrizedResolveConflicts):
788
918
 
789
 
    _conflict_type = conflicts.ParentLoop,
 
919
    _conflict_type = conflicts.ParentLoop
790
920
 
791
921
    _this_args = None
792
922
    _other_args = None
793
923
 
794
 
    @staticmethod
795
 
    def scenarios():
796
 
        # Each side dict additionally defines:
797
 
        # - dir_id: the directory being moved
798
 
        # - target_id: The target directory
799
 
        # - xfail: whether the test is expected to fail if the action is
800
 
        #     involved as 'other'
801
 
        base_scenarios = [
 
924
    # Each side dict additionally defines:
 
925
    # - dir_id: the directory being moved
 
926
    # - target_id: The target directory
 
927
    # - xfail: whether the test is expected to fail if the action is
 
928
    #   involved as 'other'
 
929
    scenarios = mirror_scenarios(
 
930
        [
802
931
            # Dirs moved into each other
803
932
            (dict(_base_actions='create_dir1_dir2'),
804
933
             ('dir1_into_dir2',
815
944
             ('dir3_into_dir2',
816
945
              dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
817
946
                   dir_id='dir3-id', target_id='dir2-id', xfail=True))),
818
 
            ]
819
 
        return mirror_scenarios(base_scenarios)
 
947
            ])
820
948
 
821
949
    def do_create_dir1_dir2(self):
822
950
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
826
954
        return [('rename', ('dir1', 'dir2/dir1'))]
827
955
 
828
956
    def check_dir1_moved(self):
829
 
        self.failIfExists('branch/dir1')
830
 
        self.failUnlessExists('branch/dir2/dir1')
 
957
        self.assertPathDoesNotExist('branch/dir1')
 
958
        self.assertPathExists('branch/dir2/dir1')
831
959
 
832
960
    def do_move_dir2_into_dir1(self):
833
961
        return [('rename', ('dir2', 'dir1/dir2'))]
834
962
 
835
963
    def check_dir2_moved(self):
836
 
        self.failIfExists('branch/dir2')
837
 
        self.failUnlessExists('branch/dir1/dir2')
 
964
        self.assertPathDoesNotExist('branch/dir2')
 
965
        self.assertPathExists('branch/dir1/dir2')
838
966
 
839
967
    def do_create_dir1_4(self):
840
968
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
846
974
        return [('rename', ('dir1', 'dir3/dir4/dir1'))]
847
975
 
848
976
    def check_dir1_2_moved(self):
849
 
        self.failIfExists('branch/dir1')
850
 
        self.failUnlessExists('branch/dir3/dir4/dir1')
851
 
        self.failUnlessExists('branch/dir3/dir4/dir1/dir2')
 
977
        self.assertPathDoesNotExist('branch/dir1')
 
978
        self.assertPathExists('branch/dir3/dir4/dir1')
 
979
        self.assertPathExists('branch/dir3/dir4/dir1/dir2')
852
980
 
853
981
    def do_move_dir3_into_dir2(self):
854
982
        return [('rename', ('dir3', 'dir1/dir2/dir3'))]
855
983
 
856
984
    def check_dir3_4_moved(self):
857
 
        self.failIfExists('branch/dir3')
858
 
        self.failUnlessExists('branch/dir1/dir2/dir3')
859
 
        self.failUnlessExists('branch/dir1/dir2/dir3/dir4')
 
985
        self.assertPathDoesNotExist('branch/dir3')
 
986
        self.assertPathExists('branch/dir1/dir2/dir3')
 
987
        self.assertPathExists('branch/dir1/dir2/dir3/dir4')
860
988
 
861
989
    def _get_resolve_path_arg(self, wt, action):
862
990
        # ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
873
1001
        if self._other['xfail']:
874
1002
            # It's a bit hackish to raise from here relying on being called for
875
1003
            # both tests but this avoid overriding test_resolve_taking_other
876
 
            raise tests.KnownFailure(
 
1004
            self.knownFailure(
877
1005
                "ParentLoop doesn't carry enough info to resolve --take-other")
878
1006
    _assert_conflict = assertParentLoop
879
1007
 
881
1009
class TestResolveNonDirectoryParent(TestResolveConflicts):
882
1010
 
883
1011
    preamble = """
884
 
$ bzr init trunk
 
1012
$ brz init trunk
 
1013
...
885
1014
$ cd trunk
886
 
$ bzr mkdir foo
887
 
$ bzr commit -m 'Create trunk'
 
1015
$ brz mkdir foo
 
1016
...
 
1017
$ brz commit -m 'Create trunk' -q
888
1018
$ echo "Boing" >foo/bar
889
 
$ bzr add foo/bar
890
 
$ bzr commit -m 'Add foo/bar'
891
 
 
892
 
$ bzr branch . -r 1 ../branch
 
1019
$ brz add -q foo/bar
 
1020
$ brz commit -q -m 'Add foo/bar'
 
1021
$ brz branch -q . -r 1 ../branch
893
1022
$ cd ../branch
894
1023
$ rm -r foo
895
1024
$ echo "Boo!" >foo
896
 
$ bzr commit -m 'foo is now a file'
897
 
 
898
 
$ bzr merge ../trunk
 
1025
$ brz commit -q -m 'foo is now a file'
 
1026
$ brz merge ../trunk
899
1027
2>+N  foo.new/bar
900
1028
2>RK  foo => foo.new/
901
1029
# FIXME: The message is misleading, foo.new *is* a directory when the message
906
1034
 
907
1035
    def test_take_this(self):
908
1036
        self.run_script("""
909
 
$ bzr rm foo.new --force
 
1037
$ brz rm -q foo.new --no-backup
910
1038
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
911
1039
# aside ? -- vila 090916
912
 
$ bzr add foo
913
 
$ bzr resolve foo.new
914
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
1040
$ brz add -q foo
 
1041
$ brz resolve foo.new
 
1042
2>1 conflict resolved, 0 remaining
 
1043
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
915
1044
""")
916
1045
 
917
1046
    def test_take_other(self):
918
1047
        self.run_script("""
919
 
$ bzr rm foo --force
920
 
$ bzr mv foo.new foo
921
 
$ bzr resolve foo
922
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
1048
$ brz rm -q foo --no-backup
 
1049
$ brz mv -q foo.new foo
 
1050
$ brz resolve foo
 
1051
2>1 conflict resolved, 0 remaining
 
1052
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
923
1053
""")
924
1054
 
925
1055
    def test_resolve_taking_this(self):
926
1056
        self.run_script("""
927
 
$ bzr resolve --take-this foo.new
928
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
1057
$ brz resolve --take-this foo.new
 
1058
2>...
 
1059
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
929
1060
""")
930
1061
 
931
1062
    def test_resolve_taking_other(self):
932
1063
        self.run_script("""
933
 
$ bzr resolve --take-other foo.new
934
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
1064
$ brz resolve --take-other foo.new
 
1065
2>...
 
1066
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
935
1067
""")
936
1068
 
937
1069
 
941
1073
        # This is nearly like TestResolveNonDirectoryParent but with branch and
942
1074
        # trunk switched. As such it should certainly produce the same
943
1075
        # conflict.
944
 
        self.run_script("""
945
 
$ bzr init trunk
 
1076
        self.assertRaises(errors.MalformedTransform,
 
1077
                          self.run_script, """
 
1078
$ brz init trunk
 
1079
...
946
1080
$ cd trunk
947
 
$ bzr mkdir foo
948
 
$ bzr commit -m 'Create trunk'
 
1081
$ brz mkdir foo
 
1082
...
 
1083
$ brz commit -m 'Create trunk' -q
949
1084
$ rm -r foo
950
1085
$ echo "Boo!" >foo
951
 
$ bzr commit -m 'foo is now a file'
952
 
 
953
 
$ bzr branch . -r 1 ../branch
 
1086
$ brz commit -m 'foo is now a file' -q
 
1087
$ brz branch -q . -r 1 ../branch -q
954
1088
$ cd ../branch
955
1089
$ echo "Boing" >foo/bar
956
 
$ bzr add foo/bar
957
 
$ bzr commit -m 'Add foo/bar'
958
 
 
959
 
$ bzr merge ../trunk
960
 
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
 
1090
$ brz add -q foo/bar -q
 
1091
$ brz commit -m 'Add foo/bar' -q
 
1092
$ brz merge ../trunk
 
1093
2>brz: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
 
1094
""")
 
1095
 
 
1096
 
 
1097
class TestNoFinalPath(script.TestCaseWithTransportAndScript):
 
1098
 
 
1099
    def test_bug_805809(self):
 
1100
        self.run_script("""
 
1101
$ brz init trunk
 
1102
Created a standalone tree (format: 2a)
 
1103
$ cd trunk
 
1104
$ echo trunk >file
 
1105
$ brz add
 
1106
adding file
 
1107
$ brz commit -m 'create file on trunk'
 
1108
2>Committing to: .../trunk/
 
1109
2>added file
 
1110
2>Committed revision 1.
 
1111
# Create a debian branch based on trunk
 
1112
$ cd ..
 
1113
$ brz branch trunk -r 1 debian
 
1114
2>Branched 1 revision.
 
1115
$ cd debian
 
1116
$ mkdir dir
 
1117
$ brz add
 
1118
adding dir
 
1119
$ brz mv file dir
 
1120
file => dir/file
 
1121
$ brz commit -m 'rename file to dir/file for debian'
 
1122
2>Committing to: .../debian/
 
1123
2>added dir
 
1124
2>renamed file => dir/file
 
1125
2>Committed revision 2.
 
1126
# Create an experimental branch with a new root-id
 
1127
$ cd ..
 
1128
$ brz init experimental
 
1129
Created a standalone tree (format: 2a)
 
1130
$ cd experimental
 
1131
# Work around merging into empty branch not being supported
 
1132
# (http://pad.lv/308562)
 
1133
$ echo something >not-empty
 
1134
$ brz add
 
1135
adding not-empty
 
1136
$ brz commit -m 'Add some content in experimental'
 
1137
2>Committing to: .../experimental/
 
1138
2>added not-empty
 
1139
2>Committed revision 1.
 
1140
# merge debian even without a common ancestor
 
1141
$ brz merge ../debian -r0..2
 
1142
2>+N  dir/
 
1143
2>+N  dir/file
 
1144
2>All changes applied successfully.
 
1145
$ brz commit -m 'merging debian into experimental'
 
1146
2>Committing to: .../experimental/
 
1147
2>added dir
 
1148
2>added dir/file
 
1149
2>Committed revision 2.
 
1150
# Create an ubuntu branch with yet another root-id
 
1151
$ cd ..
 
1152
$ brz init ubuntu
 
1153
Created a standalone tree (format: 2a)
 
1154
$ cd ubuntu
 
1155
# Work around merging into empty branch not being supported
 
1156
# (http://pad.lv/308562)
 
1157
$ echo something >not-empty-ubuntu
 
1158
$ brz add
 
1159
adding not-empty-ubuntu
 
1160
$ brz commit -m 'Add some content in experimental'
 
1161
2>Committing to: .../ubuntu/
 
1162
2>added not-empty-ubuntu
 
1163
2>Committed revision 1.
 
1164
# Also merge debian
 
1165
$ brz merge ../debian -r0..2
 
1166
2>+N  dir/
 
1167
2>+N  dir/file
 
1168
2>All changes applied successfully.
 
1169
$ brz commit -m 'merging debian'
 
1170
2>Committing to: .../ubuntu/
 
1171
2>added dir
 
1172
2>added dir/file
 
1173
2>Committed revision 2.
 
1174
# Now try to merge experimental
 
1175
$ brz merge ../experimental
 
1176
2>+N  not-empty
 
1177
2>Path conflict: dir / dir
 
1178
2>1 conflicts encountered.
961
1179
""")
962
1180
 
963
1181
 
973
1191
        return self.parser.parse_args(args)
974
1192
 
975
1193
    def test_unknown_action(self):
976
 
        self.assertRaises(errors.BadOptionValue,
 
1194
        self.assertRaises(option.BadOptionValue,
977
1195
                          self.parse, ['--action', 'take-me-to-the-moon'])
978
1196
 
979
1197
    def test_done(self):