[GRASS-SVN] r61104 - sandbox/wenzeslaus/gunittest
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Jul 1 08:36:55 PDT 2014
Author: wenzeslaus
Date: 2014-07-01 08:36:55 -0700 (Tue, 01 Jul 2014)
New Revision: 61104
Added:
sandbox/wenzeslaus/gunittest/loader.py
sandbox/wenzeslaus/gunittest/main.py
sandbox/wenzeslaus/gunittest/runner.py
sandbox/wenzeslaus/gunittest/suite.py
Log:
gunittest: initial grass versions of loader, runner, suite and main (except for discover method mostly copied from Python unittest 2.7.4)
Added: sandbox/wenzeslaus/gunittest/loader.py
===================================================================
--- sandbox/wenzeslaus/gunittest/loader.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/loader.py 2014-07-01 15:36:55 UTC (rev 61104)
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+
+"""Loading unittests."""
+
+import os
+import sys
+import fnmatch
+import unittest
+import collections
+
+import suite
+
+GrassTestDir = collections.namedtuple('GrassTestDir', ['modules'])
+GrassTestPythonModule = collections.namedtuple('GrassTestPythonModule',
+ ['name', 'module',
+ 'tested_dir',
+ 'file_dir'])
+
+
+class GrassTestLoader(unittest.TestLoader):
+
+ skip_dirs = ['.svn', 'dist.*', 'bin.*', 'OBJ.*']
+ testsuite_dir = 'testsuite'
+ files_in_testsuite = '*.py'
+ suiteClass = suite.GrassTestSuite
+
+ # TODO: we ignore all parameters
+ def discover(self, start_dir, pattern='test*.py', top_level_dir=None):
+ modules = []
+ tests = []
+ for root, dirs, files in os.walk('.'):
+ for pattern in self.skip_dirs:
+ to_skip = fnmatch.filter(dirs, pattern)
+ for skip in to_skip:
+ dirs.remove(skip)
+
+ if self.testsuite_dir in dirs:
+ full = os.path.join(root, self.testsuite_dir)
+ files = fnmatch.filter(os.listdir(full), self.files_in_testsuite)
+ module_names = [f[:-3] for f in files if not f == '__init__.py']
+ for name in module_names:
+ sys.path.insert(0, full)
+ try:
+ import importlib
+ m = importlib.import_module(name)
+ #__import__(name)
+ modules.append(GrassTestPythonModule(name=name,
+ module=m,
+ tested_dir=root,
+ file_dir=full))
+ tests.append(self.loadTestsFromModule(m))
+ except ImportError as e:
+ raise ImportError('No module named %s in %s' % (name, full))
+ # alternative is to create TestClass which will raise
+ # see unittest.loader
+ return self.suiteClass(tests)
+
+
+if __name__ == '__main__':
+ GrassTestLoader().discoverGrassTestDirs()
Property changes on: sandbox/wenzeslaus/gunittest/loader.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: sandbox/wenzeslaus/gunittest/main.py
===================================================================
--- sandbox/wenzeslaus/gunittest/main.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/main.py 2014-07-01 15:36:55 UTC (rev 61104)
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+
+from unittest.main import TestProgram, USAGE_AS_MAIN
+TestProgram.USAGE = USAGE_AS_MAIN
+
+from loader import GrassTestLoader
+from runner import GrassTestRunner
+
+
+class GrassTestProgram(TestProgram):
+
+ def _do_discovery(self, argv, Loader=None):
+ """
+
+ Taken from Python's ``unittest.main.TestProgram._do_discovery()``.
+ Line::
+
+ Loader = lambda: self.testLoader
+
+ changed to::
+
+ Loader = self.testLoader
+ """
+ if Loader is None:
+ Loader = self.testLoader
+
+ # handle command line args for test discovery
+ self.progName = '%s discover' % self.progName
+ import optparse
+ parser = optparse.OptionParser()
+ parser.prog = self.progName
+ parser.add_option('-v', '--verbose', dest='verbose', default=False,
+ help='Verbose output', action='store_true')
+ if self.failfast != False:
+ parser.add_option('-f', '--failfast', dest='failfast', default=False,
+ help='Stop on first fail or error',
+ action='store_true')
+ if self.catchbreak != False:
+ parser.add_option('-c', '--catch', dest='catchbreak', default=False,
+ help='Catch ctrl-C and display results so far',
+ action='store_true')
+ if self.buffer != False:
+ parser.add_option('-b', '--buffer', dest='buffer', default=False,
+ help='Buffer stdout and stderr during tests',
+ action='store_true')
+ parser.add_option('-s', '--start-directory', dest='start', default='.',
+ help="Directory to start discovery ('.' default)")
+ parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
+ help="Pattern to match tests ('test*.py' default)")
+ parser.add_option('-t', '--top-level-directory', dest='top', default=None,
+ help='Top level directory of project (defaults to start directory)')
+
+ options, args = parser.parse_args(argv)
+ if len(args) > 3:
+ self.usageExit()
+
+ for name, value in zip(('start', 'pattern', 'top'), args):
+ setattr(options, name, value)
+
+ # only set options from the parsing here
+ # if they weren't set explicitly in the constructor
+ if self.failfast is None:
+ self.failfast = options.failfast
+ if self.catchbreak is None:
+ self.catchbreak = options.catchbreak
+ if self.buffer is None:
+ self.buffer = options.buffer
+
+ if options.verbose:
+ self.verbosity = 2
+
+ start_dir = options.start
+ pattern = options.pattern
+ top_level_dir = options.top
+
+ loader = Loader()
+ self.test = loader.discover(start_dir, pattern, top_level_dir)
+
+
+if __name__ == '__main__':
+ GrassTestProgram(module=None, testLoader=GrassTestLoader, testRunner=GrassTestRunner)
Property changes on: sandbox/wenzeslaus/gunittest/main.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: sandbox/wenzeslaus/gunittest/runner.py
===================================================================
--- sandbox/wenzeslaus/gunittest/runner.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/runner.py 2014-07-01 15:36:55 UTC (rev 61104)
@@ -0,0 +1,202 @@
+# -*- coding: utf-8 -*-
+
+"""Running tests
+
+File content taken from Python's ``unittest.runner``, it will be used as
+a template. It is not expected that something will left.
+"""
+
+import sys
+import time
+
+from unittest import result
+from unittest.signals import registerResult
+
+__unittest = True
+
+
+class _WritelnDecorator(object):
+ """Used to decorate file-like objects with a handy 'writeln' method"""
+ def __init__(self,stream):
+ self.stream = stream
+
+ def __getattr__(self, attr):
+ if attr in ('stream', '__getstate__'):
+ raise AttributeError(attr)
+ return getattr(self.stream,attr)
+
+ def writeln(self, arg=None):
+ if arg:
+ self.write(arg)
+ self.write('\n') # text-mode streams translate to \r\n if needed
+
+
+class TextTestResult(result.TestResult):
+ """A test result class that can print formatted text results to a stream.
+
+ Used by TextTestRunner.
+ """
+ separator1 = '=' * 70
+ separator2 = '-' * 70
+
+ def __init__(self, stream, descriptions, verbosity):
+ super(TextTestResult, self).__init__(stream, descriptions, verbosity)
+ self.stream = stream
+ self.showAll = verbosity > 1
+ self.dots = verbosity == 1
+ self.descriptions = descriptions
+
+ def getDescription(self, test):
+ doc_first_line = test.shortDescription()
+ if self.descriptions and doc_first_line:
+ return '\n'.join((str(test), doc_first_line))
+ else:
+ return str(test)
+
+ def startTest(self, test):
+ super(TextTestResult, self).startTest(test)
+ if self.showAll:
+ self.stream.write(self.getDescription(test))
+ self.stream.write(" ... ")
+ self.stream.flush()
+
+ def addSuccess(self, test):
+ super(TextTestResult, self).addSuccess(test)
+ if self.showAll:
+ self.stream.writeln("ok")
+ elif self.dots:
+ self.stream.write('.')
+ self.stream.flush()
+
+ def addError(self, test, err):
+ super(TextTestResult, self).addError(test, err)
+ if self.showAll:
+ self.stream.writeln("ERROR")
+ elif self.dots:
+ self.stream.write('E')
+ self.stream.flush()
+
+ def addFailure(self, test, err):
+ super(TextTestResult, self).addFailure(test, err)
+ if self.showAll:
+ self.stream.writeln("FAIL")
+ elif self.dots:
+ self.stream.write('F')
+ self.stream.flush()
+
+ def addSkip(self, test, reason):
+ super(TextTestResult, self).addSkip(test, reason)
+ if self.showAll:
+ self.stream.writeln("skipped {0!r}".format(reason))
+ elif self.dots:
+ self.stream.write("s")
+ self.stream.flush()
+
+ def addExpectedFailure(self, test, err):
+ super(TextTestResult, self).addExpectedFailure(test, err)
+ if self.showAll:
+ self.stream.writeln("expected failure")
+ elif self.dots:
+ self.stream.write("x")
+ self.stream.flush()
+
+ def addUnexpectedSuccess(self, test):
+ super(TextTestResult, self).addUnexpectedSuccess(test)
+ if self.showAll:
+ self.stream.writeln("unexpected success")
+ elif self.dots:
+ self.stream.write("u")
+ self.stream.flush()
+
+ def printErrors(self):
+ if self.dots or self.showAll:
+ 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 GrassTestRunner(object):
+ """A test runner class that displays results in textual form.
+
+ It prints out the names of tests as they are run, errors as they
+ occur, and a summary of the results at the end of the test run.
+ """
+ resultclass = TextTestResult
+
+ def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
+ failfast=False, buffer=False, resultclass=None):
+ self.stream = _WritelnDecorator(stream)
+ self.descriptions = descriptions
+ self.verbosity = verbosity
+ self.failfast = failfast
+ self.buffer = buffer
+ if resultclass is not None:
+ self.resultclass = resultclass
+
+ def _makeResult(self):
+ return self.resultclass(self.stream, self.descriptions, self.verbosity)
+
+ def run(self, test):
+ "Run the given test case or test suite."
+ result = self._makeResult()
+ registerResult(result)
+ result.failfast = self.failfast
+ result.buffer = self.buffer
+ startTime = time.time()
+ startTestRun = getattr(result, 'startTestRun', None)
+ if startTestRun is not None:
+ startTestRun()
+ try:
+ test(result)
+ finally:
+ stopTestRun = getattr(result, 'stopTestRun', None)
+ if stopTestRun is not None:
+ stopTestRun()
+ stopTime = time.time()
+ timeTaken = stopTime - startTime
+ result.printErrors()
+ if hasattr(result, 'separator2'):
+ 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()
+
+ expectedFails = unexpectedSuccesses = skipped = 0
+ try:
+ results = map(len, (result.expectedFailures,
+ result.unexpectedSuccesses,
+ result.skipped))
+ except AttributeError:
+ pass
+ else:
+ expectedFails, unexpectedSuccesses, skipped = results
+
+ infos = []
+ if not result.wasSuccessful():
+ self.stream.write("FAILED")
+ failed, errored = map(len, (result.failures, result.errors))
+ if failed:
+ infos.append("failures=%d" % failed)
+ if errored:
+ infos.append("errors=%d" % errored)
+ else:
+ self.stream.write("OK")
+ if skipped:
+ infos.append("skipped=%d" % skipped)
+ if expectedFails:
+ infos.append("expected failures=%d" % expectedFails)
+ if unexpectedSuccesses:
+ infos.append("unexpected successes=%d" % unexpectedSuccesses)
+ if infos:
+ self.stream.writeln(" (%s)" % (", ".join(infos),))
+ else:
+ self.stream.write("\n")
+ return result
Property changes on: sandbox/wenzeslaus/gunittest/runner.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: sandbox/wenzeslaus/gunittest/suite.py
===================================================================
--- sandbox/wenzeslaus/gunittest/suite.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/suite.py 2014-07-01 15:36:55 UTC (rev 61104)
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+
+
+class GrassTestSuite(unittest.TestSuite):
+
+ def run(self, result, debug=False):
+ """
+
+ Original function implementation taken from Python's ``unittest.suite``.
+ """
+ topLevel = False
+ if getattr(result, '_testRunEntered', False) is False:
+ result._testRunEntered = topLevel = True
+
+ 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 not debug:
+ test(result)
+ else:
+ test.debug()
+
+ if topLevel:
+ self._tearDownPreviousClass(None, result)
+ self._handleModuleTearDown(result)
+ result._testRunEntered = False
+ return result
+
+
+# helper from unittest.suite for the original implementation of run
+def _isnotsuite(test):
+ "A crude way to tell apart testcases and suites with duck-typing"
+ try:
+ iter(test)
+ except TypeError:
+ return True
+ return False
Property changes on: sandbox/wenzeslaus/gunittest/suite.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
More information about the grass-commit
mailing list