56
43
# u'\xe5' == a with circle
57
44
# '\xc3\xae' == u'\xee' == i with hat
58
45
# So these are u'path' and 'id' only with a circle and a hat. (shappo?)
59
example_conflicts = conflicts.ConflictList(
60
[conflicts.MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
61
conflicts.ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
62
conflicts.TextConflict(u'p\xe5tha'),
63
conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
64
conflicts.DuplicateID('Unversioned existing file',
65
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'),
47
bzr_conflicts.MissingParent('Not deleting', u'p\xe5thg', b'\xc3\xaedg'),
48
bzr_conflicts.ContentsConflict(u'p\xe5tha', None, b'\xc3\xaeda'),
49
bzr_conflicts.TextConflict(u'p\xe5tha'),
50
bzr_conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', b'\xc3\xaedb'),
51
bzr_conflicts.DuplicateID('Unversioned existing file',
52
u'p\xe5thc', u'p\xe5thc2',
53
b'\xc3\xaedc', b'\xc3\xaedc'),
54
bzr_conflicts.DuplicateEntry('Moved existing file to',
55
u'p\xe5thdd.moved', u'p\xe5thd',
57
bzr_conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
58
None, b'\xc3\xaed2e'),
59
bzr_conflicts.UnversionedParent('Versioned directory',
60
u'p\xe5thf', b'\xc3\xaedf'),
61
bzr_conflicts.NonDirectoryParent('Created directory',
62
u'p\xe5thg', b'\xc3\xaedg'),
66
def vary_by_conflicts():
67
for conflict in example_conflicts:
68
yield (conflict.__class__.__name__, {"conflict": conflict})
79
71
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
73
def test_resolve_conflict_dir(self):
109
74
tree = self.make_branch_and_tree('.')
110
self.build_tree_contents([('hello', 'hello world4'),
111
('hello.THIS', 'hello world2'),
112
('hello.BASE', 'hello world1'),
75
self.build_tree_contents([('hello', b'hello world4'),
76
('hello.THIS', b'hello world2'),
77
('hello.BASE', b'hello world1'),
114
79
os.mkdir('hello.OTHER')
115
tree.add('hello', 'q')
116
l = conflicts.ConflictList([conflicts.TextConflict('hello')])
80
tree.add('hello', b'q')
81
l = conflicts.ConflictList([bzr_conflicts.TextConflict('hello')])
117
82
l.remove_files(tree)
119
84
def test_select_conflicts(self):
125
90
(not_selected, selected),
126
91
tree_conflicts.select_conflicts(tree, paths, **kwargs))
128
foo = conflicts.ContentsConflict('foo')
129
bar = conflicts.ContentsConflict('bar')
93
foo = bzr_conflicts.ContentsConflict('foo')
94
bar = bzr_conflicts.ContentsConflict('bar')
130
95
tree_conflicts = clist([foo, bar])
132
97
check_select(clist([bar]), clist([foo]), ['foo'])
133
98
check_select(clist(), tree_conflicts,
134
99
[''], ignore_misses=True, recurse=True)
136
foobaz = conflicts.ContentsConflict('foo/baz')
101
foobaz = bzr_conflicts.ContentsConflict('foo/baz')
137
102
tree_conflicts = clist([foobaz, bar])
139
104
check_select(clist([bar]), clist([foobaz]),
140
105
['foo'], ignore_misses=True, recurse=True)
142
qux = conflicts.PathConflict('qux', 'foo/baz')
107
qux = bzr_conflicts.PathConflict('qux', 'foo/baz')
143
108
tree_conflicts = clist([qux])
145
check_select(clist(), tree_conflicts,
110
check_select(tree_conflicts, clist(),
146
111
['foo'], ignore_misses=True, recurse=True)
147
check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
112
check_select(tree_conflicts, clist(), ['foo'], ignore_misses=True)
149
114
def test_resolve_conflicts_recursive(self):
150
115
tree = self.make_branch_and_tree('.')
151
116
self.build_tree(['dir/', 'dir/hello'])
152
117
tree.add(['dir', 'dir/hello'])
154
dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
119
dirhello = [bzr_conflicts.TextConflict('dir/hello')]
155
120
tree.set_conflicts(dirhello)
157
122
conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
161
126
self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
164
class TestConflictStanzas(tests.TestCase):
166
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)
186
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')
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__)
141
class TestConflictList(tests.TestCase):
143
def test_stanzas_roundtrip(self):
144
stanzas_iter = bzr_conflicts.ConflictList(example_conflicts).to_stanzas()
145
processed = bzr_conflicts.ConflictList.from_stanzas(stanzas_iter)
146
self.assertEqual(example_conflicts, processed)
148
def test_stringification(self):
150
bzr_conflicts.ConflictList(example_conflicts).to_strings(),
152
self.assertEqual(text, text_type(o))
198
155
# 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
249
"""The scenario list for the conflict type defined by the class.
251
Each scenario is of the form:
252
(common, (left_name, left_dict), (right_name, right_dict))
256
* left_name and right_name are the scenario names that will be combined
258
* left_dict and right_dict are the attributes specific to each half of
259
the scenario. They should include at least 'actions' and 'check' and
260
will be available as '_this' and '_other' test instance attributes.
262
Daughters classes are free to add their specific attributes as they see
263
fit in any of the three dicts.
265
This is a class method so that load_tests can find it.
267
'_base_actions' in the common dict, 'actions' and 'check' in the left
268
and right dicts use names that map to methods in the test classes. Some
269
prefixes are added to these names to get the correspong methods (see
270
_get_actions() and _get_check()). The motivation here is to avoid
271
collisions in the class namespace.
326
275
super(TestParametrizedResolveConflicts, self).setUp()
328
277
builder.start_series()
330
279
# Create an empty trunk
331
builder.build_snapshot('start', None, [
332
('add', ('', 'root-id', 'directory', ''))])
280
builder.build_snapshot(None, [
281
('add', (u'', b'root-id', 'directory', ''))],
282
revision_id=b'start')
333
283
# Add a minimal base content
334
284
base_actions = self._get_actions(self._base_actions)()
335
builder.build_snapshot('base', ['start'], base_actions)
285
builder.build_snapshot([b'start'], base_actions, revision_id=b'base')
336
286
# Modify the base content in branch
337
287
actions_other = self._get_actions(self._other['actions'])()
338
builder.build_snapshot('other', ['base'], actions_other)
288
builder.build_snapshot([b'base'], actions_other, revision_id=b'other')
339
289
# Modify the base content in trunk
340
290
actions_this = self._get_actions(self._this['actions'])()
341
builder.build_snapshot('this', ['base'], actions_this)
291
builder.build_snapshot([b'base'], actions_this, revision_id=b'this')
342
292
# builder.get_branch() tip is now 'this'
344
294
builder.finish_series()
341
class TestResolveTextConflicts(TestParametrizedResolveConflicts):
343
_conflict_type = bzr_conflicts.TextConflict
345
# Set by the scenarios
346
# path and file-id for the file involved in the conflict
350
scenarios = mirror_scenarios(
352
# File modified on both sides
353
(dict(_base_actions='create_file',
354
_path='file', _file_id=b'file-id'),
356
dict(actions='modify_file_A', check='file_has_content_A')),
358
dict(actions='modify_file_B', check='file_has_content_B')),),
359
# File modified on both sides in dir
360
(dict(_base_actions='create_file_in_dir',
361
_path='dir/file', _file_id=b'file-id'),
362
('filed_modified_A_in_dir',
363
dict(actions='modify_file_A_in_dir',
364
check='file_in_dir_has_content_A')),
366
dict(actions='modify_file_B_in_dir',
367
check='file_in_dir_has_content_B')),),
370
def do_create_file(self, path='file'):
371
return [('add', (path, b'file-id', 'file', b'trunk content\n'))]
373
def do_modify_file_A(self):
374
return [('modify', ('file', b'trunk content\nfeature A\n'))]
376
def do_modify_file_B(self):
377
return [('modify', ('file', b'trunk content\nfeature B\n'))]
379
def do_modify_file_A_in_dir(self):
380
return [('modify', ('dir/file', b'trunk content\nfeature A\n'))]
382
def do_modify_file_B_in_dir(self):
383
return [('modify', ('dir/file', b'trunk content\nfeature B\n'))]
385
def check_file_has_content_A(self, path='file'):
386
self.assertFileEqual(b'trunk content\nfeature A\n',
387
osutils.pathjoin('branch', path))
389
def check_file_has_content_B(self, path='file'):
390
self.assertFileEqual(b'trunk content\nfeature B\n',
391
osutils.pathjoin('branch', path))
393
def do_create_file_in_dir(self):
394
return [('add', ('dir', b'dir-id', 'directory', '')),
395
] + self.do_create_file('dir/file')
397
def check_file_in_dir_has_content_A(self):
398
self.check_file_has_content_A('dir/file')
400
def check_file_in_dir_has_content_B(self):
401
self.check_file_has_content_B('dir/file')
403
def _get_resolve_path_arg(self, wt, action):
406
def assertTextConflict(self, wt, c):
407
self.assertEqual(self._file_id, c.file_id)
408
self.assertEqual(self._path, c.path)
409
_assert_conflict = assertTextConflict
391
412
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
393
_conflict_type = conflicts.ContentsConflict,
414
_conflict_type = bzr_conflicts.ContentsConflict
395
# Set by load_tests from scenarios()
416
# Set by the scenarios
396
417
# path and file-id for the file involved in the conflict
421
scenarios = mirror_scenarios(
403
423
# File modified/deleted
404
424
(dict(_base_actions='create_file',
405
_path='file', _file_id='file-id'),
425
_path='file', _file_id=b'file-id'),
406
426
('file_modified',
407
427
dict(actions='modify_file', check='file_has_more_content')),
409
429
dict(actions='delete_file', check='file_doesnt_exist')),),
411
return mirror_scenarios(base_scenarios)
430
# File renamed-modified/deleted
431
(dict(_base_actions='create_file',
432
_path='new-file', _file_id=b'file-id'),
433
('file_renamed_and_modified',
434
dict(actions='modify_and_rename_file',
435
check='file_renamed_and_more_content')),
437
dict(actions='delete_file', check='file_doesnt_exist')),),
438
# File modified/deleted in dir
439
(dict(_base_actions='create_file_in_dir',
440
_path='dir/file', _file_id=b'file-id'),
441
('file_modified_in_dir',
442
dict(actions='modify_file_in_dir',
443
check='file_in_dir_has_more_content')),
444
('file_deleted_in_dir',
445
dict(actions='delete_file_in_dir',
446
check='file_in_dir_doesnt_exist')),),
413
449
def do_create_file(self):
414
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
450
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
416
452
def do_modify_file(self):
417
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
453
return [('modify', ('file', b'trunk content\nmore content\n'))]
455
def do_modify_and_rename_file(self):
456
return [('modify', ('new-file', b'trunk content\nmore content\n')),
457
('rename', ('file', 'new-file'))]
419
459
def check_file_has_more_content(self):
420
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
460
self.assertFileEqual(b'trunk content\nmore content\n', 'branch/file')
462
def check_file_renamed_and_more_content(self):
463
self.assertFileEqual(
464
b'trunk content\nmore content\n', 'branch/new-file')
422
466
def do_delete_file(self):
423
return [('unversion', 'file-id')]
467
return [('unversion', 'file')]
469
def do_delete_file_in_dir(self):
470
return [('unversion', 'dir/file')]
425
472
def check_file_doesnt_exist(self):
426
self.failIfExists('branch/file')
473
self.assertPathDoesNotExist('branch/file')
475
def do_create_file_in_dir(self):
476
return [('add', ('dir', b'dir-id', 'directory', '')),
477
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
479
def do_modify_file_in_dir(self):
480
return [('modify', ('dir/file', b'trunk content\nmore content\n'))]
482
def check_file_in_dir_has_more_content(self):
483
self.assertFileEqual(
484
b'trunk content\nmore content\n', 'branch/dir/file')
486
def check_file_in_dir_doesnt_exist(self):
487
self.assertPathDoesNotExist('branch/dir/file')
428
489
def _get_resolve_path_arg(self, wt, action):
429
490
return self._path
437
498
class TestResolvePathConflict(TestParametrizedResolveConflicts):
439
_conflict_type = conflicts.PathConflict,
500
_conflict_type = bzr_conflicts.PathConflict
441
502
def do_nothing(self):
446
# Each side dict additionally defines:
447
# - path path involved (can be '<deleted>')
505
# Each side dict additionally defines:
506
# - path path involved (can be '<deleted>')
508
scenarios = mirror_scenarios(
450
510
# File renamed/deleted
451
511
(dict(_base_actions='create_file'),
453
513
dict(actions='rename_file', check='file_renamed',
454
path='new-file', file_id='file-id')),
514
path='new-file', file_id=b'file-id')),
456
516
dict(actions='delete_file', check='file_doesnt_exist',
457
517
# PathConflicts deletion handling requires a special
458
518
# hard-coded value
459
path='<deleted>', file_id='file-id')),),
519
path='<deleted>', file_id=b'file-id')),),
520
# File renamed/deleted in dir
521
(dict(_base_actions='create_file_in_dir'),
522
('file_renamed_in_dir',
523
dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
524
path='dir/new-file', file_id=b'file-id')),
526
dict(actions='delete_file_in_dir', check='file_in_dir_doesnt_exist',
527
# PathConflicts deletion handling requires a special
529
path='<deleted>', file_id=b'file-id')),),
460
530
# File renamed/renamed differently
461
531
(dict(_base_actions='create_file'),
463
533
dict(actions='rename_file', check='file_renamed',
464
path='new-file', file_id='file-id')),
534
path='new-file', file_id=b'file-id')),
465
535
('file_renamed2',
466
536
dict(actions='rename_file2', check='file_renamed2',
467
path='new-file2', file_id='file-id')),),
537
path='new-file2', file_id=b'file-id')),),
468
538
# Dir renamed/deleted
469
539
(dict(_base_actions='create_dir'),
471
541
dict(actions='rename_dir', check='dir_renamed',
472
path='new-dir', file_id='dir-id')),
542
path='new-dir', file_id=b'dir-id')),
474
544
dict(actions='delete_dir', check='dir_doesnt_exist',
475
545
# PathConflicts deletion handling requires a special
476
546
# hard-coded value
477
path='<deleted>', file_id='dir-id')),),
547
path='<deleted>', file_id=b'dir-id')),),
478
548
# Dir renamed/renamed differently
479
549
(dict(_base_actions='create_dir'),
481
551
dict(actions='rename_dir', check='dir_renamed',
482
path='new-dir', file_id='dir-id')),
552
path='new-dir', file_id=b'dir-id')),
484
554
dict(actions='rename_dir2', check='dir_renamed2',
485
path='new-dir2', file_id='dir-id')),),
487
return mirror_scenarios(base_scenarios)
555
path='new-dir2', file_id=b'dir-id')),),
489
558
def do_create_file(self):
490
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
559
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
492
561
def do_create_dir(self):
493
return [('add', ('dir', 'dir-id', 'directory', ''))]
562
return [('add', ('dir', b'dir-id', 'directory', ''))]
495
564
def do_rename_file(self):
496
565
return [('rename', ('file', 'new-file'))]
498
567
def check_file_renamed(self):
499
self.failIfExists('branch/file')
500
self.failUnlessExists('branch/new-file')
568
self.assertPathDoesNotExist('branch/file')
569
self.assertPathExists('branch/new-file')
502
571
def do_rename_file2(self):
503
572
return [('rename', ('file', 'new-file2'))]
505
574
def check_file_renamed2(self):
506
self.failIfExists('branch/file')
507
self.failUnlessExists('branch/new-file2')
575
self.assertPathDoesNotExist('branch/file')
576
self.assertPathExists('branch/new-file2')
509
578
def do_rename_dir(self):
510
579
return [('rename', ('dir', 'new-dir'))]
512
581
def check_dir_renamed(self):
513
self.failIfExists('branch/dir')
514
self.failUnlessExists('branch/new-dir')
582
self.assertPathDoesNotExist('branch/dir')
583
self.assertPathExists('branch/new-dir')
516
585
def do_rename_dir2(self):
517
586
return [('rename', ('dir', 'new-dir2'))]
519
588
def check_dir_renamed2(self):
520
self.failIfExists('branch/dir')
521
self.failUnlessExists('branch/new-dir2')
589
self.assertPathDoesNotExist('branch/dir')
590
self.assertPathExists('branch/new-dir2')
523
592
def do_delete_file(self):
524
return [('unversion', 'file-id')]
593
return [('unversion', 'file')]
595
def do_delete_file_in_dir(self):
596
return [('unversion', 'dir/file')]
526
598
def check_file_doesnt_exist(self):
527
self.failIfExists('branch/file')
599
self.assertPathDoesNotExist('branch/file')
529
601
def do_delete_dir(self):
530
return [('unversion', 'dir-id')]
602
return [('unversion', 'dir')]
532
604
def check_dir_doesnt_exist(self):
533
self.failIfExists('branch/dir')
605
self.assertPathDoesNotExist('branch/dir')
607
def do_create_file_in_dir(self):
608
return [('add', ('dir', b'dir-id', 'directory', '')),
609
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
611
def do_rename_file_in_dir(self):
612
return [('rename', ('dir/file', 'dir/new-file'))]
614
def check_file_in_dir_renamed(self):
615
self.assertPathDoesNotExist('branch/dir/file')
616
self.assertPathExists('branch/dir/new-file')
618
def check_file_in_dir_doesnt_exist(self):
619
self.assertPathDoesNotExist('branch/dir/file')
535
621
def _get_resolve_path_arg(self, wt, action):
536
622
tpath = self._this['path']
561
647
# We create a conflict object as it was created before the fix and
562
648
# inject it into the working tree, the test will exercise the
563
649
# compatibility code.
564
old_c = conflicts.PathConflict('<deleted>', self._item_path,
650
old_c = bzr_conflicts.PathConflict('<deleted>', self._item_path,
566
wt.set_conflicts(conflicts.ConflictList([old_c]))
652
wt.set_conflicts([old_c])
569
655
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
571
_conflict_type = conflicts.DuplicateEntry,
657
_conflict_type = bzr_conflicts.DuplicateEntry
575
# Each side dict additionally defines:
659
scenarios = mirror_scenarios(
579
661
# File created with different file-ids
580
662
(dict(_base_actions='nothing'),
581
663
('filea_created',
582
664
dict(actions='create_file_a', check='file_content_a',
583
path='file', file_id='file-a-id')),
665
path='file', file_id=b'file-a-id')),
584
666
('fileb_created',
585
667
dict(actions='create_file_b', check='file_content_b',
586
path='file', file_id='file-b-id')),),
588
return mirror_scenarios(base_scenarios)
668
path='file', file_id=b'file-b-id')),),
669
# File created with different file-ids but deleted on one side
670
(dict(_base_actions='create_file_a'),
672
dict(actions='replace_file_a_by_b', check='file_content_b',
673
path='file', file_id=b'file-b-id')),
675
dict(actions='modify_file_a', check='file_new_content',
676
path='file', file_id=b'file-a-id')),),
590
679
def do_nothing(self):
593
682
def do_create_file_a(self):
594
return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
683
return [('add', ('file', b'file-a-id', 'file', b'file a content\n'))]
596
685
def check_file_content_a(self):
597
self.assertFileEqual('file a content\n', 'branch/file')
686
self.assertFileEqual(b'file a content\n', 'branch/file')
599
688
def do_create_file_b(self):
600
return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
689
return [('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
602
691
def check_file_content_b(self):
603
self.assertFileEqual('file b content\n', 'branch/file')
692
self.assertFileEqual(b'file b content\n', 'branch/file')
694
def do_replace_file_a_by_b(self):
695
return [('unversion', 'file'),
696
('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
698
def do_modify_file_a(self):
699
return [('modify', ('file', b'new content\n'))]
701
def check_file_new_content(self):
702
self.assertFileEqual(b'new content\n', 'branch/file')
605
704
def _get_resolve_path_arg(self, wt, action):
606
705
return self._this['path']
692
789
def test_keep_them_all(self):
693
790
self.run_script("""
695
$ bzr commit --strict -m 'No more conflicts nor unknown files'
792
2>2 conflicts resolved, 0 remaining
793
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
698
796
def test_adopt_child(self):
699
797
self.run_script("""
700
$ bzr mv dir/file2 file2
703
$ bzr commit --strict -m 'No more conflicts nor unknown files'
798
$ brz mv -q dir/file2 file2
799
$ brz rm -q dir --no-backup
801
2>2 conflicts resolved, 0 remaining
802
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
706
805
def test_kill_them_all(self):
707
806
self.run_script("""
710
$ bzr commit --strict -m 'No more conflicts nor unknown files'
807
$ brz rm -q dir --no-backup
809
2>2 conflicts resolved, 0 remaining
810
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
713
813
def test_resolve_taking_this(self):
714
814
self.run_script("""
715
$ bzr resolve --take-this dir
716
$ bzr commit --strict -m 'No more conflicts nor unknown files'
815
$ brz resolve --take-this dir
817
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
719
820
def test_resolve_taking_other(self):
720
821
self.run_script("""
721
$ bzr resolve --take-other dir
722
$ bzr commit --strict -m 'No more conflicts nor unknown files'
822
$ brz resolve --take-other dir
824
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
726
828
class TestResolveDeletingParent(TestResolveConflicts):
732
835
$ 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
837
$ brz commit -m 'Create trunk' -q
838
$ brz rm -q dir/file --no-backup
839
$ brz rm -q dir --no-backup
840
$ brz commit -q -m 'Remove dir/file'
841
$ brz branch -q . -r 1 ../branch
742
843
$ echo 'branch content' >dir/file2
744
$ bzr commit -m 'Add dir/file2 in branch'
844
$ brz add -q dir/file2
845
$ brz commit -q -m 'Add dir/file2 in branch'
748
848
2>Conflict: can't delete dir because it is not empty. Not deleting.
749
849
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
753
853
def test_keep_them_all(self):
754
854
self.run_script("""
756
$ bzr commit --strict -m 'No more conflicts nor unknown files'
856
2>2 conflicts resolved, 0 remaining
857
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
759
860
def test_adopt_child(self):
760
861
self.run_script("""
761
$ bzr mv dir/file2 file2
764
$ bzr commit --strict -m 'No more conflicts nor unknown files'
862
$ brz mv -q dir/file2 file2
863
$ brz rm -q dir --no-backup
865
2>2 conflicts resolved, 0 remaining
866
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
767
869
def test_kill_them_all(self):
768
870
self.run_script("""
771
$ bzr commit --strict -m 'No more conflicts nor unknown files'
871
$ brz rm -q dir --no-backup
873
2>2 conflicts resolved, 0 remaining
874
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
774
877
def test_resolve_taking_this(self):
775
878
self.run_script("""
776
$ bzr resolve --take-this dir
777
$ bzr commit --strict -m 'No more conflicts nor unknown files'
879
$ brz resolve --take-this dir
880
2>2 conflicts resolved, 0 remaining
881
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
780
884
def test_resolve_taking_other(self):
781
885
self.run_script("""
782
$ bzr resolve --take-other dir
783
$ bzr commit --strict -m 'No more conflicts nor unknown files'
886
$ brz resolve --take-other dir
889
2>2 conflicts resolved, 0 remaining
890
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
787
894
class TestResolveParentLoop(TestParametrizedResolveConflicts):
789
_conflict_type = conflicts.ParentLoop,
896
_conflict_type = bzr_conflicts.ParentLoop
791
898
_this_args = None
792
899
_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'
901
# Each side dict additionally defines:
902
# - dir_id: the directory being moved
903
# - target_id: The target directory
904
# - xfail: whether the test is expected to fail if the action is
905
# involved as 'other'
906
scenarios = mirror_scenarios(
802
908
# Dirs moved into each other
803
909
(dict(_base_actions='create_dir1_dir2'),
804
910
('dir1_into_dir2',
805
911
dict(actions='move_dir1_into_dir2', check='dir1_moved',
806
dir_id='dir1-id', target_id='dir2-id', xfail=False)),
912
dir_id=b'dir1-id', target_id=b'dir2-id', xfail=False)),
807
913
('dir2_into_dir1',
808
914
dict(actions='move_dir2_into_dir1', check='dir2_moved',
809
dir_id='dir2-id', target_id='dir1-id', xfail=False))),
915
dir_id=b'dir2-id', target_id=b'dir1-id', xfail=False))),
810
916
# Subdirs moved into each other
811
917
(dict(_base_actions='create_dir1_4'),
812
918
('dir1_into_dir4',
813
919
dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
814
dir_id='dir1-id', target_id='dir4-id', xfail=True)),
920
dir_id=b'dir1-id', target_id=b'dir4-id', xfail=True)),
815
921
('dir3_into_dir2',
816
922
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)
923
dir_id=b'dir3-id', target_id=b'dir2-id', xfail=True))),
821
926
def do_create_dir1_dir2(self):
822
return [('add', ('dir1', 'dir1-id', 'directory', '')),
823
('add', ('dir2', 'dir2-id', 'directory', '')),]
927
return [('add', ('dir1', b'dir1-id', 'directory', '')),
928
('add', ('dir2', b'dir2-id', 'directory', '')), ]
825
930
def do_move_dir1_into_dir2(self):
826
931
return [('rename', ('dir1', 'dir2/dir1'))]
828
933
def check_dir1_moved(self):
829
self.failIfExists('branch/dir1')
830
self.failUnlessExists('branch/dir2/dir1')
934
self.assertPathDoesNotExist('branch/dir1')
935
self.assertPathExists('branch/dir2/dir1')
832
937
def do_move_dir2_into_dir1(self):
833
938
return [('rename', ('dir2', 'dir1/dir2'))]
835
940
def check_dir2_moved(self):
836
self.failIfExists('branch/dir2')
837
self.failUnlessExists('branch/dir1/dir2')
941
self.assertPathDoesNotExist('branch/dir2')
942
self.assertPathExists('branch/dir1/dir2')
839
944
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', '')),]
945
return [('add', ('dir1', b'dir1-id', 'directory', '')),
946
('add', ('dir1/dir2', b'dir2-id', 'directory', '')),
947
('add', ('dir3', b'dir3-id', 'directory', '')),
948
('add', ('dir3/dir4', b'dir4-id', 'directory', '')), ]
845
950
def do_move_dir1_into_dir4(self):
846
951
return [('rename', ('dir1', 'dir3/dir4/dir1'))]
848
953
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')
954
self.assertPathDoesNotExist('branch/dir1')
955
self.assertPathExists('branch/dir3/dir4/dir1')
956
self.assertPathExists('branch/dir3/dir4/dir1/dir2')
853
958
def do_move_dir3_into_dir2(self):
854
959
return [('rename', ('dir3', 'dir1/dir2/dir3'))]
856
961
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')
962
self.assertPathDoesNotExist('branch/dir3')
963
self.assertPathExists('branch/dir1/dir2/dir3')
964
self.assertPathExists('branch/dir1/dir2/dir3/dir4')
861
966
def _get_resolve_path_arg(self, wt, action):
862
967
# ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
941
1050
# This is nearly like TestResolveNonDirectoryParent but with branch and
942
1051
# trunk switched. As such it should certainly produce the same
1053
self.assertRaises(transform.MalformedTransform,
1054
self.run_script, """
948
$ bzr commit -m 'Create trunk'
1060
$ brz commit -m 'Create trunk' -q
950
1062
$ echo "Boo!" >foo
951
$ bzr commit -m 'foo is now a file'
953
$ bzr branch . -r 1 ../branch
1063
$ brz commit -m 'foo is now a file' -q
1064
$ brz branch -q . -r 1 ../branch -q
955
1066
$ echo "Boing" >foo/bar
957
$ bzr commit -m 'Add foo/bar'
960
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1067
$ brz add -q foo/bar -q
1068
$ brz commit -m 'Add foo/bar' -q
1069
$ brz merge ../trunk
1070
2>brz: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1074
class TestNoFinalPath(script.TestCaseWithTransportAndScript):
1076
def test_bug_805809(self):
1079
Created a standalone tree (format: 2a)
1084
$ brz commit -m 'create file on trunk'
1085
2>Committing to: .../trunk/
1087
2>Committed revision 1.
1088
# Create a debian branch based on trunk
1090
$ brz branch trunk -r 1 debian
1091
2>Branched 1 revision.
1098
$ brz commit -m 'rename file to dir/file for debian'
1099
2>Committing to: .../debian/
1101
2>renamed file => dir/file
1102
2>Committed revision 2.
1103
# Create an experimental branch with a new root-id
1105
$ brz init experimental
1106
Created a standalone tree (format: 2a)
1108
# Work around merging into empty branch not being supported
1109
# (http://pad.lv/308562)
1110
$ echo something >not-empty
1113
$ brz commit -m 'Add some content in experimental'
1114
2>Committing to: .../experimental/
1116
2>Committed revision 1.
1117
# merge debian even without a common ancestor
1118
$ brz merge ../debian -r0..2
1121
2>All changes applied successfully.
1122
$ brz commit -m 'merging debian into experimental'
1123
2>Committing to: .../experimental/
1126
2>Committed revision 2.
1127
# Create an ubuntu branch with yet another root-id
1130
Created a standalone tree (format: 2a)
1132
# Work around merging into empty branch not being supported
1133
# (http://pad.lv/308562)
1134
$ echo something >not-empty-ubuntu
1136
adding not-empty-ubuntu
1137
$ brz commit -m 'Add some content in experimental'
1138
2>Committing to: .../ubuntu/
1139
2>added not-empty-ubuntu
1140
2>Committed revision 1.
1142
$ brz merge ../debian -r0..2
1145
2>All changes applied successfully.
1146
$ brz commit -m 'merging debian'
1147
2>Committing to: .../ubuntu/
1150
2>Committed revision 2.
1151
# Now try to merge experimental
1152
$ brz merge ../experimental
1154
2>Path conflict: dir / dir
1155
2>1 conflicts encountered.