~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/__init__.py

  • Committer: Martin Pool
  • Date: 2005-06-22 09:35:24 UTC
  • Revision ID: mbp@sourcefrog.net-20050622093524-b15e2d374c2ae6ea
- move standard plugins from contrib/plugins to just ./plugins

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by 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
 
 
18
from unittest import TestResult, TestCase
 
19
 
 
20
try:
 
21
    import shutil
 
22
    from subprocess import call, Popen, PIPE
 
23
except ImportError, e:
 
24
    sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
 
25
                     "this is shipped with python2.4 and available separately for 2.3\n")
 
26
    raise
 
27
 
 
28
 
 
29
class CommandFailed(Exception):
 
30
    pass
 
31
 
 
32
 
 
33
class TestBase(TestCase):
 
34
    """Base class for bzr test cases.
 
35
 
 
36
    Just defines some useful helper functions; doesn't actually test
 
37
    anything.
 
38
    """
 
39
    
 
40
    # TODO: Special methods to invoke bzr, so that we can run it
 
41
    # through a specified Python intepreter
 
42
 
 
43
    OVERRIDE_PYTHON = None # to run with alternative python 'python'
 
44
    BZRPATH = 'bzr'
 
45
    
 
46
 
 
47
    def formcmd(self, cmd):
 
48
        if isinstance(cmd, basestring):
 
49
            cmd = cmd.split()
 
50
 
 
51
        if cmd[0] == 'bzr':
 
52
            cmd[0] = self.BZRPATH
 
53
            if self.OVERRIDE_PYTHON:
 
54
                cmd.insert(0, self.OVERRIDE_PYTHON)
 
55
 
 
56
        self.log('$ %r' % cmd)
 
57
 
 
58
        return cmd
 
59
 
 
60
 
 
61
    def runcmd(self, cmd, retcode=0):
 
62
        """Run one command and check the return code.
 
63
 
 
64
        Returns a tuple of (stdout,stderr) strings.
 
65
 
 
66
        If a single string is based, it is split into words.
 
67
        For commands that are not simple space-separated words, please
 
68
        pass a list instead."""
 
69
        cmd = self.formcmd(cmd)
 
70
 
 
71
        self.log('$ ' + ' '.join(cmd))
 
72
        actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
 
73
 
 
74
        if retcode != actual_retcode:
 
75
            raise CommandFailed("test failed: %r returned %d, expected %d"
 
76
                                % (cmd, actual_retcode, retcode))
 
77
 
 
78
 
 
79
    def backtick(self, cmd, retcode=0):
 
80
        """Run a command and return its output"""
 
81
        cmd = self.formcmd(cmd)
 
82
        child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
 
83
        outd, errd = child.communicate()
 
84
        self.log(outd)
 
85
        actual_retcode = child.wait()
 
86
 
 
87
        outd = outd.replace('\r', '')
 
88
 
 
89
        if retcode != actual_retcode:
 
90
            raise CommandFailed("test failed: %r returned %d, expected %d"
 
91
                                % (cmd, actual_retcode, retcode))
 
92
 
 
93
        return outd
 
94
 
 
95
 
 
96
 
 
97
    def build_tree(self, shape):
 
98
        """Build a test tree according to a pattern.
 
99
 
 
100
        shape is a sequence of file specifications.  If the final
 
101
        character is '/', a directory is created.
 
102
 
 
103
        This doesn't add anything to a branch.
 
104
        """
 
105
        # XXX: It's OK to just create them using forward slashes on windows?
 
106
        import os
 
107
        for name in shape:
 
108
            assert isinstance(name, basestring)
 
109
            if name[-1] == '/':
 
110
                os.mkdir(name[:-1])
 
111
            else:
 
112
                f = file(name, 'wt')
 
113
                print >>f, "contents of", name
 
114
                f.close()
 
115
 
 
116
 
 
117
    def log(self, msg):
 
118
        """Log a message to a progress file"""
 
119
        print >>self.TEST_LOG, msg
 
120
               
 
121
 
 
122
class InTempDir(TestBase):
 
123
    """Base class for tests run in a temporary branch."""
 
124
    def setUp(self):
 
125
        import os
 
126
        self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
 
127
        os.mkdir(self.test_dir)
 
128
        os.chdir(self.test_dir)
 
129
        
 
130
    def tearDown(self):
 
131
        import os
 
132
        os.chdir(self.TEST_ROOT)
 
133
 
 
134
 
 
135
 
 
136
 
 
137
 
 
138
class _MyResult(TestResult):
 
139
    """
 
140
    Custom TestResult.
 
141
 
 
142
    No special behaviour for now.
 
143
    """
 
144
    def __init__(self, out):
 
145
        self.out = out
 
146
        TestResult.__init__(self)
 
147
 
 
148
    def startTest(self, test):
 
149
        # TODO: Maybe show test.shortDescription somewhere?
 
150
        print >>self.out, '%-60.60s' % test.id(),
 
151
        TestResult.startTest(self, test)
 
152
 
 
153
    def stopTest(self, test):
 
154
        # print
 
155
        TestResult.stopTest(self, test)
 
156
 
 
157
 
 
158
    def addError(self, test, err):
 
159
        print >>self.out, 'ERROR'
 
160
        TestResult.addError(self, test, err)
 
161
 
 
162
    def addFailure(self, test, err):
 
163
        print >>self.out, 'FAILURE'
 
164
        TestResult.addFailure(self, test, err)
 
165
 
 
166
    def addSuccess(self, test):
 
167
        print >>self.out, 'OK'
 
168
        TestResult.addSuccess(self, test)
 
169
 
 
170
 
 
171
 
 
172
def selftest():
 
173
    from unittest import TestLoader, TestSuite
 
174
    import bzrlib
 
175
    import bzrlib.selftest.whitebox
 
176
    import bzrlib.selftest.blackbox
 
177
    import bzrlib.selftest.versioning
 
178
    from doctest import DocTestSuite
 
179
    import os
 
180
    import shutil
 
181
    import time
 
182
    import sys
 
183
 
 
184
    _setup_test_log()
 
185
    _setup_test_dir()
 
186
    print
 
187
 
 
188
    suite = TestSuite()
 
189
    tl = TestLoader()
 
190
 
 
191
    for m in bzrlib.selftest.whitebox, \
 
192
            bzrlib.selftest.versioning:
 
193
        suite.addTest(tl.loadTestsFromModule(m))
 
194
 
 
195
    suite.addTest(bzrlib.selftest.blackbox.suite())
 
196
 
 
197
    for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
 
198
            bzrlib.commands:
 
199
        suite.addTest(DocTestSuite(m))
 
200
 
 
201
    # save stdout & stderr so there's no leakage from code-under-test
 
202
    real_stdout = sys.stdout
 
203
    real_stderr = sys.stderr
 
204
    sys.stdout = sys.stderr = TestBase.TEST_LOG
 
205
    try:
 
206
        result = _MyResult(real_stdout)
 
207
        suite.run(result)
 
208
    finally:
 
209
        sys.stdout = real_stdout
 
210
        sys.stderr = real_stderr
 
211
 
 
212
    _show_results(result)
 
213
 
 
214
    return result.wasSuccessful()
 
215
 
 
216
 
 
217
 
 
218
 
 
219
def _setup_test_log():
 
220
    import time
 
221
    import os
 
222
    
 
223
    log_filename = os.path.abspath('testbzr.log')
 
224
    TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
 
225
 
 
226
    print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
 
227
    print '%-30s %s' % ('test log', log_filename)
 
228
 
 
229
 
 
230
def _setup_test_dir():
 
231
    import os
 
232
    import shutil
 
233
    
 
234
    TestBase.ORIG_DIR = os.getcwdu()
 
235
    TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
 
236
 
 
237
    print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
 
238
 
 
239
    if os.path.exists(TestBase.TEST_ROOT):
 
240
        shutil.rmtree(TestBase.TEST_ROOT)
 
241
    os.mkdir(TestBase.TEST_ROOT)
 
242
    os.chdir(TestBase.TEST_ROOT)
 
243
 
 
244
    # make a fake bzr directory there to prevent any tests propagating
 
245
    # up onto the source directory's real branch
 
246
    os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
 
247
 
 
248
    
 
249
 
 
250
def _show_results(result):
 
251
     for case, tb in result.errors:
 
252
         _show_test_failure('ERROR', case, tb)
 
253
 
 
254
     for case, tb in result.failures:
 
255
         _show_test_failure('FAILURE', case, tb)
 
256
         
 
257
     print
 
258
     print '%4d tests run' % result.testsRun
 
259
     print '%4d errors' % len(result.errors)
 
260
     print '%4d failures' % len(result.failures)
 
261
 
 
262
 
 
263
 
 
264
def _show_test_failure(kind, case, tb):
 
265
     print (kind + '! ').ljust(60, '-')
 
266
     print case
 
267
     desc = case.shortDescription()
 
268
     if desc:
 
269
         print '   (%s)' % desc
 
270
     print tb
 
271
     print ''.ljust(60, '-')
 
272