PageRenderTime 48ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/kbe/res/scripts/common/Lib/unittest/main.py

https://bitbucket.org/kbengine/kbengine
Python | 277 lines | 271 code | 5 blank | 1 comment | 1 complexity | 44b968f021f34fde22716a350da00399 MD5 | raw file
  1. """Unittest main program"""
  2. import sys
  3. import os
  4. import types
  5. from . import loader, runner
  6. from .signals import installHandler
  7. __unittest = True
  8. FAILFAST = " -f, --failfast Stop on first failure\n"
  9. CATCHBREAK = " -c, --catch Catch control-C and display results\n"
  10. BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n"
  11. USAGE_AS_MAIN = """\
  12. Usage: %(progName)s [options] [tests]
  13. Options:
  14. -h, --help Show this message
  15. -v, --verbose Verbose output
  16. -q, --quiet Minimal output
  17. %(failfast)s%(catchbreak)s%(buffer)s
  18. Examples:
  19. %(progName)s test_module - run tests from test_module
  20. %(progName)s module.TestClass - run tests from module.TestClass
  21. %(progName)s module.Class.test_method - run specified test method
  22. [tests] can be a list of any number of test modules, classes and test
  23. methods.
  24. Alternative Usage: %(progName)s discover [options]
  25. Options:
  26. -v, --verbose Verbose output
  27. %(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
  28. -p pattern Pattern to match test files ('test*.py' default)
  29. -t directory Top level directory of project (default to
  30. start directory)
  31. For test discovery all test modules must be importable from the top
  32. level directory of the project.
  33. """
  34. USAGE_FROM_MODULE = """\
  35. Usage: %(progName)s [options] [test] [...]
  36. Options:
  37. -h, --help Show this message
  38. -v, --verbose Verbose output
  39. -q, --quiet Minimal output
  40. %(failfast)s%(catchbreak)s%(buffer)s
  41. Examples:
  42. %(progName)s - run default set of tests
  43. %(progName)s MyTestSuite - run suite 'MyTestSuite'
  44. %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
  45. %(progName)s MyTestCase - run all 'test*' test methods
  46. in MyTestCase
  47. """
  48. def _convert_name(name):
  49. # on Linux / Mac OS X 'foo.PY' is not importable, but on
  50. # Windows it is. Simpler to do a case insensitive match
  51. # a better check would be to check that the name is a
  52. # valid Python module name.
  53. if os.path.isfile(name) and name.lower().endswith('.py'):
  54. if os.path.isabs(name):
  55. rel_path = os.path.relpath(name, os.getcwd())
  56. if os.path.isabs(rel_path) or rel_path.startswith(os.pardir):
  57. return name
  58. name = rel_path
  59. # on Windows both '\' and '/' are used as path
  60. # separators. Better to replace both than rely on os.path.sep
  61. return name[:-3].replace('\\', '.').replace('/', '.')
  62. return name
  63. def _convert_names(names):
  64. return [_convert_name(name) for name in names]
  65. class TestProgram(object):
  66. """A command-line program that runs a set of tests; this is primarily
  67. for making test modules conveniently executable.
  68. """
  69. USAGE = USAGE_FROM_MODULE
  70. # defaults for testing
  71. failfast = catchbreak = buffer = progName = warnings = None
  72. def __init__(self, module='__main__', defaultTest=None, argv=None,
  73. testRunner=None, testLoader=loader.defaultTestLoader,
  74. exit=True, verbosity=1, failfast=None, catchbreak=None,
  75. buffer=None, warnings=None):
  76. if isinstance(module, str):
  77. self.module = __import__(module)
  78. for part in module.split('.')[1:]:
  79. self.module = getattr(self.module, part)
  80. else:
  81. self.module = module
  82. if argv is None:
  83. argv = sys.argv
  84. self.exit = exit
  85. self.failfast = failfast
  86. self.catchbreak = catchbreak
  87. self.verbosity = verbosity
  88. self.buffer = buffer
  89. if warnings is None and not sys.warnoptions:
  90. # even if DreprecationWarnings are ignored by default
  91. # print them anyway unless other warnings settings are
  92. # specified by the warnings arg or the -W python flag
  93. self.warnings = 'default'
  94. else:
  95. # here self.warnings is set either to the value passed
  96. # to the warnings args or to None.
  97. # If the user didn't pass a value self.warnings will
  98. # be None. This means that the behavior is unchanged
  99. # and depends on the values passed to -W.
  100. self.warnings = warnings
  101. self.defaultTest = defaultTest
  102. self.testRunner = testRunner
  103. self.testLoader = testLoader
  104. self.progName = os.path.basename(argv[0])
  105. self.parseArgs(argv)
  106. self.runTests()
  107. def usageExit(self, msg=None):
  108. if msg:
  109. print(msg)
  110. usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
  111. 'buffer': ''}
  112. if self.failfast != False:
  113. usage['failfast'] = FAILFAST
  114. if self.catchbreak != False:
  115. usage['catchbreak'] = CATCHBREAK
  116. if self.buffer != False:
  117. usage['buffer'] = BUFFEROUTPUT
  118. print(self.USAGE % usage)
  119. sys.exit(2)
  120. def parseArgs(self, argv):
  121. if ((len(argv) > 1 and argv[1].lower() == 'discover') or
  122. (len(argv) == 1 and self.module is None)):
  123. self._do_discovery(argv[2:])
  124. return
  125. import getopt
  126. long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
  127. try:
  128. options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
  129. except getopt.error as msg:
  130. self.usageExit(msg)
  131. return
  132. for opt, value in options:
  133. if opt in ('-h','-H','--help'):
  134. self.usageExit()
  135. if opt in ('-q','--quiet'):
  136. self.verbosity = 0
  137. if opt in ('-v','--verbose'):
  138. self.verbosity = 2
  139. if opt in ('-f','--failfast'):
  140. if self.failfast is None:
  141. self.failfast = True
  142. # Should this raise an exception if -f is not valid?
  143. if opt in ('-c','--catch'):
  144. if self.catchbreak is None:
  145. self.catchbreak = True
  146. # Should this raise an exception if -c is not valid?
  147. if opt in ('-b','--buffer'):
  148. if self.buffer is None:
  149. self.buffer = True
  150. # Should this raise an exception if -b is not valid?
  151. if len(args) == 0 and self.module is None:
  152. # this allows "python -m unittest -v" to still work for
  153. # test discovery. This means -c / -b / -v / -f options will
  154. # be handled twice, which is harmless but not ideal.
  155. self._do_discovery(argv[1:])
  156. return
  157. if len(args) == 0 and self.defaultTest is None:
  158. # createTests will load tests from self.module
  159. self.testNames = None
  160. elif len(args) > 0:
  161. self.testNames = _convert_names(args)
  162. if __name__ == '__main__':
  163. # to support python -m unittest ...
  164. self.module = None
  165. else:
  166. self.testNames = (self.defaultTest,)
  167. self.createTests()
  168. def createTests(self):
  169. if self.testNames is None:
  170. self.test = self.testLoader.loadTestsFromModule(self.module)
  171. else:
  172. self.test = self.testLoader.loadTestsFromNames(self.testNames,
  173. self.module)
  174. def _do_discovery(self, argv, Loader=None):
  175. if Loader is None:
  176. Loader = lambda: self.testLoader
  177. # handle command line args for test discovery
  178. self.progName = '%s discover' % self.progName
  179. import optparse
  180. parser = optparse.OptionParser()
  181. parser.prog = self.progName
  182. parser.add_option('-v', '--verbose', dest='verbose', default=False,
  183. help='Verbose output', action='store_true')
  184. if self.failfast != False:
  185. parser.add_option('-f', '--failfast', dest='failfast', default=False,
  186. help='Stop on first fail or error',
  187. action='store_true')
  188. if self.catchbreak != False:
  189. parser.add_option('-c', '--catch', dest='catchbreak', default=False,
  190. help='Catch ctrl-C and display results so far',
  191. action='store_true')
  192. if self.buffer != False:
  193. parser.add_option('-b', '--buffer', dest='buffer', default=False,
  194. help='Buffer stdout and stderr during tests',
  195. action='store_true')
  196. parser.add_option('-s', '--start-directory', dest='start', default='.',
  197. help="Directory to start discovery ('.' default)")
  198. parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
  199. help="Pattern to match tests ('test*.py' default)")
  200. parser.add_option('-t', '--top-level-directory', dest='top', default=None,
  201. help='Top level directory of project (defaults to start directory)')
  202. options, args = parser.parse_args(argv)
  203. if len(args) > 3:
  204. self.usageExit()
  205. for name, value in zip(('start', 'pattern', 'top'), args):
  206. setattr(options, name, value)
  207. # only set options from the parsing here
  208. # if they weren't set explicitly in the constructor
  209. if self.failfast is None:
  210. self.failfast = options.failfast
  211. if self.catchbreak is None:
  212. self.catchbreak = options.catchbreak
  213. if self.buffer is None:
  214. self.buffer = options.buffer
  215. if options.verbose:
  216. self.verbosity = 2
  217. start_dir = options.start
  218. pattern = options.pattern
  219. top_level_dir = options.top
  220. loader = Loader()
  221. self.test = loader.discover(start_dir, pattern, top_level_dir)
  222. def runTests(self):
  223. if self.catchbreak:
  224. installHandler()
  225. if self.testRunner is None:
  226. self.testRunner = runner.TextTestRunner
  227. if isinstance(self.testRunner, type):
  228. try:
  229. testRunner = self.testRunner(verbosity=self.verbosity,
  230. failfast=self.failfast,
  231. buffer=self.buffer,
  232. warnings=self.warnings)
  233. except TypeError:
  234. # didn't accept the verbosity, buffer or failfast arguments
  235. testRunner = self.testRunner()
  236. else:
  237. # it is assumed to be a TestRunner instance
  238. testRunner = self.testRunner
  239. self.result = testRunner.run(self.test)
  240. if self.exit:
  241. sys.exit(not self.result.wasSuccessful())
  242. main = TestProgram