/breezy/unstable

To get this branch, use:
bzr branch https://code.breezy-vcs.org/breezy/unstable

« back to all changes in this revision

Viewing changes to breezy/plugins/bisect/tests.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-24 01:39:33 UTC
  • mfrom: (3815.3776.6)
  • Revision ID: jelmer@jelmer.uk-20170524013933-ir4y4tqtrsiz2ka2
New upstream snapshot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007-2010 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
"Test suite for the bzr bisect plugin."
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
from cStringIO import StringIO
 
22
import os
 
23
import stat
 
24
import sys
 
25
import shutil
 
26
 
 
27
import breezy
 
28
from ...bzrdir import BzrDir
 
29
from .. import bisect
 
30
from . import cmds
 
31
from ...tests import (
 
32
    KnownFailure,
 
33
    TestCaseWithTransport,
 
34
    TestSkipped,
 
35
    )
 
36
 
 
37
class BisectTestCase(TestCaseWithTransport):
 
38
    """Test harness specific to the bisect plugin."""
 
39
 
 
40
    def assertRevno(self, rev):
 
41
        """Make sure we're at the right revision."""
 
42
 
 
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",
 
45
                        4: "four", 5: "five"}
 
46
 
 
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"
 
53
                                 % (rev, found_rev))
 
54
 
 
55
    def setUp(self):
 
56
        """Set up tests."""
 
57
 
 
58
        # These tests assume a branch with five revisions, and
 
59
        # a branch from version 1 containing three revisions
 
60
        # merged at version 2.
 
61
 
 
62
        TestCaseWithTransport.setUp(self)
 
63
 
 
64
        self.tree = self.make_branch_and_tree(".")
 
65
 
 
66
        test_file = open("test_file", "w")
 
67
        test_file.write("one")
 
68
        test_file.close()
 
69
        self.tree.add(self.tree.relpath(os.path.join(os.getcwd(),
 
70
                                                     'test_file')))
 
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(),
 
75
                                                     'test_file_append')))
 
76
        self.tree.commit(message = "add test files")
 
77
 
 
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)
 
84
            test_file.close()
 
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()
 
90
 
 
91
        self.tree.merge_from_branch(clone_tree.branch)
 
92
        test_file = open("test_file", "w")
 
93
        test_file.write("two")
 
94
        test_file.close()
 
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")
 
100
 
 
101
        self.subtree_rev = saved_subtree_revid
 
102
 
 
103
        file_contents = ["three", "four", "five"]
 
104
        for content in file_contents:
 
105
            test_file = open("test_file", "w")
 
106
            test_file.write(content)
 
107
            test_file.close()
 
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")
 
112
 
 
113
 
 
114
class BisectHarnessTests(BisectTestCase):
 
115
    """Tests for the harness itself."""
 
116
 
 
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()
 
124
        top_file.close()
 
125
        top_revtree.unlock()
 
126
        assert test_content == "five"
 
127
 
 
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()
 
135
        sub_file.close()
 
136
        sub_revtree.unlock()
 
137
        assert test_content == "one dot three"
 
138
 
 
139
 
 
140
class BisectCurrentUnitTests(BisectTestCase):
 
141
    """Test the BisectCurrent class."""
 
142
 
 
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.
 
147
        sio = StringIO()
 
148
        cmds.BisectCurrent().show_rev_log(out=sio)
 
149
 
 
150
    def testShowLogSubtree(self):
 
151
        """Test that a subtree's log can be shown."""
 
152
        current = cmds.BisectCurrent()
 
153
        current.switch(self.subtree_rev)
 
154
        sio = StringIO()
 
155
        current.show_rev_log(out=sio)
 
156
 
 
157
    def testSwitchVersions(self):
 
158
        """Test switching versions."""
 
159
        current = cmds.BisectCurrent()
 
160
        self.assertRevno(5)
 
161
        current.switch(4)
 
162
        self.assertRevno(4)
 
163
 
 
164
    def testReset(self):
 
165
        """Test resetting the working tree to a non-bisected state."""
 
166
        current = cmds.BisectCurrent()
 
167
        current.switch(4)
 
168
        current.reset()
 
169
        self.assertRevno(5)
 
170
        assert not os.path.exists(cmds.bisect_rev_path)
 
171
 
 
172
    def testIsMergePoint(self):
 
173
        """Test merge point detection."""
 
174
        current = cmds.BisectCurrent()
 
175
        self.assertRevno(5)
 
176
        assert not current.is_merge_point()
 
177
        current.switch(2)
 
178
        assert current.is_merge_point()
 
179
 
 
180
 
 
181
class BisectLogUnitTests(BisectTestCase):
 
182
    """Test the BisectLog class."""
 
183
 
 
184
    def testCreateBlank(self):
 
185
        """Test creation of new log."""
 
186
        bisect_log = cmds.BisectLog()
 
187
        bisect_log.save()
 
188
        assert os.path.exists(cmds.bisect_info_path)
 
189
 
 
190
    def testLoad(self):
 
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()
 
195
 
 
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")
 
201
 
 
202
    def testSave(self):
 
203
        """Test saving the log."""
 
204
        bisect_log = cmds.BisectLog()
 
205
        bisect_log._items = [("rev1", "yes"), ("rev2", "no"), ("rev3", "yes")]
 
206
        bisect_log.save()
 
207
 
 
208
        logfile = open(cmds.bisect_info_path)
 
209
        assert logfile.read() == "rev1 yes\nrev2 no\nrev3 yes\n"
 
210
 
 
211
 
 
212
class BisectFuncTests(BisectTestCase):
 
213
    """Functional tests for the bisect plugin."""
 
214
 
 
215
    def testWorkflow(self):
 
216
        """Run through a basic usage scenario."""
 
217
 
 
218
        # Start up the bisection.  When the two ends are set, we should
 
219
        # end up in the middle.
 
220
 
 
221
        self.run_bzr(['bisect', 'start'])
 
222
        self.run_bzr(['bisect', 'yes'])
 
223
        self.run_bzr(['bisect', 'no', '-r', '1'])
 
224
        self.assertRevno(3)
 
225
 
 
226
        # Mark feature as present in the middle.  Should move us
 
227
        # halfway back between the current middle and the start.
 
228
 
 
229
        self.run_bzr(['bisect', 'yes'])
 
230
        self.assertRevno(2)
 
231
 
 
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
 
235
        # rev following.
 
236
 
 
237
        self.run_bzr(['bisect', 'no'])
 
238
        self.assertRevno(3)
 
239
 
 
240
        # Run again.  Since we're done, this should do nothing.
 
241
 
 
242
        self.run_bzr(['bisect', 'no'])
 
243
        self.assertRevno(3)
 
244
 
 
245
    def testWorkflowSubtree(self):
 
246
        """Run through a usage scenario where the offending change
 
247
        is in a subtree."""
 
248
 
 
249
        # Similar to testWorkflow, but make sure the plugin traverses
 
250
        # subtrees when the "final" revision is a merge point.
 
251
 
 
252
        # This part is similar to testWorkflow.
 
253
 
 
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'])
 
258
 
 
259
        # Check to make sure we're where we expect to be.
 
260
 
 
261
        self.assertRevno(2)
 
262
 
 
263
        # Now, mark the merge point revno, meaning the feature
 
264
        # appeared at a merge point.
 
265
 
 
266
        self.run_bzr(['bisect', 'yes'])
 
267
        self.assertRevno(1.2)
 
268
 
 
269
        # Continue bisecting along the subtree to the real conclusion.
 
270
 
 
271
        self.run_bzr(['bisect', 'yes'])
 
272
        self.assertRevno(1.1)
 
273
        self.run_bzr(['bisect', 'yes'])
 
274
        self.assertRevno(1.1)
 
275
 
 
276
        # Run again.  Since we're done, this should do nothing.
 
277
 
 
278
        self.run_bzr(['bisect', 'yes'])
 
279
        self.assertRevno(1.1)
 
280
 
 
281
    def testMove(self):
 
282
        """Test manually moving to a different revision during the bisection."""
 
283
 
 
284
        # Set up a bisection in progress.
 
285
 
 
286
        self.run_bzr(['bisect', 'start'])
 
287
        self.run_bzr(['bisect', 'yes'])
 
288
        self.run_bzr(['bisect', 'no', '-r', '1'])
 
289
 
 
290
        # Move.
 
291
 
 
292
        self.run_bzr(['bisect', 'move', '-r', '2'])
 
293
        self.assertRevno(2)
 
294
 
 
295
    def testReset(self):
 
296
        """Test resetting the tree."""
 
297
 
 
298
        # Set up a bisection in progress.
 
299
 
 
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'])
 
304
 
 
305
        # Now reset.
 
306
 
 
307
        self.run_bzr(['bisect', 'reset'])
 
308
        self.assertRevno(5)
 
309
 
 
310
        # Check that reset doesn't do anything unless there's a
 
311
        # bisection in progress.
 
312
 
 
313
        test_file = open("test_file", "w")
 
314
        test_file.write("keep me")
 
315
        test_file.close()
 
316
 
 
317
        out, err = self.run_bzr(['bisect', 'reset'], retcode=3)
 
318
        self.assert_("No bisection in progress." in err)
 
319
 
 
320
        test_file = open("test_file")
 
321
        content = test_file.read().strip()
 
322
        test_file.close()
 
323
        self.failUnless(content == "keep me")
 
324
 
 
325
    def testLog(self):
 
326
        """Test saving the current bisection state, and re-loading it."""
 
327
 
 
328
        # Set up a bisection in progress.
 
329
 
 
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'])
 
334
 
 
335
        # Now save the log.
 
336
 
 
337
        self.run_bzr(['bisect', 'log', '-o', 'bisect_log'])
 
338
 
 
339
        # Reset.
 
340
 
 
341
        self.run_bzr(['bisect', 'reset'])
 
342
 
 
343
        # Read it back in.
 
344
 
 
345
        self.run_bzr(['bisect', 'replay', 'bisect_log'])
 
346
        self.assertRevno(2)
 
347
 
 
348
        # Mark another state, and see if the bisect moves in the
 
349
        # right way.
 
350
 
 
351
        self.run_bzr(['bisect', 'no'])
 
352
        self.assertRevno(3)
 
353
 
 
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")
 
359
        test_script.close()
 
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'])
 
365
        self.assertRevno(4)
 
366
 
 
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")
 
374
        test_script.close()
 
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'])
 
380
        try:
 
381
            self.assertRevno(2)
 
382
        except AssertionError:
 
383
            raise KnownFailure\
 
384
                ("bisect does not drill down into merge commits: "
 
385
                 "https://bugs.launchpad.net/bzr-bisect/+bug/539937")
 
386
        
 
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")
 
394
        test_script.close()
 
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'])
 
400
        try:
 
401
            self.assertRevno(1.2)
 
402
        except AssertionError:
 
403
            raise KnownFailure\
 
404
                ("bisect does not drill down into merge commits: "
 
405
                 "https://bugs.launchpad.net/bzr-bisect/+bug/539937")