14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
from bzrlib.selftest import InTempDir
20
from bzrlib.selftest import TestCaseInTempDir
21
from bzrlib.branch import Branch
22
from bzrlib.commit import commit
23
from bzrlib.fetch import fetch
24
from bzrlib.revision import (find_present_ancestors, combined_graph,
25
is_ancestor, MultipleRevisionSources)
26
from bzrlib.trace import mutter
27
from bzrlib.errors import NoSuchRevision
20
29
def make_branches():
21
from bzrlib.branch import Branch
22
from bzrlib.commit import commit
30
"""Create two branches
32
branch 1 has 6 commits, branch 2 has 3 commits
33
commit 10 was a psuedo merge from branch 1
34
but has been disabled until ghost support is
47
so A is missing b6 at the start
48
and B is missing a3, a4, a5
24
50
os.mkdir("branch1")
25
br1 = Branch("branch1", init=True)
26
commit(br1, "Commit one")
27
commit(br1, "Commit two")
28
commit(br1, "Commit three")
51
br1 = Branch.initialize("branch1")
53
commit(br1, "Commit one", rev_id="a@u-0-0")
54
commit(br1, "Commit two", rev_id="a@u-0-1")
55
commit(br1, "Commit three", rev_id="a@u-0-2")
30
57
os.mkdir("branch2")
31
br2 = Branch("branch2", init=True)
58
br2 = Branch.initialize("branch2")
32
59
br2.update_revisions(br1)
33
commit(br2, "Commit four")
34
commit(br2, "Commit five")
60
commit(br2, "Commit four", rev_id="b@u-0-3")
61
commit(br2, "Commit five", rev_id="b@u-0-4")
35
62
revisions_2 = br2.revision_history()
64
fetch(from_branch=br2, to_branch=br1)
36
65
br1.add_pending_merge(revisions_2[4])
37
commit(br1, "Commit six")
66
assert revisions_2[4] == 'b@u-0-4'
67
commit(br1, "Commit six", rev_id="a@u-0-3")
68
commit(br1, "Commit seven", rev_id="a@u-0-4")
69
commit(br2, "Commit eight", rev_id="b@u-0-5")
71
fetch(from_branch=br2, to_branch=br1)
72
br1.add_pending_merge(br2.revision_history()[5])
73
commit(br1, "Commit nine", rev_id="a@u-0-5")
74
# disabled - it makes testing fetch too hard,
75
# but can be easily reenabled (without the fetch
76
# when GHOSTS are supported. RBC 20050928
77
#fetch(from_branch=br1, to_branch=br2)
78
#br2.add_pending_merge(br1.revision_history()[4])
79
commit(br2, "Commit ten - no merge", rev_id="b@u-0-6")
81
#fetch(from_branch=br2, to_branch=br1)
41
class TestIsAncestor(InTempDir):
42
"""Test checking whether a revision is an ancestor of another revision"""
44
from bzrlib.revision import is_ancestor, MultipleRevisionSources
45
from bzrlib.errors import NoSuchRevision
86
class TestIsAncestor(TestCaseInTempDir):
87
def test_recorded_ancestry(self):
88
"""Test that commit records all ancestors"""
89
br1, br2 = make_branches()
90
d = [('a@u-0-0', ['a@u-0-0']),
91
('a@u-0-1', ['a@u-0-0', 'a@u-0-1']),
92
('a@u-0-2', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2']),
93
('b@u-0-3', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3']),
94
('b@u-0-4', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3',
96
('a@u-0-3', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
98
('a@u-0-4', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
99
'a@u-0-3', 'a@u-0-4']),
100
('b@u-0-5', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
102
('a@u-0-5', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
103
'b@u-0-3', 'b@u-0-4',
104
'b@u-0-5', 'a@u-0-5']),
105
('b@u-0-6', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2',
106
'b@u-0-3', 'b@u-0-4',
107
'b@u-0-5', 'b@u-0-6']),
109
br1_only = ('a@u-0-3', 'a@u-0-4', 'a@u-0-5')
110
br2_only = ('b@u-0-6',)
111
for branch in br1, br2:
112
for rev_id, anc in d:
113
if rev_id in br1_only and not branch is br1:
115
if rev_id in br2_only and not branch is br2:
117
mutter('ancestry of {%s}: %r',
118
rev_id, branch.get_ancestry(rev_id))
119
self.assertEquals(sorted(branch.get_ancestry(rev_id)),
120
[None] + sorted(anc))
123
def test_is_ancestor(self):
124
"""Test checking whether a revision is an ancestor of another revision"""
46
125
br1, br2 = make_branches()
47
126
revisions = br1.revision_history()
48
127
revisions_2 = br2.revision_history()
49
sources = MultipleRevisionSources(br1, br2)
51
assert is_ancestor(revisions[0], revisions[0], sources)
130
assert is_ancestor(revisions[0], revisions[0], br1)
52
131
assert is_ancestor(revisions[1], revisions[0], sources)
53
132
assert not is_ancestor(revisions[0], revisions[1], sources)
54
133
assert is_ancestor(revisions_2[3], revisions[0], sources)
55
self.assertRaises(NoSuchRevision, is_ancestor, revisions_2[3],
134
# disabled mbp 20050914, doesn't seem to happen anymore
135
## self.assertRaises(NoSuchRevision, is_ancestor, revisions_2[3],
136
## revisions[0], br1)
57
137
assert is_ancestor(revisions[3], revisions_2[4], sources)
58
138
assert is_ancestor(revisions[3], revisions_2[4], br1)
59
139
assert is_ancestor(revisions[3], revisions_2[3], sources)
60
assert not is_ancestor(revisions[3], revisions_2[3], br1)
140
## assert not is_ancestor(revisions[3], revisions_2[3], br1)
144
class TestIntermediateRevisions(TestCaseInTempDir):
147
from bzrlib.commit import commit
148
TestCaseInTempDir.setUp(self)
149
self.br1, self.br2 = make_branches()
151
self.br2.commit("Commit eleven", rev_id="b@u-0-7")
152
self.br2.commit("Commit twelve", rev_id="b@u-0-8")
153
self.br2.commit("Commit thirtteen", rev_id="b@u-0-9")
155
fetch(from_branch=self.br2, to_branch=self.br1)
156
self.br1.add_pending_merge(self.br2.revision_history()[6])
157
self.br1.commit("Commit fourtten", rev_id="a@u-0-6")
159
fetch(from_branch=self.br1, to_branch=self.br2)
160
self.br2.add_pending_merge(self.br1.revision_history()[6])
161
self.br2.commit("Commit fifteen", rev_id="b@u-0-10")
163
from bzrlib.revision import MultipleRevisionSources
164
self.sources = MultipleRevisionSources(self.br1, self.br2)
166
def intervene(self, ancestor, revision, revision_history=None):
167
from bzrlib.revision import get_intervening_revisions
168
return get_intervening_revisions(ancestor,revision, self.sources,
171
def test_intervene(self):
172
"""Find intermediate revisions, without requiring history"""
173
from bzrlib.errors import NotAncestor, NoSuchRevision
174
assert len(self.intervene('a@u-0-0', 'a@u-0-0')) == 0
175
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-1'), ['a@u-0-1'])
176
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-2'),
177
['a@u-0-1', 'a@u-0-2'])
178
self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-3'),
179
['a@u-0-1', 'a@u-0-2', 'b@u-0-3'])
180
self.assertEqual(self.intervene('b@u-0-3', 'a@u-0-3'),
181
['b@u-0-4', 'a@u-0-3'])
182
self.assertEqual(self.intervene('a@u-0-2', 'a@u-0-3',
183
self.br1.revision_history()),
185
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-5',
186
self.br1.revision_history()),
187
['a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
189
print ("testrevision.py 191 - intervene appears to return b..6 even"
190
"though it is not reachable!")
191
# self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-6',
192
# self.br1.revision_history()),
193
# ['a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
195
# self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-5'),
196
# ['a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
198
self.assertEqual(self.intervene('b@u-0-3', 'b@u-0-6',
199
self.br2.revision_history()),
200
['b@u-0-4', 'b@u-0-5', 'b@u-0-6'])
201
self.assertEqual(self.intervene('b@u-0-6', 'b@u-0-10'),
202
['b@u-0-7', 'b@u-0-8', 'b@u-0-9', 'b@u-0-10'])
203
self.assertEqual(self.intervene('b@u-0-6', 'b@u-0-10',
204
self.br2.revision_history()),
205
['b@u-0-7', 'b@u-0-8', 'b@u-0-9', 'b@u-0-10'])
206
self.assertRaises(NotAncestor, self.intervene, 'b@u-0-10', 'b@u-0-6',
207
self.br2.revision_history())
208
self.assertRaises(NoSuchRevision, self.intervene, 'c@u-0-10',
209
'b@u-0-6', self.br2.revision_history())
210
self.assertRaises(NoSuchRevision, self.intervene, 'b@u-0-10',
211
'c@u-0-6', self.br2.revision_history())
214
class TestCommonAncestor(TestCaseInTempDir):
215
"""Test checking whether a revision is an ancestor of another revision"""
217
def test_old_common_ancestor(self):
218
"""Pick a resonable merge base using the old functionality"""
219
from bzrlib.revision import old_common_ancestor as common_ancestor
220
br1, br2 = make_branches()
221
revisions = br1.revision_history()
222
revisions_2 = br2.revision_history()
225
expected_ancestors_list = {revisions[3]:(0, 0),
227
revisions_2[4]:(2, 1),
229
revisions_2[3]:(4, 2),
230
revisions[0]:(5, 3) }
231
ancestors_list = find_present_ancestors(revisions[3], sources)
232
assert len(expected_ancestors_list) == len(ancestors_list)
233
for key, value in expected_ancestors_list.iteritems():
234
self.assertEqual(ancestors_list[key], value,
235
"key %r, %r != %r" % (key, ancestors_list[key],
238
self.assertEqual(common_ancestor(revisions[0], revisions[0], sources),
240
self.assertEqual(common_ancestor(revisions[1], revisions[2], sources),
242
self.assertEqual(common_ancestor(revisions[1], revisions[1], sources),
244
self.assertEqual(common_ancestor(revisions[2], revisions_2[4], sources),
246
self.assertEqual(common_ancestor(revisions[3], revisions_2[4], sources),
248
self.assertEqual(common_ancestor(revisions[4], revisions_2[5], sources),
250
fetch(from_branch=br2, to_branch=br1)
251
self.assertEqual(common_ancestor(revisions[5], revisions_2[6], sources),
253
self.assertEqual(common_ancestor(revisions_2[6], revisions[5], sources),
256
def test_common_ancestor(self):
257
"""Pick a reasonable merge base"""
258
from bzrlib.revision import common_ancestor
259
br1, br2 = make_branches()
260
revisions = br1.revision_history()
261
revisions_2 = br2.revision_history()
262
sources = MultipleRevisionSources(br1, br2)
264
expected_ancestors_list = {revisions[3]:(0, 0),
266
revisions_2[4]:(2, 1),
268
revisions_2[3]:(4, 2),
269
revisions[0]:(5, 3) }
270
ancestors_list = find_present_ancestors(revisions[3], sources)
271
assert len(expected_ancestors_list) == len(ancestors_list)
272
for key, value in expected_ancestors_list.iteritems():
273
self.assertEqual(ancestors_list[key], value,
274
"key %r, %r != %r" % (key, ancestors_list[key],
277
self.assertEqual(common_ancestor(revisions[0], revisions[0], sources),
279
self.assertEqual(common_ancestor(revisions[1], revisions[2], sources),
281
self.assertEqual(common_ancestor(revisions[1], revisions[1], sources),
283
self.assertEqual(common_ancestor(revisions[2], revisions_2[4], sources),
285
self.assertEqual(common_ancestor(revisions[3], revisions_2[4], sources),
287
self.assertEqual(common_ancestor(revisions[4], revisions_2[5], sources),
289
self.assertEqual(common_ancestor(revisions[5], revisions_2[6], sources),
291
self.assertEqual(common_ancestor(revisions_2[6], revisions[5], sources),
294
def test_combined(self):
296
Ensure it's not order-sensitive
298
br1, br2 = make_branches()
299
source = MultipleRevisionSources(br1, br2)
300
combined_1 = combined_graph(br1.last_revision(),
301
br2.last_revision(), source)
302
combined_2 = combined_graph(br2.last_revision(),
303
br1.last_revision(), source)
304
assert combined_1[1] == combined_2[1]
305
assert combined_1[2] == combined_2[2]
306
assert combined_1[3] == combined_2[3]
307
assert combined_1 == combined_2