1
# Copyright (C) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
from bzrlib import bzrdir
21
from bzrlib.tests import TestCaseWithTransport, TestCase
22
from bzrlib.branch import Branch
23
from bzrlib.conflicts import (
36
from bzrlib.errors import NotConflicted
39
# TODO: Test commit with some added, and added-but-missing files
40
# RBC 20060124 is that not tested in test_commit.py ?
42
# The order of 'path' here is important - do not let it
44
# u'\xe5' == a with circle
45
# '\xc3\xae' == u'\xee' == i with hat
46
# So these are u'pathg' and 'idg' only with a circle and a hat. (shappo?)
47
example_conflicts = ConflictList([
48
MissingParent('Not deleting', u'p\xe5thg', '\xc3\xaedg'),
49
ContentsConflict(u'p\xe5tha', None, '\xc3\xaeda'),
50
TextConflict(u'p\xe5tha'),
51
PathConflict(u'p\xe5thb', u'p\xe5thc', '\xc3\xaedb'),
52
DuplicateID('Unversioned existing file', u'p\xe5thc', u'p\xe5thc2',
53
'\xc3\xaedc', '\xc3\xaedc'),
54
DuplicateEntry('Moved existing file to', u'p\xe5thdd.moved', u'p\xe5thd',
56
ParentLoop('Cancelled move', u'p\xe5the', u'p\xe5th2e',
58
UnversionedParent('Versioned directory', u'p\xe5thf', '\xc3\xaedf'),
62
class TestConflicts(TestCaseWithTransport):
64
def test_conflicts(self):
65
"""Conflicts are detected properly"""
66
tree = self.make_branch_and_tree('.',
67
format=bzrdir.BzrDirFormat6())
69
file('hello', 'w').write('hello world4')
70
file('hello.THIS', 'w').write('hello world2')
71
file('hello.BASE', 'w').write('hello world1')
72
file('hello.OTHER', 'w').write('hello world3')
73
file('hello.sploo.BASE', 'w').write('yellow world')
74
file('hello.sploo.OTHER', 'w').write('yellow world2')
76
self.assertEqual(len(list(tree.list_files())), 6)
78
conflicts = tree.conflicts()
79
self.assertEqual(len(conflicts), 2)
80
self.assert_('hello' in conflicts[0].path)
81
self.assert_('hello.sploo' in conflicts[1].path)
83
restore('hello.sploo')
84
self.assertEqual(len(tree.conflicts()), 0)
85
self.assertFileEqual('hello world2', 'hello')
86
assert not os.path.lexists('hello.sploo')
87
self.assertRaises(NotConflicted, restore, 'hello')
88
self.assertRaises(NotConflicted, restore, 'hello.sploo')
90
def test_resolve_conflict_dir(self):
91
tree = self.make_branch_and_tree('.')
93
file('hello', 'w').write('hello world4')
94
tree.add('hello', 'q')
95
file('hello.THIS', 'w').write('hello world2')
96
file('hello.BASE', 'w').write('hello world1')
97
os.mkdir('hello.OTHER')
98
l = ConflictList([TextConflict('hello')])
101
def test_select_conflicts(self):
102
tree = self.make_branch_and_tree('.')
103
tree_conflicts = ConflictList([ContentsConflict('foo'),
104
ContentsConflict('bar')])
105
self.assertEqual((ConflictList([ContentsConflict('bar')]),
106
ConflictList([ContentsConflict('foo')])),
107
tree_conflicts.select_conflicts(tree, ['foo']))
108
self.assertEqual((ConflictList(), tree_conflicts),
109
tree_conflicts.select_conflicts(tree, [''],
110
ignore_misses=True, recurse=True))
111
tree_conflicts = ConflictList([ContentsConflict('foo/baz'),
112
ContentsConflict('bar')])
113
self.assertEqual((ConflictList([ContentsConflict('bar')]),
114
ConflictList([ContentsConflict('foo/baz')])),
115
tree_conflicts.select_conflicts(tree, ['foo'],
118
tree_conflicts = ConflictList([PathConflict('qux', 'foo/baz')])
119
self.assertEqual((ConflictList(), tree_conflicts),
120
tree_conflicts.select_conflicts(tree, ['foo'],
123
self.assertEqual((tree_conflicts, ConflictList()),
124
tree_conflicts.select_conflicts(tree, ['foo'],
127
def test_resolve_conflicts_recursive(self):
128
tree = self.make_branch_and_tree('.')
129
self.build_tree(['dir/', 'dir/hello'])
130
tree.add(['dir', 'dir/hello'])
131
tree.set_conflicts(ConflictList([TextConflict('dir/hello')]))
132
resolve(tree, ['dir'], recursive=False, ignore_misses=True)
133
self.assertEqual(ConflictList([TextConflict('dir/hello')]),
135
resolve(tree, ['dir'], recursive=True, ignore_misses=True)
136
self.assertEqual(ConflictList([]),
140
class TestConflictStanzas(TestCase):
142
def test_stanza_roundtrip(self):
143
# write and read our example stanza.
144
stanza_iter = example_conflicts.to_stanzas()
145
processed = ConflictList.from_stanzas(stanza_iter)
146
for o, p in zip(processed, example_conflicts):
147
self.assertEqual(o, p)
149
self.assertIsInstance(o.path, unicode)
151
if o.file_id is not None:
152
self.assertIsInstance(o.file_id, str)
154
conflict_path = getattr(o, 'conflict_path', None)
155
if conflict_path is not None:
156
self.assertIsInstance(conflict_path, unicode)
158
conflict_file_id = getattr(o, 'conflict_file_id', None)
159
if conflict_file_id is not None:
160
self.assertIsInstance(conflict_file_id, str)
162
def test_stanzification(self):
163
for stanza in example_conflicts.to_stanzas():
164
if 'file_id' in stanza:
165
# In Stanza form, the file_id has to be unicode.
166
self.assertStartsWith(stanza['file_id'], u'\xeed')
167
self.assertStartsWith(stanza['path'], u'p\xe5th')
168
if 'conflict_path' in stanza:
169
self.assertStartsWith(stanza['conflict_path'], u'p\xe5th')
170
if 'conflict_file_id' in stanza:
171
self.assertStartsWith(stanza['conflict_file_id'], u'\xeed')