~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_conflicts.py

  • Committer: Andrew Bennetts
  • Date: 2010-10-08 08:15:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5498.
  • Revision ID: andrew.bennetts@canonical.com-20101008081514-dviqzrdfwyzsqbz2
Split NEWS into per-release doc/en/release-notes/bzr-*.txt

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,
 
22
    bzrdir,
21
23
    conflicts,
22
24
    errors,
23
25
    option,
24
 
    osutils,
25
26
    tests,
26
 
    )
27
 
from bzrlib.tests import (
28
 
    script,
29
 
    scenarios,
30
 
    )
31
 
 
32
 
 
33
 
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
34
49
 
35
50
 
36
51
# TODO: Test commit with some added, and added-but-missing files
61
76
])
62
77
 
63
78
 
64
 
def vary_by_conflicts():
65
 
    for conflict in example_conflicts:
66
 
        yield (conflict.__class__.__name__, {"conflict": conflict})
67
 
 
68
 
 
69
79
class TestConflicts(tests.TestCaseWithTransport):
70
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
 
71
108
    def test_resolve_conflict_dir(self):
72
109
        tree = self.make_branch_and_tree('.')
73
110
        self.build_tree_contents([('hello', 'hello world4'),
124
161
        self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
125
162
 
126
163
 
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__)
 
164
class TestConflictStanzas(tests.TestCase):
137
165
 
138
166
    def test_stanza_roundtrip(self):
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)
 
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)
155
185
 
156
186
    def test_stanzification(self):
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))
 
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')
178
196
 
179
197
 
180
198
# FIXME: The shell-like tests should be converted to real whitebox tests... or
192
210
        self.run_script(self.preamble)
193
211
 
194
212
 
 
213
class TestResolveTextConflicts(TestResolveConflicts):
 
214
    # TBC
 
215
    pass
 
216
 
 
217
 
195
218
def mirror_scenarios(base_scenarios):
196
219
    """Return a list of mirrored scenarios.
197
220
 
270
293
    _this = None
271
294
    _other = None
272
295
 
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
 
    """
 
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 []
298
324
 
299
325
    def setUp(self):
300
326
        super(TestParametrizedResolveConflicts, self).setUp()
362
388
        check_other()
363
389
 
364
390
 
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
 
 
430
391
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
431
392
 
432
 
    _conflict_type = conflicts.ContentsConflict
 
393
    _conflict_type = conflicts.ContentsConflict,
433
394
 
434
 
    # Set by the scenarios
 
395
    # Set by load_tests from scenarios()
435
396
    # path and file-id for the file involved in the conflict
436
397
    _path = None
437
398
    _file_id = None
438
399
 
439
 
    scenarios = mirror_scenarios(
440
 
        [
 
400
    @staticmethod
 
401
    def scenarios():
 
402
        base_scenarios = [
441
403
            # File modified/deleted
442
404
            (dict(_base_actions='create_file',
443
405
                  _path='file', _file_id='file-id'),
445
407
              dict(actions='modify_file', check='file_has_more_content')),
446
408
             ('file_deleted',
447
409
              dict(actions='delete_file', check='file_doesnt_exist')),),
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
 
            ])
 
410
            ]
 
411
        return mirror_scenarios(base_scenarios)
466
412
 
467
413
    def do_create_file(self):
468
414
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
470
416
    def do_modify_file(self):
471
417
        return [('modify', ('file-id', 'trunk content\nmore content\n'))]
472
418
 
473
 
    def do_modify_and_rename_file(self):
474
 
        return [('modify', ('file-id', 'trunk content\nmore content\n')),
475
 
                ('rename', ('file', 'new-file'))]
476
 
 
477
419
    def check_file_has_more_content(self):
478
420
        self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
479
421
 
480
 
    def check_file_renamed_and_more_content(self):
481
 
        self.assertFileEqual('trunk content\nmore content\n', 'branch/new-file')
482
 
 
483
422
    def do_delete_file(self):
484
423
        return [('unversion', 'file-id')]
485
424
 
486
425
    def check_file_doesnt_exist(self):
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')
 
426
        self.failIfExists('branch/file')
501
427
 
502
428
    def _get_resolve_path_arg(self, wt, action):
503
429
        return self._path
510
436
 
511
437
class TestResolvePathConflict(TestParametrizedResolveConflicts):
512
438
 
513
 
    _conflict_type = conflicts.PathConflict
 
439
    _conflict_type = conflicts.PathConflict,
514
440
 
515
441
    def do_nothing(self):
516
442
        return []
517
443
 
518
 
    # Each side dict additionally defines:
519
 
    # - path path involved (can be '<deleted>')
520
 
    # - file-id involved
521
 
    scenarios = mirror_scenarios(
522
 
        [
 
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 = [
523
450
            # File renamed/deleted
524
451
            (dict(_base_actions='create_file'),
525
452
             ('file_renamed',
530
457
                   # PathConflicts deletion handling requires a special
531
458
                   # hard-coded value
532
459
                   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')),),
543
460
            # File renamed/renamed differently
544
461
            (dict(_base_actions='create_file'),
545
462
             ('file_renamed',
566
483
             ('dir_renamed2',
567
484
              dict(actions='rename_dir2', check='dir_renamed2',
568
485
                   path='new-dir2', file_id='dir-id')),),
569
 
            ])
 
486
        ]
 
487
        return mirror_scenarios(base_scenarios)
570
488
 
571
489
    def do_create_file(self):
572
490
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
578
496
        return [('rename', ('file', 'new-file'))]
579
497
 
580
498
    def check_file_renamed(self):
581
 
        self.assertPathDoesNotExist('branch/file')
582
 
        self.assertPathExists('branch/new-file')
 
499
        self.failIfExists('branch/file')
 
500
        self.failUnlessExists('branch/new-file')
583
501
 
584
502
    def do_rename_file2(self):
585
503
        return [('rename', ('file', 'new-file2'))]
586
504
 
587
505
    def check_file_renamed2(self):
588
 
        self.assertPathDoesNotExist('branch/file')
589
 
        self.assertPathExists('branch/new-file2')
 
506
        self.failIfExists('branch/file')
 
507
        self.failUnlessExists('branch/new-file2')
590
508
 
591
509
    def do_rename_dir(self):
592
510
        return [('rename', ('dir', 'new-dir'))]
593
511
 
594
512
    def check_dir_renamed(self):
595
 
        self.assertPathDoesNotExist('branch/dir')
596
 
        self.assertPathExists('branch/new-dir')
 
513
        self.failIfExists('branch/dir')
 
514
        self.failUnlessExists('branch/new-dir')
597
515
 
598
516
    def do_rename_dir2(self):
599
517
        return [('rename', ('dir', 'new-dir2'))]
600
518
 
601
519
    def check_dir_renamed2(self):
602
 
        self.assertPathDoesNotExist('branch/dir')
603
 
        self.assertPathExists('branch/new-dir2')
 
520
        self.failIfExists('branch/dir')
 
521
        self.failUnlessExists('branch/new-dir2')
604
522
 
605
523
    def do_delete_file(self):
606
524
        return [('unversion', 'file-id')]
607
525
 
608
526
    def check_file_doesnt_exist(self):
609
 
        self.assertPathDoesNotExist('branch/file')
 
527
        self.failIfExists('branch/file')
610
528
 
611
529
    def do_delete_dir(self):
612
530
        return [('unversion', 'dir-id')]
613
531
 
614
532
    def check_dir_doesnt_exist(self):
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')
 
533
        self.failIfExists('branch/dir')
630
534
 
631
535
    def _get_resolve_path_arg(self, wt, action):
632
536
        tpath = self._this['path']
664
568
 
665
569
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
666
570
 
667
 
    _conflict_type = conflicts.DuplicateEntry
 
571
    _conflict_type = conflicts.DuplicateEntry,
668
572
 
669
 
    scenarios = mirror_scenarios(
670
 
        [
 
573
    @staticmethod
 
574
    def scenarios():
 
575
        # Each side dict additionally defines:
 
576
        # - path involved
 
577
        # - file-id involved
 
578
        base_scenarios = [
671
579
            # File created with different file-ids
672
580
            (dict(_base_actions='nothing'),
673
581
             ('filea_created',
676
584
             ('fileb_created',
677
585
              dict(actions='create_file_b', check='file_content_b',
678
586
                   path='file', file_id='file-b-id')),),
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
 
            ])
 
587
            ]
 
588
        return mirror_scenarios(base_scenarios)
688
589
 
689
590
    def do_nothing(self):
690
591
        return []
701
602
    def check_file_content_b(self):
702
603
        self.assertFileEqual('file b content\n', 'branch/file')
703
604
 
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
 
 
714
605
    def _get_resolve_path_arg(self, wt, action):
715
606
        return self._this['path']
716
607
 
734
625
    # tests MissingParent resolution :-/
735
626
    preamble = """
736
627
$ bzr init trunk
737
 
...
738
628
$ cd trunk
739
629
$ mkdir dir
740
 
$ bzr add -q dir
741
 
$ bzr commit -m 'Create trunk' -q
 
630
$ bzr add dir
 
631
$ bzr commit -m 'Create trunk'
 
632
 
742
633
$ echo 'trunk content' >dir/file
743
 
$ bzr add -q dir/file
744
 
$ bzr commit -q -m 'Add dir/file in trunk'
745
 
$ 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
746
638
$ cd ../branch
747
 
$ bzr rm dir -q
748
 
$ bzr commit -q -m 'Remove dir in branch'
 
639
$ bzr rm dir
 
640
$ bzr commit -m 'Remove dir in branch'
 
641
 
749
642
$ bzr merge ../trunk
750
643
2>+N  dir/
751
644
2>+N  dir/file
756
649
 
757
650
    def test_take_this(self):
758
651
        self.run_script("""
759
 
$ bzr rm -q dir --no-backup
 
652
$ bzr rm dir  --force
760
653
$ bzr resolve dir
761
 
2>2 conflicts resolved, 0 remaining
762
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
654
$ bzr commit --strict -m 'No more conflicts nor unknown files'
763
655
""")
764
656
 
765
657
    def test_take_other(self):
766
658
        self.run_script("""
767
659
$ bzr resolve dir
768
 
2>2 conflicts resolved, 0 remaining
769
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
660
$ bzr commit --strict -m 'No more conflicts nor unknown files'
770
661
""")
771
662
 
772
663
 
774
665
 
775
666
    preamble = """
776
667
$ bzr init trunk
777
 
...
778
668
$ cd trunk
779
669
$ mkdir dir
780
670
$ echo 'trunk content' >dir/file
781
 
$ bzr add -q
782
 
$ bzr commit -m 'Create trunk' -q
 
671
$ bzr add
 
672
$ bzr commit -m 'Create trunk'
 
673
 
783
674
$ echo 'trunk content' >dir/file2
784
 
$ bzr add -q dir/file2
785
 
$ bzr commit -q -m 'Add dir/file2 in branch'
786
 
$ 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
787
679
$ cd ../branch
788
 
$ bzr rm -q dir/file --no-backup
789
 
$ bzr rm -q dir
790
 
$ 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
 
791
684
$ bzr merge ../trunk
792
685
2>+N  dir/
793
686
2>+N  dir/file2
799
692
    def test_keep_them_all(self):
800
693
        self.run_script("""
801
694
$ bzr resolve dir
802
 
2>2 conflicts resolved, 0 remaining
803
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
695
$ bzr commit --strict -m 'No more conflicts nor unknown files'
804
696
""")
805
697
 
806
698
    def test_adopt_child(self):
807
699
        self.run_script("""
808
 
$ bzr mv -q dir/file2 file2
809
 
$ bzr rm -q dir --no-backup
 
700
$ bzr mv dir/file2 file2
 
701
$ bzr rm dir --force
810
702
$ bzr resolve dir
811
 
2>2 conflicts resolved, 0 remaining
812
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
703
$ bzr commit --strict -m 'No more conflicts nor unknown files'
813
704
""")
814
705
 
815
706
    def test_kill_them_all(self):
816
707
        self.run_script("""
817
 
$ bzr rm -q dir --no-backup
 
708
$ bzr rm dir --force
818
709
$ bzr resolve dir
819
 
2>2 conflicts resolved, 0 remaining
820
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
710
$ bzr commit --strict -m 'No more conflicts nor unknown files'
821
711
""")
822
712
 
823
713
    def test_resolve_taking_this(self):
824
714
        self.run_script("""
825
715
$ bzr resolve --take-this dir
826
 
2>...
827
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
716
$ bzr commit --strict -m 'No more conflicts nor unknown files'
828
717
""")
829
718
 
830
719
    def test_resolve_taking_other(self):
831
720
        self.run_script("""
832
721
$ bzr resolve --take-other dir
833
 
2>...
834
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
722
$ bzr commit --strict -m 'No more conflicts nor unknown files'
835
723
""")
836
724
 
837
725
 
839
727
 
840
728
    preamble = """
841
729
$ bzr init trunk
842
 
...
843
730
$ cd trunk
844
731
$ mkdir dir
845
732
$ echo 'trunk content' >dir/file
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
 
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
852
741
$ cd ../branch
853
742
$ echo 'branch content' >dir/file2
854
 
$ bzr add -q dir/file2
855
 
$ bzr commit -q -m 'Add dir/file2 in branch'
 
743
$ bzr add dir/file2
 
744
$ bzr commit -m 'Add dir/file2 in branch'
 
745
 
856
746
$ bzr merge ../trunk
857
747
2>-D  dir/file
858
748
2>Conflict: can't delete dir because it is not empty.  Not deleting.
863
753
    def test_keep_them_all(self):
864
754
        self.run_script("""
865
755
$ bzr resolve dir
866
 
2>2 conflicts resolved, 0 remaining
867
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
756
$ bzr commit --strict -m 'No more conflicts nor unknown files'
868
757
""")
869
758
 
870
759
    def test_adopt_child(self):
871
760
        self.run_script("""
872
 
$ bzr mv -q dir/file2 file2
873
 
$ bzr rm -q dir --no-backup
 
761
$ bzr mv dir/file2 file2
 
762
$ bzr rm dir --force
874
763
$ bzr resolve dir
875
 
2>2 conflicts resolved, 0 remaining
876
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
764
$ bzr commit --strict -m 'No more conflicts nor unknown files'
877
765
""")
878
766
 
879
767
    def test_kill_them_all(self):
880
768
        self.run_script("""
881
 
$ bzr rm -q dir --no-backup
 
769
$ bzr rm dir --force
882
770
$ bzr resolve dir
883
 
2>2 conflicts resolved, 0 remaining
884
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
771
$ bzr commit --strict -m 'No more conflicts nor unknown files'
885
772
""")
886
773
 
887
774
    def test_resolve_taking_this(self):
888
775
        self.run_script("""
889
776
$ bzr resolve --take-this dir
890
 
2>2 conflicts resolved, 0 remaining
891
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
777
$ bzr commit --strict -m 'No more conflicts nor unknown files'
892
778
""")
893
779
 
894
780
    def test_resolve_taking_other(self):
895
781
        self.run_script("""
896
782
$ bzr resolve --take-other dir
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'
 
783
$ bzr commit --strict -m 'No more conflicts nor unknown files'
901
784
""")
902
785
 
903
786
 
904
787
class TestResolveParentLoop(TestParametrizedResolveConflicts):
905
788
 
906
 
    _conflict_type = conflicts.ParentLoop
 
789
    _conflict_type = conflicts.ParentLoop,
907
790
 
908
791
    _this_args = None
909
792
    _other_args = None
910
793
 
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
 
        [
 
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 = [
918
802
            # Dirs moved into each other
919
803
            (dict(_base_actions='create_dir1_dir2'),
920
804
             ('dir1_into_dir2',
931
815
             ('dir3_into_dir2',
932
816
              dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
933
817
                   dir_id='dir3-id', target_id='dir2-id', xfail=True))),
934
 
            ])
 
818
            ]
 
819
        return mirror_scenarios(base_scenarios)
935
820
 
936
821
    def do_create_dir1_dir2(self):
937
822
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
941
826
        return [('rename', ('dir1', 'dir2/dir1'))]
942
827
 
943
828
    def check_dir1_moved(self):
944
 
        self.assertPathDoesNotExist('branch/dir1')
945
 
        self.assertPathExists('branch/dir2/dir1')
 
829
        self.failIfExists('branch/dir1')
 
830
        self.failUnlessExists('branch/dir2/dir1')
946
831
 
947
832
    def do_move_dir2_into_dir1(self):
948
833
        return [('rename', ('dir2', 'dir1/dir2'))]
949
834
 
950
835
    def check_dir2_moved(self):
951
 
        self.assertPathDoesNotExist('branch/dir2')
952
 
        self.assertPathExists('branch/dir1/dir2')
 
836
        self.failIfExists('branch/dir2')
 
837
        self.failUnlessExists('branch/dir1/dir2')
953
838
 
954
839
    def do_create_dir1_4(self):
955
840
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
961
846
        return [('rename', ('dir1', 'dir3/dir4/dir1'))]
962
847
 
963
848
    def check_dir1_2_moved(self):
964
 
        self.assertPathDoesNotExist('branch/dir1')
965
 
        self.assertPathExists('branch/dir3/dir4/dir1')
966
 
        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')
967
852
 
968
853
    def do_move_dir3_into_dir2(self):
969
854
        return [('rename', ('dir3', 'dir1/dir2/dir3'))]
970
855
 
971
856
    def check_dir3_4_moved(self):
972
 
        self.assertPathDoesNotExist('branch/dir3')
973
 
        self.assertPathExists('branch/dir1/dir2/dir3')
974
 
        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')
975
860
 
976
861
    def _get_resolve_path_arg(self, wt, action):
977
862
        # ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
988
873
        if self._other['xfail']:
989
874
            # It's a bit hackish to raise from here relying on being called for
990
875
            # both tests but this avoid overriding test_resolve_taking_other
991
 
            self.knownFailure(
 
876
            raise tests.KnownFailure(
992
877
                "ParentLoop doesn't carry enough info to resolve --take-other")
993
878
    _assert_conflict = assertParentLoop
994
879
 
997
882
 
998
883
    preamble = """
999
884
$ bzr init trunk
1000
 
...
1001
885
$ cd trunk
1002
886
$ bzr mkdir foo
1003
 
...
1004
 
$ bzr commit -m 'Create trunk' -q
 
887
$ bzr commit -m 'Create trunk'
1005
888
$ echo "Boing" >foo/bar
1006
 
$ bzr add -q foo/bar
1007
 
$ bzr commit -q -m 'Add foo/bar'
1008
 
$ 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
1009
893
$ cd ../branch
1010
894
$ rm -r foo
1011
895
$ echo "Boo!" >foo
1012
 
$ bzr commit -q -m 'foo is now a file'
 
896
$ bzr commit -m 'foo is now a file'
 
897
 
1013
898
$ bzr merge ../trunk
1014
899
2>+N  foo.new/bar
1015
900
2>RK  foo => foo.new/
1021
906
 
1022
907
    def test_take_this(self):
1023
908
        self.run_script("""
1024
 
$ bzr rm -q foo.new --no-backup
 
909
$ bzr rm foo.new --force
1025
910
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
1026
911
# aside ? -- vila 090916
1027
 
$ bzr add -q foo
 
912
$ bzr add foo
1028
913
$ bzr resolve foo.new
1029
 
2>1 conflict resolved, 0 remaining
1030
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
914
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1031
915
""")
1032
916
 
1033
917
    def test_take_other(self):
1034
918
        self.run_script("""
1035
 
$ bzr rm -q foo --no-backup
1036
 
$ bzr mv -q foo.new foo
 
919
$ bzr rm foo --force
 
920
$ bzr mv foo.new foo
1037
921
$ bzr resolve foo
1038
 
2>1 conflict resolved, 0 remaining
1039
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
922
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1040
923
""")
1041
924
 
1042
925
    def test_resolve_taking_this(self):
1043
926
        self.run_script("""
1044
927
$ bzr resolve --take-this foo.new
1045
 
2>...
1046
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
928
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1047
929
""")
1048
930
 
1049
931
    def test_resolve_taking_other(self):
1050
932
        self.run_script("""
1051
933
$ bzr resolve --take-other foo.new
1052
 
2>...
1053
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
934
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1054
935
""")
1055
936
 
1056
937
 
1060
941
        # This is nearly like TestResolveNonDirectoryParent but with branch and
1061
942
        # trunk switched. As such it should certainly produce the same
1062
943
        # conflict.
1063
 
        self.assertRaises(errors.MalformedTransform,
1064
 
                          self.run_script,"""
 
944
        self.run_script("""
1065
945
$ bzr init trunk
1066
 
...
1067
946
$ cd trunk
1068
947
$ bzr mkdir foo
1069
 
...
1070
 
$ bzr commit -m 'Create trunk' -q
 
948
$ bzr commit -m 'Create trunk'
1071
949
$ rm -r foo
1072
950
$ echo "Boo!" >foo
1073
 
$ bzr commit -m 'foo is now a file' -q
1074
 
$ bzr branch -q . -r 1 ../branch -q
 
951
$ bzr commit -m 'foo is now a file'
 
952
 
 
953
$ bzr branch . -r 1 ../branch
1075
954
$ cd ../branch
1076
955
$ echo "Boing" >foo/bar
1077
 
$ bzr add -q foo/bar -q
1078
 
$ bzr commit -m 'Add foo/bar' -q
 
956
$ bzr add foo/bar
 
957
$ bzr commit -m 'Add foo/bar'
 
958
 
1079
959
$ bzr merge ../trunk
1080
960
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1081
961
""")
1082
962
 
1083
963
 
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
 
 
1169
964
class TestResolveActionOption(tests.TestCase):
1170
965
 
1171
966
    def setUp(self):