~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to testsweet.py

  • Committer: Martin Pool
  • Date: 2005-08-19 21:34:32 UTC
  • Revision ID: mbp@sourcefrog.net-20050819213432-4fa923a97c45d845
- add schema and example for new inventory form

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
* utilities to run external commands and check their return code
31
31
  and/or output
32
32
 
33
 
Test cases should normally subclass testsweet.TestCase.  The test runner should
 
33
Test cases should normally subclass TestBase.  The test runner should
34
34
call runsuite().
35
35
 
36
36
This is meant to become independent of bzr, though that's not quite
37
37
true yet.
38
38
"""  
39
39
 
40
 
import unittest
41
 
import sys
 
40
 
 
41
from unittest import TestResult, TestCase
42
42
 
43
43
# XXX: Don't need this anymore now we depend on python2.4
44
44
def _need_subprocess():
50
50
    pass
51
51
 
52
52
 
 
53
 
53
54
class TestSkipped(Exception):
54
55
    """Indicates that a test was intentionally skipped, rather than failing."""
55
56
    # XXX: Not used yet
56
57
 
57
58
 
58
 
class TestCase(unittest.TestCase):
 
59
class TestBase(TestCase):
59
60
    """Base class for bzr test cases.
60
61
 
61
62
    Just defines some useful helper functions; doesn't actually test
72
73
 
73
74
 
74
75
    def setUp(self):
75
 
        super(TestCase, self).setUp()
76
 
        # save stdout & stderr so there's no leakage from code-under-test
77
 
        self.real_stdout = sys.stdout
78
 
        self.real_stderr = sys.stderr
79
 
        sys.stdout = sys.stderr = TestCase.TEST_LOG
 
76
        super(TestBase, self).setUp()
80
77
        self.log("%s setup" % self.id())
81
78
 
 
79
 
82
80
    def tearDown(self):
83
 
        sys.stdout = self.real_stdout
84
 
        sys.stderr = self.real_stderr
 
81
        super(TestBase, self).tearDown()
85
82
        self.log("%s teardown" % self.id())
86
83
        self.log('')
87
 
        super(TestCase, self).tearDown()
 
84
 
88
85
 
89
86
    def formcmd(self, cmd):
90
87
        if isinstance(cmd, basestring):
215
212
            
216
213
 
217
214
 
218
 
class InTempDir(TestCase):
 
215
class InTempDir(TestBase):
219
216
    """Base class for tests run in a temporary branch."""
220
217
    def setUp(self):
221
 
        super(InTempDir, self).setUp()
222
218
        import os
223
219
        self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
224
220
        os.mkdir(self.test_dir)
227
223
    def tearDown(self):
228
224
        import os
229
225
        os.chdir(self.TEST_ROOT)
230
 
        super(InTempDir, self).tearDown()
231
 
 
232
 
 
233
 
class _MyResult(unittest._TextTestResult):
 
226
 
 
227
 
 
228
 
 
229
 
 
230
 
 
231
class _MyResult(TestResult):
234
232
    """
235
233
    Custom TestResult.
236
234
 
237
235
    No special behaviour for now.
238
236
    """
239
237
    def __init__(self, out, style):
240
 
        super(_MyResult, self).__init__(out, False, 0)
241
238
        self.out = out
 
239
        TestResult.__init__(self)
242
240
        assert style in ('none', 'progress', 'verbose')
243
241
        self.style = style
244
242
 
 
243
 
245
244
    def startTest(self, test):
246
 
        super(_MyResult, self).startTest(test)
247
245
        # TODO: Maybe show test.shortDescription somewhere?
248
246
        what = test.id()
249
247
        # python2.3 has the bad habit of just "runit" for doctests
250
248
        if what == 'runit':
251
249
            what = test.shortDescription()
 
250
        
252
251
        if self.style == 'verbose':
253
252
            print >>self.out, '%-60.60s' % what,
254
253
            self.out.flush()
 
254
        elif self.style == 'progress':
 
255
            self.out.write('~')
 
256
            self.out.flush()
 
257
        TestResult.startTest(self, test)
 
258
 
 
259
 
 
260
    def stopTest(self, test):
 
261
        # print
 
262
        TestResult.stopTest(self, test)
 
263
 
255
264
 
256
265
    def addError(self, test, err):
257
266
        if self.style == 'verbose':
258
267
            print >>self.out, 'ERROR'
259
 
        elif self.style == 'progress':
260
 
            self.stream.write('E')
261
 
        self.stream.flush()
262
 
        super(_MyResult, self).addError(test, err)
 
268
        TestResult.addError(self, test, err)
 
269
        _show_test_failure('error', test, err, self.out)
263
270
 
264
271
    def addFailure(self, test, err):
265
272
        if self.style == 'verbose':
266
273
            print >>self.out, 'FAILURE'
267
 
        elif self.style == 'progress':
268
 
            self.stream.write('F')
269
 
        self.stream.flush()
270
 
        super(_MyResult, self).addFailure(test, err)
 
274
        TestResult.addFailure(self, test, err)
 
275
        _show_test_failure('failure', test, err, self.out)
271
276
 
272
277
    def addSuccess(self, test):
273
278
        if self.style == 'verbose':
274
279
            print >>self.out, 'OK'
275
 
        elif self.style == 'progress':
276
 
            self.stream.write('~')
277
 
        self.stream.flush()
278
 
        super(_MyResult, self).addSuccess(test)
279
 
 
280
 
    def printErrors(self):
281
 
        if self.style == 'progress':
282
 
            self.stream.writeln()
283
 
        super(_MyResult, self).printErrors()
284
 
 
285
 
    def printErrorList(self, flavour, errors):
286
 
        for test, err in errors:
287
 
            self.stream.writeln(self.separator1)
288
 
            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
289
 
            self.stream.writeln(self.separator2)
290
 
            self.stream.writeln("%s" % err)
291
 
            if isinstance(test, TestCase):
292
 
                self.stream.writeln()
293
 
                self.stream.writeln('log from this test:')
294
 
                print >>self.stream, test._log_buf
295
 
 
296
 
 
297
 
class TestSuite(unittest.TestSuite):
298
 
    
299
 
    def __init__(self, tests=(), name='test'):
300
 
        super(TestSuite, self).__init__(tests)
301
 
        self._name = name
302
 
 
303
 
    def run(self, result):
304
 
        import os
305
 
        import shutil
306
 
        import time
307
 
        
308
 
        self._setup_test_log()
309
 
        self._setup_test_dir()
310
 
        print
311
 
    
312
 
        return super(TestSuite,self).run(result)
313
 
 
314
 
    def _setup_test_log(self):
315
 
        import time
316
 
        import os
317
 
        
318
 
        log_filename = os.path.abspath(self._name + '.log')
319
 
        # line buffered
320
 
        TestCase.TEST_LOG = open(log_filename, 'wt', buffering=1)
321
 
    
322
 
        print >>TestCase.TEST_LOG, "tests run at " + time.ctime()
323
 
        print '%-30s %s' % ('test log', log_filename)
324
 
 
325
 
    def _setup_test_dir(self):
326
 
        import os
327
 
        import shutil
328
 
        
329
 
        TestCase.ORIG_DIR = os.getcwdu()
330
 
        TestCase.TEST_ROOT = os.path.abspath(self._name + '.tmp')
331
 
    
332
 
        print '%-30s %s' % ('running tests in', TestCase.TEST_ROOT)
333
 
    
334
 
        if os.path.exists(TestCase.TEST_ROOT):
335
 
            shutil.rmtree(TestCase.TEST_ROOT)
336
 
        os.mkdir(TestCase.TEST_ROOT)
337
 
        os.chdir(TestCase.TEST_ROOT)
338
 
    
339
 
        # make a fake bzr directory there to prevent any tests propagating
340
 
        # up onto the source directory's real branch
341
 
        os.mkdir(os.path.join(TestCase.TEST_ROOT, '.bzr'))
342
 
 
343
 
 
344
 
class TextTestRunner(unittest.TextTestRunner):
345
 
 
346
 
    def __init__(self, stream=sys.stderr, descriptions=1, verbosity=0, style='progress'):
347
 
        super(TextTestRunner, self).__init__(stream, descriptions, verbosity)
348
 
        self.style = style
349
 
 
350
 
    def _makeResult(self):
351
 
        return _MyResult(self.stream, self.style)
352
 
 
353
 
    # If we want the old 4 line summary output (count, 0 failures, 0 errors)
354
 
    # we can override run() too.
355
 
 
356
 
 
357
 
def run_suite(a_suite, name='test', verbose=False):
358
 
    suite = TestSuite((a_suite,),name)
359
 
    if verbose:
360
 
        style = 'verbose'
361
 
    else:
362
 
        style = 'progress'
363
 
    runner = TextTestRunner(stream=sys.stdout, style=style)
364
 
    result = runner.run(suite)
 
280
        TestResult.addSuccess(self, test)
 
281
 
 
282
 
 
283
 
 
284
def run_suite(suite, name='test', verbose=False):
 
285
    import os
 
286
    import shutil
 
287
    import time
 
288
    import sys
 
289
    
 
290
    _setup_test_log(name)
 
291
    _setup_test_dir(name)
 
292
    print
 
293
 
 
294
    # save stdout & stderr so there's no leakage from code-under-test
 
295
    real_stdout = sys.stdout
 
296
    real_stderr = sys.stderr
 
297
    sys.stdout = sys.stderr = TestBase.TEST_LOG
 
298
    try:
 
299
        if verbose:
 
300
            style = 'verbose'
 
301
        else:
 
302
            style = 'progress'
 
303
        result = _MyResult(real_stdout, style)
 
304
        suite.run(result)
 
305
    finally:
 
306
        sys.stdout = real_stdout
 
307
        sys.stderr = real_stderr
 
308
 
 
309
    _show_results(result)
 
310
 
365
311
    return result.wasSuccessful()
 
312
 
 
313
 
 
314
 
 
315
def _setup_test_log(name):
 
316
    import time
 
317
    import os
 
318
    
 
319
    log_filename = os.path.abspath(name + '.log')
 
320
    TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
 
321
 
 
322
    print >>TestBase.TEST_LOG, "tests run at " + time.ctime()
 
323
    print '%-30s %s' % ('test log', log_filename)
 
324
 
 
325
 
 
326
def _setup_test_dir(name):
 
327
    import os
 
328
    import shutil
 
329
    
 
330
    TestBase.ORIG_DIR = os.getcwdu()
 
331
    TestBase.TEST_ROOT = os.path.abspath(name + '.tmp')
 
332
 
 
333
    print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
 
334
 
 
335
    if os.path.exists(TestBase.TEST_ROOT):
 
336
        shutil.rmtree(TestBase.TEST_ROOT)
 
337
    os.mkdir(TestBase.TEST_ROOT)
 
338
    os.chdir(TestBase.TEST_ROOT)
 
339
 
 
340
    # make a fake bzr directory there to prevent any tests propagating
 
341
    # up onto the source directory's real branch
 
342
    os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
 
343
 
 
344
    
 
345
 
 
346
def _show_results(result):
 
347
     print
 
348
     print '%4d tests run' % result.testsRun
 
349
     print '%4d errors' % len(result.errors)
 
350
     print '%4d failures' % len(result.failures)
 
351
 
 
352
 
 
353
 
 
354
def _show_test_failure(kind, case, exc_info, out):
 
355
    from traceback import print_exception
 
356
 
 
357
    print >>out
 
358
    print >>out, '-' * 60
 
359
    print >>out, case
 
360
    
 
361
    desc = case.shortDescription()
 
362
    if desc:
 
363
        print >>out, '   (%s)' % desc
 
364
         
 
365
    print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
 
366
        
 
367
    if isinstance(case, TestBase):
 
368
        print >>out
 
369
        print >>out, 'log from this test:'
 
370
        print >>out, case._log_buf
 
371
         
 
372
    print >>out, '-' * 60
 
373
    
 
374