src/tests/pkg5unittest.py
author Brad Hall <bhall@eng.sun.com>
Tue, 05 Aug 2008 17:08:47 -0700
changeset 448 bcfa99ac18b0
parent 436 5f150abbfba7
child 502 3f98e94acc4a
permissions -rw-r--r--
2664 test suite baseline enhancements

#!/usr/bin/python2.4
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#

# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.

import baseline
import string
import sys
import time
import unittest

OUTPUT_DOTS=0           # Dots ...
OUTPUT_VERBOSE=1        # Verbose
OUTPUT_PARSEABLE=2      # Machine readable

class SuccessfulException(Exception):
        """An exception for situations where raising an exception is the
        correct behavior for a test in the test suite. This is useful for
        testing the testsuite behavior itself, but should not be used in
        testing other code."""
        pass

class Pkg5TestCase(unittest.TestCase):
        def __init__(self, methodName='runTest'):
                super(Pkg5TestCase, self).__init__(methodName)
                self.__testMethodName = methodName

        def __str__(self):
                return "%s.py %s.%s" % (self.__class__.__module__,
                    self.__class__.__name__, self.__testMethodName)

        def run(self, result=None):
                # The only difference between this code and the original
                # code in unittest.TestCase.run is that
                # except SuccessfulException: has been added and counted as
                # a successful test.
                if result is None:
                        result = self.defaultTestResult()
                result.startTest(self)
                testMethod = getattr(self, self._TestCase__testMethodName)
                try:
                        try:
                                self.setUp()
                        except KeyboardInterrupt:
                                raise
                        except SuccessfulException:
                                result.addSuccess(self)
                                return
                        except:
                                result.addError(self, self._TestCase__exc_info())
                                return

                        ok = False
                        try:
                                testMethod()
                                ok = True
                        except self.failureException:
                                result.addFailure(self, self._TestCase__exc_info())
                        except KeyboardInterrupt:
                                raise
                        except:
                                result.addError(self, self._TestCase__exc_info())

                        try:
                                self.tearDown()
                        except KeyboardInterrupt:
                                raise
                        except:
                                result.addError(self, self._TestCase__exc_info())
                                ok = False
                        if ok:
                                result.addSuccess(self)
                finally:
                        result.stopTest(self)

class _Pkg5TestResult(unittest._TextTestResult):
        baseline = None
        machsep = "|"
        def __init__(self, stream, output, baseline):
                unittest.TestResult.__init__(self)
                self.stream = stream
                self.output = output
                self.baseline = baseline
                self.success = []

        def addSuccess(self, test):
                unittest.TestResult.addSuccess(self, test)
                bresult = self.baseline.handleresult(str(test), "pass")
                if self.output == OUTPUT_VERBOSE or \
                    self.output == OUTPUT_PARSEABLE:
                        res = ""
                        if bresult == True:
                                res = "pass"
                        else:
                                res = "pass (FAIL)"
                        self.stream.writeln(res)
                elif self.output == OUTPUT_DOTS:
                        self.stream.write('.')
                self.success.append(test)

        def addError(self, test, err):
                unittest.TestResult.addError(self, test, err)
                if self.output == OUTPUT_VERBOSE or \
                    self.output == OUTPUT_PARSEABLE:
                        self.stream.writeln("ERROR")
                elif self.output == OUTPUT_DOTS:
                        self.stream.write('E')
                bresult = self.baseline.handleresult(str(test), "error")

        def addFailure(self, test, err):
                unittest.TestResult.addFailure(self, test, err)
                bresult = self.baseline.handleresult(str(test), "fail")
                if self.output == OUTPUT_VERBOSE or \
                    self.output == OUTPUT_PARSEABLE:
                        res = ""
                        if bresult == True:
                                res = "FAIL (pass)"
                        else:
                                res = "FAIL"
                        self.stream.writeln(res)
                elif self.output == OUTPUT_DOTS:
                        self.stream.write('F')

        def getDescription(self, test):
                return str(test)

        def startTest(self, test):
                unittest.TestResult.startTest(self, test)
                if not self.output == OUTPUT_DOTS:
                        self.stream.write(
                            string.ljust(self.getDescription(test), 60))
                if self.output == OUTPUT_VERBOSE:
                        self.stream.write("   ")
                if self.output == OUTPUT_PARSEABLE:
                        self.stream.write(" | ")
                self.stream.flush()

        def printErrors(self):
                self.stream.writeln()
                self.printErrorList('ERROR', self.errors)
                self.printErrorList('FAIL', self.failures)

        def printErrorList(self, flavour, errors):
                for test, err in errors:
                        self.stream.writeln(self.separator1)
                        self.stream.writeln("%s: %s" %
                            (flavour, self.getDescription(test)))
                        self.stream.writeln(self.separator2)
                        self.stream.writeln("%s" % err)

class Pkg5TestRunner(unittest.TextTestRunner):
        """TestRunner for test suites that we want to be able to compare
        against a result baseline."""
        baseline = None
        sep1 = '=' * 70
        sep2 = '-' * 70

        def __init__(self, baseline, stream=sys.stderr, output=OUTPUT_DOTS):
                """Set up the runner, creating a baseline object that has
                a name of 'suite'_baseline.pkl, where suite is 'cli', 'api',
                etc."""
                # output is one of "dots", "verbose", "machine"
                super(Pkg5TestRunner, self).__init__(stream)
                self.baseline = baseline
                self.output = output

        def _makeResult(self):
                return _Pkg5TestResult(self.stream, self.output, self.baseline)

        def run(self, test):
                "Run the given test case or test suite."
                result = self._makeResult()
                startTime = time.time()
                test(result)
                stopTime = time.time()
                timeTaken = stopTime - startTime
                result.printErrors()
                self.stream.writeln(result.separator2)
                run = result.testsRun
                self.stream.writeln("Ran %d test%s in %.3fs" %
                    (run, run != 1 and "s" or "", timeTaken))
                self.stream.writeln()
                if not result.wasSuccessful():
                        self.stream.write("FAILED (")
                        success, failed, errored, mismatches = map(len,
                            (result.success, result.failures, result.errors,
                                self.baseline.getfailures()))
                        self.stream.write("successes=%d, " % success)
                        self.stream.write("failures=%d, " % failed)
                        self.stream.write("errors=%d, " % errored)
                        self.stream.write("mismatches=%d" % mismatches)
                        self.stream.writeln(")")
                else:
                        self.stream.writeln("OK")
                return result