/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: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

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 ..sixish import text_type
 
28
from . import (
 
29
    script,
 
30
    scenarios,
 
31
    )
 
32
 
 
33
 
 
34
load_tests = scenarios.load_tests_apply_scenarios
49
35
 
50
36
 
51
37
# TODO: Test commit with some added, and added-but-missing files
57
43
# '\xc3\xae' == u'\xee' == i with hat
58
44
# So these are u'path' and 'id' only with a circle and a hat. (shappo?)
59
45
example_conflicts = conflicts.ConflictList(
60
 
    [conflicts.MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
61
 
     conflicts.ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
 
46
    [conflicts.MissingParent('Not deleting', u'p\xe5thg', b'\xc3\xaedg'),
 
47
     conflicts.ContentsConflict(u'p\xe5tha', None, b'\xc3\xaeda'),
62
48
     conflicts.TextConflict(u'p\xe5tha'),
63
 
     conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
 
49
     conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', b'\xc3\xaedb'),
64
50
     conflicts.DuplicateID('Unversioned existing file',
65
51
                           u'p\xe5thc', u'p\xe5thc2',
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
 
])
 
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})
77
68
 
78
69
 
79
70
class TestConflicts(tests.TestCaseWithTransport):
80
71
 
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
72
    def test_resolve_conflict_dir(self):
109
73
        tree = self.make_branch_and_tree('.')
110
 
        self.build_tree_contents([('hello', 'hello world4'),
111
 
                                  ('hello.THIS', 'hello world2'),
112
 
                                  ('hello.BASE', 'hello world1'),
 
74
        self.build_tree_contents([('hello', b'hello world4'),
 
75
                                  ('hello.THIS', b'hello world2'),
 
76
                                  ('hello.BASE', b'hello world1'),
113
77
                                  ])
114
78
        os.mkdir('hello.OTHER')
115
 
        tree.add('hello', 'q')
 
79
        tree.add('hello', b'q')
116
80
        l = conflicts.ConflictList([conflicts.TextConflict('hello')])
117
81
        l.remove_files(tree)
118
82
 
133
97
        check_select(clist(), tree_conflicts,
134
98
                     [''], ignore_misses=True, recurse=True)
135
99
 
136
 
        foobaz  = conflicts.ContentsConflict('foo/baz')
 
100
        foobaz = conflicts.ContentsConflict('foo/baz')
137
101
        tree_conflicts = clist([foobaz, bar])
138
102
 
139
103
        check_select(clist([bar]), clist([foobaz]),
144
108
 
145
109
        check_select(clist(), tree_conflicts,
146
110
                     ['foo'], ignore_misses=True, recurse=True)
147
 
        check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
 
111
        check_select(tree_conflicts, clist(), ['foo'], ignore_misses=True)
148
112
 
149
113
    def test_resolve_conflicts_recursive(self):
150
114
        tree = self.make_branch_and_tree('.')
151
115
        self.build_tree(['dir/', 'dir/hello'])
152
116
        tree.add(['dir', 'dir/hello'])
153
117
 
154
 
        dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
 
118
        dirhello = conflicts.ConflictList(
 
119
            [conflicts.TextConflict('dir/hello')])
155
120
        tree.set_conflicts(dirhello)
156
121
 
157
122
        conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
161
126
        self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
162
127
 
163
128
 
164
 
class TestConflictStanzas(tests.TestCase):
 
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__)
165
139
 
166
140
    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)
 
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)
185
157
 
186
158
    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')
 
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))
196
180
 
197
181
 
198
182
# FIXME: The shell-like tests should be converted to real whitebox tests... or
203
187
# FIXME: Tests missing for DuplicateID conflict type
204
188
class TestResolveConflicts(script.TestCaseWithTransportAndScript):
205
189
 
206
 
    preamble = None # The setup script set by daughter classes
 
190
    preamble = None  # The setup script set by daughter classes
207
191
 
208
192
    def setUp(self):
209
193
        super(TestResolveConflicts, self).setUp()
210
194
        self.run_script(self.preamble)
211
195
 
212
196
 
213
 
class TestResolveTextConflicts(TestResolveConflicts):
214
 
    # TBC
215
 
    pass
216
 
 
217
 
 
218
197
def mirror_scenarios(base_scenarios):
219
198
    """Return a list of mirrored scenarios.
220
199
 
293
272
    _this = None
294
273
    _other = None
295
274
 
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 []
 
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
    """
324
300
 
325
301
    def setUp(self):
326
302
        super(TestParametrizedResolveConflicts, self).setUp()
328
304
        builder.start_series()
329
305
 
330
306
        # Create an empty trunk
331
 
        builder.build_snapshot('start', None, [
332
 
                ('add', ('', 'root-id', 'directory', ''))])
 
307
        builder.build_snapshot(None, [
 
308
            ('add', (u'', b'root-id', 'directory', ''))],
 
309
            revision_id=b'start')
333
310
        # Add a minimal base content
334
311
        base_actions = self._get_actions(self._base_actions)()
335
 
        builder.build_snapshot('base', ['start'], base_actions)
 
312
        builder.build_snapshot([b'start'], base_actions, revision_id=b'base')
336
313
        # Modify the base content in branch
337
314
        actions_other = self._get_actions(self._other['actions'])()
338
 
        builder.build_snapshot('other', ['base'], actions_other)
 
315
        builder.build_snapshot([b'base'], actions_other, revision_id=b'other')
339
316
        # Modify the base content in trunk
340
317
        actions_this = self._get_actions(self._this['actions'])()
341
 
        builder.build_snapshot('this', ['base'], actions_this)
 
318
        builder.build_snapshot([b'base'], actions_this, revision_id=b'this')
342
319
        # builder.get_branch() tip is now 'this'
343
320
 
344
321
        builder.finish_series()
352
329
 
353
330
    def _merge_other_into_this(self):
354
331
        b = self.builder.get_branch()
355
 
        wt = b.bzrdir.sprout('branch').open_workingtree()
356
 
        wt.merge_from_branch(b, 'other')
 
332
        wt = b.controldir.sprout('branch').open_workingtree()
 
333
        wt.merge_from_branch(b, b'other')
357
334
        return wt
358
335
 
359
336
    def assertConflict(self, wt):
388
365
        check_other()
389
366
 
390
367
 
 
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
 
391
439
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
392
440
 
393
 
    _conflict_type = conflicts.ContentsConflict,
 
441
    _conflict_type = conflicts.ContentsConflict
394
442
 
395
 
    # Set by load_tests from scenarios()
 
443
    # Set by the scenarios
396
444
    # path and file-id for the file involved in the conflict
397
445
    _path = None
398
446
    _file_id = None
399
447
 
400
 
    @staticmethod
401
 
    def scenarios():
402
 
        base_scenarios = [
 
448
    scenarios = mirror_scenarios(
 
449
        [
403
450
            # File modified/deleted
404
451
            (dict(_base_actions='create_file',
405
 
                  _path='file', _file_id='file-id'),
 
452
                  _path='file', _file_id=b'file-id'),
406
453
             ('file_modified',
407
454
              dict(actions='modify_file', check='file_has_more_content')),
408
455
             ('file_deleted',
409
456
              dict(actions='delete_file', check='file_doesnt_exist')),),
410
 
            ]
411
 
        return mirror_scenarios(base_scenarios)
 
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
            ])
412
475
 
413
476
    def do_create_file(self):
414
 
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
 
477
        return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
415
478
 
416
479
    def do_modify_file(self):
417
 
        return [('modify', ('file-id', 'trunk content\nmore content\n'))]
 
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'))]
418
485
 
419
486
    def check_file_has_more_content(self):
420
 
        self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
 
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')
421
492
 
422
493
    def do_delete_file(self):
423
 
        return [('unversion', 'file-id')]
 
494
        return [('unversion', 'file')]
 
495
 
 
496
    def do_delete_file_in_dir(self):
 
497
        return [('unversion', 'dir/file')]
424
498
 
425
499
    def check_file_doesnt_exist(self):
426
 
        self.failIfExists('branch/file')
 
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')
427
515
 
428
516
    def _get_resolve_path_arg(self, wt, action):
429
517
        return self._path
436
524
 
437
525
class TestResolvePathConflict(TestParametrizedResolveConflicts):
438
526
 
439
 
    _conflict_type = conflicts.PathConflict,
 
527
    _conflict_type = conflicts.PathConflict
440
528
 
441
529
    def do_nothing(self):
442
530
        return []
443
531
 
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 = [
 
532
    # Each side dict additionally defines:
 
533
    # - path path involved (can be '<deleted>')
 
534
    # - file-id involved
 
535
    scenarios = mirror_scenarios(
 
536
        [
450
537
            # File renamed/deleted
451
538
            (dict(_base_actions='create_file'),
452
539
             ('file_renamed',
453
540
              dict(actions='rename_file', check='file_renamed',
454
 
                   path='new-file', file_id='file-id')),
 
541
                   path='new-file', file_id=b'file-id')),
455
542
             ('file_deleted',
456
543
              dict(actions='delete_file', check='file_doesnt_exist',
457
544
                   # PathConflicts deletion handling requires a special
458
545
                   # hard-coded value
459
 
                   path='<deleted>', file_id='file-id')),),
 
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')),),
460
557
            # File renamed/renamed differently
461
558
            (dict(_base_actions='create_file'),
462
559
             ('file_renamed',
463
560
              dict(actions='rename_file', check='file_renamed',
464
 
                   path='new-file', file_id='file-id')),
 
561
                   path='new-file', file_id=b'file-id')),
465
562
             ('file_renamed2',
466
563
              dict(actions='rename_file2', check='file_renamed2',
467
 
                   path='new-file2', file_id='file-id')),),
 
564
                   path='new-file2', file_id=b'file-id')),),
468
565
            # Dir renamed/deleted
469
566
            (dict(_base_actions='create_dir'),
470
567
             ('dir_renamed',
471
568
              dict(actions='rename_dir', check='dir_renamed',
472
 
                   path='new-dir', file_id='dir-id')),
 
569
                   path='new-dir', file_id=b'dir-id')),
473
570
             ('dir_deleted',
474
571
              dict(actions='delete_dir', check='dir_doesnt_exist',
475
572
                   # PathConflicts deletion handling requires a special
476
573
                   # hard-coded value
477
 
                   path='<deleted>', file_id='dir-id')),),
 
574
                   path='<deleted>', file_id=b'dir-id')),),
478
575
            # Dir renamed/renamed differently
479
576
            (dict(_base_actions='create_dir'),
480
577
             ('dir_renamed',
481
578
              dict(actions='rename_dir', check='dir_renamed',
482
 
                   path='new-dir', file_id='dir-id')),
 
579
                   path='new-dir', file_id=b'dir-id')),
483
580
             ('dir_renamed2',
484
581
              dict(actions='rename_dir2', check='dir_renamed2',
485
 
                   path='new-dir2', file_id='dir-id')),),
486
 
        ]
487
 
        return mirror_scenarios(base_scenarios)
 
582
                   path='new-dir2', file_id=b'dir-id')),),
 
583
            ])
488
584
 
489
585
    def do_create_file(self):
490
 
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
 
586
        return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
491
587
 
492
588
    def do_create_dir(self):
493
 
        return [('add', ('dir', 'dir-id', 'directory', ''))]
 
589
        return [('add', ('dir', b'dir-id', 'directory', ''))]
494
590
 
495
591
    def do_rename_file(self):
496
592
        return [('rename', ('file', 'new-file'))]
497
593
 
498
594
    def check_file_renamed(self):
499
 
        self.failIfExists('branch/file')
500
 
        self.failUnlessExists('branch/new-file')
 
595
        self.assertPathDoesNotExist('branch/file')
 
596
        self.assertPathExists('branch/new-file')
501
597
 
502
598
    def do_rename_file2(self):
503
599
        return [('rename', ('file', 'new-file2'))]
504
600
 
505
601
    def check_file_renamed2(self):
506
 
        self.failIfExists('branch/file')
507
 
        self.failUnlessExists('branch/new-file2')
 
602
        self.assertPathDoesNotExist('branch/file')
 
603
        self.assertPathExists('branch/new-file2')
508
604
 
509
605
    def do_rename_dir(self):
510
606
        return [('rename', ('dir', 'new-dir'))]
511
607
 
512
608
    def check_dir_renamed(self):
513
 
        self.failIfExists('branch/dir')
514
 
        self.failUnlessExists('branch/new-dir')
 
609
        self.assertPathDoesNotExist('branch/dir')
 
610
        self.assertPathExists('branch/new-dir')
515
611
 
516
612
    def do_rename_dir2(self):
517
613
        return [('rename', ('dir', 'new-dir2'))]
518
614
 
519
615
    def check_dir_renamed2(self):
520
 
        self.failIfExists('branch/dir')
521
 
        self.failUnlessExists('branch/new-dir2')
 
616
        self.assertPathDoesNotExist('branch/dir')
 
617
        self.assertPathExists('branch/new-dir2')
522
618
 
523
619
    def do_delete_file(self):
524
 
        return [('unversion', 'file-id')]
 
620
        return [('unversion', 'file')]
 
621
 
 
622
    def do_delete_file_in_dir(self):
 
623
        return [('unversion', 'dir/file')]
525
624
 
526
625
    def check_file_doesnt_exist(self):
527
 
        self.failIfExists('branch/file')
 
626
        self.assertPathDoesNotExist('branch/file')
528
627
 
529
628
    def do_delete_dir(self):
530
 
        return [('unversion', 'dir-id')]
 
629
        return [('unversion', 'dir')]
531
630
 
532
631
    def check_dir_doesnt_exist(self):
533
 
        self.failIfExists('branch/dir')
 
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')
534
647
 
535
648
    def _get_resolve_path_arg(self, wt, action):
536
649
        tpath = self._this['path']
546
659
        tfile_id = self._this['file_id']
547
660
        opath = self._other['path']
548
661
        ofile_id = self._other['file_id']
549
 
        self.assertEqual(tfile_id, ofile_id) # Sanity check
 
662
        self.assertEqual(tfile_id, ofile_id)  # Sanity check
550
663
        self.assertEqual(tfile_id, c.file_id)
551
664
        self.assertEqual(tpath, c.path)
552
665
        self.assertEqual(opath, c.conflict_path)
568
681
 
569
682
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
570
683
 
571
 
    _conflict_type = conflicts.DuplicateEntry,
 
684
    _conflict_type = conflicts.DuplicateEntry
572
685
 
573
 
    @staticmethod
574
 
    def scenarios():
575
 
        # Each side dict additionally defines:
576
 
        # - path involved
577
 
        # - file-id involved
578
 
        base_scenarios = [
 
686
    scenarios = mirror_scenarios(
 
687
        [
579
688
            # File created with different file-ids
580
689
            (dict(_base_actions='nothing'),
581
690
             ('filea_created',
582
691
              dict(actions='create_file_a', check='file_content_a',
583
 
                   path='file', file_id='file-a-id')),
 
692
                   path='file', file_id=b'file-a-id')),
584
693
             ('fileb_created',
585
694
              dict(actions='create_file_b', check='file_content_b',
586
 
                   path='file', file_id='file-b-id')),),
587
 
            ]
588
 
        return mirror_scenarios(base_scenarios)
 
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
            ])
589
705
 
590
706
    def do_nothing(self):
591
707
        return []
592
708
 
593
709
    def do_create_file_a(self):
594
 
        return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
 
710
        return [('add', ('file', b'file-a-id', 'file', b'file a content\n'))]
595
711
 
596
712
    def check_file_content_a(self):
597
 
        self.assertFileEqual('file a content\n', 'branch/file')
 
713
        self.assertFileEqual(b'file a content\n', 'branch/file')
598
714
 
599
715
    def do_create_file_b(self):
600
 
        return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
 
716
        return [('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
601
717
 
602
718
    def check_file_content_b(self):
603
 
        self.assertFileEqual('file b content\n', 'branch/file')
 
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')
604
730
 
605
731
    def _get_resolve_path_arg(self, wt, action):
606
732
        return self._this['path']
610
736
        tfile_id = self._this['file_id']
611
737
        opath = self._other['path']
612
738
        ofile_id = self._other['file_id']
613
 
        self.assertEqual(tpath, opath) # Sanity check
 
739
        self.assertEqual(tpath, opath)  # Sanity check
614
740
        self.assertEqual(tfile_id, c.file_id)
615
741
        self.assertEqual(tpath + '.moved', c.path)
616
742
        self.assertEqual(tpath, c.conflict_path)
624
750
    # FIXME: While this *creates* UnversionedParent conflicts, this really only
625
751
    # tests MissingParent resolution :-/
626
752
    preamble = """
627
 
$ bzr init trunk
 
753
$ brz init trunk
 
754
...
628
755
$ cd trunk
629
756
$ mkdir dir
630
 
$ bzr add dir
631
 
$ bzr commit -m 'Create trunk'
632
 
 
 
757
$ brz add -q dir
 
758
$ brz commit -m 'Create trunk' -q
633
759
$ 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
 
760
$ brz add -q dir/file
 
761
$ brz commit -q -m 'Add dir/file in trunk'
 
762
$ brz branch -q . -r 1 ../branch
638
763
$ cd ../branch
639
 
$ bzr rm dir
640
 
$ bzr commit -m 'Remove dir in branch'
641
 
 
642
 
$ bzr merge ../trunk
 
764
$ brz rm dir -q
 
765
$ brz commit -q -m 'Remove dir in branch'
 
766
$ brz merge ../trunk
643
767
2>+N  dir/
644
768
2>+N  dir/file
645
769
2>Conflict adding files to dir.  Created directory.
649
773
 
650
774
    def test_take_this(self):
651
775
        self.run_script("""
652
 
$ bzr rm dir  --force
653
 
$ bzr resolve dir
654
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
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'
655
780
""")
656
781
 
657
782
    def test_take_other(self):
658
783
        self.run_script("""
659
 
$ bzr resolve dir
660
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
784
$ brz resolve dir
 
785
2>2 conflicts resolved, 0 remaining
 
786
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
661
787
""")
662
788
 
663
789
 
664
790
class TestResolveMissingParent(TestResolveConflicts):
665
791
 
666
792
    preamble = """
667
 
$ bzr init trunk
 
793
$ brz init trunk
 
794
...
668
795
$ cd trunk
669
796
$ mkdir dir
670
797
$ echo 'trunk content' >dir/file
671
 
$ bzr add
672
 
$ bzr commit -m 'Create trunk'
673
 
 
 
798
$ brz add -q
 
799
$ brz commit -m 'Create trunk' -q
674
800
$ 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
 
801
$ brz add -q dir/file2
 
802
$ brz commit -q -m 'Add dir/file2 in branch'
 
803
$ brz branch -q . -r 1 ../branch
679
804
$ cd ../branch
680
 
$ bzr rm dir/file --force
681
 
$ bzr rm dir
682
 
$ bzr commit -m 'Remove dir/file'
683
 
 
684
 
$ bzr merge ../trunk
 
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
685
809
2>+N  dir/
686
810
2>+N  dir/file2
687
811
2>Conflict adding files to dir.  Created directory.
691
815
 
692
816
    def test_keep_them_all(self):
693
817
        self.run_script("""
694
 
$ bzr resolve dir
695
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
818
$ brz resolve dir
 
819
2>2 conflicts resolved, 0 remaining
 
820
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
696
821
""")
697
822
 
698
823
    def test_adopt_child(self):
699
824
        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'
 
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'
704
830
""")
705
831
 
706
832
    def test_kill_them_all(self):
707
833
        self.run_script("""
708
 
$ bzr rm dir --force
709
 
$ bzr resolve dir
710
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
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'
711
838
""")
712
839
 
713
840
    def test_resolve_taking_this(self):
714
841
        self.run_script("""
715
 
$ bzr resolve --take-this dir
716
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
842
$ brz resolve --take-this dir
 
843
2>...
 
844
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
717
845
""")
718
846
 
719
847
    def test_resolve_taking_other(self):
720
848
        self.run_script("""
721
 
$ bzr resolve --take-other dir
722
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
849
$ brz resolve --take-other dir
 
850
2>...
 
851
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
723
852
""")
724
853
 
725
854
 
726
855
class TestResolveDeletingParent(TestResolveConflicts):
727
856
 
728
857
    preamble = """
729
 
$ bzr init trunk
 
858
$ brz init trunk
 
859
...
730
860
$ cd trunk
731
861
$ mkdir dir
732
862
$ 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
 
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
741
869
$ cd ../branch
742
870
$ echo 'branch content' >dir/file2
743
 
$ bzr add dir/file2
744
 
$ bzr commit -m 'Add dir/file2 in branch'
745
 
 
746
 
$ bzr merge ../trunk
 
871
$ brz add -q dir/file2
 
872
$ brz commit -q -m 'Add dir/file2 in branch'
 
873
$ brz merge ../trunk
747
874
2>-D  dir/file
748
875
2>Conflict: can't delete dir because it is not empty.  Not deleting.
749
876
2>Conflict because dir is not versioned, but has versioned children.  Versioned directory.
752
879
 
753
880
    def test_keep_them_all(self):
754
881
        self.run_script("""
755
 
$ bzr resolve dir
756
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
882
$ brz resolve dir
 
883
2>2 conflicts resolved, 0 remaining
 
884
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
757
885
""")
758
886
 
759
887
    def test_adopt_child(self):
760
888
        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'
 
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'
765
894
""")
766
895
 
767
896
    def test_kill_them_all(self):
768
897
        self.run_script("""
769
 
$ bzr rm dir --force
770
 
$ bzr resolve dir
771
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
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'
772
902
""")
773
903
 
774
904
    def test_resolve_taking_this(self):
775
905
        self.run_script("""
776
 
$ bzr resolve --take-this dir
777
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
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'
778
909
""")
779
910
 
780
911
    def test_resolve_taking_other(self):
781
912
        self.run_script("""
782
 
$ bzr resolve --take-other dir
783
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
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'
784
918
""")
785
919
 
786
920
 
787
921
class TestResolveParentLoop(TestParametrizedResolveConflicts):
788
922
 
789
 
    _conflict_type = conflicts.ParentLoop,
 
923
    _conflict_type = conflicts.ParentLoop
790
924
 
791
925
    _this_args = None
792
926
    _other_args = None
793
927
 
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 = [
 
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
        [
802
935
            # Dirs moved into each other
803
936
            (dict(_base_actions='create_dir1_dir2'),
804
937
             ('dir1_into_dir2',
805
938
              dict(actions='move_dir1_into_dir2', check='dir1_moved',
806
 
                   dir_id='dir1-id', target_id='dir2-id', xfail=False)),
 
939
                   dir_id=b'dir1-id', target_id=b'dir2-id', xfail=False)),
807
940
             ('dir2_into_dir1',
808
941
              dict(actions='move_dir2_into_dir1', check='dir2_moved',
809
 
                   dir_id='dir2-id', target_id='dir1-id', xfail=False))),
 
942
                   dir_id=b'dir2-id', target_id=b'dir1-id', xfail=False))),
810
943
            # Subdirs moved into each other
811
944
            (dict(_base_actions='create_dir1_4'),
812
945
             ('dir1_into_dir4',
813
946
              dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
814
 
                   dir_id='dir1-id', target_id='dir4-id', xfail=True)),
 
947
                   dir_id=b'dir1-id', target_id=b'dir4-id', xfail=True)),
815
948
             ('dir3_into_dir2',
816
949
              dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
817
 
                   dir_id='dir3-id', target_id='dir2-id', xfail=True))),
818
 
            ]
819
 
        return mirror_scenarios(base_scenarios)
 
950
                   dir_id=b'dir3-id', target_id=b'dir2-id', xfail=True))),
 
951
            ])
820
952
 
821
953
    def do_create_dir1_dir2(self):
822
 
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
823
 
                ('add', ('dir2', 'dir2-id', 'directory', '')),]
 
954
        return [('add', ('dir1', b'dir1-id', 'directory', '')),
 
955
                ('add', ('dir2', b'dir2-id', 'directory', '')), ]
824
956
 
825
957
    def do_move_dir1_into_dir2(self):
826
958
        return [('rename', ('dir1', 'dir2/dir1'))]
827
959
 
828
960
    def check_dir1_moved(self):
829
 
        self.failIfExists('branch/dir1')
830
 
        self.failUnlessExists('branch/dir2/dir1')
 
961
        self.assertPathDoesNotExist('branch/dir1')
 
962
        self.assertPathExists('branch/dir2/dir1')
831
963
 
832
964
    def do_move_dir2_into_dir1(self):
833
965
        return [('rename', ('dir2', 'dir1/dir2'))]
834
966
 
835
967
    def check_dir2_moved(self):
836
 
        self.failIfExists('branch/dir2')
837
 
        self.failUnlessExists('branch/dir1/dir2')
 
968
        self.assertPathDoesNotExist('branch/dir2')
 
969
        self.assertPathExists('branch/dir1/dir2')
838
970
 
839
971
    def do_create_dir1_4(self):
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', '')),]
 
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', '')), ]
844
976
 
845
977
    def do_move_dir1_into_dir4(self):
846
978
        return [('rename', ('dir1', 'dir3/dir4/dir1'))]
847
979
 
848
980
    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')
 
981
        self.assertPathDoesNotExist('branch/dir1')
 
982
        self.assertPathExists('branch/dir3/dir4/dir1')
 
983
        self.assertPathExists('branch/dir3/dir4/dir1/dir2')
852
984
 
853
985
    def do_move_dir3_into_dir2(self):
854
986
        return [('rename', ('dir3', 'dir1/dir2/dir3'))]
855
987
 
856
988
    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')
 
989
        self.assertPathDoesNotExist('branch/dir3')
 
990
        self.assertPathExists('branch/dir1/dir2/dir3')
 
991
        self.assertPathExists('branch/dir1/dir2/dir3/dir4')
860
992
 
861
993
    def _get_resolve_path_arg(self, wt, action):
862
994
        # ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
873
1005
        if self._other['xfail']:
874
1006
            # It's a bit hackish to raise from here relying on being called for
875
1007
            # both tests but this avoid overriding test_resolve_taking_other
876
 
            raise tests.KnownFailure(
 
1008
            self.knownFailure(
877
1009
                "ParentLoop doesn't carry enough info to resolve --take-other")
878
1010
    _assert_conflict = assertParentLoop
879
1011
 
881
1013
class TestResolveNonDirectoryParent(TestResolveConflicts):
882
1014
 
883
1015
    preamble = """
884
 
$ bzr init trunk
 
1016
$ brz init trunk
 
1017
...
885
1018
$ cd trunk
886
 
$ bzr mkdir foo
887
 
$ bzr commit -m 'Create trunk'
 
1019
$ brz mkdir foo
 
1020
...
 
1021
$ brz commit -m 'Create trunk' -q
888
1022
$ echo "Boing" >foo/bar
889
 
$ bzr add foo/bar
890
 
$ bzr commit -m 'Add foo/bar'
891
 
 
892
 
$ bzr branch . -r 1 ../branch
 
1023
$ brz add -q foo/bar
 
1024
$ brz commit -q -m 'Add foo/bar'
 
1025
$ brz branch -q . -r 1 ../branch
893
1026
$ cd ../branch
894
1027
$ rm -r foo
895
1028
$ echo "Boo!" >foo
896
 
$ bzr commit -m 'foo is now a file'
897
 
 
898
 
$ bzr merge ../trunk
 
1029
$ brz commit -q -m 'foo is now a file'
 
1030
$ brz merge ../trunk
 
1031
2>RK  foo => foo.new/
899
1032
2>+N  foo.new/bar
900
 
2>RK  foo => foo.new/
901
1033
# FIXME: The message is misleading, foo.new *is* a directory when the message
902
1034
# is displayed -- vila 090916
903
1035
2>Conflict: foo.new is not a directory, but has files in it.  Created directory.
906
1038
 
907
1039
    def test_take_this(self):
908
1040
        self.run_script("""
909
 
$ bzr rm foo.new --force
 
1041
$ brz rm -q foo.new --no-backup
910
1042
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
911
1043
# aside ? -- vila 090916
912
 
$ bzr add foo
913
 
$ bzr resolve foo.new
914
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
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'
915
1048
""")
916
1049
 
917
1050
    def test_take_other(self):
918
1051
        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'
 
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'
923
1057
""")
924
1058
 
925
1059
    def test_resolve_taking_this(self):
926
1060
        self.run_script("""
927
 
$ bzr resolve --take-this foo.new
928
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
1061
$ brz resolve --take-this foo.new
 
1062
2>...
 
1063
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
929
1064
""")
930
1065
 
931
1066
    def test_resolve_taking_other(self):
932
1067
        self.run_script("""
933
 
$ bzr resolve --take-other foo.new
934
 
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
1068
$ brz resolve --take-other foo.new
 
1069
2>...
 
1070
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
935
1071
""")
936
1072
 
937
1073
 
941
1077
        # This is nearly like TestResolveNonDirectoryParent but with branch and
942
1078
        # trunk switched. As such it should certainly produce the same
943
1079
        # conflict.
944
 
        self.run_script("""
945
 
$ bzr init trunk
 
1080
        self.assertRaises(errors.MalformedTransform,
 
1081
                          self.run_script, """
 
1082
$ brz init trunk
 
1083
...
946
1084
$ cd trunk
947
 
$ bzr mkdir foo
948
 
$ bzr commit -m 'Create trunk'
 
1085
$ brz mkdir foo
 
1086
...
 
1087
$ brz commit -m 'Create trunk' -q
949
1088
$ rm -r foo
950
1089
$ echo "Boo!" >foo
951
 
$ bzr commit -m 'foo is now a file'
952
 
 
953
 
$ bzr branch . -r 1 ../branch
 
1090
$ brz commit -m 'foo is now a file' -q
 
1091
$ brz branch -q . -r 1 ../branch -q
954
1092
$ cd ../branch
955
1093
$ 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')]
 
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.
961
1183
""")
962
1184
 
963
1185
 
966
1188
    def setUp(self):
967
1189
        super(TestResolveActionOption, self).setUp()
968
1190
        self.options = [conflicts.ResolveActionOption()]
969
 
        self.parser = option.get_optparser(dict((o.name, o)
970
 
                                                for o in self.options))
 
1191
        self.parser = option.get_optparser(self.options)
971
1192
 
972
1193
    def parse(self, args):
973
1194
        return self.parser.parse_args(args)
974
1195
 
975
1196
    def test_unknown_action(self):
976
 
        self.assertRaises(errors.BadOptionValue,
 
1197
        self.assertRaises(option.BadOptionValue,
977
1198
                          self.parse, ['--action', 'take-me-to-the-moon'])
978
1199
 
979
1200
    def test_done(self):
980
1201
        opts, args = self.parse(['--action', 'done'])
981
 
        self.assertEqual({'action':'done'}, opts)
 
1202
        self.assertEqual({'action': 'done'}, opts)
982
1203
 
983
1204
    def test_take_this(self):
984
1205
        opts, args = self.parse(['--action', 'take-this'])