1
# Copyright (C) 2005-2010 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29
from bzrlib.tests import script
32
def load_tests(standard_tests, module, loader):
33
result = loader.suiteClass()
35
sp_tests, remaining_tests = tests.split_suite_by_condition(
36
standard_tests, tests.condition_isinstance((
37
TestParametrizedResolveConflicts,
39
# Each test class defines its own scenarios. This is needed for
40
# TestResolvePathConflictBefore531967 that verifies that the same tests as
41
# TestResolvePathConflict still pass.
42
for test in tests.iter_suite_tests(sp_tests):
43
tests.apply_scenarios(test, test.scenarios(), result)
45
# No parametrization for the remaining tests
46
result.addTests(remaining_tests)
51
# TODO: Test commit with some added, and added-but-missing files
52
# RBC 20060124 is that not tested in test_commit.py ?
54
# The order of 'path' here is important - do not let it
56
# u'\xe5' == a with circle
57
# '\xc3\xae' == u'\xee' == i with hat
58
# 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'),
79
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
def test_resolve_conflict_dir(self):
109
tree = self.make_branch_and_tree('.')
110
self.build_tree_contents([('hello', 'hello world4'),
111
('hello.THIS', 'hello world2'),
112
('hello.BASE', 'hello world1'),
114
os.mkdir('hello.OTHER')
115
tree.add('hello', 'q')
116
l = conflicts.ConflictList([conflicts.TextConflict('hello')])
119
def test_select_conflicts(self):
120
tree = self.make_branch_and_tree('.')
121
clist = conflicts.ConflictList
123
def check_select(not_selected, selected, paths, **kwargs):
125
(not_selected, selected),
126
tree_conflicts.select_conflicts(tree, paths, **kwargs))
128
foo = conflicts.ContentsConflict('foo')
129
bar = conflicts.ContentsConflict('bar')
130
tree_conflicts = clist([foo, bar])
132
check_select(clist([bar]), clist([foo]), ['foo'])
133
check_select(clist(), tree_conflicts,
134
[''], ignore_misses=True, recurse=True)
136
foobaz = conflicts.ContentsConflict('foo/baz')
137
tree_conflicts = clist([foobaz, bar])
139
check_select(clist([bar]), clist([foobaz]),
140
['foo'], ignore_misses=True, recurse=True)
142
qux = conflicts.PathConflict('qux', 'foo/baz')
143
tree_conflicts = clist([qux])
145
check_select(clist(), tree_conflicts,
146
['foo'], ignore_misses=True, recurse=True)
147
check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
149
def test_resolve_conflicts_recursive(self):
150
tree = self.make_branch_and_tree('.')
151
self.build_tree(['dir/', 'dir/hello'])
152
tree.add(['dir', 'dir/hello'])
154
dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
155
tree.set_conflicts(dirhello)
157
conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
158
self.assertEqual(dirhello, tree.conflicts())
160
conflicts.resolve(tree, ['dir'], recursive=True, ignore_misses=True)
161
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')
198
# FIXME: The shell-like tests should be converted to real whitebox tests... or
199
# moved to a blackbox module -- vila 20100205
201
# FIXME: test missing for multiple conflicts
203
# FIXME: Tests missing for DuplicateID conflict type
204
class TestResolveConflicts(script.TestCaseWithTransportAndScript):
206
preamble = None # The setup script set by daughter classes
209
super(TestResolveConflicts, self).setUp()
210
self.run_script(self.preamble)
213
class TestResolveTextConflicts(TestResolveConflicts):
218
# FIXME: Get rid of parametrized (in the class name) once we delete
219
# TestResolveConflicts -- vila 20100308
220
class TestParametrizedResolveConflicts(tests.TestCaseWithTransport):
221
"""This class provides a base to test single conflict resolution.
223
The aim is to define scenarios in daughter classes (one for each conflict
224
type) that create a single conflict object when one branch is merged in
225
another (and vice versa). Each class can define as many scenarios as
226
needed. Each scenario should define a couple of actions that will be
227
swapped to define the sibling scenarios.
229
From there, both resolutions are tested (--take-this and --take-other).
231
Each conflict type use its attributes in a specific way, so each class
232
should define a specific _assert_conflict method.
234
Since the resolution change the working tree state, each action should
235
define an associated check.
238
# Set by daughter classes
239
_conflict_type = None
240
_assert_conflict = None
245
_other_actions = None
249
# Set by _this_actions and other_actions
256
def mirror_scenarios(klass, base_scenarios):
259
"""Modify dict to apply to the given side.
261
'actions' key is turned into '_actions_this' if side is 'this' for
265
# Turn each key into _side_key
266
for k,v in d.iteritems():
267
t['_%s_%s' % (k, side)] = v
269
# Each base scenario is duplicated switching the roles of 'this' and
271
left = [l for l, r, c in base_scenarios]
272
right = [r for l, r, c in base_scenarios]
273
common = [c for l, r, c in base_scenarios]
274
for (lname, ldict), (rname, rdict), common in zip(left, right, common):
275
a = tests.multiply_scenarios([(lname, adapt(ldict, 'this'))],
276
[(rname, adapt(rdict, 'other'))])
277
b = tests.multiply_scenarios(
278
[(rname, adapt(rdict, 'this'))],
279
[(lname, adapt(ldict, 'other'))])
280
# Inject the common parameters in all scenarios
281
for name, d in a + b:
283
scenarios.extend(a + b)
287
def scenarios(klass):
288
# Only concrete classes return actual scenarios
292
super(TestParametrizedResolveConflicts, self).setUp()
293
builder = self.make_branch_builder('trunk')
294
builder.start_series()
296
# Create an empty trunk
297
builder.build_snapshot('start', None, [
298
('add', ('', 'root-id', 'directory', ''))])
299
# Add a minimal base content
300
_, _, actions_base = self._get_actions(self._actions_base)()
301
builder.build_snapshot('base', ['start'], actions_base)
302
# Modify the base content in branch
303
(self._other_path, self._other_id,
304
actions_other) = self._get_actions(self._actions_other)()
305
builder.build_snapshot('other', ['base'], actions_other)
306
# Modify the base content in trunk
307
(self._this_path, self._this_id,
308
actions_this) = self._get_actions(self._actions_this)()
309
builder.build_snapshot('this', ['base'], actions_this)
310
# builder.get_branch() tip is now 'this'
312
builder.finish_series()
313
self.builder = builder
315
def _get_actions(self, name):
316
return getattr(self, 'do_%s' % name)
318
def _get_check(self, name):
319
return getattr(self, 'check_%s' % name)
321
def assertConflict(self, wt):
322
confs = wt.conflicts()
323
self.assertLength(1, confs)
325
self.assertIsInstance(c, self._conflict_type)
326
self._assert_conflict(wt, c)
328
def check_resolved(self, wt, path, action):
329
conflicts.resolve(wt, [path], action=action)
330
# Check that we don't have any conflicts nor unknown left
331
self.assertLength(0, wt.conflicts())
332
self.assertLength(0, list(wt.unknowns()))
334
def do_create_file(self):
335
return ('file', 'file-id',
336
[('add', ('file', 'file-id', 'file', 'trunk content\n'))])
338
def do_create_dir(self):
339
return ('dir', 'dir-id', [('add', ('dir', 'dir-id', 'directory', ''))])
341
def do_modify_file(self):
342
return ('file', 'file-id',
343
[('modify', ('file-id', 'trunk content\nmore content\n'))])
345
def check_file_has_more_content(self):
346
self.assertFileEqual('trunk content\nmore content\n', 'branch/file')
348
def do_delete_file(self):
349
return ('file', 'file-id', [('unversion', 'file-id')])
351
def check_file_doesnt_exist(self):
352
self.failIfExists('branch/file')
354
def do_rename_file(self):
355
return ('new-file', 'file-id', [('rename', ('file', 'new-file'))])
357
def check_file_renamed(self):
358
self.failIfExists('branch/file')
359
self.failUnlessExists('branch/new-file')
361
def do_rename_dir(self):
362
return ('new-dir', 'dir-id', [('rename', ('dir', 'new-dir'))])
364
def check_dir_renamed(self):
365
self.failIfExists('branch/dir')
366
self.failUnlessExists('branch/new-dir')
368
def do_rename_dir2(self):
369
return ('new-dir2', 'dir-id', [('rename', ('dir', 'new-dir2'))])
371
def check_dir_renamed2(self):
372
self.failIfExists('branch/dir')
373
self.failUnlessExists('branch/new-dir2')
375
def do_delete_dir(self):
376
return ('<deleted>', 'dir-id', [('unversion', 'dir-id')])
378
def check_dir_doesnt_exist(self):
379
self.failIfExists('branch/dir')
381
def _merge_other_into_this(self):
382
b = self.builder.get_branch()
383
wt = b.bzrdir.sprout('branch').open_workingtree()
384
wt.merge_from_branch(b, 'other')
387
def test_resolve_taking_this(self):
388
wt = self._merge_other_into_this()
389
self.assertConflict(wt)
390
self.check_resolved(wt, self._item_path, 'take_this')
391
check_this = self._get_check(self._check_this)
394
def test_resolve_taking_other(self):
395
wt = self._merge_other_into_this()
396
self.assertConflict(wt)
397
self.check_resolved(wt, self._item_path, 'take_other')
398
check_other = self._get_check(self._check_other)
402
class TestResolveContentsConflict(TestParametrizedResolveConflicts):
404
_conflict_type = conflicts.ContentsConflict,
406
def scenarios(klass):
407
common = dict(_actions_base='create_file',
408
_item_path='file', item_id='file-id',
411
(('file_modified', dict(actions='modify_file',
412
check='file_has_more_content')),
413
('file_deleted', dict(actions='delete_file',
414
check='file_doesnt_exist')),
415
dict(_actions_base='create_file',
416
_item_path='file', item_id='file-id',)),
418
return klass.mirror_scenarios(base_scenarios)
420
def assertContentsConflict(self, wt, c):
421
self.assertEqual(self._other_id, c.file_id)
422
self.assertEqual(self._other_path, c.path)
423
_assert_conflict = assertContentsConflict
427
class TestResolvePathConflict(TestParametrizedResolveConflicts):
429
_conflict_type = conflicts.PathConflict,
432
def scenarios(klass):
433
for_dirs = dict(_actions_base='create_dir',
434
_item_path='new-dir', _item_id='dir-id',)
437
dict(actions='rename_file', check='file_renamed')),
439
dict(actions='delete_file', check='file_doesnt_exist')),
440
dict(_actions_base='create_file',
441
_item_path='new-file', _item_id='file-id',)),
443
dict(actions='rename_dir', check='dir_renamed')),
445
dict(actions='delete_dir', check='dir_doesnt_exist')),
448
dict(actions='rename_dir', check='dir_renamed')),
450
dict(actions='rename_dir2', check='dir_renamed2')),
453
return klass.mirror_scenarios(base_scenarios)
455
def do_delete_file(self):
456
sup = super(TestResolvePathConflict, self).do_delete_file()
457
# PathConflicts handle deletion differently and requires a special
459
return ('<deleted>',) + sup[1:]
461
def assertPathConflict(self, wt, c):
462
self.assertEqual(self._item_id, c.file_id)
463
self.assertEqual(self._this_path, c.path)
464
self.assertEqual(self._other_path, c.conflict_path)
465
_assert_conflict = assertPathConflict
468
class TestResolvePathConflictBefore531967(TestResolvePathConflict):
469
"""Same as TestResolvePathConflict but a specific conflict object.
472
def assertPathConflict(self, c):
473
# We create a conflict object as it was created before the fix and
474
# inject it into the working tree, the test will exercise the
475
# compatibility code.
476
old_c = conflicts.PathConflict('<deleted>', self._item_path,
478
wt.set_conflicts(conflicts.ConflictList([old_c]))
481
class TestResolveDuplicateEntry(TestResolveConflicts):
486
$ echo 'trunk content' >file
488
$ bzr commit -m 'Create trunk'
490
$ echo 'trunk content too' >file2
492
$ bzr commit -m 'Add file2 in trunk'
494
$ bzr branch . -r 1 ../branch
496
$ echo 'branch content' >file2
498
$ bzr commit -m 'Add file2 in branch'
502
2>R file2 => file2.moved
503
2>Conflict adding file file2. Moved existing file to file2.moved.
504
2>1 conflicts encountered.
507
def test_keep_this(self):
509
$ bzr rm file2 --force
510
$ bzr mv file2.moved file2
512
$ bzr commit --strict -m 'No more conflicts nor unknown files'
515
def test_keep_other(self):
516
self.failIfExists('branch/file2.moved')
518
$ bzr rm file2.moved --force
520
$ bzr commit --strict -m 'No more conflicts nor unknown files'
522
self.failIfExists('branch/file2.moved')
524
def test_resolve_taking_this(self):
526
$ bzr resolve --take-this file2
527
$ bzr commit --strict -m 'No more conflicts nor unknown files'
530
def test_resolve_taking_other(self):
532
$ bzr resolve --take-other file2
533
$ bzr commit --strict -m 'No more conflicts nor unknown files'
537
class TestResolveUnversionedParent(TestResolveConflicts):
539
# FIXME: Add the reverse tests: dir deleted in trunk, file added in branch
541
# FIXME: While this *creates* UnversionedParent conflicts, this really only
542
# tests MissingParent resolution :-/
548
$ bzr commit -m 'Create trunk'
550
$ echo 'trunk content' >dir/file
552
$ bzr commit -m 'Add dir/file in trunk'
554
$ bzr branch . -r 1 ../branch
557
$ bzr commit -m 'Remove dir in branch'
562
2>Conflict adding files to dir. Created directory.
563
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
564
2>2 conflicts encountered.
567
def test_take_this(self):
571
$ bzr commit --strict -m 'No more conflicts nor unknown files'
574
def test_take_other(self):
577
$ bzr commit --strict -m 'No more conflicts nor unknown files'
581
class TestResolveMissingParent(TestResolveConflicts):
587
$ echo 'trunk content' >dir/file
589
$ bzr commit -m 'Create trunk'
591
$ echo 'trunk content' >dir/file2
593
$ bzr commit -m 'Add dir/file2 in branch'
595
$ bzr branch . -r 1 ../branch
597
$ bzr rm dir/file --force
599
$ bzr commit -m 'Remove dir/file'
604
2>Conflict adding files to dir. Created directory.
605
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
606
2>2 conflicts encountered.
609
def test_keep_them_all(self):
612
$ bzr commit --strict -m 'No more conflicts nor unknown files'
615
def test_adopt_child(self):
617
$ bzr mv dir/file2 file2
620
$ bzr commit --strict -m 'No more conflicts nor unknown files'
623
def test_kill_them_all(self):
627
$ bzr commit --strict -m 'No more conflicts nor unknown files'
630
def test_resolve_taking_this(self):
632
$ bzr resolve --take-this dir
633
$ bzr commit --strict -m 'No more conflicts nor unknown files'
636
def test_resolve_taking_other(self):
638
$ bzr resolve --take-other dir
639
$ bzr commit --strict -m 'No more conflicts nor unknown files'
643
class TestResolveDeletingParent(TestResolveConflicts):
649
$ echo 'trunk content' >dir/file
651
$ bzr commit -m 'Create trunk'
653
$ bzr rm dir/file --force
655
$ bzr commit -m 'Remove dir/file'
657
$ bzr branch . -r 1 ../branch
659
$ echo 'branch content' >dir/file2
661
$ bzr commit -m 'Add dir/file2 in branch'
665
2>Conflict: can't delete dir because it is not empty. Not deleting.
666
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
667
2>2 conflicts encountered.
670
def test_keep_them_all(self):
673
$ bzr commit --strict -m 'No more conflicts nor unknown files'
676
def test_adopt_child(self):
678
$ bzr mv dir/file2 file2
681
$ bzr commit --strict -m 'No more conflicts nor unknown files'
684
def test_kill_them_all(self):
688
$ bzr commit --strict -m 'No more conflicts nor unknown files'
691
def test_resolve_taking_this(self):
693
$ bzr resolve --take-this dir
694
$ bzr commit --strict -m 'No more conflicts nor unknown files'
697
def test_resolve_taking_other(self):
699
$ bzr resolve --take-other dir
700
$ bzr commit --strict -m 'No more conflicts nor unknown files'
704
class OldTestResolvePathConflict(TestResolveConflicts):
711
$ bzr commit -m 'Create trunk'
713
$ bzr mv file file-in-trunk
714
$ bzr commit -m 'Renamed to file-in-trunk'
716
$ bzr branch . -r 1 ../branch
718
$ bzr mv file file-in-branch
719
$ bzr commit -m 'Renamed to file-in-branch'
722
2>R file-in-branch => file-in-trunk
723
2>Path conflict: file-in-branch / file-in-trunk
724
2>1 conflicts encountered.
727
def test_keep_source(self):
729
$ bzr resolve file-in-trunk
730
$ bzr commit --strict -m 'No more conflicts nor unknown files'
733
def test_keep_target(self):
735
$ bzr mv file-in-trunk file-in-branch
736
$ bzr resolve file-in-branch
737
$ bzr commit --strict -m 'No more conflicts nor unknown files'
740
def test_resolve_taking_this(self):
742
$ bzr resolve --take-this file-in-branch
743
$ bzr commit --strict -m 'No more conflicts nor unknown files'
746
def test_resolve_taking_other(self):
748
$ bzr resolve --take-other file-in-branch
749
$ bzr commit --strict -m 'No more conflicts nor unknown files'
753
class TestResolveParentLoop(TestResolveConflicts):
760
$ bzr commit -m 'Create trunk'
763
$ bzr commit -m 'Moved dir2 into dir1'
765
$ bzr branch . -r 1 ../branch
768
$ bzr commit -m 'Moved dir1 into dir2'
771
2>Conflict moving dir2/dir1 into dir2. Cancelled move.
772
2>1 conflicts encountered.
775
def test_take_this(self):
778
$ bzr commit --strict -m 'No more conflicts nor unknown files'
781
def test_take_other(self):
783
$ bzr mv dir2/dir1 dir1
786
$ bzr commit --strict -m 'No more conflicts nor unknown files'
789
def test_resolve_taking_this(self):
791
$ bzr resolve --take-this dir2
792
$ bzr commit --strict -m 'No more conflicts nor unknown files'
794
self.failUnlessExists('dir2')
796
def test_resolve_taking_other(self):
798
$ bzr resolve --take-other dir2
799
$ bzr commit --strict -m 'No more conflicts nor unknown files'
801
self.failUnlessExists('dir1')
804
class TestResolveNonDirectoryParent(TestResolveConflicts):
810
$ bzr commit -m 'Create trunk'
811
$ echo "Boing" >foo/bar
813
$ bzr commit -m 'Add foo/bar'
815
$ bzr branch . -r 1 ../branch
819
$ bzr commit -m 'foo is now a file'
824
# FIXME: The message is misleading, foo.new *is* a directory when the message
825
# is displayed -- vila 090916
826
2>Conflict: foo.new is not a directory, but has files in it. Created directory.
827
2>1 conflicts encountered.
830
def test_take_this(self):
832
$ bzr rm foo.new --force
833
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
834
# aside ? -- vila 090916
836
$ bzr resolve foo.new
837
$ bzr commit --strict -m 'No more conflicts nor unknown files'
840
def test_take_other(self):
845
$ bzr commit --strict -m 'No more conflicts nor unknown files'
848
def test_resolve_taking_this(self):
850
$ bzr resolve --take-this foo.new
851
$ bzr commit --strict -m 'No more conflicts nor unknown files'
854
def test_resolve_taking_other(self):
856
$ bzr resolve --take-other foo.new
857
$ bzr commit --strict -m 'No more conflicts nor unknown files'
861
class TestMalformedTransform(script.TestCaseWithTransportAndScript):
863
def test_bug_430129(self):
864
# This is nearly like TestResolveNonDirectoryParent but with branch and
865
# trunk switched. As such it should certainly produce the same
871
$ bzr commit -m 'Create trunk'
874
$ bzr commit -m 'foo is now a file'
876
$ bzr branch . -r 1 ../branch
878
$ echo "Boing" >foo/bar
880
$ bzr commit -m 'Add foo/bar'
883
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
887
class TestResolveActionOption(tests.TestCase):
890
super(TestResolveActionOption, self).setUp()
891
self.options = [conflicts.ResolveActionOption()]
892
self.parser = option.get_optparser(dict((o.name, o)
893
for o in self.options))
895
def parse(self, args):
896
return self.parser.parse_args(args)
898
def test_unknown_action(self):
899
self.assertRaises(errors.BadOptionValue,
900
self.parse, ['--action', 'take-me-to-the-moon'])
903
opts, args = self.parse(['--action', 'done'])
904
self.assertEqual({'action':'done'}, opts)
906
def test_take_this(self):
907
opts, args = self.parse(['--action', 'take-this'])
908
self.assertEqual({'action': 'take_this'}, opts)
909
opts, args = self.parse(['--take-this'])
910
self.assertEqual({'action': 'take_this'}, opts)
912
def test_take_other(self):
913
opts, args = self.parse(['--action', 'take-other'])
914
self.assertEqual({'action': 'take_other'}, opts)
915
opts, args = self.parse(['--take-other'])
916
self.assertEqual({'action': 'take_other'}, opts)