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)
143
class TestIntermediateRevisions(TestCaseInTempDir):
146
from bzrlib.commit import commit
147
TestCaseInTempDir.setUp(self)
148
self.br1, self.br2 = make_branches()
150
self.br2.commit("Commit eleven", rev_id="b@u-0-7")
151
self.br2.commit("Commit twelve", rev_id="b@u-0-8")
152
self.br2.commit("Commit thirtteen", rev_id="b@u-0-9")
154
fetch(from_branch=self.br2, to_branch=self.br1)
155
self.br1.add_pending_merge(self.br2.revision_history()[6])
156
self.br1.commit("Commit fourtten", rev_id="a@u-0-6")
158
fetch(from_branch=self.br1, to_branch=self.br2)
159
self.br2.add_pending_merge(self.br1.revision_history()[6])
160
self.br2.commit("Commit fifteen", rev_id="b@u-0-10")
162
from bzrlib.revision import MultipleRevisionSources
163
self.sources = MultipleRevisionSources(self.br1, self.br2)
165
def intervene(self, ancestor, revision, revision_history=None):
166
from bzrlib.revision import get_intervening_revisions
167
return get_intervening_revisions(ancestor,revision, self.sources,
170
def test_intervene(self):
171
"""Find intermediate revisions, without requiring history"""
172
from bzrlib.errors import NotAncestor, NoSuchRevision
173
assert len(self.intervene('a@u-0-0', 'a@u-0-0')) == 0
174
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-1'), ['a@u-0-1'])
175
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-2'),
176
['a@u-0-1', 'a@u-0-2'])
177
self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-3'),
178
['a@u-0-1', 'a@u-0-2', 'b@u-0-3'])
179
self.assertEqual(self.intervene('b@u-0-3', 'a@u-0-3'),
180
['b@u-0-4', 'a@u-0-3'])
181
self.assertEqual(self.intervene('a@u-0-2', 'a@u-0-3',
182
self.br1.revision_history()),
184
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-5',
185
self.br1.revision_history()),
186
['a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
188
print ("testrevision.py 191 - intervene appears to return b..6 even"
189
"though it is not reachable!")
190
# self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-6',
191
# self.br1.revision_history()),
192
# ['a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
194
# self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-5'),
195
# ['a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
197
self.assertEqual(self.intervene('b@u-0-3', 'b@u-0-6',
198
self.br2.revision_history()),
199
['b@u-0-4', 'b@u-0-5', 'b@u-0-6'])
200
self.assertEqual(self.intervene('b@u-0-6', 'b@u-0-10'),
201
['b@u-0-7', 'b@u-0-8', 'b@u-0-9', 'b@u-0-10'])
202
self.assertEqual(self.intervene('b@u-0-6', 'b@u-0-10',
203
self.br2.revision_history()),
204
['b@u-0-7', 'b@u-0-8', 'b@u-0-9', 'b@u-0-10'])
205
self.assertRaises(NotAncestor, self.intervene, 'b@u-0-10', 'b@u-0-6',
206
self.br2.revision_history())
207
self.assertRaises(NoSuchRevision, self.intervene, 'c@u-0-10',
208
'b@u-0-6', self.br2.revision_history())
209
self.assertRaises(NoSuchRevision, self.intervene, 'b@u-0-10',
210
'c@u-0-6', self.br2.revision_history())
213
class TestCommonAncestor(TestCaseInTempDir):
214
"""Test checking whether a revision is an ancestor of another revision"""
216
def test_old_common_ancestor(self):
217
"""Pick a resonable merge base using the old functionality"""
218
from bzrlib.revision import old_common_ancestor as common_ancestor
219
br1, br2 = make_branches()
220
revisions = br1.revision_history()
221
revisions_2 = br2.revision_history()
224
expected_ancestors_list = {revisions[3]:(0, 0),
226
revisions_2[4]:(2, 1),
228
revisions_2[3]:(4, 2),
229
revisions[0]:(5, 3) }
230
ancestors_list = find_present_ancestors(revisions[3], sources)
231
assert len(expected_ancestors_list) == len(ancestors_list)
232
for key, value in expected_ancestors_list.iteritems():
233
self.assertEqual(ancestors_list[key], value,
234
"key %r, %r != %r" % (key, ancestors_list[key],
237
self.assertEqual(common_ancestor(revisions[0], revisions[0], sources),
239
self.assertEqual(common_ancestor(revisions[1], revisions[2], sources),
241
self.assertEqual(common_ancestor(revisions[1], revisions[1], sources),
243
self.assertEqual(common_ancestor(revisions[2], revisions_2[4], sources),
245
self.assertEqual(common_ancestor(revisions[3], revisions_2[4], sources),
247
self.assertEqual(common_ancestor(revisions[4], revisions_2[5], sources),
249
fetch(from_branch=br2, to_branch=br1)
250
self.assertEqual(common_ancestor(revisions[5], revisions_2[6], sources),
252
self.assertEqual(common_ancestor(revisions_2[6], revisions[5], sources),
255
def test_common_ancestor(self):
256
"""Pick a reasonable merge base"""
257
from bzrlib.revision import common_ancestor
258
br1, br2 = make_branches()
259
revisions = br1.revision_history()
260
revisions_2 = br2.revision_history()
261
sources = MultipleRevisionSources(br1, br2)
262
expected_ancestors_list = {revisions[3]:(0, 0),
264
revisions_2[4]:(2, 1),
266
revisions_2[3]:(4, 2),
267
revisions[0]:(5, 3) }
268
ancestors_list = find_present_ancestors(revisions[3], sources)
269
assert len(expected_ancestors_list) == len(ancestors_list)
270
for key, value in expected_ancestors_list.iteritems():
271
self.assertEqual(ancestors_list[key], value,
272
"key %r, %r != %r" % (key, ancestors_list[key],
274
self.assertEqual(common_ancestor(revisions[0], revisions[0], sources),
276
self.assertEqual(common_ancestor(revisions[1], revisions[2], sources),
278
self.assertEqual(common_ancestor(revisions[1], revisions[1], sources),
280
self.assertEqual(common_ancestor(revisions[2], revisions_2[4], sources),
282
self.assertEqual(common_ancestor(revisions[3], revisions_2[4], sources),
284
self.assertEqual(common_ancestor(revisions[4], revisions_2[5], sources),
286
self.assertEqual(common_ancestor(revisions[5], revisions_2[6], sources),
288
self.assertEqual(common_ancestor(revisions_2[6], revisions[5], sources),
291
def test_combined(self):
293
Ensure it's not order-sensitive
295
br1, br2 = make_branches()
296
source = MultipleRevisionSources(br1, br2)
297
combined_1 = combined_graph(br1.last_revision(),
298
br2.last_revision(), source)
299
combined_2 = combined_graph(br2.last_revision(),
300
br1.last_revision(), source)
301
assert combined_1[1] == combined_2[1]
302
assert combined_1[2] == combined_2[2]
303
assert combined_1[3] == combined_2[3]
304
assert combined_1 == combined_2