57
43
# '\xc3\xae' == u'\xee' == i with hat
58
44
# So these are u'path' and 'id' only with a circle and a hat. (shappo?)
59
45
example_conflicts = conflicts.ConflictList(
60
[conflicts.MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
61
conflicts.ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
46
[conflicts.MissingParent('Not deleting', u'p\xe5thg', b'\xc3\xaedg'),
47
conflicts.ContentsConflict(u'p\xe5tha', None, b'\xc3\xaeda'),
62
48
conflicts.TextConflict(u'p\xe5tha'),
63
conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
49
conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', b'\xc3\xaedb'),
64
50
conflicts.DuplicateID('Unversioned existing file',
65
51
u'p\xe5thc', u'p\xe5thc2',
66
'\xc3\xaedc', '\xc3\xaedc'),
67
conflicts.DuplicateEntry('Moved existing file to',
68
u'p\xe5thdd.moved', u'p\xe5thd',
70
conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
72
conflicts.UnversionedParent('Versioned directory',
73
u'p\xe5thf', '\xc3\xaedf'),
74
conflicts.NonDirectoryParent('Created directory',
75
u'p\xe5thg', '\xc3\xaedg'),
52
b'\xc3\xaedc', b'\xc3\xaedc'),
53
conflicts.DuplicateEntry('Moved existing file to',
54
u'p\xe5thdd.moved', u'p\xe5thd',
56
conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
57
None, b'\xc3\xaed2e'),
58
conflicts.UnversionedParent('Versioned directory',
59
u'p\xe5thf', b'\xc3\xaedf'),
60
conflicts.NonDirectoryParent('Created directory',
61
u'p\xe5thg', b'\xc3\xaedg'),
65
def vary_by_conflicts():
66
for conflict in example_conflicts:
67
yield (conflict.__class__.__name__, {"conflict": conflict})
79
70
class TestConflicts(tests.TestCaseWithTransport):
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'),
93
self.assertLength(6, list(tree.list_files()))
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')
108
72
def test_resolve_conflict_dir(self):
109
73
tree = self.make_branch_and_tree('.')
110
self.build_tree_contents([('hello', 'hello world4'),
111
('hello.THIS', 'hello world2'),
112
('hello.BASE', 'hello world1'),
74
self.build_tree_contents([('hello', b'hello world4'),
75
('hello.THIS', b'hello world2'),
76
('hello.BASE', b'hello world1'),
114
78
os.mkdir('hello.OTHER')
115
tree.add('hello', 'q')
79
tree.add('hello', b'q')
116
80
l = conflicts.ConflictList([conflicts.TextConflict('hello')])
117
81
l.remove_files(tree)
161
126
self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
164
class TestConflictStanzas(tests.TestCase):
129
class TestPerConflict(tests.TestCase):
131
scenarios = scenarios.multiply_scenarios(vary_by_conflicts())
133
def test_stringification(self):
134
text = text_type(self.conflict)
135
self.assertContainsString(text, self.conflict.path)
136
self.assertContainsString(text.lower(), "conflict")
137
self.assertContainsString(repr(self.conflict),
138
self.conflict.__class__.__name__)
166
140
def test_stanza_roundtrip(self):
167
# write and read our example stanza.
168
stanza_iter = example_conflicts.to_stanzas()
169
processed = conflicts.ConflictList.from_stanzas(stanza_iter)
170
for o, p in zip(processed, example_conflicts):
171
self.assertEqual(o, p)
173
self.assertIsInstance(o.path, unicode)
175
if o.file_id is not None:
176
self.assertIsInstance(o.file_id, str)
178
conflict_path = getattr(o, 'conflict_path', None)
179
if conflict_path is not None:
180
self.assertIsInstance(conflict_path, unicode)
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)
142
o = conflicts.Conflict.factory(**p.as_stanza().as_dict())
143
self.assertEqual(o, p)
145
self.assertIsInstance(o.path, text_type)
147
if o.file_id is not None:
148
self.assertIsInstance(o.file_id, bytes)
150
conflict_path = getattr(o, 'conflict_path', None)
151
if conflict_path is not None:
152
self.assertIsInstance(conflict_path, text_type)
154
conflict_file_id = getattr(o, 'conflict_file_id', None)
155
if conflict_file_id is not None:
156
self.assertIsInstance(conflict_file_id, bytes)
186
158
def test_stanzification(self):
187
for stanza in example_conflicts.to_stanzas():
188
if 'file_id' in stanza:
189
# In Stanza form, the file_id has to be unicode.
190
self.assertStartsWith(stanza['file_id'], u'\xeed')
191
self.assertStartsWith(stanza['path'], u'p\xe5th')
192
if 'conflict_path' in stanza:
193
self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
194
if 'conflict_file_id' in stanza:
195
self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
159
stanza = self.conflict.as_stanza()
160
if 'file_id' in stanza:
161
# In Stanza form, the file_id has to be unicode.
162
self.assertStartsWith(stanza['file_id'], u'\xeed')
163
self.assertStartsWith(stanza['path'], u'p\xe5th')
164
if 'conflict_path' in stanza:
165
self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
166
if 'conflict_file_id' in stanza:
167
self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
170
class TestConflictList(tests.TestCase):
172
def test_stanzas_roundtrip(self):
173
stanzas_iter = example_conflicts.to_stanzas()
174
processed = conflicts.ConflictList.from_stanzas(stanzas_iter)
175
self.assertEqual(example_conflicts, processed)
177
def test_stringification(self):
178
for text, o in zip(example_conflicts.to_strings(), example_conflicts):
179
self.assertEqual(text, text_type(o))
198
182
# FIXME: The shell-like tests should be converted to real whitebox tests... or
298
"""Return the scenario list for the conflict type defined by the class.
300
Each scenario is of the form:
301
(common, (left_name, left_dict), (right_name, right_dict))
305
* left_name and right_name are the scenario names that will be combined
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.
311
Daughters classes are free to add their specific attributes as they see
312
fit in any of the three dicts.
314
This is a class method so that load_tests can find it.
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.
322
# Only concrete classes return actual scenarios
276
"""The scenario list for the conflict type defined by the class.
278
Each scenario is of the form:
279
(common, (left_name, left_dict), (right_name, right_dict))
283
* left_name and right_name are the scenario names that will be combined
285
* left_dict and right_dict are the attributes specific to each half of
286
the scenario. They should include at least 'actions' and 'check' and
287
will be available as '_this' and '_other' test instance attributes.
289
Daughters classes are free to add their specific attributes as they see
290
fit in any of the three dicts.
292
This is a class method so that load_tests can find it.
294
'_base_actions' in the common dict, 'actions' and 'check' in the left
295
and right dicts use names that map to methods in the test classes. Some
296
prefixes are added to these names to get the correspong methods (see
297
_get_actions() and _get_check()). The motivation here is to avoid
298
collisions in the class namespace.
326
302
super(TestParametrizedResolveConflicts, self).setUp()
328
304
builder.start_series()
330
306
# Create an empty trunk
331
builder.build_snapshot('start', None, [
332
('add', ('', 'root-id', 'directory', ''))])
307
builder.build_snapshot(None, [
308
('add', (u'', b'root-id', 'directory', ''))],
309
revision_id=b'start')
333
310
# Add a minimal base content
334
311
base_actions = self._get_actions(self._base_actions)()
335
builder.build_snapshot('base', ['start'], base_actions)
312
builder.build_snapshot([b'start'], base_actions, revision_id=b'base')
336
313
# Modify the base content in branch
337
314
actions_other = self._get_actions(self._other['actions'])()
338
builder.build_snapshot('other', ['base'], actions_other)
315
builder.build_snapshot([b'base'], actions_other, revision_id=b'other')
339
316
# Modify the base content in trunk
340
317
actions_this = self._get_actions(self._this['actions'])()
341
builder.build_snapshot('this', ['base'], actions_this)
318
builder.build_snapshot([b'base'], actions_this, revision_id=b'this')
342
319
# builder.get_branch() tip is now 'this'
344
321
builder.finish_series()
368
class TestResolveTextConflicts(TestParametrizedResolveConflicts):
370
_conflict_type = conflicts.TextConflict
372
# Set by the scenarios
373
# path and file-id for the file involved in the conflict
377
scenarios = mirror_scenarios(
379
# File modified on both sides
380
(dict(_base_actions='create_file',
381
_path='file', _file_id=b'file-id'),
383
dict(actions='modify_file_A', check='file_has_content_A')),
385
dict(actions='modify_file_B', check='file_has_content_B')),),
386
# File modified on both sides in dir
387
(dict(_base_actions='create_file_in_dir',
388
_path='dir/file', _file_id=b'file-id'),
389
('filed_modified_A_in_dir',
390
dict(actions='modify_file_A_in_dir',
391
check='file_in_dir_has_content_A')),
393
dict(actions='modify_file_B_in_dir',
394
check='file_in_dir_has_content_B')),),
397
def do_create_file(self, path='file'):
398
return [('add', (path, b'file-id', 'file', b'trunk content\n'))]
400
def do_modify_file_A(self):
401
return [('modify', ('file', b'trunk content\nfeature A\n'))]
403
def do_modify_file_B(self):
404
return [('modify', ('file', b'trunk content\nfeature B\n'))]
406
def do_modify_file_A_in_dir(self):
407
return [('modify', ('dir/file', b'trunk content\nfeature A\n'))]
409
def do_modify_file_B_in_dir(self):
410
return [('modify', ('dir/file', b'trunk content\nfeature B\n'))]
412
def check_file_has_content_A(self, path='file'):
413
self.assertFileEqual(b'trunk content\nfeature A\n',
414
osutils.pathjoin('branch', path))
416
def check_file_has_content_B(self, path='file'):
417
self.assertFileEqual(b'trunk content\nfeature B\n',
418
osutils.pathjoin('branch', path))
420
def do_create_file_in_dir(self):
421
return [('add', ('dir', b'dir-id', 'directory', '')),
422
] + self.do_create_file('dir/file')
424
def check_file_in_dir_has_content_A(self):
425
self.check_file_has_content_A('dir/file')
427
def check_file_in_dir_has_content_B(self):
428
self.check_file_has_content_B('dir/file')
430
def _get_resolve_path_arg(self, wt, action):
433
def assertTextConflict(self, wt, c):
434
self.assertEqual(self._file_id, c.file_id)
435
self.assertEqual(self._path, c.path)
436
_assert_conflict = assertTextConflict
391
439
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
393
_conflict_type = conflicts.ContentsConflict,
441
_conflict_type = conflicts.ContentsConflict
395
# Set by load_tests from scenarios()
443
# Set by the scenarios
396
444
# path and file-id for the file involved in the conflict
448
scenarios = mirror_scenarios(
403
450
# File modified/deleted
404
451
(dict(_base_actions='create_file',
405
_path='file', _file_id='file-id'),
452
_path='file', _file_id=b'file-id'),
406
453
('file_modified',
407
454
dict(actions='modify_file', check='file_has_more_content')),
409
456
dict(actions='delete_file', check='file_doesnt_exist')),),
411
return mirror_scenarios(base_scenarios)
457
# File renamed-modified/deleted
458
(dict(_base_actions='create_file',
459
_path='new-file', _file_id=b'file-id'),
460
('file_renamed_and_modified',
461
dict(actions='modify_and_rename_file',
462
check='file_renamed_and_more_content')),
464
dict(actions='delete_file', check='file_doesnt_exist')),),
465
# File modified/deleted in dir
466
(dict(_base_actions='create_file_in_dir',
467
_path='dir/file', _file_id=b'file-id'),
468
('file_modified_in_dir',
469
dict(actions='modify_file_in_dir',
470
check='file_in_dir_has_more_content')),
471
('file_deleted_in_dir',
472
dict(actions='delete_file_in_dir',
473
check='file_in_dir_doesnt_exist')),),
413
476
def do_create_file(self):
414
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
477
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
416
479
def do_modify_file(self):
417
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
480
return [('modify', ('file', b'trunk content\nmore content\n'))]
482
def do_modify_and_rename_file(self):
483
return [('modify', ('new-file', b'trunk content\nmore content\n')),
484
('rename', ('file', 'new-file'))]
419
486
def check_file_has_more_content(self):
420
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
487
self.assertFileEqual(b'trunk content\nmore content\n', 'branch/file')
489
def check_file_renamed_and_more_content(self):
490
self.assertFileEqual(
491
b'trunk content\nmore content\n', 'branch/new-file')
422
493
def do_delete_file(self):
423
return [('unversion', 'file-id')]
494
return [('unversion', 'file')]
496
def do_delete_file_in_dir(self):
497
return [('unversion', 'dir/file')]
425
499
def check_file_doesnt_exist(self):
426
self.failIfExists('branch/file')
500
self.assertPathDoesNotExist('branch/file')
502
def do_create_file_in_dir(self):
503
return [('add', ('dir', b'dir-id', 'directory', '')),
504
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
506
def do_modify_file_in_dir(self):
507
return [('modify', ('dir/file', b'trunk content\nmore content\n'))]
509
def check_file_in_dir_has_more_content(self):
510
self.assertFileEqual(
511
b'trunk content\nmore content\n', 'branch/dir/file')
513
def check_file_in_dir_doesnt_exist(self):
514
self.assertPathDoesNotExist('branch/dir/file')
428
516
def _get_resolve_path_arg(self, wt, action):
429
517
return self._path
437
525
class TestResolvePathConflict(TestParametrizedResolveConflicts):
439
_conflict_type = conflicts.PathConflict,
527
_conflict_type = conflicts.PathConflict
441
529
def do_nothing(self):
446
# Each side dict additionally defines:
447
# - path path involved (can be '<deleted>')
532
# Each side dict additionally defines:
533
# - path path involved (can be '<deleted>')
535
scenarios = mirror_scenarios(
450
537
# File renamed/deleted
451
538
(dict(_base_actions='create_file'),
453
540
dict(actions='rename_file', check='file_renamed',
454
path='new-file', file_id='file-id')),
541
path='new-file', file_id=b'file-id')),
456
543
dict(actions='delete_file', check='file_doesnt_exist',
457
544
# PathConflicts deletion handling requires a special
458
545
# hard-coded value
459
path='<deleted>', file_id='file-id')),),
546
path='<deleted>', file_id=b'file-id')),),
547
# File renamed/deleted in dir
548
(dict(_base_actions='create_file_in_dir'),
549
('file_renamed_in_dir',
550
dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
551
path='dir/new-file', file_id=b'file-id')),
553
dict(actions='delete_file_in_dir', check='file_in_dir_doesnt_exist',
554
# PathConflicts deletion handling requires a special
556
path='<deleted>', file_id=b'file-id')),),
460
557
# File renamed/renamed differently
461
558
(dict(_base_actions='create_file'),
463
560
dict(actions='rename_file', check='file_renamed',
464
path='new-file', file_id='file-id')),
561
path='new-file', file_id=b'file-id')),
465
562
('file_renamed2',
466
563
dict(actions='rename_file2', check='file_renamed2',
467
path='new-file2', file_id='file-id')),),
564
path='new-file2', file_id=b'file-id')),),
468
565
# Dir renamed/deleted
469
566
(dict(_base_actions='create_dir'),
471
568
dict(actions='rename_dir', check='dir_renamed',
472
path='new-dir', file_id='dir-id')),
569
path='new-dir', file_id=b'dir-id')),
474
571
dict(actions='delete_dir', check='dir_doesnt_exist',
475
572
# PathConflicts deletion handling requires a special
476
573
# hard-coded value
477
path='<deleted>', file_id='dir-id')),),
574
path='<deleted>', file_id=b'dir-id')),),
478
575
# Dir renamed/renamed differently
479
576
(dict(_base_actions='create_dir'),
481
578
dict(actions='rename_dir', check='dir_renamed',
482
path='new-dir', file_id='dir-id')),
579
path='new-dir', file_id=b'dir-id')),
484
581
dict(actions='rename_dir2', check='dir_renamed2',
485
path='new-dir2', file_id='dir-id')),),
487
return mirror_scenarios(base_scenarios)
582
path='new-dir2', file_id=b'dir-id')),),
489
585
def do_create_file(self):
490
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
586
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
492
588
def do_create_dir(self):
493
return [('add', ('dir', 'dir-id', 'directory', ''))]
589
return [('add', ('dir', b'dir-id', 'directory', ''))]
495
591
def do_rename_file(self):
496
592
return [('rename', ('file', 'new-file'))]
498
594
def check_file_renamed(self):
499
self.failIfExists('branch/file')
500
self.failUnlessExists('branch/new-file')
595
self.assertPathDoesNotExist('branch/file')
596
self.assertPathExists('branch/new-file')
502
598
def do_rename_file2(self):
503
599
return [('rename', ('file', 'new-file2'))]
505
601
def check_file_renamed2(self):
506
self.failIfExists('branch/file')
507
self.failUnlessExists('branch/new-file2')
602
self.assertPathDoesNotExist('branch/file')
603
self.assertPathExists('branch/new-file2')
509
605
def do_rename_dir(self):
510
606
return [('rename', ('dir', 'new-dir'))]
512
608
def check_dir_renamed(self):
513
self.failIfExists('branch/dir')
514
self.failUnlessExists('branch/new-dir')
609
self.assertPathDoesNotExist('branch/dir')
610
self.assertPathExists('branch/new-dir')
516
612
def do_rename_dir2(self):
517
613
return [('rename', ('dir', 'new-dir2'))]
519
615
def check_dir_renamed2(self):
520
self.failIfExists('branch/dir')
521
self.failUnlessExists('branch/new-dir2')
616
self.assertPathDoesNotExist('branch/dir')
617
self.assertPathExists('branch/new-dir2')
523
619
def do_delete_file(self):
524
return [('unversion', 'file-id')]
620
return [('unversion', 'file')]
622
def do_delete_file_in_dir(self):
623
return [('unversion', 'dir/file')]
526
625
def check_file_doesnt_exist(self):
527
self.failIfExists('branch/file')
626
self.assertPathDoesNotExist('branch/file')
529
628
def do_delete_dir(self):
530
return [('unversion', 'dir-id')]
629
return [('unversion', 'dir')]
532
631
def check_dir_doesnt_exist(self):
533
self.failIfExists('branch/dir')
632
self.assertPathDoesNotExist('branch/dir')
634
def do_create_file_in_dir(self):
635
return [('add', ('dir', b'dir-id', 'directory', '')),
636
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
638
def do_rename_file_in_dir(self):
639
return [('rename', ('dir/file', 'dir/new-file'))]
641
def check_file_in_dir_renamed(self):
642
self.assertPathDoesNotExist('branch/dir/file')
643
self.assertPathExists('branch/dir/new-file')
645
def check_file_in_dir_doesnt_exist(self):
646
self.assertPathDoesNotExist('branch/dir/file')
535
648
def _get_resolve_path_arg(self, wt, action):
536
649
tpath = self._this['path']
569
682
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
571
_conflict_type = conflicts.DuplicateEntry,
684
_conflict_type = conflicts.DuplicateEntry
575
# Each side dict additionally defines:
686
scenarios = mirror_scenarios(
579
688
# File created with different file-ids
580
689
(dict(_base_actions='nothing'),
581
690
('filea_created',
582
691
dict(actions='create_file_a', check='file_content_a',
583
path='file', file_id='file-a-id')),
692
path='file', file_id=b'file-a-id')),
584
693
('fileb_created',
585
694
dict(actions='create_file_b', check='file_content_b',
586
path='file', file_id='file-b-id')),),
588
return mirror_scenarios(base_scenarios)
695
path='file', file_id=b'file-b-id')),),
696
# File created with different file-ids but deleted on one side
697
(dict(_base_actions='create_file_a'),
699
dict(actions='replace_file_a_by_b', check='file_content_b',
700
path='file', file_id=b'file-b-id')),
702
dict(actions='modify_file_a', check='file_new_content',
703
path='file', file_id=b'file-a-id')),),
590
706
def do_nothing(self):
593
709
def do_create_file_a(self):
594
return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
710
return [('add', ('file', b'file-a-id', 'file', b'file a content\n'))]
596
712
def check_file_content_a(self):
597
self.assertFileEqual('file a content\n', 'branch/file')
713
self.assertFileEqual(b'file a content\n', 'branch/file')
599
715
def do_create_file_b(self):
600
return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
716
return [('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
602
718
def check_file_content_b(self):
603
self.assertFileEqual('file b content\n', 'branch/file')
719
self.assertFileEqual(b'file b content\n', 'branch/file')
721
def do_replace_file_a_by_b(self):
722
return [('unversion', 'file'),
723
('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
725
def do_modify_file_a(self):
726
return [('modify', ('file', b'new content\n'))]
728
def check_file_new_content(self):
729
self.assertFileEqual(b'new content\n', 'branch/file')
605
731
def _get_resolve_path_arg(self, wt, action):
606
732
return self._this['path']
692
816
def test_keep_them_all(self):
693
817
self.run_script("""
695
$ bzr commit --strict -m 'No more conflicts nor unknown files'
819
2>2 conflicts resolved, 0 remaining
820
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
698
823
def test_adopt_child(self):
699
824
self.run_script("""
700
$ bzr mv dir/file2 file2
703
$ bzr commit --strict -m 'No more conflicts nor unknown files'
825
$ brz mv -q dir/file2 file2
826
$ brz rm -q dir --no-backup
828
2>2 conflicts resolved, 0 remaining
829
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
706
832
def test_kill_them_all(self):
707
833
self.run_script("""
710
$ bzr commit --strict -m 'No more conflicts nor unknown files'
834
$ brz rm -q dir --no-backup
836
2>2 conflicts resolved, 0 remaining
837
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
713
840
def test_resolve_taking_this(self):
714
841
self.run_script("""
715
$ bzr resolve --take-this dir
716
$ bzr commit --strict -m 'No more conflicts nor unknown files'
842
$ brz resolve --take-this dir
844
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
719
847
def test_resolve_taking_other(self):
720
848
self.run_script("""
721
$ bzr resolve --take-other dir
722
$ bzr commit --strict -m 'No more conflicts nor unknown files'
849
$ brz resolve --take-other dir
851
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
726
855
class TestResolveDeletingParent(TestResolveConflicts):
732
862
$ echo 'trunk content' >dir/file
734
$ bzr commit -m 'Create trunk'
736
$ bzr rm dir/file --force
738
$ bzr commit -m 'Remove dir/file'
740
$ bzr branch . -r 1 ../branch
864
$ brz commit -m 'Create trunk' -q
865
$ brz rm -q dir/file --no-backup
866
$ brz rm -q dir --no-backup
867
$ brz commit -q -m 'Remove dir/file'
868
$ brz branch -q . -r 1 ../branch
742
870
$ echo 'branch content' >dir/file2
744
$ bzr commit -m 'Add dir/file2 in branch'
871
$ brz add -q dir/file2
872
$ brz commit -q -m 'Add dir/file2 in branch'
748
875
2>Conflict: can't delete dir because it is not empty. Not deleting.
749
876
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
753
880
def test_keep_them_all(self):
754
881
self.run_script("""
756
$ bzr commit --strict -m 'No more conflicts nor unknown files'
883
2>2 conflicts resolved, 0 remaining
884
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
759
887
def test_adopt_child(self):
760
888
self.run_script("""
761
$ bzr mv dir/file2 file2
764
$ bzr commit --strict -m 'No more conflicts nor unknown files'
889
$ brz mv -q dir/file2 file2
890
$ brz rm -q dir --no-backup
892
2>2 conflicts resolved, 0 remaining
893
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
767
896
def test_kill_them_all(self):
768
897
self.run_script("""
771
$ bzr commit --strict -m 'No more conflicts nor unknown files'
898
$ brz rm -q dir --no-backup
900
2>2 conflicts resolved, 0 remaining
901
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
774
904
def test_resolve_taking_this(self):
775
905
self.run_script("""
776
$ bzr resolve --take-this dir
777
$ bzr commit --strict -m 'No more conflicts nor unknown files'
906
$ brz resolve --take-this dir
907
2>2 conflicts resolved, 0 remaining
908
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
780
911
def test_resolve_taking_other(self):
781
912
self.run_script("""
782
$ bzr resolve --take-other dir
783
$ bzr commit --strict -m 'No more conflicts nor unknown files'
913
$ brz resolve --take-other dir
916
2>2 conflicts resolved, 0 remaining
917
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
787
921
class TestResolveParentLoop(TestParametrizedResolveConflicts):
789
_conflict_type = conflicts.ParentLoop,
923
_conflict_type = conflicts.ParentLoop
791
925
_this_args = None
792
926
_other_args = None
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'
928
# Each side dict additionally defines:
929
# - dir_id: the directory being moved
930
# - target_id: The target directory
931
# - xfail: whether the test is expected to fail if the action is
932
# involved as 'other'
933
scenarios = mirror_scenarios(
802
935
# Dirs moved into each other
803
936
(dict(_base_actions='create_dir1_dir2'),
804
937
('dir1_into_dir2',
805
938
dict(actions='move_dir1_into_dir2', check='dir1_moved',
806
dir_id='dir1-id', target_id='dir2-id', xfail=False)),
939
dir_id=b'dir1-id', target_id=b'dir2-id', xfail=False)),
807
940
('dir2_into_dir1',
808
941
dict(actions='move_dir2_into_dir1', check='dir2_moved',
809
dir_id='dir2-id', target_id='dir1-id', xfail=False))),
942
dir_id=b'dir2-id', target_id=b'dir1-id', xfail=False))),
810
943
# Subdirs moved into each other
811
944
(dict(_base_actions='create_dir1_4'),
812
945
('dir1_into_dir4',
813
946
dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
814
dir_id='dir1-id', target_id='dir4-id', xfail=True)),
947
dir_id=b'dir1-id', target_id=b'dir4-id', xfail=True)),
815
948
('dir3_into_dir2',
816
949
dict(actions='move_dir3_into_dir2', check='dir3_4_moved',
817
dir_id='dir3-id', target_id='dir2-id', xfail=True))),
819
return mirror_scenarios(base_scenarios)
950
dir_id=b'dir3-id', target_id=b'dir2-id', xfail=True))),
821
953
def do_create_dir1_dir2(self):
822
return [('add', ('dir1', 'dir1-id', 'directory', '')),
823
('add', ('dir2', 'dir2-id', 'directory', '')),]
954
return [('add', ('dir1', b'dir1-id', 'directory', '')),
955
('add', ('dir2', b'dir2-id', 'directory', '')), ]
825
957
def do_move_dir1_into_dir2(self):
826
958
return [('rename', ('dir1', 'dir2/dir1'))]
828
960
def check_dir1_moved(self):
829
self.failIfExists('branch/dir1')
830
self.failUnlessExists('branch/dir2/dir1')
961
self.assertPathDoesNotExist('branch/dir1')
962
self.assertPathExists('branch/dir2/dir1')
832
964
def do_move_dir2_into_dir1(self):
833
965
return [('rename', ('dir2', 'dir1/dir2'))]
835
967
def check_dir2_moved(self):
836
self.failIfExists('branch/dir2')
837
self.failUnlessExists('branch/dir1/dir2')
968
self.assertPathDoesNotExist('branch/dir2')
969
self.assertPathExists('branch/dir1/dir2')
839
971
def do_create_dir1_4(self):
840
return [('add', ('dir1', 'dir1-id', 'directory', '')),
841
('add', ('dir1/dir2', 'dir2-id', 'directory', '')),
842
('add', ('dir3', 'dir3-id', 'directory', '')),
843
('add', ('dir3/dir4', 'dir4-id', 'directory', '')),]
972
return [('add', ('dir1', b'dir1-id', 'directory', '')),
973
('add', ('dir1/dir2', b'dir2-id', 'directory', '')),
974
('add', ('dir3', b'dir3-id', 'directory', '')),
975
('add', ('dir3/dir4', b'dir4-id', 'directory', '')), ]
845
977
def do_move_dir1_into_dir4(self):
846
978
return [('rename', ('dir1', 'dir3/dir4/dir1'))]
848
980
def check_dir1_2_moved(self):
849
self.failIfExists('branch/dir1')
850
self.failUnlessExists('branch/dir3/dir4/dir1')
851
self.failUnlessExists('branch/dir3/dir4/dir1/dir2')
981
self.assertPathDoesNotExist('branch/dir1')
982
self.assertPathExists('branch/dir3/dir4/dir1')
983
self.assertPathExists('branch/dir3/dir4/dir1/dir2')
853
985
def do_move_dir3_into_dir2(self):
854
986
return [('rename', ('dir3', 'dir1/dir2/dir3'))]
856
988
def check_dir3_4_moved(self):
857
self.failIfExists('branch/dir3')
858
self.failUnlessExists('branch/dir1/dir2/dir3')
859
self.failUnlessExists('branch/dir1/dir2/dir3/dir4')
989
self.assertPathDoesNotExist('branch/dir3')
990
self.assertPathExists('branch/dir1/dir2/dir3')
991
self.assertPathExists('branch/dir1/dir2/dir3/dir4')
861
993
def _get_resolve_path_arg(self, wt, action):
862
994
# ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
941
1077
# This is nearly like TestResolveNonDirectoryParent but with branch and
942
1078
# trunk switched. As such it should certainly produce the same
1080
self.assertRaises(errors.MalformedTransform,
1081
self.run_script, """
948
$ bzr commit -m 'Create trunk'
1087
$ brz commit -m 'Create trunk' -q
950
1089
$ echo "Boo!" >foo
951
$ bzr commit -m 'foo is now a file'
953
$ bzr branch . -r 1 ../branch
1090
$ brz commit -m 'foo is now a file' -q
1091
$ brz branch -q . -r 1 ../branch -q
955
1093
$ echo "Boing" >foo/bar
957
$ bzr commit -m 'Add foo/bar'
960
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1094
$ brz add -q foo/bar -q
1095
$ brz commit -m 'Add foo/bar' -q
1096
$ brz merge ../trunk
1097
2>brz: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1101
class TestNoFinalPath(script.TestCaseWithTransportAndScript):
1103
def test_bug_805809(self):
1106
Created a standalone tree (format: 2a)
1111
$ brz commit -m 'create file on trunk'
1112
2>Committing to: .../trunk/
1114
2>Committed revision 1.
1115
# Create a debian branch based on trunk
1117
$ brz branch trunk -r 1 debian
1118
2>Branched 1 revision.
1125
$ brz commit -m 'rename file to dir/file for debian'
1126
2>Committing to: .../debian/
1128
2>renamed file => dir/file
1129
2>Committed revision 2.
1130
# Create an experimental branch with a new root-id
1132
$ brz init experimental
1133
Created a standalone tree (format: 2a)
1135
# Work around merging into empty branch not being supported
1136
# (http://pad.lv/308562)
1137
$ echo something >not-empty
1140
$ brz commit -m 'Add some content in experimental'
1141
2>Committing to: .../experimental/
1143
2>Committed revision 1.
1144
# merge debian even without a common ancestor
1145
$ brz merge ../debian -r0..2
1148
2>All changes applied successfully.
1149
$ brz commit -m 'merging debian into experimental'
1150
2>Committing to: .../experimental/
1153
2>Committed revision 2.
1154
# Create an ubuntu branch with yet another root-id
1157
Created a standalone tree (format: 2a)
1159
# Work around merging into empty branch not being supported
1160
# (http://pad.lv/308562)
1161
$ echo something >not-empty-ubuntu
1163
adding not-empty-ubuntu
1164
$ brz commit -m 'Add some content in experimental'
1165
2>Committing to: .../ubuntu/
1166
2>added not-empty-ubuntu
1167
2>Committed revision 1.
1169
$ brz merge ../debian -r0..2
1172
2>All changes applied successfully.
1173
$ brz commit -m 'merging debian'
1174
2>Committing to: .../ubuntu/
1177
2>Committed revision 2.
1178
# Now try to merge experimental
1179
$ brz merge ../experimental
1181
2>Path conflict: dir / dir
1182
2>1 conflicts encountered.