1
# Copyright (C) 2007-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
18
"""Tests of the 'brz bisect' command."""
28
TestCaseWithTransport,
31
from ...controldir import ControlDir
34
class BisectTestCase(TestCaseWithTransport):
35
"""Test harness specific to the bisect plugin."""
37
def assertRevno(self, rev):
38
"""Make sure we're at the right revision."""
40
rev_contents = {1: "one", 1.1: "one dot one", 1.2: "one dot two",
41
1.3: "one dot three", 2: "two", 3: "three",
44
test_file = open("test_file")
45
content = test_file.read().strip()
46
if content != rev_contents[rev]:
47
rev_ids = dict((rev_contents[k], k) for k in rev_contents.keys())
48
found_rev = rev_ids[content]
49
raise AssertionError("expected rev %0.1f, found rev %0.1f"
55
# These tests assume a branch with five revisions, and
56
# a branch from version 1 containing three revisions
57
# merged at version 2.
59
TestCaseWithTransport.setUp(self)
61
self.tree = self.make_branch_and_tree(".")
63
test_file = open("test_file", "w")
64
test_file.write("one")
66
self.tree.add(self.tree.relpath(os.path.join(os.getcwd(),
68
test_file_append = open("test_file_append", "a")
69
test_file_append.write("one\n")
70
test_file_append.close()
71
self.tree.add(self.tree.relpath(os.path.join(os.getcwd(),
73
self.tree.commit(message="add test files")
75
ControlDir.open(".").sprout("../temp-clone")
76
clone_controldir = ControlDir.open("../temp-clone")
77
clone_tree = clone_controldir.open_workingtree()
78
for content in ["one dot one", "one dot two", "one dot three"]:
79
test_file = open("../temp-clone/test_file", "w")
80
test_file.write(content)
82
test_file_append = open("../temp-clone/test_file_append", "a")
83
test_file_append.write(content + "\n")
84
test_file_append.close()
85
clone_tree.commit(message="make branch test change")
86
saved_subtree_revid = clone_tree.branch.last_revision()
88
self.tree.merge_from_branch(clone_tree.branch)
89
test_file = open("test_file", "w")
90
test_file.write("two")
92
test_file_append = open("test_file_append", "a")
93
test_file_append.write("two\n")
94
test_file_append.close()
95
self.tree.commit(message="merge external branch")
96
shutil.rmtree("../temp-clone")
98
self.subtree_rev = saved_subtree_revid
100
file_contents = ["three", "four", "five"]
101
for content in file_contents:
102
test_file = open("test_file", "w")
103
test_file.write(content)
105
test_file_append = open("test_file_append", "a")
106
test_file_append.write(content + "\n")
107
test_file_append.close()
108
self.tree.commit(message="make test change")
110
def testWorkflow(self):
111
"""Run through a basic usage scenario."""
113
# Start up the bisection. When the two ends are set, we should
114
# end up in the middle.
116
self.run_bzr(['bisect', 'start'])
117
self.run_bzr(['bisect', 'yes'])
118
self.run_bzr(['bisect', 'no', '-r', '1'])
121
# Mark feature as present in the middle. Should move us
122
# halfway back between the current middle and the start.
124
self.run_bzr(['bisect', 'yes'])
127
# Mark feature as not present. Since this is only one
128
# rev back from the lowest marked revision with the feature,
129
# the process should end, with the current rev set to the
132
self.run_bzr(['bisect', 'no'])
135
# Run again. Since we're done, this should do nothing.
137
self.run_bzr(['bisect', 'no'])
140
def testWorkflowSubtree(self):
141
"""Run through a usage scenario where the offending change
144
# Similar to testWorkflow, but make sure the plugin traverses
145
# subtrees when the "final" revision is a merge point.
147
# This part is similar to testWorkflow.
149
self.run_bzr(['bisect', 'start'])
150
self.run_bzr(['bisect', 'yes'])
151
self.run_bzr(['bisect', 'no', '-r', '1'])
152
self.run_bzr(['bisect', 'yes'])
154
# Check to make sure we're where we expect to be.
158
# Now, mark the merge point revno, meaning the feature
159
# appeared at a merge point.
161
self.run_bzr(['bisect', 'yes'])
162
self.assertRevno(1.2)
164
# Continue bisecting along the subtree to the real conclusion.
166
self.run_bzr(['bisect', 'yes'])
167
self.assertRevno(1.1)
168
self.run_bzr(['bisect', 'yes'])
169
self.assertRevno(1.1)
171
# Run again. Since we're done, this should do nothing.
173
self.run_bzr(['bisect', 'yes'])
174
self.assertRevno(1.1)
177
"""Test manually moving to a different revision during the bisection."""
179
# Set up a bisection in progress.
181
self.run_bzr(['bisect', 'start'])
182
self.run_bzr(['bisect', 'yes'])
183
self.run_bzr(['bisect', 'no', '-r', '1'])
187
self.run_bzr(['bisect', 'move', '-r', '2'])
191
"""Test resetting the tree."""
193
# Set up a bisection in progress.
195
self.run_bzr(['bisect', 'start'])
196
self.run_bzr(['bisect', 'yes'])
197
self.run_bzr(['bisect', 'no', '-r', '1'])
198
self.run_bzr(['bisect', 'yes'])
202
self.run_bzr(['bisect', 'reset'])
205
# Check that reset doesn't do anything unless there's a
206
# bisection in progress.
208
test_file = open("test_file", "w")
209
test_file.write("keep me")
212
out, err = self.run_bzr(['bisect', 'reset'], retcode=3)
213
self.assertIn("No bisection in progress.", err)
215
test_file = open("test_file")
216
content = test_file.read().strip()
218
self.assertEqual(content, "keep me")
221
"""Test saving the current bisection state, and re-loading it."""
223
# Set up a bisection in progress.
225
self.run_bzr(['bisect', 'start'])
226
self.run_bzr(['bisect', 'yes'])
227
self.run_bzr(['bisect', 'no', '-r', '1'])
228
self.run_bzr(['bisect', 'yes'])
232
self.run_bzr(['bisect', 'log', '-o', 'bisect_log'])
236
self.run_bzr(['bisect', 'reset'])
240
self.run_bzr(['bisect', 'replay', 'bisect_log'])
243
# Mark another state, and see if the bisect moves in the
246
self.run_bzr(['bisect', 'no'])
249
def testRunScript(self):
250
"""Make a test script and run it."""
251
test_script = open("test_script", "w")
252
test_script.write("#!/bin/sh\n"
253
"grep -q '^four' test_file_append\n")
255
os.chmod("test_script", stat.S_IRWXU)
256
self.run_bzr(['bisect', 'start'])
257
self.run_bzr(['bisect', 'yes'])
258
self.run_bzr(['bisect', 'no', '-r', '1'])
259
self.run_bzr(['bisect', 'run', './test_script'])
262
def testRunScriptMergePoint(self):
263
"""Make a test script and run it."""
264
if sys.platform == "win32":
265
raise TestSkipped("Unable to run shell script on windows")
266
test_script = open("test_script", "w")
267
test_script.write("#!/bin/sh\n"
268
"grep -q '^two' test_file_append\n")
270
os.chmod("test_script", stat.S_IRWXU)
271
self.run_bzr(['bisect', 'start'])
272
self.run_bzr(['bisect', 'yes'])
273
self.run_bzr(['bisect', 'no', '-r', '1'])
274
self.run_bzr(['bisect', 'run', './test_script'])
277
except AssertionError:
278
raise KnownFailure("bisect does not drill down into merge commits: "
279
"https://bugs.launchpad.net/bzr-bisect/+bug/539937")
281
def testRunScriptSubtree(self):
282
"""Make a test script and run it."""
283
if sys.platform == "win32":
284
raise TestSkipped("Unable to run shell script on windows")
285
test_script = open("test_script", "w")
286
test_script.write("#!/bin/sh\n"
287
"grep -q '^one dot two' test_file_append\n")
289
os.chmod("test_script", stat.S_IRWXU)
290
self.run_bzr(['bisect', 'start'])
291
self.run_bzr(['bisect', 'yes'])
292
self.run_bzr(['bisect', 'no', '-r', '1'])
293
self.run_bzr(['bisect', 'run', './test_script'])
295
self.assertRevno(1.2)
296
except AssertionError:
297
raise KnownFailure("bisect does not drill down into merge commits: "
298
"https://bugs.launchpad.net/bzr-bisect/+bug/539937")