runner.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- coding: utf-8 -*-
  2. """!@package grass.gunittest.runner
  3. @brief Testing framework module for running tests in Python unittest fashion
  4. Copyright (C) 2014 by the GRASS Development Team
  5. This program is free software under the GNU General Public
  6. License (>=v2). Read the file COPYING that comes with GRASS GIS
  7. for details.
  8. @author Vaclav Petras
  9. File content taken from Python's ``unittest.runner``, it will be used as
  10. a template. It is not expected that something will left.
  11. """
  12. import sys
  13. import time
  14. from unittest import result
  15. from unittest.signals import registerResult
  16. __unittest = True
  17. class _WritelnDecorator(object):
  18. """Used to decorate file-like objects with a handy 'writeln' method"""
  19. def __init__(self,stream):
  20. self.stream = stream
  21. def __getattr__(self, attr):
  22. if attr in ('stream', '__getstate__'):
  23. raise AttributeError(attr)
  24. return getattr(self.stream,attr)
  25. def writeln(self, arg=None):
  26. if arg:
  27. self.write(arg)
  28. self.write('\n') # text-mode streams translate to \r\n if needed
  29. class TextTestResult(result.TestResult):
  30. """A test result class that can print formatted text results to a stream.
  31. Used by TextTestRunner.
  32. """
  33. separator1 = '=' * 70
  34. separator2 = '-' * 70
  35. def __init__(self, stream, descriptions, verbosity):
  36. super(TextTestResult, self).__init__(stream, descriptions, verbosity)
  37. self.stream = stream
  38. self.showAll = verbosity > 1
  39. self.dots = verbosity == 1
  40. self.descriptions = descriptions
  41. def getDescription(self, test):
  42. doc_first_line = test.shortDescription()
  43. if self.descriptions and doc_first_line:
  44. return '\n'.join((str(test), doc_first_line))
  45. else:
  46. return str(test)
  47. def startTest(self, test):
  48. super(TextTestResult, self).startTest(test)
  49. if self.showAll:
  50. self.stream.write(self.getDescription(test))
  51. self.stream.write(" ... ")
  52. self.stream.flush()
  53. def addSuccess(self, test):
  54. super(TextTestResult, self).addSuccess(test)
  55. if self.showAll:
  56. self.stream.writeln("ok")
  57. elif self.dots:
  58. self.stream.write('.')
  59. self.stream.flush()
  60. def addError(self, test, err):
  61. super(TextTestResult, self).addError(test, err)
  62. if self.showAll:
  63. self.stream.writeln("ERROR")
  64. elif self.dots:
  65. self.stream.write('E')
  66. self.stream.flush()
  67. def addFailure(self, test, err):
  68. super(TextTestResult, self).addFailure(test, err)
  69. if self.showAll:
  70. self.stream.writeln("FAIL")
  71. elif self.dots:
  72. self.stream.write('F')
  73. self.stream.flush()
  74. def addSkip(self, test, reason):
  75. super(TextTestResult, self).addSkip(test, reason)
  76. if self.showAll:
  77. self.stream.writeln("skipped {0!r}".format(reason))
  78. elif self.dots:
  79. self.stream.write("s")
  80. self.stream.flush()
  81. def addExpectedFailure(self, test, err):
  82. super(TextTestResult, self).addExpectedFailure(test, err)
  83. if self.showAll:
  84. self.stream.writeln("expected failure")
  85. elif self.dots:
  86. self.stream.write("x")
  87. self.stream.flush()
  88. def addUnexpectedSuccess(self, test):
  89. super(TextTestResult, self).addUnexpectedSuccess(test)
  90. if self.showAll:
  91. self.stream.writeln("unexpected success")
  92. elif self.dots:
  93. self.stream.write("u")
  94. self.stream.flush()
  95. def printErrors(self):
  96. if self.dots or self.showAll:
  97. self.stream.writeln()
  98. self.printErrorList('ERROR', self.errors)
  99. self.printErrorList('FAIL', self.failures)
  100. def printErrorList(self, flavour, errors):
  101. for test, err in errors:
  102. self.stream.writeln(self.separator1)
  103. self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
  104. self.stream.writeln(self.separator2)
  105. self.stream.writeln("%s" % err)
  106. class GrassTestRunner(object):
  107. """A test runner class that displays results in textual form.
  108. It prints out the names of tests as they are run, errors as they
  109. occur, and a summary of the results at the end of the test run.
  110. """
  111. resultclass = TextTestResult
  112. def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
  113. failfast=False, buffer=False, resultclass=None):
  114. self.stream = _WritelnDecorator(stream)
  115. self.descriptions = descriptions
  116. self.verbosity = verbosity
  117. self.failfast = failfast
  118. self.buffer = buffer
  119. if resultclass is not None:
  120. self.resultclass = resultclass
  121. def _makeResult(self):
  122. return self.resultclass(self.stream, self.descriptions, self.verbosity)
  123. def run(self, test):
  124. "Run the given test case or test suite."
  125. result = self._makeResult()
  126. registerResult(result)
  127. result.failfast = self.failfast
  128. result.buffer = self.buffer
  129. startTime = time.time()
  130. startTestRun = getattr(result, 'startTestRun', None)
  131. if startTestRun is not None:
  132. startTestRun()
  133. try:
  134. test(result)
  135. finally:
  136. stopTestRun = getattr(result, 'stopTestRun', None)
  137. if stopTestRun is not None:
  138. stopTestRun()
  139. stopTime = time.time()
  140. timeTaken = stopTime - startTime
  141. result.printErrors()
  142. if hasattr(result, 'separator2'):
  143. self.stream.writeln(result.separator2)
  144. run = result.testsRun
  145. self.stream.writeln("Ran %d test%s in %.3fs" %
  146. (run, run != 1 and "s" or "", timeTaken))
  147. self.stream.writeln()
  148. expectedFails = unexpectedSuccesses = skipped = 0
  149. try:
  150. results = map(len, (result.expectedFailures,
  151. result.unexpectedSuccesses,
  152. result.skipped))
  153. except AttributeError:
  154. pass
  155. else:
  156. expectedFails, unexpectedSuccesses, skipped = results
  157. infos = []
  158. if not result.wasSuccessful():
  159. self.stream.write("FAILED")
  160. failed, errored = map(len, (result.failures, result.errors))
  161. if failed:
  162. infos.append("failures=%d" % failed)
  163. if errored:
  164. infos.append("errors=%d" % errored)
  165. else:
  166. self.stream.write("OK")
  167. if skipped:
  168. infos.append("skipped=%d" % skipped)
  169. if expectedFails:
  170. infos.append("expected failures=%d" % expectedFails)
  171. if unexpectedSuccesses:
  172. infos.append("unexpected successes=%d" % unexpectedSuccesses)
  173. if infos:
  174. self.stream.writeln(" (%s)" % (", ".join(infos),))
  175. else:
  176. self.stream.write("\n")
  177. return result