~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_conflicts.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-16 19:18:39 UTC
  • mto: This revision was merged to the branch mainline in revision 6391.
  • Revision ID: jelmer@samba.org-20111216191839-eg681lxqibi1qxu1
Fix remaining tests.

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
21
    bzrdir,
23
22
    conflicts,
24
23
    errors,
25
24
    option,
 
25
    osutils,
26
26
    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
 
27
    )
 
28
from bzrlib.tests 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
76
62
])
77
63
 
78
64
 
 
65
def vary_by_conflicts():
 
66
    for conflict in example_conflicts:
 
67
        yield (conflict.__class__.__name__, {"conflict": conflict})
 
68
 
 
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
74
        self.build_tree_contents([('hello', 'hello world4'),
161
125
        self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
162
126
 
163
127
 
164
 
class TestConflictStanzas(tests.TestCase):
 
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__)
165
138
 
166
139
    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)
 
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)
185
156
 
186
157
    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')
 
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))
196
179
 
197
180
 
198
181
# FIXME: The shell-like tests should be converted to real whitebox tests... or
210
193
        self.run_script(self.preamble)
211
194
 
212
195
 
213
 
class TestResolveTextConflicts(TestResolveConflicts):
214
 
    # TBC
215
 
    pass
216
 
 
217
 
 
218
196
def mirror_scenarios(base_scenarios):
219
197
    """Return a list of mirrored scenarios.
220
198
 
293
271
    _this = None
294
272
    _other = None
295
273
 
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 []
 
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
    """
324
299
 
325
300
    def setUp(self):
326
301
        super(TestParametrizedResolveConflicts, self).setUp()
388
363
        check_other()
389
364
 
390
365
 
 
366
class TestResolveTextConflicts(TestParametrizedResolveConflicts):
 
367
 
 
368
    _conflict_type = conflicts.TextConflict
 
369
 
 
370
    # Set by the scenarios
 
371
    # path and file-id for the file involved in the conflict
 
372
    _path = None
 
373
    _file_id = None
 
374
 
 
375
    scenarios = mirror_scenarios(
 
376
        [
 
377
            # File modified on both sides
 
378
            (dict(_base_actions='create_file',
 
379
                  _path='file', _file_id='file-id'),
 
380
             ('filed_modified_A',
 
381
              dict(actions='modify_file_A', check='file_has_content_A')),
 
382
             ('file_modified_B',
 
383
              dict(actions='modify_file_B', check='file_has_content_B')),),
 
384
            # File modified on both sides in dir
 
385
            (dict(_base_actions='create_file_in_dir',
 
386
                  _path='dir/file', _file_id='file-id'),
 
387
             ('filed_modified_A_in_dir',
 
388
              dict(actions='modify_file_A',
 
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
 
391
431
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
392
432
 
393
 
    _conflict_type = conflicts.ContentsConflict,
 
433
    _conflict_type = conflicts.ContentsConflict
394
434
 
395
 
    # Set by load_tests from scenarios()
 
435
    # Set by the scenarios
396
436
    # path and file-id for the file involved in the conflict
397
437
    _path = None
398
438
    _file_id = None
399
439
 
400
 
    @staticmethod
401
 
    def scenarios():
402
 
        base_scenarios = [
 
440
    scenarios = mirror_scenarios(
 
441
        [
403
442
            # File modified/deleted
404
443
            (dict(_base_actions='create_file',
405
444
                  _path='file', _file_id='file-id'),
407
446
              dict(actions='modify_file', check='file_has_more_content')),
408
447
             ('file_deleted',
409
448
              dict(actions='delete_file', check='file_doesnt_exist')),),
410
 
            ]
411
 
        return mirror_scenarios(base_scenarios)
 
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
            ])
412
467
 
413
468
    def do_create_file(self):
414
469
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
416
471
    def do_modify_file(self):
417
472
        return [('modify', ('file-id', 'trunk content\nmore content\n'))]
418
473
 
 
474
    def do_modify_and_rename_file(self):
 
475
        return [('modify', ('file-id', 'trunk content\nmore content\n')),
 
476
                ('rename', ('file', 'new-file'))]
 
477
 
419
478
    def check_file_has_more_content(self):
420
479
        self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
421
480
 
 
481
    def check_file_renamed_and_more_content(self):
 
482
        self.assertFileEqual('trunk content\nmore content\n', 'branch/new-file')
 
483
 
422
484
    def do_delete_file(self):
423
485
        return [('unversion', 'file-id')]
424
486
 
425
487
    def check_file_doesnt_exist(self):
426
 
        self.failIfExists('branch/file')
 
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')
427
502
 
428
503
    def _get_resolve_path_arg(self, wt, action):
429
504
        return self._path
436
511
 
437
512
class TestResolvePathConflict(TestParametrizedResolveConflicts):
438
513
 
439
 
    _conflict_type = conflicts.PathConflict,
 
514
    _conflict_type = conflicts.PathConflict
440
515
 
441
516
    def do_nothing(self):
442
517
        return []
443
518
 
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 = [
 
519
    # Each side dict additionally defines:
 
520
    # - path path involved (can be '<deleted>')
 
521
    # - file-id involved
 
522
    scenarios = mirror_scenarios(
 
523
        [
450
524
            # File renamed/deleted
451
525
            (dict(_base_actions='create_file'),
452
526
             ('file_renamed',
457
531
                   # PathConflicts deletion handling requires a special
458
532
                   # hard-coded value
459
533
                   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')),),
460
544
            # File renamed/renamed differently
461
545
            (dict(_base_actions='create_file'),
462
546
             ('file_renamed',
483
567
             ('dir_renamed2',
484
568
              dict(actions='rename_dir2', check='dir_renamed2',
485
569
                   path='new-dir2', file_id='dir-id')),),
486
 
        ]
487
 
        return mirror_scenarios(base_scenarios)
 
570
            ])
488
571
 
489
572
    def do_create_file(self):
490
573
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
496
579
        return [('rename', ('file', 'new-file'))]
497
580
 
498
581
    def check_file_renamed(self):
499
 
        self.failIfExists('branch/file')
500
 
        self.failUnlessExists('branch/new-file')
 
582
        self.assertPathDoesNotExist('branch/file')
 
583
        self.assertPathExists('branch/new-file')
501
584
 
502
585
    def do_rename_file2(self):
503
586
        return [('rename', ('file', 'new-file2'))]
504
587
 
505
588
    def check_file_renamed2(self):
506
 
        self.failIfExists('branch/file')
507
 
        self.failUnlessExists('branch/new-file2')
 
589
        self.assertPathDoesNotExist('branch/file')
 
590
        self.assertPathExists('branch/new-file2')
508
591
 
509
592
    def do_rename_dir(self):
510
593
        return [('rename', ('dir', 'new-dir'))]
511
594
 
512
595
    def check_dir_renamed(self):
513
 
        self.failIfExists('branch/dir')
514
 
        self.failUnlessExists('branch/new-dir')
 
596
        self.assertPathDoesNotExist('branch/dir')
 
597
        self.assertPathExists('branch/new-dir')
515
598
 
516
599
    def do_rename_dir2(self):
517
600
        return [('rename', ('dir', 'new-dir2'))]
518
601
 
519
602
    def check_dir_renamed2(self):
520
 
        self.failIfExists('branch/dir')
521
 
        self.failUnlessExists('branch/new-dir2')
 
603
        self.assertPathDoesNotExist('branch/dir')
 
604
        self.assertPathExists('branch/new-dir2')
522
605
 
523
606
    def do_delete_file(self):
524
607
        return [('unversion', 'file-id')]
525
608
 
526
609
    def check_file_doesnt_exist(self):
527
 
        self.failIfExists('branch/file')
 
610
        self.assertPathDoesNotExist('branch/file')
528
611
 
529
612
    def do_delete_dir(self):
530
613
        return [('unversion', 'dir-id')]
531
614
 
532
615
    def check_dir_doesnt_exist(self):
533
 
        self.failIfExists('branch/dir')
 
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')
534
631
 
535
632
    def _get_resolve_path_arg(self, wt, action):
536
633
        tpath = self._this['path']
568
665
 
569
666
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
570
667
 
571
 
    _conflict_type = conflicts.DuplicateEntry,
 
668
    _conflict_type = conflicts.DuplicateEntry
572
669
 
573
 
    @staticmethod
574
 
    def scenarios():
575
 
        # Each side dict additionally defines:
576
 
        # - path involved
577
 
        # - file-id involved
578
 
        base_scenarios = [
 
670
    scenarios = mirror_scenarios(
 
671
        [
579
672
            # File created with different file-ids
580
673
            (dict(_base_actions='nothing'),
581
674
             ('filea_created',
584
677
             ('fileb_created',
585
678
              dict(actions='create_file_b', check='file_content_b',
586
679
                   path='file', file_id='file-b-id')),),
587
 
            ]
588
 
        return mirror_scenarios(base_scenarios)
 
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
            ])
589
689
 
590
690
    def do_nothing(self):
591
691
        return []
602
702
    def check_file_content_b(self):
603
703
        self.assertFileEqual('file b content\n', 'branch/file')
604
704
 
 
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
 
605
715
    def _get_resolve_path_arg(self, wt, action):
606
716
        return self._this['path']
607
717
 
649
759
        self.run_script("""
650
760
$ bzr rm -q dir  --force
651
761
$ bzr resolve dir
 
762
2>2 conflicts resolved, 0 remaining
652
763
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
653
764
""")
654
765
 
655
766
    def test_take_other(self):
656
767
        self.run_script("""
657
768
$ bzr resolve dir
 
769
2>2 conflicts resolved, 0 remaining
658
770
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
659
771
""")
660
772
 
688
800
    def test_keep_them_all(self):
689
801
        self.run_script("""
690
802
$ bzr resolve dir
 
803
2>2 conflicts resolved, 0 remaining
691
804
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
692
805
""")
693
806
 
696
809
$ bzr mv -q dir/file2 file2
697
810
$ bzr rm -q dir --force
698
811
$ bzr resolve dir
 
812
2>2 conflicts resolved, 0 remaining
699
813
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
700
814
""")
701
815
 
703
817
        self.run_script("""
704
818
$ bzr rm -q dir --force
705
819
$ bzr resolve dir
 
820
2>2 conflicts resolved, 0 remaining
706
821
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
707
822
""")
708
823
 
749
864
    def test_keep_them_all(self):
750
865
        self.run_script("""
751
866
$ bzr resolve dir
 
867
2>2 conflicts resolved, 0 remaining
752
868
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
753
869
""")
754
870
 
757
873
$ bzr mv -q dir/file2 file2
758
874
$ bzr rm -q dir --force
759
875
$ bzr resolve dir
 
876
2>2 conflicts resolved, 0 remaining
760
877
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
761
878
""")
762
879
 
764
881
        self.run_script("""
765
882
$ bzr rm -q dir --force
766
883
$ bzr resolve dir
 
884
2>2 conflicts resolved, 0 remaining
767
885
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
768
886
""")
769
887
 
770
888
    def test_resolve_taking_this(self):
771
889
        self.run_script("""
772
890
$ bzr resolve --take-this dir
 
891
2>2 conflicts resolved, 0 remaining
773
892
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
774
893
""")
775
894
 
778
897
$ bzr resolve --take-other dir
779
898
2>deleted dir/file2
780
899
2>deleted dir
 
900
2>2 conflicts resolved, 0 remaining
781
901
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
782
902
""")
783
903
 
784
904
 
785
905
class TestResolveParentLoop(TestParametrizedResolveConflicts):
786
906
 
787
 
    _conflict_type = conflicts.ParentLoop,
 
907
    _conflict_type = conflicts.ParentLoop
788
908
 
789
909
    _this_args = None
790
910
    _other_args = None
791
911
 
792
 
    @staticmethod
793
 
    def scenarios():
794
 
        # Each side dict additionally defines:
795
 
        # - dir_id: the directory being moved
796
 
        # - target_id: The target directory
797
 
        # - xfail: whether the test is expected to fail if the action is
798
 
        #     involved as 'other'
799
 
        base_scenarios = [
 
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
        [
800
919
            # Dirs moved into each other
801
920
            (dict(_base_actions='create_dir1_dir2'),
802
921
             ('dir1_into_dir2',
813
932
             ('dir3_into_dir2',
814
933
              dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
815
934
                   dir_id='dir3-id', target_id='dir2-id', xfail=True))),
816
 
            ]
817
 
        return mirror_scenarios(base_scenarios)
 
935
            ])
818
936
 
819
937
    def do_create_dir1_dir2(self):
820
938
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
824
942
        return [('rename', ('dir1', 'dir2/dir1'))]
825
943
 
826
944
    def check_dir1_moved(self):
827
 
        self.failIfExists('branch/dir1')
828
 
        self.failUnlessExists('branch/dir2/dir1')
 
945
        self.assertPathDoesNotExist('branch/dir1')
 
946
        self.assertPathExists('branch/dir2/dir1')
829
947
 
830
948
    def do_move_dir2_into_dir1(self):
831
949
        return [('rename', ('dir2', 'dir1/dir2'))]
832
950
 
833
951
    def check_dir2_moved(self):
834
 
        self.failIfExists('branch/dir2')
835
 
        self.failUnlessExists('branch/dir1/dir2')
 
952
        self.assertPathDoesNotExist('branch/dir2')
 
953
        self.assertPathExists('branch/dir1/dir2')
836
954
 
837
955
    def do_create_dir1_4(self):
838
956
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
844
962
        return [('rename', ('dir1', 'dir3/dir4/dir1'))]
845
963
 
846
964
    def check_dir1_2_moved(self):
847
 
        self.failIfExists('branch/dir1')
848
 
        self.failUnlessExists('branch/dir3/dir4/dir1')
849
 
        self.failUnlessExists('branch/dir3/dir4/dir1/dir2')
 
965
        self.assertPathDoesNotExist('branch/dir1')
 
966
        self.assertPathExists('branch/dir3/dir4/dir1')
 
967
        self.assertPathExists('branch/dir3/dir4/dir1/dir2')
850
968
 
851
969
    def do_move_dir3_into_dir2(self):
852
970
        return [('rename', ('dir3', 'dir1/dir2/dir3'))]
853
971
 
854
972
    def check_dir3_4_moved(self):
855
 
        self.failIfExists('branch/dir3')
856
 
        self.failUnlessExists('branch/dir1/dir2/dir3')
857
 
        self.failUnlessExists('branch/dir1/dir2/dir3/dir4')
 
973
        self.assertPathDoesNotExist('branch/dir3')
 
974
        self.assertPathExists('branch/dir1/dir2/dir3')
 
975
        self.assertPathExists('branch/dir1/dir2/dir3/dir4')
858
976
 
859
977
    def _get_resolve_path_arg(self, wt, action):
860
978
        # ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
871
989
        if self._other['xfail']:
872
990
            # It's a bit hackish to raise from here relying on being called for
873
991
            # both tests but this avoid overriding test_resolve_taking_other
874
 
            raise tests.KnownFailure(
 
992
            self.knownFailure(
875
993
                "ParentLoop doesn't carry enough info to resolve --take-other")
876
994
    _assert_conflict = assertParentLoop
877
995
 
909
1027
# aside ? -- vila 090916
910
1028
$ bzr add -q foo
911
1029
$ bzr resolve foo.new
 
1030
2>1 conflict resolved, 0 remaining
912
1031
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
913
1032
""")
914
1033
 
917
1036
$ bzr rm -q foo --force
918
1037
$ bzr mv -q foo.new foo
919
1038
$ bzr resolve foo
 
1039
2>1 conflict resolved, 0 remaining
920
1040
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
921
1041
""")
922
1042
 
941
1061
        # This is nearly like TestResolveNonDirectoryParent but with branch and
942
1062
        # trunk switched. As such it should certainly produce the same
943
1063
        # conflict.
944
 
        self.run_script("""
 
1064
        self.assertRaises(errors.MalformedTransform,
 
1065
                          self.run_script,"""
945
1066
$ bzr init trunk
946
1067
...
947
1068
$ cd trunk
961
1082
""")
962
1083
 
963
1084
 
 
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
 
964
1170
class TestResolveActionOption(tests.TestCase):
965
1171
 
966
1172
    def setUp(self):