/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_conflicts.py

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

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