~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_conflicts.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil, Patch Queue Manager, Jelmer Vernooij
  • Date: 2017-01-17 16:20:41 UTC
  • mfrom: (6619.1.2 trunk)
  • Revision ID: tarmac-20170117162041-oo62uk1qsmgc9j31
Merge 2.7 into trunk including fixes for bugs #1622039, #1644003, #1579093 and #1645017. [r=vila]

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