| Index: Tools/Scripts/webkitpy/thirdparty/unittest2/suite.py
|
| diff --git a/Tools/Scripts/webkitpy/thirdparty/unittest2/suite.py b/Tools/Scripts/webkitpy/thirdparty/unittest2/suite.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..370ca5f13e9ea911369794c204a0f3a32e0d0700
|
| --- /dev/null
|
| +++ b/Tools/Scripts/webkitpy/thirdparty/unittest2/suite.py
|
| @@ -0,0 +1,287 @@
|
| +"""TestSuite"""
|
| +
|
| +import sys
|
| +import unittest
|
| +from unittest2 import case, util
|
| +
|
| +__unittest = True
|
| +
|
| +
|
| +class BaseTestSuite(unittest.TestSuite):
|
| + """A simple test suite that doesn't provide class or module shared fixtures.
|
| + """
|
| + def __init__(self, tests=()):
|
| + self._tests = []
|
| + self.addTests(tests)
|
| +
|
| + def __repr__(self):
|
| + return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
|
| +
|
| + def __eq__(self, other):
|
| + if not isinstance(other, self.__class__):
|
| + return NotImplemented
|
| + return list(self) == list(other)
|
| +
|
| + def __ne__(self, other):
|
| + return not self == other
|
| +
|
| + # Can't guarantee hash invariant, so flag as unhashable
|
| + __hash__ = None
|
| +
|
| + def __iter__(self):
|
| + return iter(self._tests)
|
| +
|
| + def countTestCases(self):
|
| + cases = 0
|
| + for test in self:
|
| + cases += test.countTestCases()
|
| + return cases
|
| +
|
| + def addTest(self, test):
|
| + # sanity checks
|
| + if not hasattr(test, '__call__'):
|
| + raise TypeError("%r is not callable" % (repr(test),))
|
| + if isinstance(test, type) and issubclass(test,
|
| + (case.TestCase, TestSuite)):
|
| + raise TypeError("TestCases and TestSuites must be instantiated "
|
| + "before passing them to addTest()")
|
| + self._tests.append(test)
|
| +
|
| + def addTests(self, tests):
|
| + if isinstance(tests, basestring):
|
| + raise TypeError("tests must be an iterable of tests, not a string")
|
| + for test in tests:
|
| + self.addTest(test)
|
| +
|
| + def run(self, result):
|
| + for test in self:
|
| + if result.shouldStop:
|
| + break
|
| + test(result)
|
| + return result
|
| +
|
| + def __call__(self, *args, **kwds):
|
| + return self.run(*args, **kwds)
|
| +
|
| + def debug(self):
|
| + """Run the tests without collecting errors in a TestResult"""
|
| + for test in self:
|
| + test.debug()
|
| +
|
| +
|
| +class TestSuite(BaseTestSuite):
|
| + """A test suite is a composite test consisting of a number of TestCases.
|
| +
|
| + For use, create an instance of TestSuite, then add test case instances.
|
| + When all tests have been added, the suite can be passed to a test
|
| + runner, such as TextTestRunner. It will run the individual test cases
|
| + in the order in which they were added, aggregating the results. When
|
| + subclassing, do not forget to call the base class constructor.
|
| + """
|
| +
|
| +
|
| + def run(self, result):
|
| + self._wrapped_run(result)
|
| + self._tearDownPreviousClass(None, result)
|
| + self._handleModuleTearDown(result)
|
| + return result
|
| +
|
| + def debug(self):
|
| + """Run the tests without collecting errors in a TestResult"""
|
| + debug = _DebugResult()
|
| + self._wrapped_run(debug, True)
|
| + self._tearDownPreviousClass(None, debug)
|
| + self._handleModuleTearDown(debug)
|
| +
|
| + ################################
|
| + # private methods
|
| + def _wrapped_run(self, result, debug=False):
|
| + for test in self:
|
| + if result.shouldStop:
|
| + break
|
| +
|
| + if _isnotsuite(test):
|
| + self._tearDownPreviousClass(test, result)
|
| + self._handleModuleFixture(test, result)
|
| + self._handleClassSetUp(test, result)
|
| + result._previousTestClass = test.__class__
|
| +
|
| + if (getattr(test.__class__, '_classSetupFailed', False) or
|
| + getattr(result, '_moduleSetUpFailed', False)):
|
| + continue
|
| +
|
| + if hasattr(test, '_wrapped_run'):
|
| + test._wrapped_run(result, debug)
|
| + elif not debug:
|
| + test(result)
|
| + else:
|
| + test.debug()
|
| +
|
| + def _handleClassSetUp(self, test, result):
|
| + previousClass = getattr(result, '_previousTestClass', None)
|
| + currentClass = test.__class__
|
| + if currentClass == previousClass:
|
| + return
|
| + if result._moduleSetUpFailed:
|
| + return
|
| + if getattr(currentClass, "__unittest_skip__", False):
|
| + return
|
| +
|
| + try:
|
| + currentClass._classSetupFailed = False
|
| + except TypeError:
|
| + # test may actually be a function
|
| + # so its class will be a builtin-type
|
| + pass
|
| +
|
| + setUpClass = getattr(currentClass, 'setUpClass', None)
|
| + if setUpClass is not None:
|
| + try:
|
| + setUpClass()
|
| + except Exception, e:
|
| + if isinstance(result, _DebugResult):
|
| + raise
|
| + currentClass._classSetupFailed = True
|
| + className = util.strclass(currentClass)
|
| + errorName = 'setUpClass (%s)' % className
|
| + self._addClassOrModuleLevelException(result, e, errorName)
|
| +
|
| + def _get_previous_module(self, result):
|
| + previousModule = None
|
| + previousClass = getattr(result, '_previousTestClass', None)
|
| + if previousClass is not None:
|
| + previousModule = previousClass.__module__
|
| + return previousModule
|
| +
|
| +
|
| + def _handleModuleFixture(self, test, result):
|
| + previousModule = self._get_previous_module(result)
|
| + currentModule = test.__class__.__module__
|
| + if currentModule == previousModule:
|
| + return
|
| +
|
| + self._handleModuleTearDown(result)
|
| +
|
| +
|
| + result._moduleSetUpFailed = False
|
| + try:
|
| + module = sys.modules[currentModule]
|
| + except KeyError:
|
| + return
|
| + setUpModule = getattr(module, 'setUpModule', None)
|
| + if setUpModule is not None:
|
| + try:
|
| + setUpModule()
|
| + except Exception, e:
|
| + if isinstance(result, _DebugResult):
|
| + raise
|
| + result._moduleSetUpFailed = True
|
| + errorName = 'setUpModule (%s)' % currentModule
|
| + self._addClassOrModuleLevelException(result, e, errorName)
|
| +
|
| + def _addClassOrModuleLevelException(self, result, exception, errorName):
|
| + error = _ErrorHolder(errorName)
|
| + addSkip = getattr(result, 'addSkip', None)
|
| + if addSkip is not None and isinstance(exception, case.SkipTest):
|
| + addSkip(error, str(exception))
|
| + else:
|
| + result.addError(error, sys.exc_info())
|
| +
|
| + def _handleModuleTearDown(self, result):
|
| + previousModule = self._get_previous_module(result)
|
| + if previousModule is None:
|
| + return
|
| + if result._moduleSetUpFailed:
|
| + return
|
| +
|
| + try:
|
| + module = sys.modules[previousModule]
|
| + except KeyError:
|
| + return
|
| +
|
| + tearDownModule = getattr(module, 'tearDownModule', None)
|
| + if tearDownModule is not None:
|
| + try:
|
| + tearDownModule()
|
| + except Exception, e:
|
| + if isinstance(result, _DebugResult):
|
| + raise
|
| + errorName = 'tearDownModule (%s)' % previousModule
|
| + self._addClassOrModuleLevelException(result, e, errorName)
|
| +
|
| + def _tearDownPreviousClass(self, test, result):
|
| + previousClass = getattr(result, '_previousTestClass', None)
|
| + currentClass = test.__class__
|
| + if currentClass == previousClass:
|
| + return
|
| + if getattr(previousClass, '_classSetupFailed', False):
|
| + return
|
| + if getattr(result, '_moduleSetUpFailed', False):
|
| + return
|
| + if getattr(previousClass, "__unittest_skip__", False):
|
| + return
|
| +
|
| + tearDownClass = getattr(previousClass, 'tearDownClass', None)
|
| + if tearDownClass is not None:
|
| + try:
|
| + tearDownClass()
|
| + except Exception, e:
|
| + if isinstance(result, _DebugResult):
|
| + raise
|
| + className = util.strclass(previousClass)
|
| + errorName = 'tearDownClass (%s)' % className
|
| + self._addClassOrModuleLevelException(result, e, errorName)
|
| +
|
| +
|
| +class _ErrorHolder(object):
|
| + """
|
| + Placeholder for a TestCase inside a result. As far as a TestResult
|
| + is concerned, this looks exactly like a unit test. Used to insert
|
| + arbitrary errors into a test suite run.
|
| + """
|
| + # Inspired by the ErrorHolder from Twisted:
|
| + # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
|
| +
|
| + # attribute used by TestResult._exc_info_to_string
|
| + failureException = None
|
| +
|
| + def __init__(self, description):
|
| + self.description = description
|
| +
|
| + def id(self):
|
| + return self.description
|
| +
|
| + def shortDescription(self):
|
| + return None
|
| +
|
| + def __repr__(self):
|
| + return "<ErrorHolder description=%r>" % (self.description,)
|
| +
|
| + def __str__(self):
|
| + return self.id()
|
| +
|
| + def run(self, result):
|
| + # could call result.addError(...) - but this test-like object
|
| + # shouldn't be run anyway
|
| + pass
|
| +
|
| + def __call__(self, result):
|
| + return self.run(result)
|
| +
|
| + def countTestCases(self):
|
| + return 0
|
| +
|
| +def _isnotsuite(test):
|
| + "A crude way to tell apart testcases and suites with duck-typing"
|
| + try:
|
| + iter(test)
|
| + except TypeError:
|
| + return True
|
| + return False
|
| +
|
| +
|
| +class _DebugResult(object):
|
| + "Used by the TestSuite to hold previous class when running in debug."
|
| + _previousTestClass = None
|
| + _moduleSetUpFailed = False
|
| + shouldStop = False
|
|
|