~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_conflicts.py

  • Committer: Martin Pool
  • Date: 2010-06-02 05:03:31 UTC
  • mto: This revision was merged to the branch mainline in revision 5279.
  • Revision ID: mbp@canonical.com-20100602050331-n2p1qt8hfsahspnv
Correct more sloppy use of the term 'Linux'

Show diffs side-by-side

added added

removed removed

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