~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-02-12 04:33:05 UTC
  • mfrom: (5031 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5032.
  • Revision ID: andrew.bennetts@canonical.com-20100212043305-ujdbsdoviql2t7i3
Merge lp:bzr

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
22
22
    conflicts,
23
23
    errors,
24
24
    option,
25
 
    osutils,
26
25
    tests,
27
26
    )
28
 
from bzrlib.tests import (
29
 
    script,
30
 
    scenarios,
31
 
    )
32
 
 
33
 
 
34
 
load_tests = scenarios.load_tests_apply_scenarios
 
27
from bzrlib.tests import script
35
28
 
36
29
 
37
30
# TODO: Test commit with some added, and added-but-missing files
62
55
])
63
56
 
64
57
 
65
 
def vary_by_conflicts():
66
 
    for conflict in example_conflicts:
67
 
        yield (conflict.__class__.__name__, {"conflict": conflict})
68
 
 
69
 
 
70
58
class TestConflicts(tests.TestCaseWithTransport):
71
59
 
 
60
    def test_conflicts(self):
 
61
        """Conflicts are detected properly"""
 
62
        # Use BzrDirFormat6 so we can fake conflicts
 
63
        tree = self.make_branch_and_tree('.', format=bzrdir.BzrDirFormat6())
 
64
        self.build_tree_contents([('hello', 'hello world4'),
 
65
                                  ('hello.THIS', 'hello world2'),
 
66
                                  ('hello.BASE', 'hello world1'),
 
67
                                  ('hello.OTHER', 'hello world3'),
 
68
                                  ('hello.sploo.BASE', 'yellowworld'),
 
69
                                  ('hello.sploo.OTHER', 'yellowworld2'),
 
70
                                  ])
 
71
        tree.lock_read()
 
72
        self.assertEqual(6, len(list(tree.list_files())))
 
73
        tree.unlock()
 
74
        tree_conflicts = tree.conflicts()
 
75
        self.assertEqual(2, len(tree_conflicts))
 
76
        self.assertTrue('hello' in tree_conflicts[0].path)
 
77
        self.assertTrue('hello.sploo' in tree_conflicts[1].path)
 
78
        conflicts.restore('hello')
 
79
        conflicts.restore('hello.sploo')
 
80
        self.assertEqual(0, len(tree.conflicts()))
 
81
        self.assertFileEqual('hello world2', 'hello')
 
82
        self.assertFalse(os.path.lexists('hello.sploo'))
 
83
        self.assertRaises(errors.NotConflicted, conflicts.restore, 'hello')
 
84
        self.assertRaises(errors.NotConflicted,
 
85
                          conflicts.restore, 'hello.sploo')
 
86
 
72
87
    def test_resolve_conflict_dir(self):
73
88
        tree = self.make_branch_and_tree('.')
74
89
        self.build_tree_contents([('hello', 'hello world4'),
125
140
        self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
126
141
 
127
142
 
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__)
 
143
class TestConflictStanzas(tests.TestCase):
138
144
 
139
145
    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)
 
146
        # write and read our example stanza.
 
147
        stanza_iter = example_conflicts.to_stanzas()
 
148
        processed = conflicts.ConflictList.from_stanzas(stanza_iter)
 
149
        for o, p in zip(processed, example_conflicts):
 
150
            self.assertEqual(o, p)
 
151
 
 
152
            self.assertIsInstance(o.path, unicode)
 
153
 
 
154
            if o.file_id is not None:
 
155
                self.assertIsInstance(o.file_id, str)
 
156
 
 
157
            conflict_path = getattr(o, 'conflict_path', None)
 
158
            if conflict_path is not None:
 
159
                self.assertIsInstance(conflict_path, unicode)
 
160
 
 
161
            conflict_file_id = getattr(o, 'conflict_file_id', None)
 
162
            if conflict_file_id is not None:
 
163
                self.assertIsInstance(conflict_file_id, str)
156
164
 
157
165
    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))
 
166
        for stanza in example_conflicts.to_stanzas():
 
167
            if 'file_id' in stanza:
 
168
                # In Stanza form, the file_id has to be unicode.
 
169
                self.assertStartsWith(stanza['file_id'], u'\xeed')
 
170
            self.assertStartsWith(stanza['path'], u'p\xe5th')
 
171
            if 'conflict_path' in stanza:
 
172
                self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
 
173
            if 'conflict_file_id' in stanza:
 
174
                self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
179
175
 
180
176
 
181
177
# FIXME: The shell-like tests should be converted to real whitebox tests... or
182
178
# moved to a blackbox module -- vila 20100205
183
179
 
184
 
# FIXME: test missing for multiple conflicts
185
 
 
186
180
# FIXME: Tests missing for DuplicateID conflict type
187
181
class TestResolveConflicts(script.TestCaseWithTransportAndScript):
188
182
 
193
187
        self.run_script(self.preamble)
194
188
 
195
189
 
196
 
def mirror_scenarios(base_scenarios):
197
 
    """Return a list of mirrored scenarios.
198
 
 
199
 
    Each scenario in base_scenarios is duplicated switching the roles of 'this'
200
 
    and 'other'
201
 
    """
202
 
    scenarios = []
203
 
    for common, (lname, ldict), (rname, rdict) in base_scenarios:
204
 
        a = tests.multiply_scenarios([(lname, dict(_this=ldict))],
205
 
                                     [(rname, dict(_other=rdict))])
206
 
        b = tests.multiply_scenarios([(rname, dict(_this=rdict))],
207
 
                                     [(lname, dict(_other=ldict))])
208
 
        # Inject the common parameters in all scenarios
209
 
        for name, d in a + b:
210
 
            d.update(common)
211
 
        scenarios.extend(a + b)
212
 
    return scenarios
213
 
 
214
 
 
215
 
# FIXME: Get rid of parametrized (in the class name) once we delete
216
 
# TestResolveConflicts -- vila 20100308
217
 
class TestParametrizedResolveConflicts(tests.TestCaseWithTransport):
218
 
    """This class provides a base to test single conflict resolution.
219
 
 
220
 
    Since all conflict objects are created with specific semantics for their
221
 
    attributes, each class should implement the necessary functions and
222
 
    attributes described below.
223
 
 
224
 
    Each class should define the scenarios that create the expected (single)
225
 
    conflict.
226
 
 
227
 
    Each scenario describes:
228
 
    * how to create 'base' tree (and revision)
229
 
    * how to create 'left' tree (and revision, parent rev 'base')
230
 
    * how to create 'right' tree (and revision, parent rev 'base')
231
 
    * how to check that changes in 'base'->'left' have been taken
232
 
    * how to check that changes in 'base'->'right' have been taken
233
 
 
234
 
    From each base scenario, we generate two concrete scenarios where:
235
 
    * this=left, other=right
236
 
    * this=right, other=left
237
 
 
238
 
    Then the test case verifies each concrete scenario by:
239
 
    * creating a branch containing the 'base', 'this' and 'other' revisions
240
 
    * creating a working tree for the 'this' revision
241
 
    * performing the merge of 'other' into 'this'
242
 
    * verifying the expected conflict was generated
243
 
    * resolving with --take-this or --take-other, and running the corresponding
244
 
      checks (for either 'base'->'this', or 'base'->'other')
245
 
 
246
 
    :cvar _conflict_type: The expected class of the generated conflict.
247
 
 
248
 
    :cvar _assert_conflict: A method receiving the working tree and the
249
 
        conflict object and checking its attributes.
250
 
 
251
 
    :cvar _base_actions: The branchbuilder actions to create the 'base'
252
 
        revision.
253
 
 
254
 
    :cvar _this: The dict related to 'base' -> 'this'. It contains at least:
255
 
      * 'actions': The branchbuilder actions to create the 'this'
256
 
          revision.
257
 
      * 'check': how to check the changes after resolution with --take-this.
258
 
 
259
 
    :cvar _other: The dict related to 'base' -> 'other'. It contains at least:
260
 
      * 'actions': The branchbuilder actions to create the 'other'
261
 
          revision.
262
 
      * 'check': how to check the changes after resolution with --take-other.
263
 
    """
264
 
 
265
 
    # Set by daughter classes
266
 
    _conflict_type = None
267
 
    _assert_conflict = None
268
 
 
269
 
    # Set by load_tests
270
 
    _base_actions = None
271
 
    _this = None
272
 
    _other = None
273
 
 
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
 
    """
299
 
 
300
 
    def setUp(self):
301
 
        super(TestParametrizedResolveConflicts, self).setUp()
302
 
        builder = self.make_branch_builder('trunk')
303
 
        builder.start_series()
304
 
 
305
 
        # Create an empty trunk
306
 
        builder.build_snapshot('start', None, [
307
 
                ('add', ('', 'root-id', 'directory', ''))])
308
 
        # Add a minimal base content
309
 
        base_actions = self._get_actions(self._base_actions)()
310
 
        builder.build_snapshot('base', ['start'], base_actions)
311
 
        # Modify the base content in branch
312
 
        actions_other = self._get_actions(self._other['actions'])()
313
 
        builder.build_snapshot('other', ['base'], actions_other)
314
 
        # Modify the base content in trunk
315
 
        actions_this = self._get_actions(self._this['actions'])()
316
 
        builder.build_snapshot('this', ['base'], actions_this)
317
 
        # builder.get_branch() tip is now 'this'
318
 
 
319
 
        builder.finish_series()
320
 
        self.builder = builder
321
 
 
322
 
    def _get_actions(self, name):
323
 
        return getattr(self, 'do_%s' % name)
324
 
 
325
 
    def _get_check(self, name):
326
 
        return getattr(self, 'check_%s' % name)
327
 
 
328
 
    def _merge_other_into_this(self):
329
 
        b = self.builder.get_branch()
330
 
        wt = b.bzrdir.sprout('branch').open_workingtree()
331
 
        wt.merge_from_branch(b, 'other')
332
 
        return wt
333
 
 
334
 
    def assertConflict(self, wt):
335
 
        confs = wt.conflicts()
336
 
        self.assertLength(1, confs)
337
 
        c = confs[0]
338
 
        self.assertIsInstance(c, self._conflict_type)
339
 
        self._assert_conflict(wt, c)
340
 
 
341
 
    def _get_resolve_path_arg(self, wt, action):
342
 
        raise NotImplementedError(self._get_resolve_path_arg)
343
 
 
344
 
    def check_resolved(self, wt, action):
345
 
        path = self._get_resolve_path_arg(wt, action)
346
 
        conflicts.resolve(wt, [path], action=action)
347
 
        # Check that we don't have any conflicts nor unknown left
348
 
        self.assertLength(0, wt.conflicts())
349
 
        self.assertLength(0, list(wt.unknowns()))
350
 
 
351
 
    def test_resolve_taking_this(self):
352
 
        wt = self._merge_other_into_this()
353
 
        self.assertConflict(wt)
354
 
        self.check_resolved(wt, 'take_this')
355
 
        check_this = self._get_check(self._this['check'])
356
 
        check_this()
357
 
 
358
 
    def test_resolve_taking_other(self):
359
 
        wt = self._merge_other_into_this()
360
 
        self.assertConflict(wt)
361
 
        self.check_resolved(wt, 'take_other')
362
 
        check_other = self._get_check(self._other['check'])
363
 
        check_other()
364
 
 
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
 
 
431
 
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
432
 
 
433
 
    _conflict_type = conflicts.ContentsConflict
434
 
 
435
 
    # Set by the scenarios
436
 
    # path and file-id for the file involved in the conflict
437
 
    _path = None
438
 
    _file_id = None
439
 
 
440
 
    scenarios = mirror_scenarios(
441
 
        [
442
 
            # File modified/deleted
443
 
            (dict(_base_actions='create_file',
444
 
                  _path='file', _file_id='file-id'),
445
 
             ('file_modified',
446
 
              dict(actions='modify_file', check='file_has_more_content')),
447
 
             ('file_deleted',
448
 
              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
 
            ])
467
 
 
468
 
    def do_create_file(self):
469
 
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
470
 
 
471
 
    def do_modify_file(self):
472
 
        return [('modify', ('file-id', 'trunk content\nmore content\n'))]
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
 
 
478
 
    def check_file_has_more_content(self):
479
 
        self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
480
 
 
481
 
    def check_file_renamed_and_more_content(self):
482
 
        self.assertFileEqual('trunk content\nmore content\n', 'branch/new-file')
483
 
 
484
 
    def do_delete_file(self):
485
 
        return [('unversion', 'file-id')]
486
 
 
487
 
    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')
502
 
 
503
 
    def _get_resolve_path_arg(self, wt, action):
504
 
        return self._path
505
 
 
506
 
    def assertContentsConflict(self, wt, c):
507
 
        self.assertEqual(self._file_id, c.file_id)
508
 
        self.assertEqual(self._path, c.path)
509
 
    _assert_conflict = assertContentsConflict
510
 
 
511
 
 
512
 
class TestResolvePathConflict(TestParametrizedResolveConflicts):
513
 
 
514
 
    _conflict_type = conflicts.PathConflict
515
 
 
516
 
    def do_nothing(self):
517
 
        return []
518
 
 
519
 
    # Each side dict additionally defines:
520
 
    # - path path involved (can be '<deleted>')
521
 
    # - file-id involved
522
 
    scenarios = mirror_scenarios(
523
 
        [
524
 
            # File renamed/deleted
525
 
            (dict(_base_actions='create_file'),
526
 
             ('file_renamed',
527
 
              dict(actions='rename_file', check='file_renamed',
528
 
                   path='new-file', file_id='file-id')),
529
 
             ('file_deleted',
530
 
              dict(actions='delete_file', check='file_doesnt_exist',
531
 
                   # PathConflicts deletion handling requires a special
532
 
                   # hard-coded value
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')),),
544
 
            # File renamed/renamed differently
545
 
            (dict(_base_actions='create_file'),
546
 
             ('file_renamed',
547
 
              dict(actions='rename_file', check='file_renamed',
548
 
                   path='new-file', file_id='file-id')),
549
 
             ('file_renamed2',
550
 
              dict(actions='rename_file2', check='file_renamed2',
551
 
                   path='new-file2', file_id='file-id')),),
552
 
            # Dir renamed/deleted
553
 
            (dict(_base_actions='create_dir'),
554
 
             ('dir_renamed',
555
 
              dict(actions='rename_dir', check='dir_renamed',
556
 
                   path='new-dir', file_id='dir-id')),
557
 
             ('dir_deleted',
558
 
              dict(actions='delete_dir', check='dir_doesnt_exist',
559
 
                   # PathConflicts deletion handling requires a special
560
 
                   # hard-coded value
561
 
                   path='<deleted>', file_id='dir-id')),),
562
 
            # Dir renamed/renamed differently
563
 
            (dict(_base_actions='create_dir'),
564
 
             ('dir_renamed',
565
 
              dict(actions='rename_dir', check='dir_renamed',
566
 
                   path='new-dir', file_id='dir-id')),
567
 
             ('dir_renamed2',
568
 
              dict(actions='rename_dir2', check='dir_renamed2',
569
 
                   path='new-dir2', file_id='dir-id')),),
570
 
            ])
571
 
 
572
 
    def do_create_file(self):
573
 
        return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
574
 
 
575
 
    def do_create_dir(self):
576
 
        return [('add', ('dir', 'dir-id', 'directory', ''))]
577
 
 
578
 
    def do_rename_file(self):
579
 
        return [('rename', ('file', 'new-file'))]
580
 
 
581
 
    def check_file_renamed(self):
582
 
        self.assertPathDoesNotExist('branch/file')
583
 
        self.assertPathExists('branch/new-file')
584
 
 
585
 
    def do_rename_file2(self):
586
 
        return [('rename', ('file', 'new-file2'))]
587
 
 
588
 
    def check_file_renamed2(self):
589
 
        self.assertPathDoesNotExist('branch/file')
590
 
        self.assertPathExists('branch/new-file2')
591
 
 
592
 
    def do_rename_dir(self):
593
 
        return [('rename', ('dir', 'new-dir'))]
594
 
 
595
 
    def check_dir_renamed(self):
596
 
        self.assertPathDoesNotExist('branch/dir')
597
 
        self.assertPathExists('branch/new-dir')
598
 
 
599
 
    def do_rename_dir2(self):
600
 
        return [('rename', ('dir', 'new-dir2'))]
601
 
 
602
 
    def check_dir_renamed2(self):
603
 
        self.assertPathDoesNotExist('branch/dir')
604
 
        self.assertPathExists('branch/new-dir2')
605
 
 
606
 
    def do_delete_file(self):
607
 
        return [('unversion', 'file-id')]
608
 
 
609
 
    def check_file_doesnt_exist(self):
610
 
        self.assertPathDoesNotExist('branch/file')
611
 
 
612
 
    def do_delete_dir(self):
613
 
        return [('unversion', 'dir-id')]
614
 
 
615
 
    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')
631
 
 
632
 
    def _get_resolve_path_arg(self, wt, action):
633
 
        tpath = self._this['path']
634
 
        opath = self._other['path']
635
 
        if tpath == '<deleted>':
636
 
            path = opath
637
 
        else:
638
 
            path = tpath
639
 
        return path
640
 
 
641
 
    def assertPathConflict(self, wt, c):
642
 
        tpath = self._this['path']
643
 
        tfile_id = self._this['file_id']
644
 
        opath = self._other['path']
645
 
        ofile_id = self._other['file_id']
646
 
        self.assertEqual(tfile_id, ofile_id) # Sanity check
647
 
        self.assertEqual(tfile_id, c.file_id)
648
 
        self.assertEqual(tpath, c.path)
649
 
        self.assertEqual(opath, c.conflict_path)
650
 
    _assert_conflict = assertPathConflict
651
 
 
652
 
 
653
 
class TestResolvePathConflictBefore531967(TestResolvePathConflict):
654
 
    """Same as TestResolvePathConflict but a specific conflict object.
655
 
    """
656
 
 
657
 
    def assertPathConflict(self, c):
658
 
        # We create a conflict object as it was created before the fix and
659
 
        # inject it into the working tree, the test will exercise the
660
 
        # compatibility code.
661
 
        old_c = conflicts.PathConflict('<deleted>', self._item_path,
662
 
                                       file_id=None)
663
 
        wt.set_conflicts(conflicts.ConflictList([old_c]))
664
 
 
665
 
 
666
 
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
667
 
 
668
 
    _conflict_type = conflicts.DuplicateEntry
669
 
 
670
 
    scenarios = mirror_scenarios(
671
 
        [
672
 
            # File created with different file-ids
673
 
            (dict(_base_actions='nothing'),
674
 
             ('filea_created',
675
 
              dict(actions='create_file_a', check='file_content_a',
676
 
                   path='file', file_id='file-a-id')),
677
 
             ('fileb_created',
678
 
              dict(actions='create_file_b', check='file_content_b',
679
 
                   path='file', file_id='file-b-id')),),
680
 
            ])
681
 
 
682
 
    def do_nothing(self):
683
 
        return []
684
 
 
685
 
    def do_create_file_a(self):
686
 
        return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
687
 
 
688
 
    def check_file_content_a(self):
689
 
        self.assertFileEqual('file a content\n', 'branch/file')
690
 
 
691
 
    def do_create_file_b(self):
692
 
        return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
693
 
 
694
 
    def check_file_content_b(self):
695
 
        self.assertFileEqual('file b content\n', 'branch/file')
696
 
 
697
 
    def _get_resolve_path_arg(self, wt, action):
698
 
        return self._this['path']
699
 
 
700
 
    def assertDuplicateEntry(self, wt, c):
701
 
        tpath = self._this['path']
702
 
        tfile_id = self._this['file_id']
703
 
        opath = self._other['path']
704
 
        ofile_id = self._other['file_id']
705
 
        self.assertEqual(tpath, opath) # Sanity check
706
 
        self.assertEqual(tfile_id, c.file_id)
707
 
        self.assertEqual(tpath + '.moved', c.path)
708
 
        self.assertEqual(tpath, c.conflict_path)
709
 
    _assert_conflict = assertDuplicateEntry
 
190
class TestResolveTextConflicts(TestResolveConflicts):
 
191
    # TBC
 
192
    pass
 
193
 
 
194
 
 
195
class TestResolveContentConflicts(TestResolveConflicts):
 
196
 
 
197
    # FIXME: We need to add the reverse case (delete in trunk, modify in
 
198
    # branch) but that could wait until the resolution mechanism is implemented.
 
199
 
 
200
    preamble = """
 
201
$ bzr init trunk
 
202
$ cd trunk
 
203
$ echo 'trunk content' >file
 
204
$ bzr add file
 
205
$ bzr commit -m 'Create trunk'
 
206
 
 
207
$ bzr branch . ../branch
 
208
$ cd ../branch
 
209
$ bzr rm file
 
210
$ bzr commit -m 'Delete file'
 
211
 
 
212
$ cd ../trunk
 
213
$ echo 'more content' >>file
 
214
$ bzr commit -m 'Modify file'
 
215
 
 
216
$ cd ../branch
 
217
$ bzr merge ../trunk
 
218
2>+N  file.OTHER
 
219
2>Contents conflict in file
 
220
2>1 conflicts encountered.
 
221
"""
 
222
 
 
223
    def test_take_this(self):
 
224
        self.run_script("""
 
225
$ bzr rm file.OTHER --force # a simple rm file.OTHER is valid too
 
226
$ bzr resolve file
 
227
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
228
""")
 
229
 
 
230
    def test_take_other(self):
 
231
        self.run_script("""
 
232
$ bzr mv file.OTHER file
 
233
$ bzr resolve file
 
234
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
235
""")
 
236
 
 
237
    def test_resolve_taking_this(self):
 
238
        self.run_script("""
 
239
$ bzr resolve --take-this file
 
240
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
241
""")
 
242
 
 
243
    def test_resolve_taking_other(self):
 
244
        self.run_script("""
 
245
$ bzr resolve --take-other file
 
246
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
247
""")
 
248
 
 
249
 
 
250
class TestResolveDuplicateEntry(TestResolveConflicts):
 
251
 
 
252
    preamble = """
 
253
$ bzr init trunk
 
254
$ cd trunk
 
255
$ echo 'trunk content' >file
 
256
$ bzr add file
 
257
$ bzr commit -m 'Create trunk'
 
258
$ echo 'trunk content too' >file2
 
259
$ bzr add file2
 
260
$ bzr commit -m 'Add file2 in trunk'
 
261
 
 
262
$ bzr branch . -r 1 ../branch
 
263
$ cd ../branch
 
264
$ echo 'branch content' >file2
 
265
$ bzr add file2
 
266
$ bzr commit -m 'Add file2 in branch'
 
267
 
 
268
$ bzr merge ../trunk
 
269
2>+N  file2
 
270
2>R   file2 => file2.moved
 
271
2>Conflict adding file file2.  Moved existing file to file2.moved.
 
272
2>1 conflicts encountered.
 
273
"""
 
274
 
 
275
    def test_keep_this(self):
 
276
        self.run_script("""
 
277
$ bzr rm file2  --force
 
278
$ bzr mv file2.moved file2
 
279
$ bzr resolve file2
 
280
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
281
""")
 
282
 
 
283
    def test_keep_other(self):
 
284
        self.failIfExists('branch/file2.moved')
 
285
        self.run_script("""
 
286
$ bzr rm file2.moved --force
 
287
$ bzr resolve file2
 
288
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
289
""")
 
290
        self.failIfExists('branch/file2.moved')
 
291
 
 
292
    def test_resolve_taking_this(self):
 
293
        self.run_script("""
 
294
$ bzr resolve --take-this file2
 
295
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
296
""")
 
297
 
 
298
    def test_resolve_taking_other(self):
 
299
        self.run_script("""
 
300
$ bzr resolve --take-other file2
 
301
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
302
""")
710
303
 
711
304
 
712
305
class TestResolveUnversionedParent(TestResolveConflicts):
717
310
    # tests MissingParent resolution :-/
718
311
    preamble = """
719
312
$ bzr init trunk
720
 
...
721
313
$ cd trunk
722
314
$ mkdir dir
723
 
$ bzr add -q dir
724
 
$ bzr commit -m 'Create trunk' -q
 
315
$ bzr add dir
 
316
$ bzr commit -m 'Create trunk'
725
317
$ echo 'trunk content' >dir/file
726
 
$ bzr add -q dir/file
727
 
$ bzr commit -q -m 'Add dir/file in trunk'
728
 
$ bzr branch -q . -r 1 ../branch
 
318
$ bzr add dir/file
 
319
$ bzr commit -m 'Add dir/file in trunk'
 
320
 
 
321
$ bzr branch . -r 1 ../branch
729
322
$ cd ../branch
730
 
$ bzr rm dir -q
731
 
$ bzr commit -q -m 'Remove dir in branch'
 
323
$ bzr rm dir
 
324
$ bzr commit -m 'Remove dir in branch'
 
325
 
732
326
$ bzr merge ../trunk
733
327
2>+N  dir/
734
328
2>+N  dir/file
739
333
 
740
334
    def test_take_this(self):
741
335
        self.run_script("""
742
 
$ bzr rm -q dir  --force
 
336
$ bzr rm dir  --force
743
337
$ bzr resolve dir
744
 
2>2 conflict(s) resolved, 0 remaining
745
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
338
$ bzr commit --strict -m 'No more conflicts nor unknown files'
746
339
""")
747
340
 
748
341
    def test_take_other(self):
749
342
        self.run_script("""
750
343
$ bzr resolve dir
751
 
2>2 conflict(s) resolved, 0 remaining
752
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
344
$ bzr commit --strict -m 'No more conflicts nor unknown files'
753
345
""")
754
346
 
755
347
 
757
349
 
758
350
    preamble = """
759
351
$ bzr init trunk
760
 
...
761
352
$ cd trunk
762
353
$ mkdir dir
763
354
$ echo 'trunk content' >dir/file
764
 
$ bzr add -q
765
 
$ bzr commit -m 'Create trunk' -q
 
355
$ bzr add
 
356
$ bzr commit -m 'Create trunk'
766
357
$ echo 'trunk content' >dir/file2
767
 
$ bzr add -q dir/file2
768
 
$ bzr commit -q -m 'Add dir/file2 in branch'
769
 
$ bzr branch -q . -r 1 ../branch
 
358
$ bzr add dir/file2
 
359
$ bzr commit -m 'Add dir/file2 in branch'
 
360
 
 
361
$ bzr branch . -r 1 ../branch
770
362
$ cd ../branch
771
 
$ bzr rm -q dir/file --force
772
 
$ bzr rm -q dir
773
 
$ bzr commit -q -m 'Remove dir/file'
 
363
$ bzr rm dir/file --force
 
364
$ bzr rm dir
 
365
$ bzr commit -m 'Remove dir/file'
 
366
 
774
367
$ bzr merge ../trunk
775
368
2>+N  dir/
776
369
2>+N  dir/file2
782
375
    def test_keep_them_all(self):
783
376
        self.run_script("""
784
377
$ bzr resolve dir
785
 
2>2 conflict(s) resolved, 0 remaining
786
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
378
$ bzr commit --strict -m 'No more conflicts nor unknown files'
787
379
""")
788
380
 
789
381
    def test_adopt_child(self):
790
382
        self.run_script("""
791
 
$ bzr mv -q dir/file2 file2
792
 
$ bzr rm -q dir --force
 
383
$ bzr mv dir/file2 file2
 
384
$ bzr rm dir --force
793
385
$ bzr resolve dir
794
 
2>2 conflict(s) resolved, 0 remaining
795
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
386
$ bzr commit --strict -m 'No more conflicts nor unknown files'
796
387
""")
797
388
 
798
389
    def test_kill_them_all(self):
799
390
        self.run_script("""
800
 
$ bzr rm -q dir --force
 
391
$ bzr rm dir --force
801
392
$ bzr resolve dir
802
 
2>2 conflict(s) resolved, 0 remaining
803
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
393
$ bzr commit --strict -m 'No more conflicts nor unknown files'
804
394
""")
805
395
 
806
396
    def test_resolve_taking_this(self):
807
397
        self.run_script("""
808
398
$ bzr resolve --take-this dir
809
 
2>...
810
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
399
$ bzr commit --strict -m 'No more conflicts nor unknown files'
811
400
""")
812
401
 
813
402
    def test_resolve_taking_other(self):
814
403
        self.run_script("""
815
404
$ bzr resolve --take-other dir
816
 
2>...
817
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
405
$ bzr commit --strict -m 'No more conflicts nor unknown files'
818
406
""")
819
407
 
820
408
 
822
410
 
823
411
    preamble = """
824
412
$ bzr init trunk
825
 
...
826
413
$ cd trunk
827
414
$ mkdir dir
828
415
$ echo 'trunk content' >dir/file
829
 
$ bzr add -q
830
 
$ bzr commit -m 'Create trunk' -q
831
 
$ bzr rm -q dir/file --force
832
 
$ bzr rm -q dir --force
833
 
$ bzr commit -q -m 'Remove dir/file'
834
 
$ bzr branch -q . -r 1 ../branch
 
416
$ bzr add
 
417
$ bzr commit -m 'Create trunk'
 
418
$ bzr rm dir/file --force
 
419
$ bzr rm dir --force
 
420
$ bzr commit -m 'Remove dir/file'
 
421
 
 
422
$ bzr branch . -r 1 ../branch
835
423
$ cd ../branch
836
424
$ echo 'branch content' >dir/file2
837
 
$ bzr add -q dir/file2
838
 
$ bzr commit -q -m 'Add dir/file2 in branch'
 
425
$ bzr add dir/file2
 
426
$ bzr commit -m 'Add dir/file2 in branch'
 
427
 
839
428
$ bzr merge ../trunk
840
429
2>-D  dir/file
841
430
2>Conflict: can't delete dir because it is not empty.  Not deleting.
846
435
    def test_keep_them_all(self):
847
436
        self.run_script("""
848
437
$ bzr resolve dir
849
 
2>2 conflict(s) resolved, 0 remaining
850
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
438
$ bzr commit --strict -m 'No more conflicts nor unknown files'
851
439
""")
852
440
 
853
441
    def test_adopt_child(self):
854
442
        self.run_script("""
855
 
$ bzr mv -q dir/file2 file2
856
 
$ bzr rm -q dir --force
 
443
$ bzr mv dir/file2 file2
 
444
$ bzr rm dir --force
857
445
$ bzr resolve dir
858
 
2>2 conflict(s) resolved, 0 remaining
859
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
446
$ bzr commit --strict -m 'No more conflicts nor unknown files'
860
447
""")
861
448
 
862
449
    def test_kill_them_all(self):
863
450
        self.run_script("""
864
 
$ bzr rm -q dir --force
 
451
$ bzr rm dir --force
865
452
$ bzr resolve dir
866
 
2>2 conflict(s) resolved, 0 remaining
867
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
453
$ bzr commit --strict -m 'No more conflicts nor unknown files'
868
454
""")
869
455
 
870
456
    def test_resolve_taking_this(self):
871
457
        self.run_script("""
872
458
$ bzr resolve --take-this dir
873
 
2>2 conflict(s) resolved, 0 remaining
874
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
459
$ bzr commit --strict -m 'No more conflicts nor unknown files'
875
460
""")
876
461
 
877
462
    def test_resolve_taking_other(self):
878
463
        self.run_script("""
879
464
$ bzr resolve --take-other dir
880
 
2>deleted dir/file2
881
 
2>deleted dir
882
 
2>2 conflict(s) resolved, 0 remaining
883
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
884
 
""")
885
 
 
886
 
 
887
 
class TestResolveParentLoop(TestParametrizedResolveConflicts):
888
 
 
889
 
    _conflict_type = conflicts.ParentLoop
890
 
 
891
 
    _this_args = None
892
 
    _other_args = None
893
 
 
894
 
    # Each side dict additionally defines:
895
 
    # - dir_id: the directory being moved
896
 
    # - target_id: The target directory
897
 
    # - xfail: whether the test is expected to fail if the action is
898
 
    #   involved as 'other'
899
 
    scenarios = mirror_scenarios(
900
 
        [
901
 
            # Dirs moved into each other
902
 
            (dict(_base_actions='create_dir1_dir2'),
903
 
             ('dir1_into_dir2',
904
 
              dict(actions='move_dir1_into_dir2', check='dir1_moved',
905
 
                   dir_id='dir1-id', target_id='dir2-id', xfail=False)),
906
 
             ('dir2_into_dir1',
907
 
              dict(actions='move_dir2_into_dir1', check='dir2_moved',
908
 
                   dir_id='dir2-id', target_id='dir1-id', xfail=False))),
909
 
            # Subdirs moved into each other
910
 
            (dict(_base_actions='create_dir1_4'),
911
 
             ('dir1_into_dir4',
912
 
              dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
913
 
                   dir_id='dir1-id', target_id='dir4-id', xfail=True)),
914
 
             ('dir3_into_dir2',
915
 
              dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
916
 
                   dir_id='dir3-id', target_id='dir2-id', xfail=True))),
917
 
            ])
918
 
 
919
 
    def do_create_dir1_dir2(self):
920
 
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
921
 
                ('add', ('dir2', 'dir2-id', 'directory', '')),]
922
 
 
923
 
    def do_move_dir1_into_dir2(self):
924
 
        return [('rename', ('dir1', 'dir2/dir1'))]
925
 
 
926
 
    def check_dir1_moved(self):
927
 
        self.assertPathDoesNotExist('branch/dir1')
928
 
        self.assertPathExists('branch/dir2/dir1')
929
 
 
930
 
    def do_move_dir2_into_dir1(self):
931
 
        return [('rename', ('dir2', 'dir1/dir2'))]
932
 
 
933
 
    def check_dir2_moved(self):
934
 
        self.assertPathDoesNotExist('branch/dir2')
935
 
        self.assertPathExists('branch/dir1/dir2')
936
 
 
937
 
    def do_create_dir1_4(self):
938
 
        return [('add', ('dir1', 'dir1-id', 'directory', '')),
939
 
                ('add', ('dir1/dir2', 'dir2-id', 'directory', '')),
940
 
                ('add', ('dir3', 'dir3-id', 'directory', '')),
941
 
                ('add', ('dir3/dir4', 'dir4-id', 'directory', '')),]
942
 
 
943
 
    def do_move_dir1_into_dir4(self):
944
 
        return [('rename', ('dir1', 'dir3/dir4/dir1'))]
945
 
 
946
 
    def check_dir1_2_moved(self):
947
 
        self.assertPathDoesNotExist('branch/dir1')
948
 
        self.assertPathExists('branch/dir3/dir4/dir1')
949
 
        self.assertPathExists('branch/dir3/dir4/dir1/dir2')
950
 
 
951
 
    def do_move_dir3_into_dir2(self):
952
 
        return [('rename', ('dir3', 'dir1/dir2/dir3'))]
953
 
 
954
 
    def check_dir3_4_moved(self):
955
 
        self.assertPathDoesNotExist('branch/dir3')
956
 
        self.assertPathExists('branch/dir1/dir2/dir3')
957
 
        self.assertPathExists('branch/dir1/dir2/dir3/dir4')
958
 
 
959
 
    def _get_resolve_path_arg(self, wt, action):
960
 
        # ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
961
 
        # But since <path> doesn't exist in the working tree, we need to use
962
 
        # <conflict_path> instead, and that, in turn, is given by dir_id. Pfew.
963
 
        return wt.id2path(self._other['dir_id'])
964
 
 
965
 
    def assertParentLoop(self, wt, c):
966
 
        self.assertEqual(self._other['dir_id'], c.file_id)
967
 
        self.assertEqual(self._other['target_id'], c.conflict_file_id)
968
 
        # The conflict paths are irrelevant (they are deterministic but not
969
 
        # worth checking since they don't provide the needed information
970
 
        # anyway)
971
 
        if self._other['xfail']:
972
 
            # It's a bit hackish to raise from here relying on being called for
973
 
            # both tests but this avoid overriding test_resolve_taking_other
974
 
            self.knownFailure(
975
 
                "ParentLoop doesn't carry enough info to resolve --take-other")
976
 
    _assert_conflict = assertParentLoop
 
465
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
466
""")
 
467
 
 
468
 
 
469
class TestResolvePathConflict(TestResolveConflicts):
 
470
 
 
471
    preamble = """
 
472
$ bzr init trunk
 
473
$ cd trunk
 
474
$ echo 'Boo!' >file
 
475
$ bzr add
 
476
$ bzr commit -m 'Create trunk'
 
477
$ bzr mv file file-in-trunk
 
478
$ bzr commit -m 'Renamed to file-in-trunk'
 
479
 
 
480
$ bzr branch . -r 1 ../branch
 
481
$ cd ../branch
 
482
$ bzr mv file file-in-branch
 
483
$ bzr commit -m 'Renamed to file-in-branch'
 
484
 
 
485
$ bzr merge ../trunk
 
486
2>R   file-in-branch => file-in-trunk
 
487
2>Path conflict: file-in-branch / file-in-trunk
 
488
2>1 conflicts encountered.
 
489
"""
 
490
 
 
491
    def test_keep_source(self):
 
492
        self.run_script("""
 
493
$ bzr resolve file-in-trunk
 
494
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
495
""")
 
496
 
 
497
    def test_keep_target(self):
 
498
        self.run_script("""
 
499
$ bzr mv file-in-trunk file-in-branch
 
500
$ bzr resolve file-in-branch
 
501
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
502
""")
 
503
 
 
504
    def test_resolve_taking_this(self):
 
505
        self.run_script("""
 
506
$ bzr resolve --take-this file-in-branch
 
507
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
508
""")
 
509
 
 
510
    def test_resolve_taking_other(self):
 
511
        self.run_script("""
 
512
$ bzr resolve --take-other file-in-branch
 
513
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
514
""")
 
515
 
 
516
 
 
517
class TestResolveParentLoop(TestResolveConflicts):
 
518
 
 
519
    preamble = """
 
520
$ bzr init trunk
 
521
$ cd trunk
 
522
$ bzr mkdir dir1
 
523
$ bzr mkdir dir2
 
524
$ bzr commit -m 'Create trunk'
 
525
$ bzr mv dir2 dir1
 
526
$ bzr commit -m 'Moved dir2 into dir1'
 
527
 
 
528
$ bzr branch . -r 1 ../branch
 
529
$ cd ../branch
 
530
$ bzr mv dir1 dir2
 
531
$ bzr commit -m 'Moved dir1 into dir2'
 
532
 
 
533
$ bzr merge ../trunk
 
534
2>Conflict moving dir2/dir1 into dir2.  Cancelled move.
 
535
2>1 conflicts encountered.
 
536
"""
 
537
 
 
538
    def test_take_this(self):
 
539
        self.run_script("""
 
540
$ bzr resolve dir2
 
541
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
542
""")
 
543
 
 
544
    def test_take_other(self):
 
545
        self.run_script("""
 
546
$ bzr mv dir2/dir1 dir1
 
547
$ bzr mv dir2 dir1
 
548
$ bzr resolve dir2
 
549
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
550
""")
 
551
 
 
552
    def test_resolve_taking_this(self):
 
553
        self.run_script("""
 
554
$ bzr resolve --take-this dir2
 
555
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
556
""")
 
557
        self.failUnlessExists('dir2')
 
558
 
 
559
    def test_resolve_taking_other(self):
 
560
        self.run_script("""
 
561
$ bzr resolve --take-other dir2
 
562
$ bzr commit --strict -m 'No more conflicts nor unknown files'
 
563
""")
 
564
        self.failUnlessExists('dir1')
977
565
 
978
566
 
979
567
class TestResolveNonDirectoryParent(TestResolveConflicts):
980
568
 
981
569
    preamble = """
982
570
$ bzr init trunk
983
 
...
984
571
$ cd trunk
985
572
$ bzr mkdir foo
986
 
...
987
 
$ bzr commit -m 'Create trunk' -q
 
573
$ bzr commit -m 'Create trunk'
988
574
$ echo "Boing" >foo/bar
989
 
$ bzr add -q foo/bar
990
 
$ bzr commit -q -m 'Add foo/bar'
991
 
$ bzr branch -q . -r 1 ../branch
 
575
$ bzr add foo/bar
 
576
$ bzr commit -m 'Add foo/bar'
 
577
 
 
578
$ bzr branch . -r 1 ../branch
992
579
$ cd ../branch
993
580
$ rm -r foo
994
581
$ echo "Boo!" >foo
995
 
$ bzr commit -q -m 'foo is now a file'
 
582
$ bzr commit -m 'foo is now a file'
 
583
 
996
584
$ bzr merge ../trunk
997
585
2>+N  foo.new/bar
998
586
2>RK  foo => foo.new/
1004
592
 
1005
593
    def test_take_this(self):
1006
594
        self.run_script("""
1007
 
$ bzr rm -q foo.new --force
 
595
$ bzr rm foo.new --force
1008
596
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
1009
597
# aside ? -- vila 090916
1010
 
$ bzr add -q foo
 
598
$ bzr add foo
1011
599
$ bzr resolve foo.new
1012
 
2>1 conflict(s) resolved, 0 remaining
1013
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
600
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1014
601
""")
1015
602
 
1016
603
    def test_take_other(self):
1017
604
        self.run_script("""
1018
 
$ bzr rm -q foo --force
1019
 
$ bzr mv -q foo.new foo
 
605
$ bzr rm foo --force
 
606
$ bzr mv foo.new foo
1020
607
$ bzr resolve foo
1021
 
2>1 conflict(s) resolved, 0 remaining
1022
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
608
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1023
609
""")
1024
610
 
1025
611
    def test_resolve_taking_this(self):
1026
612
        self.run_script("""
1027
613
$ bzr resolve --take-this foo.new
1028
 
2>...
1029
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
614
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1030
615
""")
1031
616
 
1032
617
    def test_resolve_taking_other(self):
1033
618
        self.run_script("""
1034
619
$ bzr resolve --take-other foo.new
1035
 
2>...
1036
 
$ bzr commit -q --strict -m 'No more conflicts nor unknown files'
 
620
$ bzr commit --strict -m 'No more conflicts nor unknown files'
1037
621
""")
1038
622
 
1039
623
 
1045
629
        # conflict.
1046
630
        self.run_script("""
1047
631
$ bzr init trunk
1048
 
...
1049
632
$ cd trunk
1050
633
$ bzr mkdir foo
1051
 
...
1052
 
$ bzr commit -m 'Create trunk' -q
 
634
$ bzr commit -m 'Create trunk'
1053
635
$ rm -r foo
1054
636
$ echo "Boo!" >foo
1055
 
$ bzr commit -m 'foo is now a file' -q
1056
 
$ bzr branch -q . -r 1 ../branch -q
 
637
$ bzr commit -m 'foo is now a file'
 
638
 
 
639
$ bzr branch . -r 1 ../branch
1057
640
$ cd ../branch
1058
641
$ echo "Boing" >foo/bar
1059
 
$ bzr add -q foo/bar -q
1060
 
$ bzr commit -m 'Add foo/bar' -q
 
642
$ bzr add foo/bar
 
643
$ bzr commit -m 'Add foo/bar'
 
644
 
1061
645
$ bzr merge ../trunk
1062
646
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1063
647
""")
1064
648
 
1065
649
 
1066
 
class TestNoFinalPath(script.TestCaseWithTransportAndScript):
1067
 
 
1068
 
    def test_bug_805809(self):
1069
 
        self.run_script("""
1070
 
$ bzr init trunk
1071
 
Created a standalone tree (format: 2a)
1072
 
$ cd trunk
1073
 
$ echo trunk >file
1074
 
$ bzr add
1075
 
adding file
1076
 
$ bzr commit -m 'create file on trunk'
1077
 
2>Committing to: .../trunk/
1078
 
2>added file
1079
 
2>Committed revision 1.
1080
 
# Create a debian branch based on trunk
1081
 
$ cd ..
1082
 
$ bzr branch trunk -r 1 debian
1083
 
2>Branched 1 revision(s).
1084
 
$ cd debian
1085
 
$ mkdir dir
1086
 
$ bzr add
1087
 
adding dir
1088
 
$ bzr mv file dir
1089
 
file => dir/file
1090
 
$ bzr commit -m 'rename file to dir/file for debian'
1091
 
2>Committing to: .../debian/
1092
 
2>added dir
1093
 
2>renamed file => dir/file
1094
 
2>Committed revision 2.
1095
 
# Create an experimental branch with a new root-id
1096
 
$ cd ..
1097
 
$ bzr init experimental
1098
 
Created a standalone tree (format: 2a)
1099
 
$ cd experimental
1100
 
# Work around merging into empty branch not being supported
1101
 
# (http://pad.lv/308562)
1102
 
$ echo something >not-empty
1103
 
$ bzr add
1104
 
adding not-empty
1105
 
$ bzr commit -m 'Add some content in experimental'
1106
 
2>Committing to: .../experimental/
1107
 
2>added not-empty
1108
 
2>Committed revision 1.
1109
 
# merge debian even without a common ancestor
1110
 
$ bzr merge ../debian -r0..2
1111
 
2>+N  dir/
1112
 
2>+N  dir/file
1113
 
2>All changes applied successfully.
1114
 
$ bzr commit -m 'merging debian into experimental'
1115
 
2>Committing to: .../experimental/
1116
 
2>added dir
1117
 
2>added dir/file
1118
 
2>Committed revision 2.
1119
 
# Create an ubuntu branch with yet another root-id
1120
 
$ cd ..
1121
 
$ bzr init ubuntu
1122
 
Created a standalone tree (format: 2a)
1123
 
$ cd ubuntu
1124
 
# Work around merging into empty branch not being supported
1125
 
# (http://pad.lv/308562)
1126
 
$ echo something >not-empty-ubuntu
1127
 
$ bzr add
1128
 
adding not-empty-ubuntu
1129
 
$ bzr commit -m 'Add some content in experimental'
1130
 
2>Committing to: .../ubuntu/
1131
 
2>added not-empty-ubuntu
1132
 
2>Committed revision 1.
1133
 
# Also merge debian
1134
 
$ bzr merge ../debian -r0..2
1135
 
2>+N  dir/
1136
 
2>+N  dir/file
1137
 
2>All changes applied successfully.
1138
 
$ bzr commit -m 'merging debian'
1139
 
2>Committing to: .../ubuntu/
1140
 
2>added dir
1141
 
2>added dir/file
1142
 
2>Committed revision 2.
1143
 
# Now try to merge experimental
1144
 
$ bzr merge ../experimental
1145
 
2>+N  not-empty
1146
 
2>Path conflict: dir / dir
1147
 
2>1 conflicts encountered.
1148
 
""")
1149
 
 
1150
 
 
1151
650
class TestResolveActionOption(tests.TestCase):
1152
651
 
1153
652
    def setUp(self):