56
42
# u'\xe5' == a with circle
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
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'),
46
bzr_conflicts.MissingParent('Not deleting', u'p\xe5thg', b'\xc3\xaedg'),
47
bzr_conflicts.ContentsConflict(u'p\xe5tha', None, b'\xc3\xaeda'),
48
bzr_conflicts.TextConflict(u'p\xe5tha'),
49
bzr_conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', b'\xc3\xaedb'),
50
bzr_conflicts.DuplicateID('Unversioned existing file',
51
u'p\xe5thc', u'p\xe5thc2',
52
b'\xc3\xaedc', b'\xc3\xaedc'),
53
bzr_conflicts.DuplicateEntry('Moved existing file to',
54
u'p\xe5thdd.moved', u'p\xe5thd',
56
bzr_conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
57
None, b'\xc3\xaed2e'),
58
bzr_conflicts.UnversionedParent('Versioned directory',
59
u'p\xe5thf', b'\xc3\xaedf'),
60
bzr_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')
116
l = conflicts.ConflictList([conflicts.TextConflict('hello')])
79
tree.add('hello', b'q')
80
l = conflicts.ConflictList([bzr_conflicts.TextConflict('hello')])
117
81
l.remove_files(tree)
119
83
def test_select_conflicts(self):
125
89
(not_selected, selected),
126
90
tree_conflicts.select_conflicts(tree, paths, **kwargs))
128
foo = conflicts.ContentsConflict('foo')
129
bar = conflicts.ContentsConflict('bar')
92
foo = bzr_conflicts.ContentsConflict('foo')
93
bar = bzr_conflicts.ContentsConflict('bar')
130
94
tree_conflicts = clist([foo, bar])
132
96
check_select(clist([bar]), clist([foo]), ['foo'])
133
97
check_select(clist(), tree_conflicts,
134
98
[''], ignore_misses=True, recurse=True)
136
foobaz = conflicts.ContentsConflict('foo/baz')
100
foobaz = bzr_conflicts.ContentsConflict('foo/baz')
137
101
tree_conflicts = clist([foobaz, bar])
139
103
check_select(clist([bar]), clist([foobaz]),
140
104
['foo'], ignore_misses=True, recurse=True)
142
qux = conflicts.PathConflict('qux', 'foo/baz')
106
qux = bzr_conflicts.PathConflict('qux', 'foo/baz')
143
107
tree_conflicts = clist([qux])
145
check_select(clist(), tree_conflicts,
109
check_select(tree_conflicts, clist(),
146
110
['foo'], ignore_misses=True, recurse=True)
147
check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
111
check_select(tree_conflicts, clist(), ['foo'], ignore_misses=True)
149
113
def test_resolve_conflicts_recursive(self):
150
114
tree = self.make_branch_and_tree('.')
151
115
self.build_tree(['dir/', 'dir/hello'])
152
116
tree.add(['dir', 'dir/hello'])
154
dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
118
dirhello = [bzr_conflicts.TextConflict('dir/hello')]
155
119
tree.set_conflicts(dirhello)
157
121
conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
161
125
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')
128
class TestPerConflict(tests.TestCase):
130
scenarios = scenarios.multiply_scenarios(vary_by_conflicts())
132
def test_stringification(self):
133
text = str(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__)
140
class TestConflictList(tests.TestCase):
142
def test_stanzas_roundtrip(self):
143
stanzas_iter = bzr_conflicts.ConflictList(example_conflicts).to_stanzas()
144
processed = bzr_conflicts.ConflictList.from_stanzas(stanzas_iter)
145
self.assertEqual(example_conflicts, processed)
147
def test_stringification(self):
149
bzr_conflicts.ConflictList(example_conflicts).to_strings(),
151
self.assertEqual(text, str(o))
198
154
# 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
248
"""The scenario list for the conflict type defined by the class.
250
Each scenario is of the form:
251
(common, (left_name, left_dict), (right_name, right_dict))
255
* left_name and right_name are the scenario names that will be combined
257
* left_dict and right_dict are the attributes specific to each half of
258
the scenario. They should include at least 'actions' and 'check' and
259
will be available as '_this' and '_other' test instance attributes.
261
Daughters classes are free to add their specific attributes as they see
262
fit in any of the three dicts.
264
This is a class method so that load_tests can find it.
266
'_base_actions' in the common dict, 'actions' and 'check' in the left
267
and right dicts use names that map to methods in the test classes. Some
268
prefixes are added to these names to get the correspong methods (see
269
_get_actions() and _get_check()). The motivation here is to avoid
270
collisions in the class namespace.
326
274
super(TestParametrizedResolveConflicts, self).setUp()
328
276
builder.start_series()
330
278
# Create an empty trunk
331
builder.build_snapshot('start', None, [
332
('add', ('', 'root-id', 'directory', ''))])
279
builder.build_snapshot(None, [
280
('add', (u'', b'root-id', 'directory', ''))],
281
revision_id=b'start')
333
282
# Add a minimal base content
334
283
base_actions = self._get_actions(self._base_actions)()
335
builder.build_snapshot('base', ['start'], base_actions)
284
builder.build_snapshot([b'start'], base_actions, revision_id=b'base')
336
285
# Modify the base content in branch
337
286
actions_other = self._get_actions(self._other['actions'])()
338
builder.build_snapshot('other', ['base'], actions_other)
287
builder.build_snapshot([b'base'], actions_other, revision_id=b'other')
339
288
# Modify the base content in trunk
340
289
actions_this = self._get_actions(self._this['actions'])()
341
builder.build_snapshot('this', ['base'], actions_this)
290
builder.build_snapshot([b'base'], actions_this, revision_id=b'this')
342
291
# builder.get_branch() tip is now 'this'
344
293
builder.finish_series()
340
class TestResolveTextConflicts(TestParametrizedResolveConflicts):
342
_conflict_type = bzr_conflicts.TextConflict
344
# Set by the scenarios
345
# path and file-id for the file involved in the conflict
349
scenarios = mirror_scenarios(
351
# File modified on both sides
352
(dict(_base_actions='create_file',
353
_path='file', _file_id=b'file-id'),
355
dict(actions='modify_file_A', check='file_has_content_A')),
357
dict(actions='modify_file_B', check='file_has_content_B')),),
358
# File modified on both sides in dir
359
(dict(_base_actions='create_file_in_dir',
360
_path='dir/file', _file_id=b'file-id'),
361
('filed_modified_A_in_dir',
362
dict(actions='modify_file_A_in_dir',
363
check='file_in_dir_has_content_A')),
365
dict(actions='modify_file_B_in_dir',
366
check='file_in_dir_has_content_B')),),
369
def do_create_file(self, path='file'):
370
return [('add', (path, b'file-id', 'file', b'trunk content\n'))]
372
def do_modify_file_A(self):
373
return [('modify', ('file', b'trunk content\nfeature A\n'))]
375
def do_modify_file_B(self):
376
return [('modify', ('file', b'trunk content\nfeature B\n'))]
378
def do_modify_file_A_in_dir(self):
379
return [('modify', ('dir/file', b'trunk content\nfeature A\n'))]
381
def do_modify_file_B_in_dir(self):
382
return [('modify', ('dir/file', b'trunk content\nfeature B\n'))]
384
def check_file_has_content_A(self, path='file'):
385
self.assertFileEqual(b'trunk content\nfeature A\n',
386
osutils.pathjoin('branch', path))
388
def check_file_has_content_B(self, path='file'):
389
self.assertFileEqual(b'trunk content\nfeature B\n',
390
osutils.pathjoin('branch', path))
392
def do_create_file_in_dir(self):
393
return [('add', ('dir', b'dir-id', 'directory', '')),
394
] + self.do_create_file('dir/file')
396
def check_file_in_dir_has_content_A(self):
397
self.check_file_has_content_A('dir/file')
399
def check_file_in_dir_has_content_B(self):
400
self.check_file_has_content_B('dir/file')
402
def _get_resolve_path_arg(self, wt, action):
405
def assertTextConflict(self, wt, c):
406
self.assertEqual(self._file_id, c.file_id)
407
self.assertEqual(self._path, c.path)
408
_assert_conflict = assertTextConflict
391
411
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
393
_conflict_type = conflicts.ContentsConflict,
413
_conflict_type = bzr_conflicts.ContentsConflict
395
# Set by load_tests from scenarios()
415
# Set by the scenarios
396
416
# path and file-id for the file involved in the conflict
420
scenarios = mirror_scenarios(
403
422
# File modified/deleted
404
423
(dict(_base_actions='create_file',
405
_path='file', _file_id='file-id'),
424
_path='file', _file_id=b'file-id'),
406
425
('file_modified',
407
426
dict(actions='modify_file', check='file_has_more_content')),
409
428
dict(actions='delete_file', check='file_doesnt_exist')),),
411
return mirror_scenarios(base_scenarios)
429
# File renamed-modified/deleted
430
(dict(_base_actions='create_file',
431
_path='new-file', _file_id=b'file-id'),
432
('file_renamed_and_modified',
433
dict(actions='modify_and_rename_file',
434
check='file_renamed_and_more_content')),
436
dict(actions='delete_file', check='file_doesnt_exist')),),
437
# File modified/deleted in dir
438
(dict(_base_actions='create_file_in_dir',
439
_path='dir/file', _file_id=b'file-id'),
440
('file_modified_in_dir',
441
dict(actions='modify_file_in_dir',
442
check='file_in_dir_has_more_content')),
443
('file_deleted_in_dir',
444
dict(actions='delete_file_in_dir',
445
check='file_in_dir_doesnt_exist')),),
413
448
def do_create_file(self):
414
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
449
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
416
451
def do_modify_file(self):
417
return [('modify', ('file-id', 'trunk content\nmore content\n'))]
452
return [('modify', ('file', b'trunk content\nmore content\n'))]
454
def do_modify_and_rename_file(self):
455
return [('modify', ('new-file', b'trunk content\nmore content\n')),
456
('rename', ('file', 'new-file'))]
419
458
def check_file_has_more_content(self):
420
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
459
self.assertFileEqual(b'trunk content\nmore content\n', 'branch/file')
461
def check_file_renamed_and_more_content(self):
462
self.assertFileEqual(
463
b'trunk content\nmore content\n', 'branch/new-file')
422
465
def do_delete_file(self):
423
return [('unversion', 'file-id')]
466
return [('unversion', 'file')]
468
def do_delete_file_in_dir(self):
469
return [('unversion', 'dir/file')]
425
471
def check_file_doesnt_exist(self):
426
self.failIfExists('branch/file')
472
self.assertPathDoesNotExist('branch/file')
474
def do_create_file_in_dir(self):
475
return [('add', ('dir', b'dir-id', 'directory', '')),
476
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
478
def do_modify_file_in_dir(self):
479
return [('modify', ('dir/file', b'trunk content\nmore content\n'))]
481
def check_file_in_dir_has_more_content(self):
482
self.assertFileEqual(
483
b'trunk content\nmore content\n', 'branch/dir/file')
485
def check_file_in_dir_doesnt_exist(self):
486
self.assertPathDoesNotExist('branch/dir/file')
428
488
def _get_resolve_path_arg(self, wt, action):
429
489
return self._path
437
497
class TestResolvePathConflict(TestParametrizedResolveConflicts):
439
_conflict_type = conflicts.PathConflict,
499
_conflict_type = bzr_conflicts.PathConflict
441
501
def do_nothing(self):
446
# Each side dict additionally defines:
447
# - path path involved (can be '<deleted>')
504
# Each side dict additionally defines:
505
# - path path involved (can be '<deleted>')
507
scenarios = mirror_scenarios(
450
509
# File renamed/deleted
451
510
(dict(_base_actions='create_file'),
453
512
dict(actions='rename_file', check='file_renamed',
454
path='new-file', file_id='file-id')),
513
path='new-file', file_id=b'file-id')),
456
515
dict(actions='delete_file', check='file_doesnt_exist',
457
516
# PathConflicts deletion handling requires a special
458
517
# hard-coded value
459
path='<deleted>', file_id='file-id')),),
518
path='<deleted>', file_id=b'file-id')),),
519
# File renamed/deleted in dir
520
(dict(_base_actions='create_file_in_dir'),
521
('file_renamed_in_dir',
522
dict(actions='rename_file_in_dir', check='file_in_dir_renamed',
523
path='dir/new-file', file_id=b'file-id')),
525
dict(actions='delete_file_in_dir', check='file_in_dir_doesnt_exist',
526
# PathConflicts deletion handling requires a special
528
path='<deleted>', file_id=b'file-id')),),
460
529
# File renamed/renamed differently
461
530
(dict(_base_actions='create_file'),
463
532
dict(actions='rename_file', check='file_renamed',
464
path='new-file', file_id='file-id')),
533
path='new-file', file_id=b'file-id')),
465
534
('file_renamed2',
466
535
dict(actions='rename_file2', check='file_renamed2',
467
path='new-file2', file_id='file-id')),),
536
path='new-file2', file_id=b'file-id')),),
468
537
# Dir renamed/deleted
469
538
(dict(_base_actions='create_dir'),
471
540
dict(actions='rename_dir', check='dir_renamed',
472
path='new-dir', file_id='dir-id')),
541
path='new-dir', file_id=b'dir-id')),
474
543
dict(actions='delete_dir', check='dir_doesnt_exist',
475
544
# PathConflicts deletion handling requires a special
476
545
# hard-coded value
477
path='<deleted>', file_id='dir-id')),),
546
path='<deleted>', file_id=b'dir-id')),),
478
547
# Dir renamed/renamed differently
479
548
(dict(_base_actions='create_dir'),
481
550
dict(actions='rename_dir', check='dir_renamed',
482
path='new-dir', file_id='dir-id')),
551
path='new-dir', file_id=b'dir-id')),
484
553
dict(actions='rename_dir2', check='dir_renamed2',
485
path='new-dir2', file_id='dir-id')),),
487
return mirror_scenarios(base_scenarios)
554
path='new-dir2', file_id=b'dir-id')),),
489
557
def do_create_file(self):
490
return [('add', ('file', 'file-id', 'file', 'trunk content\n'))]
558
return [('add', ('file', b'file-id', 'file', b'trunk content\n'))]
492
560
def do_create_dir(self):
493
return [('add', ('dir', 'dir-id', 'directory', ''))]
561
return [('add', ('dir', b'dir-id', 'directory', ''))]
495
563
def do_rename_file(self):
496
564
return [('rename', ('file', 'new-file'))]
498
566
def check_file_renamed(self):
499
self.failIfExists('branch/file')
500
self.failUnlessExists('branch/new-file')
567
self.assertPathDoesNotExist('branch/file')
568
self.assertPathExists('branch/new-file')
502
570
def do_rename_file2(self):
503
571
return [('rename', ('file', 'new-file2'))]
505
573
def check_file_renamed2(self):
506
self.failIfExists('branch/file')
507
self.failUnlessExists('branch/new-file2')
574
self.assertPathDoesNotExist('branch/file')
575
self.assertPathExists('branch/new-file2')
509
577
def do_rename_dir(self):
510
578
return [('rename', ('dir', 'new-dir'))]
512
580
def check_dir_renamed(self):
513
self.failIfExists('branch/dir')
514
self.failUnlessExists('branch/new-dir')
581
self.assertPathDoesNotExist('branch/dir')
582
self.assertPathExists('branch/new-dir')
516
584
def do_rename_dir2(self):
517
585
return [('rename', ('dir', 'new-dir2'))]
519
587
def check_dir_renamed2(self):
520
self.failIfExists('branch/dir')
521
self.failUnlessExists('branch/new-dir2')
588
self.assertPathDoesNotExist('branch/dir')
589
self.assertPathExists('branch/new-dir2')
523
591
def do_delete_file(self):
524
return [('unversion', 'file-id')]
592
return [('unversion', 'file')]
594
def do_delete_file_in_dir(self):
595
return [('unversion', 'dir/file')]
526
597
def check_file_doesnt_exist(self):
527
self.failIfExists('branch/file')
598
self.assertPathDoesNotExist('branch/file')
529
600
def do_delete_dir(self):
530
return [('unversion', 'dir-id')]
601
return [('unversion', 'dir')]
532
603
def check_dir_doesnt_exist(self):
533
self.failIfExists('branch/dir')
604
self.assertPathDoesNotExist('branch/dir')
606
def do_create_file_in_dir(self):
607
return [('add', ('dir', b'dir-id', 'directory', '')),
608
('add', ('dir/file', b'file-id', 'file', b'trunk content\n'))]
610
def do_rename_file_in_dir(self):
611
return [('rename', ('dir/file', 'dir/new-file'))]
613
def check_file_in_dir_renamed(self):
614
self.assertPathDoesNotExist('branch/dir/file')
615
self.assertPathExists('branch/dir/new-file')
617
def check_file_in_dir_doesnt_exist(self):
618
self.assertPathDoesNotExist('branch/dir/file')
535
620
def _get_resolve_path_arg(self, wt, action):
536
621
tpath = self._this['path']
561
646
# We create a conflict object as it was created before the fix and
562
647
# inject it into the working tree, the test will exercise the
563
648
# compatibility code.
564
old_c = conflicts.PathConflict('<deleted>', self._item_path,
649
old_c = bzr_conflicts.PathConflict('<deleted>', self._item_path,
566
wt.set_conflicts(conflicts.ConflictList([old_c]))
651
wt.set_conflicts([old_c])
569
654
class TestResolveDuplicateEntry(TestParametrizedResolveConflicts):
571
_conflict_type = conflicts.DuplicateEntry,
656
_conflict_type = bzr_conflicts.DuplicateEntry
575
# Each side dict additionally defines:
658
scenarios = mirror_scenarios(
579
660
# File created with different file-ids
580
661
(dict(_base_actions='nothing'),
581
662
('filea_created',
582
663
dict(actions='create_file_a', check='file_content_a',
583
path='file', file_id='file-a-id')),
664
path='file', file_id=b'file-a-id')),
584
665
('fileb_created',
585
666
dict(actions='create_file_b', check='file_content_b',
586
path='file', file_id='file-b-id')),),
588
return mirror_scenarios(base_scenarios)
667
path='file', file_id=b'file-b-id')),),
668
# File created with different file-ids but deleted on one side
669
(dict(_base_actions='create_file_a'),
671
dict(actions='replace_file_a_by_b', check='file_content_b',
672
path='file', file_id=b'file-b-id')),
674
dict(actions='modify_file_a', check='file_new_content',
675
path='file', file_id=b'file-a-id')),),
590
678
def do_nothing(self):
593
681
def do_create_file_a(self):
594
return [('add', ('file', 'file-a-id', 'file', 'file a content\n'))]
682
return [('add', ('file', b'file-a-id', 'file', b'file a content\n'))]
596
684
def check_file_content_a(self):
597
self.assertFileEqual('file a content\n', 'branch/file')
685
self.assertFileEqual(b'file a content\n', 'branch/file')
599
687
def do_create_file_b(self):
600
return [('add', ('file', 'file-b-id', 'file', 'file b content\n'))]
688
return [('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
602
690
def check_file_content_b(self):
603
self.assertFileEqual('file b content\n', 'branch/file')
691
self.assertFileEqual(b'file b content\n', 'branch/file')
693
def do_replace_file_a_by_b(self):
694
return [('unversion', 'file'),
695
('add', ('file', b'file-b-id', 'file', b'file b content\n'))]
697
def do_modify_file_a(self):
698
return [('modify', ('file', b'new content\n'))]
700
def check_file_new_content(self):
701
self.assertFileEqual(b'new content\n', 'branch/file')
605
703
def _get_resolve_path_arg(self, wt, action):
606
704
return self._this['path']
692
788
def test_keep_them_all(self):
693
789
self.run_script("""
695
$ bzr commit --strict -m 'No more conflicts nor unknown files'
791
2>2 conflicts resolved, 0 remaining
792
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
698
795
def test_adopt_child(self):
699
796
self.run_script("""
700
$ bzr mv dir/file2 file2
703
$ bzr commit --strict -m 'No more conflicts nor unknown files'
797
$ brz mv -q dir/file2 file2
798
$ brz rm -q dir --no-backup
800
2>2 conflicts resolved, 0 remaining
801
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
706
804
def test_kill_them_all(self):
707
805
self.run_script("""
710
$ bzr commit --strict -m 'No more conflicts nor unknown files'
806
$ brz rm -q dir --no-backup
808
2>2 conflicts resolved, 0 remaining
809
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
713
812
def test_resolve_taking_this(self):
714
813
self.run_script("""
715
$ bzr resolve --take-this dir
716
$ bzr commit --strict -m 'No more conflicts nor unknown files'
814
$ brz resolve --take-this dir
816
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
719
819
def test_resolve_taking_other(self):
720
820
self.run_script("""
721
$ bzr resolve --take-other dir
722
$ bzr commit --strict -m 'No more conflicts nor unknown files'
821
$ brz resolve --take-other dir
823
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
726
827
class TestResolveDeletingParent(TestResolveConflicts):
732
834
$ 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
836
$ brz commit -m 'Create trunk' -q
837
$ brz rm -q dir/file --no-backup
838
$ brz rm -q dir --no-backup
839
$ brz commit -q -m 'Remove dir/file'
840
$ brz branch -q . -r 1 ../branch
742
842
$ echo 'branch content' >dir/file2
744
$ bzr commit -m 'Add dir/file2 in branch'
843
$ brz add -q dir/file2
844
$ brz commit -q -m 'Add dir/file2 in branch'
748
847
2>Conflict: can't delete dir because it is not empty. Not deleting.
749
848
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
753
852
def test_keep_them_all(self):
754
853
self.run_script("""
756
$ bzr commit --strict -m 'No more conflicts nor unknown files'
855
2>2 conflicts resolved, 0 remaining
856
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
759
859
def test_adopt_child(self):
760
860
self.run_script("""
761
$ bzr mv dir/file2 file2
764
$ bzr commit --strict -m 'No more conflicts nor unknown files'
861
$ brz mv -q dir/file2 file2
862
$ brz rm -q dir --no-backup
864
2>2 conflicts resolved, 0 remaining
865
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
767
868
def test_kill_them_all(self):
768
869
self.run_script("""
771
$ bzr commit --strict -m 'No more conflicts nor unknown files'
870
$ brz rm -q dir --no-backup
872
2>2 conflicts resolved, 0 remaining
873
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
774
876
def test_resolve_taking_this(self):
775
877
self.run_script("""
776
$ bzr resolve --take-this dir
777
$ bzr commit --strict -m 'No more conflicts nor unknown files'
878
$ brz resolve --take-this dir
879
2>2 conflicts resolved, 0 remaining
880
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
780
883
def test_resolve_taking_other(self):
781
884
self.run_script("""
782
$ bzr resolve --take-other dir
783
$ bzr commit --strict -m 'No more conflicts nor unknown files'
885
$ brz resolve --take-other dir
888
2>2 conflicts resolved, 0 remaining
889
$ brz commit -q --strict -m 'No more conflicts nor unknown files'
787
893
class TestResolveParentLoop(TestParametrizedResolveConflicts):
789
_conflict_type = conflicts.ParentLoop,
895
_conflict_type = bzr_conflicts.ParentLoop
791
897
_this_args = None
792
898
_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'
900
# Each side dict additionally defines:
901
# - dir_id: the directory being moved
902
# - target_id: The target directory
903
# - xfail: whether the test is expected to fail if the action is
904
# involved as 'other'
905
scenarios = mirror_scenarios(
802
907
# Dirs moved into each other
803
908
(dict(_base_actions='create_dir1_dir2'),
804
909
('dir1_into_dir2',
805
910
dict(actions='move_dir1_into_dir2', check='dir1_moved',
806
dir_id='dir1-id', target_id='dir2-id', xfail=False)),
911
dir_id=b'dir1-id', target_id=b'dir2-id', xfail=False)),
807
912
('dir2_into_dir1',
808
913
dict(actions='move_dir2_into_dir1', check='dir2_moved',
809
dir_id='dir2-id', target_id='dir1-id', xfail=False))),
914
dir_id=b'dir2-id', target_id=b'dir1-id', xfail=False))),
810
915
# Subdirs moved into each other
811
916
(dict(_base_actions='create_dir1_4'),
812
917
('dir1_into_dir4',
813
918
dict(actions='move_dir1_into_dir4', check='dir1_2_moved',
814
dir_id='dir1-id', target_id='dir4-id', xfail=True)),
919
dir_id=b'dir1-id', target_id=b'dir4-id', xfail=True)),
815
920
('dir3_into_dir2',
816
921
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)
922
dir_id=b'dir3-id', target_id=b'dir2-id', xfail=True))),
821
925
def do_create_dir1_dir2(self):
822
return [('add', ('dir1', 'dir1-id', 'directory', '')),
823
('add', ('dir2', 'dir2-id', 'directory', '')),]
926
return [('add', ('dir1', b'dir1-id', 'directory', '')),
927
('add', ('dir2', b'dir2-id', 'directory', '')), ]
825
929
def do_move_dir1_into_dir2(self):
826
930
return [('rename', ('dir1', 'dir2/dir1'))]
828
932
def check_dir1_moved(self):
829
self.failIfExists('branch/dir1')
830
self.failUnlessExists('branch/dir2/dir1')
933
self.assertPathDoesNotExist('branch/dir1')
934
self.assertPathExists('branch/dir2/dir1')
832
936
def do_move_dir2_into_dir1(self):
833
937
return [('rename', ('dir2', 'dir1/dir2'))]
835
939
def check_dir2_moved(self):
836
self.failIfExists('branch/dir2')
837
self.failUnlessExists('branch/dir1/dir2')
940
self.assertPathDoesNotExist('branch/dir2')
941
self.assertPathExists('branch/dir1/dir2')
839
943
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', '')),]
944
return [('add', ('dir1', b'dir1-id', 'directory', '')),
945
('add', ('dir1/dir2', b'dir2-id', 'directory', '')),
946
('add', ('dir3', b'dir3-id', 'directory', '')),
947
('add', ('dir3/dir4', b'dir4-id', 'directory', '')), ]
845
949
def do_move_dir1_into_dir4(self):
846
950
return [('rename', ('dir1', 'dir3/dir4/dir1'))]
848
952
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')
953
self.assertPathDoesNotExist('branch/dir1')
954
self.assertPathExists('branch/dir3/dir4/dir1')
955
self.assertPathExists('branch/dir3/dir4/dir1/dir2')
853
957
def do_move_dir3_into_dir2(self):
854
958
return [('rename', ('dir3', 'dir1/dir2/dir3'))]
856
960
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')
961
self.assertPathDoesNotExist('branch/dir3')
962
self.assertPathExists('branch/dir1/dir2/dir3')
963
self.assertPathExists('branch/dir1/dir2/dir3/dir4')
861
965
def _get_resolve_path_arg(self, wt, action):
862
966
# ParentLoop says: moving <conflict_path> into <path>. Cancelled move.
941
1049
# This is nearly like TestResolveNonDirectoryParent but with branch and
942
1050
# trunk switched. As such it should certainly produce the same
1052
self.assertRaises(transform.MalformedTransform,
1053
self.run_script, """
948
$ bzr commit -m 'Create trunk'
1059
$ brz commit -m 'Create trunk' -q
950
1061
$ echo "Boo!" >foo
951
$ bzr commit -m 'foo is now a file'
953
$ bzr branch . -r 1 ../branch
1062
$ brz commit -m 'foo is now a file' -q
1063
$ brz branch -q . -r 1 ../branch -q
955
1065
$ echo "Boing" >foo/bar
957
$ bzr commit -m 'Add foo/bar'
960
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1066
$ brz add -q foo/bar -q
1067
$ brz commit -m 'Add foo/bar' -q
1068
$ brz merge ../trunk
1069
2>brz: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
1073
class TestNoFinalPath(script.TestCaseWithTransportAndScript):
1075
def test_bug_805809(self):
1078
Created a standalone tree (format: 2a)
1083
$ brz commit -m 'create file on trunk'
1084
2>Committing to: .../trunk/
1086
2>Committed revision 1.
1087
# Create a debian branch based on trunk
1089
$ brz branch trunk -r 1 debian
1090
2>Branched 1 revision.
1097
$ brz commit -m 'rename file to dir/file for debian'
1098
2>Committing to: .../debian/
1100
2>renamed file => dir/file
1101
2>Committed revision 2.
1102
# Create an experimental branch with a new root-id
1104
$ brz init experimental
1105
Created a standalone tree (format: 2a)
1107
# Work around merging into empty branch not being supported
1108
# (http://pad.lv/308562)
1109
$ echo something >not-empty
1112
$ brz commit -m 'Add some content in experimental'
1113
2>Committing to: .../experimental/
1115
2>Committed revision 1.
1116
# merge debian even without a common ancestor
1117
$ brz merge ../debian -r0..2
1120
2>All changes applied successfully.
1121
$ brz commit -m 'merging debian into experimental'
1122
2>Committing to: .../experimental/
1125
2>Committed revision 2.
1126
# Create an ubuntu branch with yet another root-id
1129
Created a standalone tree (format: 2a)
1131
# Work around merging into empty branch not being supported
1132
# (http://pad.lv/308562)
1133
$ echo something >not-empty-ubuntu
1135
adding not-empty-ubuntu
1136
$ brz commit -m 'Add some content in experimental'
1137
2>Committing to: .../ubuntu/
1138
2>added not-empty-ubuntu
1139
2>Committed revision 1.
1141
$ brz merge ../debian -r0..2
1144
2>All changes applied successfully.
1145
$ brz commit -m 'merging debian'
1146
2>Committing to: .../ubuntu/
1149
2>Committed revision 2.
1150
# Now try to merge experimental
1151
$ brz merge ../experimental
1153
2>Path conflict: dir / dir
1154
2>1 conflicts encountered.