1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
27
from bzrlib.tests import script
30
# TODO: Test commit with some added, and added-but-missing files
31
# RBC 20060124 is that not tested in test_commit.py ?
33
# The order of 'path' here is important - do not let it
35
# u'\xe5' == a with circle
36
# '\xc3\xae' == u'\xee' == i with hat
37
# So these are u'path' and 'id' only with a circle and a hat. (shappo?)
38
example_conflicts = conflicts.ConflictList(
39
[conflicts.MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
40
conflicts.ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
41
conflicts.TextConflict(u'p\xe5tha'),
42
conflicts.PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
43
conflicts.DuplicateID('Unversioned existing file',
44
u'p\xe5thc', u'p\xe5thc2',
45
'\xc3\xaedc', '\xc3\xaedc'),
46
conflicts.DuplicateEntry('Moved existing file to',
47
u'p\xe5thdd.moved', u'p\xe5thd',
49
conflicts.ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
51
conflicts.UnversionedParent('Versioned directory',
52
u'p\xe5thf', '\xc3\xaedf'),
53
conflicts.NonDirectoryParent('Created directory',
54
u'p\xe5thg', '\xc3\xaedg'),
58
class TestConflicts(tests.TestCaseWithTransport):
60
def test_conflicts(self):
61
"""Conflicts are detected properly"""
62
# Use BzrDirFormat6 so we can fake conflicts
63
tree = self.make_branch_and_tree('.', format=bzrdir.BzrDirFormat6())
64
self.build_tree_contents([('hello', 'hello world4'),
65
('hello.THIS', 'hello world2'),
66
('hello.BASE', 'hello world1'),
67
('hello.OTHER', 'hello world3'),
68
('hello.sploo.BASE', 'yellowworld'),
69
('hello.sploo.OTHER', 'yellowworld2'),
72
self.assertEqual(6, len(list(tree.list_files())))
74
tree_conflicts = tree.conflicts()
75
self.assertEqual(2, len(tree_conflicts))
76
self.assertTrue('hello' in tree_conflicts[0].path)
77
self.assertTrue('hello.sploo' in tree_conflicts[1].path)
78
conflicts.restore('hello')
79
conflicts.restore('hello.sploo')
80
self.assertEqual(0, len(tree.conflicts()))
81
self.assertFileEqual('hello world2', 'hello')
82
self.assertFalse(os.path.lexists('hello.sploo'))
83
self.assertRaises(errors.NotConflicted, conflicts.restore, 'hello')
84
self.assertRaises(errors.NotConflicted,
85
conflicts.restore, 'hello.sploo')
87
def test_resolve_conflict_dir(self):
88
tree = self.make_branch_and_tree('.')
89
self.build_tree_contents([('hello', 'hello world4'),
90
('hello.THIS', 'hello world2'),
91
('hello.BASE', 'hello world1'),
93
os.mkdir('hello.OTHER')
94
tree.add('hello', 'q')
95
l = conflicts.ConflictList([conflicts.TextConflict('hello')])
98
def test_select_conflicts(self):
99
tree = self.make_branch_and_tree('.')
100
clist = conflicts.ConflictList
102
def check_select(not_selected, selected, paths, **kwargs):
104
(not_selected, selected),
105
tree_conflicts.select_conflicts(tree, paths, **kwargs))
107
foo = conflicts.ContentsConflict('foo')
108
bar = conflicts.ContentsConflict('bar')
109
tree_conflicts = clist([foo, bar])
111
check_select(clist([bar]), clist([foo]), ['foo'])
112
check_select(clist(), tree_conflicts,
113
[''], ignore_misses=True, recurse=True)
115
foobaz = conflicts.ContentsConflict('foo/baz')
116
tree_conflicts = clist([foobaz, bar])
118
check_select(clist([bar]), clist([foobaz]),
119
['foo'], ignore_misses=True, recurse=True)
121
qux = conflicts.PathConflict('qux', 'foo/baz')
122
tree_conflicts = clist([qux])
124
check_select(clist(), tree_conflicts,
125
['foo'], ignore_misses=True, recurse=True)
126
check_select (tree_conflicts, clist(), ['foo'], ignore_misses=True)
128
def test_resolve_conflicts_recursive(self):
129
tree = self.make_branch_and_tree('.')
130
self.build_tree(['dir/', 'dir/hello'])
131
tree.add(['dir', 'dir/hello'])
133
dirhello = conflicts.ConflictList([conflicts.TextConflict('dir/hello')])
134
tree.set_conflicts(dirhello)
136
conflicts.resolve(tree, ['dir'], recursive=False, ignore_misses=True)
137
self.assertEqual(dirhello, tree.conflicts())
139
conflicts.resolve(tree, ['dir'], recursive=True, ignore_misses=True)
140
self.assertEqual(conflicts.ConflictList([]), tree.conflicts())
143
class TestConflictStanzas(tests.TestCase):
145
def test_stanza_roundtrip(self):
146
# write and read our example stanza.
147
stanza_iter = example_conflicts.to_stanzas()
148
processed = conflicts.ConflictList.from_stanzas(stanza_iter)
149
for o, p in zip(processed, example_conflicts):
150
self.assertEqual(o, p)
152
self.assertIsInstance(o.path, unicode)
154
if o.file_id is not None:
155
self.assertIsInstance(o.file_id, str)
157
conflict_path = getattr(o, 'conflict_path', None)
158
if conflict_path is not None:
159
self.assertIsInstance(conflict_path, unicode)
161
conflict_file_id = getattr(o, 'conflict_file_id', None)
162
if conflict_file_id is not None:
163
self.assertIsInstance(conflict_file_id, str)
165
def test_stanzification(self):
166
for stanza in example_conflicts.to_stanzas():
167
if 'file_id' in stanza:
168
# In Stanza form, the file_id has to be unicode.
169
self.assertStartsWith(stanza['file_id'], u'\xeed')
170
self.assertStartsWith(stanza['path'], u'p\xe5th')
171
if 'conflict_path' in stanza:
172
self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
173
if 'conflict_file_id' in stanza:
174
self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')
177
# FIXME: The shell-like tests should be converted to real whitebox tests... or
178
# moved to a blackbox module -- vila 20100205
180
# FIXME: Tests missing for DuplicateID conflict type
181
class TestResolveConflicts(script.TestCaseWithTransportAndScript):
183
preamble = None # The setup script set by daughter classes
186
super(TestResolveConflicts, self).setUp()
187
self.run_script(self.preamble)
190
class TestResolveTextConflicts(TestResolveConflicts):
195
class TestResolveContentConflicts(TestResolveConflicts):
197
# FIXME: We need to add the reverse case (delete in trunk, modify in
198
# branch) but that could wait until the resolution mechanism is implemented.
203
$ echo 'trunk content' >file
205
$ bzr commit -m 'Create trunk'
207
$ bzr branch . ../branch
210
$ bzr commit -m 'Delete file'
213
$ echo 'more content' >>file
214
$ bzr commit -m 'Modify file'
219
2>Contents conflict in file
220
2>1 conflicts encountered.
223
def test_take_this(self):
225
$ bzr rm file.OTHER --force # a simple rm file.OTHER is valid too
227
$ bzr commit --strict -m 'No more conflicts nor unknown files'
230
def test_take_other(self):
232
$ bzr mv file.OTHER file
234
$ bzr commit --strict -m 'No more conflicts nor unknown files'
237
def test_resolve_taking_this(self):
239
$ bzr resolve --take-this file
240
$ bzr commit --strict -m 'No more conflicts nor unknown files'
243
def test_resolve_taking_other(self):
245
$ bzr resolve --take-other file
246
$ bzr commit --strict -m 'No more conflicts nor unknown files'
250
class TestResolveDuplicateEntry(TestResolveConflicts):
255
$ echo 'trunk content' >file
257
$ bzr commit -m 'Create trunk'
258
$ echo 'trunk content too' >file2
260
$ bzr commit -m 'Add file2 in trunk'
262
$ bzr branch . -r 1 ../branch
264
$ echo 'branch content' >file2
266
$ bzr commit -m 'Add file2 in branch'
270
2>R file2 => file2.moved
271
2>Conflict adding file file2. Moved existing file to file2.moved.
272
2>1 conflicts encountered.
275
def test_keep_this(self):
277
$ bzr rm file2 --force
278
$ bzr mv file2.moved file2
280
$ bzr commit --strict -m 'No more conflicts nor unknown files'
283
def test_keep_other(self):
284
self.failIfExists('branch/file2.moved')
286
$ bzr rm file2.moved --force
288
$ bzr commit --strict -m 'No more conflicts nor unknown files'
290
self.failIfExists('branch/file2.moved')
292
def test_resolve_taking_this(self):
294
$ bzr resolve --take-this file2
295
$ bzr commit --strict -m 'No more conflicts nor unknown files'
298
def test_resolve_taking_other(self):
300
$ bzr resolve --take-other file2
301
$ bzr commit --strict -m 'No more conflicts nor unknown files'
305
class TestResolveUnversionedParent(TestResolveConflicts):
307
# FIXME: Add the reverse tests: dir deleted in trunk, file added in branch
309
# FIXME: While this *creates* UnversionedParent conflicts, this really only
310
# tests MissingParent resolution :-/
316
$ bzr commit -m 'Create trunk'
317
$ echo 'trunk content' >dir/file
319
$ bzr commit -m 'Add dir/file in trunk'
321
$ bzr branch . -r 1 ../branch
324
$ bzr commit -m 'Remove dir in branch'
329
2>Conflict adding files to dir. Created directory.
330
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
331
2>2 conflicts encountered.
334
def test_take_this(self):
338
$ bzr commit --strict -m 'No more conflicts nor unknown files'
341
def test_take_other(self):
344
$ bzr commit --strict -m 'No more conflicts nor unknown files'
348
class TestResolveMissingParent(TestResolveConflicts):
354
$ echo 'trunk content' >dir/file
356
$ bzr commit -m 'Create trunk'
357
$ echo 'trunk content' >dir/file2
359
$ bzr commit -m 'Add dir/file2 in branch'
361
$ bzr branch . -r 1 ../branch
363
$ bzr rm dir/file --force
365
$ bzr commit -m 'Remove dir/file'
370
2>Conflict adding files to dir. Created directory.
371
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
372
2>2 conflicts encountered.
375
def test_keep_them_all(self):
378
$ bzr commit --strict -m 'No more conflicts nor unknown files'
381
def test_adopt_child(self):
383
$ bzr mv dir/file2 file2
386
$ bzr commit --strict -m 'No more conflicts nor unknown files'
389
def test_kill_them_all(self):
393
$ bzr commit --strict -m 'No more conflicts nor unknown files'
396
def test_resolve_taking_this(self):
398
$ bzr resolve --take-this dir
399
$ bzr commit --strict -m 'No more conflicts nor unknown files'
402
def test_resolve_taking_other(self):
404
$ bzr resolve --take-other dir
405
$ bzr commit --strict -m 'No more conflicts nor unknown files'
409
class TestResolveDeletingParent(TestResolveConflicts):
415
$ echo 'trunk content' >dir/file
417
$ bzr commit -m 'Create trunk'
418
$ bzr rm dir/file --force
420
$ bzr commit -m 'Remove dir/file'
422
$ bzr branch . -r 1 ../branch
424
$ echo 'branch content' >dir/file2
426
$ bzr commit -m 'Add dir/file2 in branch'
430
2>Conflict: can't delete dir because it is not empty. Not deleting.
431
2>Conflict because dir is not versioned, but has versioned children. Versioned directory.
432
2>2 conflicts encountered.
435
def test_keep_them_all(self):
438
$ bzr commit --strict -m 'No more conflicts nor unknown files'
441
def test_adopt_child(self):
443
$ bzr mv dir/file2 file2
446
$ bzr commit --strict -m 'No more conflicts nor unknown files'
449
def test_kill_them_all(self):
453
$ bzr commit --strict -m 'No more conflicts nor unknown files'
456
def test_resolve_taking_this(self):
458
$ bzr resolve --take-this dir
459
$ bzr commit --strict -m 'No more conflicts nor unknown files'
462
def test_resolve_taking_other(self):
464
$ bzr resolve --take-other dir
465
$ bzr commit --strict -m 'No more conflicts nor unknown files'
469
class TestResolvePathConflict(TestResolveConflicts):
476
$ bzr commit -m 'Create trunk'
477
$ bzr mv file file-in-trunk
478
$ bzr commit -m 'Renamed to file-in-trunk'
480
$ bzr branch . -r 1 ../branch
482
$ bzr mv file file-in-branch
483
$ bzr commit -m 'Renamed to file-in-branch'
486
2>R file-in-branch => file-in-trunk
487
2>Path conflict: file-in-branch / file-in-trunk
488
2>1 conflicts encountered.
491
def test_keep_source(self):
493
$ bzr resolve file-in-trunk
494
$ bzr commit --strict -m 'No more conflicts nor unknown files'
497
def test_keep_target(self):
499
$ bzr mv file-in-trunk file-in-branch
500
$ bzr resolve file-in-branch
501
$ bzr commit --strict -m 'No more conflicts nor unknown files'
504
def test_resolve_taking_this(self):
506
$ bzr resolve --take-this file-in-branch
507
$ bzr commit --strict -m 'No more conflicts nor unknown files'
510
def test_resolve_taking_other(self):
512
$ bzr resolve --take-other file-in-branch
513
$ bzr commit --strict -m 'No more conflicts nor unknown files'
517
class TestResolveParentLoop(TestResolveConflicts):
524
$ bzr commit -m 'Create trunk'
526
$ bzr commit -m 'Moved dir2 into dir1'
528
$ bzr branch . -r 1 ../branch
531
$ bzr commit -m 'Moved dir1 into dir2'
534
2>Conflict moving dir2/dir1 into dir2. Cancelled move.
535
2>1 conflicts encountered.
538
def test_take_this(self):
541
$ bzr commit --strict -m 'No more conflicts nor unknown files'
544
def test_take_other(self):
546
$ bzr mv dir2/dir1 dir1
549
$ bzr commit --strict -m 'No more conflicts nor unknown files'
552
def test_resolve_taking_this(self):
554
$ bzr resolve --take-this dir2
555
$ bzr commit --strict -m 'No more conflicts nor unknown files'
557
self.failUnlessExists('dir2')
559
def test_resolve_taking_other(self):
561
$ bzr resolve --take-other dir2
562
$ bzr commit --strict -m 'No more conflicts nor unknown files'
564
self.failUnlessExists('dir1')
567
class TestResolveNonDirectoryParent(TestResolveConflicts):
573
$ bzr commit -m 'Create trunk'
574
$ echo "Boing" >foo/bar
576
$ bzr commit -m 'Add foo/bar'
578
$ bzr branch . -r 1 ../branch
582
$ bzr commit -m 'foo is now a file'
587
# FIXME: The message is misleading, foo.new *is* a directory when the message
588
# is displayed -- vila 090916
589
2>Conflict: foo.new is not a directory, but has files in it. Created directory.
590
2>1 conflicts encountered.
593
def test_take_this(self):
595
$ bzr rm foo.new --force
596
# FIXME: Isn't it weird that foo is now unkown even if foo.new has been put
597
# aside ? -- vila 090916
599
$ bzr resolve foo.new
600
$ bzr commit --strict -m 'No more conflicts nor unknown files'
603
def test_take_other(self):
608
$ bzr commit --strict -m 'No more conflicts nor unknown files'
611
def test_resolve_taking_this(self):
613
$ bzr resolve --take-this foo.new
614
$ bzr commit --strict -m 'No more conflicts nor unknown files'
617
def test_resolve_taking_other(self):
619
$ bzr resolve --take-other foo.new
620
$ bzr commit --strict -m 'No more conflicts nor unknown files'
624
class TestMalformedTransform(script.TestCaseWithTransportAndScript):
626
def test_bug_430129(self):
627
# This is nearly like TestResolveNonDirectoryParent but with branch and
628
# trunk switched. As such it should certainly produce the same
634
$ bzr commit -m 'Create trunk'
637
$ bzr commit -m 'foo is now a file'
639
$ bzr branch . -r 1 ../branch
641
$ echo "Boing" >foo/bar
643
$ bzr commit -m 'Add foo/bar'
646
2>bzr: ERROR: Tree transform is malformed [('unversioned executability', 'new-1')]
650
class TestResolveActionOption(tests.TestCase):
653
super(TestResolveActionOption, self).setUp()
654
self.options = [conflicts.ResolveActionOption()]
655
self.parser = option.get_optparser(dict((o.name, o)
656
for o in self.options))
658
def parse(self, args):
659
return self.parser.parse_args(args)
661
def test_unknown_action(self):
662
self.assertRaises(errors.BadOptionValue,
663
self.parse, ['--action', 'take-me-to-the-moon'])
666
opts, args = self.parse(['--action', 'done'])
667
self.assertEqual({'action':'done'}, opts)
669
def test_take_this(self):
670
opts, args = self.parse(['--action', 'take-this'])
671
self.assertEqual({'action': 'take_this'}, opts)
672
opts, args = self.parse(['--take-this'])
673
self.assertEqual({'action': 'take_this'}, opts)
675
def test_take_other(self):
676
opts, args = self.parse(['--action', 'take-other'])
677
self.assertEqual({'action': 'take_other'}, opts)
678
opts, args = self.parse(['--take-other'])
679
self.assertEqual({'action': 'take_other'}, opts)