~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/__init__.py

  • Committer: Robert Collins
  • Date: 2005-08-23 06:52:09 UTC
  • mto: (974.1.50) (1185.1.10) (1092.3.1)
  • mto: This revision was merged to the branch mainline in revision 1139.
  • Revision ID: robertc@robertcollins.net-20050823065209-81cd5962c401751b
move io redirection into each test case from the global runner

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
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
 
    import sys
25
 
    sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
26
 
                     "this is shipped with python2.4 and available separately for 2.3\n")
27
 
    raise
28
 
 
29
 
 
30
 
class CommandFailed(Exception):
31
 
    pass
32
 
 
33
 
 
34
 
class TestBase(TestCase):
35
 
    """Base class for bzr test cases.
36
 
 
37
 
    Just defines some useful helper functions; doesn't actually test
38
 
    anything.
39
 
    """
40
 
    
41
 
    # TODO: Special methods to invoke bzr, so that we can run it
42
 
    # through a specified Python intepreter
43
 
 
44
 
    OVERRIDE_PYTHON = None # to run with alternative python 'python'
45
 
    BZRPATH = 'bzr'
46
 
 
47
 
    _log_buf = ""
48
 
 
49
 
 
50
 
    def formcmd(self, cmd):
51
 
        if isinstance(cmd, basestring):
52
 
            cmd = cmd.split()
53
 
 
54
 
        if cmd[0] == 'bzr':
55
 
            cmd[0] = self.BZRPATH
56
 
            if self.OVERRIDE_PYTHON:
57
 
                cmd.insert(0, self.OVERRIDE_PYTHON)
58
 
 
59
 
        self.log('$ %r' % cmd)
60
 
 
61
 
        return cmd
62
 
 
63
 
 
64
 
    def runcmd(self, cmd, retcode=0):
65
 
        """Run one command and check the return code.
66
 
 
67
 
        Returns a tuple of (stdout,stderr) strings.
68
 
 
69
 
        If a single string is based, it is split into words.
70
 
        For commands that are not simple space-separated words, please
71
 
        pass a list instead."""
72
 
        cmd = self.formcmd(cmd)
73
 
 
74
 
        self.log('$ ' + ' '.join(cmd))
75
 
        actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
76
 
 
77
 
        if retcode != actual_retcode:
78
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
79
 
                                % (cmd, actual_retcode, retcode))
80
 
 
81
 
 
82
 
    def backtick(self, cmd, retcode=0):
83
 
        """Run a command and return its output"""
84
 
        cmd = self.formcmd(cmd)
85
 
        child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
86
 
        outd, errd = child.communicate()
87
 
        self.log(outd)
88
 
        actual_retcode = child.wait()
89
 
 
90
 
        outd = outd.replace('\r', '')
91
 
 
92
 
        if retcode != actual_retcode:
93
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
94
 
                                % (cmd, actual_retcode, retcode))
95
 
 
96
 
        return outd
97
 
 
98
 
 
99
 
 
100
 
    def build_tree(self, shape):
101
 
        """Build a test tree according to a pattern.
102
 
 
103
 
        shape is a sequence of file specifications.  If the final
104
 
        character is '/', a directory is created.
105
 
 
106
 
        This doesn't add anything to a branch.
107
 
        """
108
 
        # XXX: It's OK to just create them using forward slashes on windows?
109
 
        import os
110
 
        for name in shape:
111
 
            assert isinstance(name, basestring)
112
 
            if name[-1] == '/':
113
 
                os.mkdir(name[:-1])
114
 
            else:
115
 
                f = file(name, 'wt')
116
 
                print >>f, "contents of", name
117
 
                f.close()
118
 
 
119
 
 
120
 
    def log(self, msg):
121
 
        """Log a message to a progress file"""
122
 
        self._log_buf = self._log_buf + str(msg) + '\n'
123
 
        print >>self.TEST_LOG, msg
124
 
 
125
 
 
126
 
    def check_inventory_shape(self, inv, shape):
127
 
        """
128
 
        Compare an inventory to a list of expected names.
129
 
 
130
 
        Fail if they are not precisely equal.
131
 
        """
132
 
        extras = []
133
 
        shape = list(shape)             # copy
134
 
        for path, ie in inv.entries():
135
 
            name = path.replace('\\', '/')
136
 
            if ie.kind == 'dir':
137
 
                name = name + '/'
138
 
            if name in shape:
139
 
                shape.remove(name)
140
 
            else:
141
 
                extras.append(name)
142
 
        if shape:
143
 
            self.fail("expected paths not found in inventory: %r" % shape)
144
 
        if extras:
145
 
            self.fail("unexpected paths found in inventory: %r" % extras)
146
 
 
147
 
 
148
 
    def check_file_contents(self, filename, expect):
149
 
        self.log("check contents of file %s" % filename)
150
 
        contents = file(filename, 'r').read()
151
 
        if contents != expect:
152
 
            self.log("expected: %r" % expected)
153
 
            self.log("actually: %r" % contents)
154
 
            self.fail("contents of %s not as expected")
155
 
            
156
 
 
157
 
 
158
 
class InTempDir(TestBase):
159
 
    """Base class for tests run in a temporary branch."""
160
 
    def setUp(self):
161
 
        import os
162
 
        self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
163
 
        os.mkdir(self.test_dir)
164
 
        os.chdir(self.test_dir)
 
18
from testsweet import TestCase, run_suite, InTempDir
 
19
import bzrlib.commands
 
20
 
 
21
MODULES_TO_TEST = []
 
22
MODULES_TO_DOCTEST = []
 
23
 
 
24
 
 
25
class BzrTestBase(InTempDir):
 
26
    """bzr-specific test base class"""
 
27
    def run_bzr(self, *args, **kwargs):
 
28
        retcode = kwargs.get('retcode', 0)
 
29
        self.assertEquals(bzrlib.commands.run_bzr(args), retcode)
165
30
        
166
 
    def tearDown(self):
167
 
        import os
168
 
        os.chdir(self.TEST_ROOT)
169
 
 
170
 
 
171
 
 
172
 
 
173
 
 
174
 
class _MyResult(TestResult):
175
 
    """
176
 
    Custom TestResult.
177
 
 
178
 
    No special behaviour for now.
179
 
    """
180
 
    def __init__(self, out):
181
 
        self.out = out
182
 
        TestResult.__init__(self)
183
 
 
184
 
    def startTest(self, test):
185
 
        # TODO: Maybe show test.shortDescription somewhere?
186
 
        print >>self.out, '%-60.60s' % test.id(),
187
 
        self.out.flush()
188
 
        TestResult.startTest(self, test)
189
 
 
190
 
    def stopTest(self, test):
191
 
        # print
192
 
        TestResult.stopTest(self, test)
193
 
 
194
 
 
195
 
    def addError(self, test, err):
196
 
        print >>self.out, 'ERROR'
197
 
        TestResult.addError(self, test, err)
198
 
        _show_test_failure('error', test, err, self.out)
199
 
 
200
 
    def addFailure(self, test, err):
201
 
        print >>self.out, 'FAILURE'
202
 
        TestResult.addFailure(self, test, err)
203
 
        _show_test_failure('failure', test, err, self.out)
204
 
 
205
 
    def addSuccess(self, test):
206
 
        print >>self.out, 'OK'
207
 
        TestResult.addSuccess(self, test)
208
 
 
209
 
 
210
 
 
211
 
def selftest():
 
31
 
 
32
def selftest(verbose=False):
212
33
    from unittest import TestLoader, TestSuite
213
 
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, bzrlib.commands
214
 
 
215
 
    import bzrlib.selftest.whitebox
216
 
    import bzrlib.selftest.blackbox
217
 
    import bzrlib.selftest.versioning
218
 
    import bzrlib.selftest.testmerge3
219
 
    import bzrlib.merge_core
 
34
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
 
35
    import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
220
36
    from doctest import DocTestSuite
221
37
    import os
222
38
    import shutil
223
39
    import time
224
40
    import sys
225
 
 
226
 
    TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
227
 
    print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
228
 
 
229
 
    _setup_test_log()
230
 
    _setup_test_dir()
 
41
    import unittest
 
42
 
 
43
    global MODULES_TO_TEST, MODULES_TO_DOCTEST
 
44
 
 
45
    testmod_names = \
 
46
                  ['bzrlib.selftest.whitebox',
 
47
                   'bzrlib.selftest.versioning',
 
48
                   'bzrlib.selftest.testinv',
 
49
                   'bzrlib.selftest.testmerge3',
 
50
                   'bzrlib.selftest.testhashcache',
 
51
                   'bzrlib.selftest.teststatus',
 
52
                   'bzrlib.selftest.testlog',
 
53
                   'bzrlib.selftest.blackbox',
 
54
                   'bzrlib.selftest.testrevisionnamespaces',
 
55
                   'bzrlib.selftest.testbranch',
 
56
                   'bzrlib.selftest.testrevision',
 
57
                   'bzrlib.merge_core',
 
58
                   'bzrlib.selftest.testdiff',
 
59
                   ]
 
60
 
 
61
    # XXX: should also test bzrlib.merge_core, but they seem to be out
 
62
    # of date with the code.
 
63
 
 
64
    for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
 
65
              bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
 
66
        if m not in MODULES_TO_DOCTEST:
 
67
            MODULES_TO_DOCTEST.append(m)
 
68
 
 
69
    
 
70
    TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
 
71
    print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
 
72
 
231
73
    print
232
74
 
233
75
    suite = TestSuite()
234
 
    tl = TestLoader()
235
 
 
236
 
    # should also test bzrlib.merge_core, but they seem to be out of date with
237
 
    # the code.
238
 
 
239
 
    for m in bzrlib.selftest.whitebox, \
240
 
            bzrlib.selftest.versioning, \
241
 
            bzrlib.selftest.testmerge3:
242
 
        suite.addTest(tl.loadTestsFromModule(m))
243
 
 
244
 
    for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
245
 
            bzrlib.commands, \
246
 
            bzrlib.merge3:
 
76
 
 
77
    suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
 
78
 
 
79
    for m in MODULES_TO_TEST:
 
80
         suite.addTest(TestLoader().loadTestsFromModule(m))
 
81
 
 
82
    for m in (MODULES_TO_DOCTEST):
247
83
        suite.addTest(DocTestSuite(m))
248
84
 
249
 
    suite.addTest(bzrlib.selftest.blackbox.suite())
250
 
 
251
 
    # save stdout & stderr so there's no leakage from code-under-test
252
 
    real_stdout = sys.stdout
253
 
    real_stderr = sys.stderr
254
 
    sys.stdout = sys.stderr = TestBase.TEST_LOG
255
 
    try:
256
 
        result = _MyResult(real_stdout)
257
 
        suite.run(result)
258
 
    finally:
259
 
        sys.stdout = real_stdout
260
 
        sys.stderr = real_stderr
261
 
 
262
 
    _show_results(result)
263
 
 
264
 
    return result.wasSuccessful()
265
 
 
266
 
 
267
 
 
268
 
 
269
 
def _setup_test_log():
270
 
    import time
271
 
    import os
272
 
    
273
 
    log_filename = os.path.abspath('testbzr.log')
274
 
    TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
275
 
 
276
 
    print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
277
 
    print '%-30s %s' % ('test log', log_filename)
278
 
 
279
 
 
280
 
def _setup_test_dir():
281
 
    import os
282
 
    import shutil
283
 
    
284
 
    TestBase.ORIG_DIR = os.getcwdu()
285
 
    TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
286
 
 
287
 
    print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
288
 
 
289
 
    if os.path.exists(TestBase.TEST_ROOT):
290
 
        shutil.rmtree(TestBase.TEST_ROOT)
291
 
    os.mkdir(TestBase.TEST_ROOT)
292
 
    os.chdir(TestBase.TEST_ROOT)
293
 
 
294
 
    # make a fake bzr directory there to prevent any tests propagating
295
 
    # up onto the source directory's real branch
296
 
    os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
297
 
 
298
 
    
299
 
 
300
 
def _show_results(result):
301
 
     print
302
 
     print '%4d tests run' % result.testsRun
303
 
     print '%4d errors' % len(result.errors)
304
 
     print '%4d failures' % len(result.failures)
305
 
 
306
 
 
307
 
 
308
 
def _show_test_failure(kind, case, exc_info, out):
309
 
    from traceback import print_exception
310
 
    
311
 
    print >>out, '-' * 60
312
 
    print >>out, case
313
 
    
314
 
    desc = case.shortDescription()
315
 
    if desc:
316
 
        print >>out, '   (%s)' % desc
317
 
         
318
 
    print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
319
 
        
320
 
    if isinstance(case, TestBase):
321
 
        print >>out
322
 
        print >>out, 'log from this test:'
323
 
        print >>out, case._log_buf
324
 
         
325
 
    print >>out, '-' * 60
326
 
    
 
85
    for p in bzrlib.plugin.all_plugins:
 
86
        if hasattr(p, 'test_suite'):
 
87
            suite.addTest(p.test_suite())
 
88
 
 
89
    import bzrlib.merge_core
 
90
    suite.addTest(unittest.makeSuite(bzrlib.merge_core.MergeTest, 'test_'))
 
91
 
 
92
    return run_suite(suite, 'testbzr', verbose=verbose)
 
93
 
 
94
 
327
95