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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"Test suite for the bzr bisect plugin."
19
from __future__ import absolute_import
21
from cStringIO import StringIO
28
from ...bzrdir import BzrDir
31
from ...tests import (
33
TestCaseWithTransport,
37
class BisectTestCase(TestCaseWithTransport):
38
"""Test harness specific to the bisect plugin."""
40
def assertRevno(self, rev):
41
"""Make sure we're at the right revision."""
43
rev_contents = {1: "one", 1.1: "one dot one", 1.2: "one dot two",
44
1.3: "one dot three", 2: "two", 3: "three",
47
test_file = open("test_file")
48
content = test_file.read().strip()
49
if content != rev_contents[rev]:
50
rev_ids = dict((rev_contents[k], k) for k in rev_contents.keys())
51
found_rev = rev_ids[content]
52
raise AssertionError("expected rev %0.1f, found rev %0.1f"
58
# These tests assume a branch with five revisions, and
59
# a branch from version 1 containing three revisions
60
# merged at version 2.
62
TestCaseWithTransport.setUp(self)
64
self.tree = self.make_branch_and_tree(".")
66
test_file = open("test_file", "w")
67
test_file.write("one")
69
self.tree.add(self.tree.relpath(os.path.join(os.getcwd(),
71
test_file_append = open("test_file_append", "a")
72
test_file_append.write("one\n")
73
test_file_append.close()
74
self.tree.add(self.tree.relpath(os.path.join(os.getcwd(),
76
self.tree.commit(message = "add test files")
78
BzrDir.open(".").sprout("../temp-clone")
79
clone_bzrdir = BzrDir.open("../temp-clone")
80
clone_tree = clone_bzrdir.open_workingtree()
81
for content in ["one dot one", "one dot two", "one dot three"]:
82
test_file = open("../temp-clone/test_file", "w")
83
test_file.write(content)
85
test_file_append = open("../temp-clone/test_file_append", "a")
86
test_file_append.write(content + "\n")
87
test_file_append.close()
88
clone_tree.commit(message = "make branch test change")
89
saved_subtree_revid = clone_tree.branch.last_revision()
91
self.tree.merge_from_branch(clone_tree.branch)
92
test_file = open("test_file", "w")
93
test_file.write("two")
95
test_file_append = open("test_file_append", "a")
96
test_file_append.write("two\n")
97
test_file_append.close()
98
self.tree.commit(message = "merge external branch")
99
shutil.rmtree("../temp-clone")
101
self.subtree_rev = saved_subtree_revid
103
file_contents = ["three", "four", "five"]
104
for content in file_contents:
105
test_file = open("test_file", "w")
106
test_file.write(content)
108
test_file_append = open("test_file_append", "a")
109
test_file_append.write(content + "\n")
110
test_file_append.close()
111
self.tree.commit(message = "make test change")
114
class BisectHarnessTests(BisectTestCase):
115
"""Tests for the harness itself."""
117
def testLastRev(self):
118
"""Test that the last revision is correct."""
119
repo = self.tree.branch.repository
120
top_revtree = repo.revision_tree(self.tree.last_revision())
121
top_revtree.lock_read()
122
top_file = top_revtree.get_file(top_revtree.path2id("test_file"))
123
test_content = top_file.read().strip()
126
assert test_content == "five"
128
def testSubtreeRev(self):
129
"""Test that the last revision in a subtree is correct."""
130
repo = self.tree.branch.repository
131
sub_revtree = repo.revision_tree(self.subtree_rev)
132
sub_revtree.lock_read()
133
sub_file = sub_revtree.get_file(sub_revtree.path2id("test_file"))
134
test_content = sub_file.read().strip()
137
assert test_content == "one dot three"
140
class BisectCurrentUnitTests(BisectTestCase):
141
"""Test the BisectCurrent class."""
143
def testShowLog(self):
144
"""Test that the log can be shown."""
145
# Not a very good test; just makes sure the code doesn't fail,
146
# not that the output makes any sense.
148
cmds.BisectCurrent().show_rev_log(out=sio)
150
def testShowLogSubtree(self):
151
"""Test that a subtree's log can be shown."""
152
current = cmds.BisectCurrent()
153
current.switch(self.subtree_rev)
155
current.show_rev_log(out=sio)
157
def testSwitchVersions(self):
158
"""Test switching versions."""
159
current = cmds.BisectCurrent()
165
"""Test resetting the working tree to a non-bisected state."""
166
current = cmds.BisectCurrent()
170
assert not os.path.exists(cmds.bisect_rev_path)
172
def testIsMergePoint(self):
173
"""Test merge point detection."""
174
current = cmds.BisectCurrent()
176
assert not current.is_merge_point()
178
assert current.is_merge_point()
181
class BisectLogUnitTests(BisectTestCase):
182
"""Test the BisectLog class."""
184
def testCreateBlank(self):
185
"""Test creation of new log."""
186
bisect_log = cmds.BisectLog()
188
assert os.path.exists(cmds.bisect_info_path)
191
"""Test loading a log."""
192
preloaded_log = open(cmds.bisect_info_path, "w")
193
preloaded_log.write("rev1 yes\nrev2 no\nrev3 yes\n")
194
preloaded_log.close()
196
bisect_log = cmds.BisectLog()
197
assert len(bisect_log._items) == 3
198
assert bisect_log._items[0] == ("rev1", "yes")
199
assert bisect_log._items[1] == ("rev2", "no")
200
assert bisect_log._items[2] == ("rev3", "yes")
203
"""Test saving the log."""
204
bisect_log = cmds.BisectLog()
205
bisect_log._items = [("rev1", "yes"), ("rev2", "no"), ("rev3", "yes")]
208
logfile = open(cmds.bisect_info_path)
209
assert logfile.read() == "rev1 yes\nrev2 no\nrev3 yes\n"
212
class BisectFuncTests(BisectTestCase):
213
"""Functional tests for the bisect plugin."""
215
def testWorkflow(self):
216
"""Run through a basic usage scenario."""
218
# Start up the bisection. When the two ends are set, we should
219
# end up in the middle.
221
self.run_bzr(['bisect', 'start'])
222
self.run_bzr(['bisect', 'yes'])
223
self.run_bzr(['bisect', 'no', '-r', '1'])
226
# Mark feature as present in the middle. Should move us
227
# halfway back between the current middle and the start.
229
self.run_bzr(['bisect', 'yes'])
232
# Mark feature as not present. Since this is only one
233
# rev back from the lowest marked revision with the feature,
234
# the process should end, with the current rev set to the
237
self.run_bzr(['bisect', 'no'])
240
# Run again. Since we're done, this should do nothing.
242
self.run_bzr(['bisect', 'no'])
245
def testWorkflowSubtree(self):
246
"""Run through a usage scenario where the offending change
249
# Similar to testWorkflow, but make sure the plugin traverses
250
# subtrees when the "final" revision is a merge point.
252
# This part is similar to testWorkflow.
254
self.run_bzr(['bisect', 'start'])
255
self.run_bzr(['bisect', 'yes'])
256
self.run_bzr(['bisect', 'no', '-r', '1'])
257
self.run_bzr(['bisect', 'yes'])
259
# Check to make sure we're where we expect to be.
263
# Now, mark the merge point revno, meaning the feature
264
# appeared at a merge point.
266
self.run_bzr(['bisect', 'yes'])
267
self.assertRevno(1.2)
269
# Continue bisecting along the subtree to the real conclusion.
271
self.run_bzr(['bisect', 'yes'])
272
self.assertRevno(1.1)
273
self.run_bzr(['bisect', 'yes'])
274
self.assertRevno(1.1)
276
# Run again. Since we're done, this should do nothing.
278
self.run_bzr(['bisect', 'yes'])
279
self.assertRevno(1.1)
282
"""Test manually moving to a different revision during the bisection."""
284
# Set up a bisection in progress.
286
self.run_bzr(['bisect', 'start'])
287
self.run_bzr(['bisect', 'yes'])
288
self.run_bzr(['bisect', 'no', '-r', '1'])
292
self.run_bzr(['bisect', 'move', '-r', '2'])
296
"""Test resetting the tree."""
298
# Set up a bisection in progress.
300
self.run_bzr(['bisect', 'start'])
301
self.run_bzr(['bisect', 'yes'])
302
self.run_bzr(['bisect', 'no', '-r', '1'])
303
self.run_bzr(['bisect', 'yes'])
307
self.run_bzr(['bisect', 'reset'])
310
# Check that reset doesn't do anything unless there's a
311
# bisection in progress.
313
test_file = open("test_file", "w")
314
test_file.write("keep me")
317
out, err = self.run_bzr(['bisect', 'reset'], retcode=3)
318
self.assertIn("No bisection in progress.", err)
320
test_file = open("test_file")
321
content = test_file.read().strip()
323
self.assertEqual(content, "keep me")
326
"""Test saving the current bisection state, and re-loading it."""
328
# Set up a bisection in progress.
330
self.run_bzr(['bisect', 'start'])
331
self.run_bzr(['bisect', 'yes'])
332
self.run_bzr(['bisect', 'no', '-r', '1'])
333
self.run_bzr(['bisect', 'yes'])
337
self.run_bzr(['bisect', 'log', '-o', 'bisect_log'])
341
self.run_bzr(['bisect', 'reset'])
345
self.run_bzr(['bisect', 'replay', 'bisect_log'])
348
# Mark another state, and see if the bisect moves in the
351
self.run_bzr(['bisect', 'no'])
354
def testRunScript(self):
355
"""Make a test script and run it."""
356
test_script = open("test_script", "w")
357
test_script.write("#!/bin/sh\n"
358
"grep -q '^four' test_file_append\n")
360
os.chmod("test_script", stat.S_IRWXU)
361
self.run_bzr(['bisect', 'start'])
362
self.run_bzr(['bisect', 'yes'])
363
self.run_bzr(['bisect', 'no', '-r', '1'])
364
self.run_bzr(['bisect', 'run', './test_script'])
367
def testRunScriptMergePoint(self):
368
"""Make a test script and run it."""
369
if sys.platform == "win32":
370
raise TestSkipped("Unable to run shell script on windows")
371
test_script = open("test_script", "w")
372
test_script.write("#!/bin/sh\n"
373
"grep -q '^two' test_file_append\n")
375
os.chmod("test_script", stat.S_IRWXU)
376
self.run_bzr(['bisect', 'start'])
377
self.run_bzr(['bisect', 'yes'])
378
self.run_bzr(['bisect', 'no', '-r', '1'])
379
self.run_bzr(['bisect', 'run', './test_script'])
382
except AssertionError:
384
("bisect does not drill down into merge commits: "
385
"https://bugs.launchpad.net/bzr-bisect/+bug/539937")
387
def testRunScriptSubtree(self):
388
"""Make a test script and run it."""
389
if sys.platform == "win32":
390
raise TestSkipped("Unable to run shell script on windows")
391
test_script = open("test_script", "w")
392
test_script.write("#!/bin/sh\n"
393
"grep -q '^one dot two' test_file_append\n")
395
os.chmod("test_script", stat.S_IRWXU)
396
self.run_bzr(['bisect', 'start'])
397
self.run_bzr(['bisect', 'yes'])
398
self.run_bzr(['bisect', 'no', '-r', '1'])
399
self.run_bzr(['bisect', 'run', './test_script'])
401
self.assertRevno(1.2)
402
except AssertionError:
404
("bisect does not drill down into merge commits: "
405
"https://bugs.launchpad.net/bzr-bisect/+bug/539937")