blob: bd5f2a44a97d7ec80cdc6d257229ac7c3c0b8336 [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Unittest main program"""
2
3import sys
4import os
5import types
6
7from . import loader, runner
Michael Foord65b69a12010-03-27 13:25:41 +00008from .signals import installHandler
Benjamin Petersonbed7d042009-07-19 21:01:52 +00009
Benjamin Petersondccc1fc2010-03-22 00:15:53 +000010__unittest = True
11
Benjamin Petersonb48af542010-04-11 20:43:16 +000012FAILFAST = " -f, --failfast Stop on first failure\n"
13CATCHBREAK = " -c, --catch Catch control-C and display results\n"
14BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n"
Michael Foord65b69a12010-03-27 13:25:41 +000015
Benjamin Petersonbed7d042009-07-19 21:01:52 +000016USAGE_AS_MAIN = """\
17Usage: %(progName)s [options] [tests]
18
19Options:
20 -h, --help Show this message
21 -v, --verbose Verbose output
22 -q, --quiet Minimal output
Benjamin Petersonb48af542010-04-11 20:43:16 +000023%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersonbed7d042009-07-19 21:01:52 +000024Examples:
Michael Foordf707aa72010-05-10 20:23:58 +000025 %(progName)s test_module - run tests from test_module
26 %(progName)s module.TestClass - run tests from module.TestClass
27 %(progName)s module.Class.test_method - run specified test method
Benjamin Petersonbed7d042009-07-19 21:01:52 +000028
29[tests] can be a list of any number of test modules, classes and test
30methods.
31
32Alternative Usage: %(progName)s discover [options]
33
34Options:
35 -v, --verbose Verbose output
Benjamin Petersonb48af542010-04-11 20:43:16 +000036%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
Benjamin Petersonbed7d042009-07-19 21:01:52 +000037 -p pattern Pattern to match test files ('test*.py' default)
38 -t directory Top level directory of project (default to
39 start directory)
40
41For test discovery all test modules must be importable from the top
42level directory of the project.
43"""
44
45USAGE_FROM_MODULE = """\
46Usage: %(progName)s [options] [test] [...]
47
48Options:
49 -h, --help Show this message
50 -v, --verbose Verbose output
51 -q, --quiet Minimal output
Benjamin Petersonb48af542010-04-11 20:43:16 +000052%(failfast)s%(catchbreak)s%(buffer)s
Benjamin Petersonbed7d042009-07-19 21:01:52 +000053Examples:
54 %(progName)s - run default set of tests
55 %(progName)s MyTestSuite - run suite 'MyTestSuite'
56 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
57 %(progName)s MyTestCase - run all 'test*' test methods
58 in MyTestCase
59"""
60
Michael Foord65b69a12010-03-27 13:25:41 +000061
62
Benjamin Petersonbed7d042009-07-19 21:01:52 +000063class TestProgram(object):
64 """A command-line program that runs a set of tests; this is primarily
65 for making test modules conveniently executable.
66 """
Benjamin Petersoneab4b4c2010-03-22 02:53:52 +000067 USAGE = USAGE_FROM_MODULE
Michael Foord65b69a12010-03-27 13:25:41 +000068
69 # defaults for testing
Ezio Melotti60901872010-12-01 00:56:10 +000070 failfast = catchbreak = buffer = progName = warnings = None
Michael Foord65b69a12010-03-27 13:25:41 +000071
Michael Foord4a8cf3c2010-05-07 15:35:24 +000072 def __init__(self, module='__main__', defaultTest=None, argv=None,
73 testRunner=None, testLoader=loader.defaultTestLoader,
74 exit=True, verbosity=1, failfast=None, catchbreak=None,
Ezio Melotti60901872010-12-01 00:56:10 +000075 buffer=None, warnings=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +000076 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
85 self.exit = exit
Benjamin Peterson8769fd82010-03-22 01:13:48 +000086 self.failfast = failfast
Michael Foord65b69a12010-03-27 13:25:41 +000087 self.catchbreak = catchbreak
Benjamin Petersonbed7d042009-07-19 21:01:52 +000088 self.verbosity = verbosity
Benjamin Petersonb48af542010-04-11 20:43:16 +000089 self.buffer = buffer
Ezio Melotti60901872010-12-01 00:56:10 +000090 if warnings is None and not sys.warnoptions:
91 # even if DreprecationWarnings are ignored by default
92 # print them anyway unless other warnings settings are
93 # specified by the warnings arg or the -W python flag
94 self.warnings = 'default'
95 else:
96 # here self.warnings is set either to the value passed
97 # to the warnings args or to None.
98 # If the user didn't pass a value self.warnings will
99 # be None. This means that the behavior is unchanged
100 # and depends on the values passed to -W.
101 self.warnings = warnings
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000102 self.defaultTest = defaultTest
103 self.testRunner = testRunner
104 self.testLoader = testLoader
105 self.progName = os.path.basename(argv[0])
106 self.parseArgs(argv)
107 self.runTests()
108
109 def usageExit(self, msg=None):
110 if msg:
111 print(msg)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000112 usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
113 'buffer': ''}
Michael Foord65b69a12010-03-27 13:25:41 +0000114 if self.failfast != False:
115 usage['failfast'] = FAILFAST
116 if self.catchbreak != False:
117 usage['catchbreak'] = CATCHBREAK
Benjamin Petersonb48af542010-04-11 20:43:16 +0000118 if self.buffer != False:
119 usage['buffer'] = BUFFEROUTPUT
Michael Foord65b69a12010-03-27 13:25:41 +0000120 print(self.USAGE % usage)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000121 sys.exit(2)
122
123 def parseArgs(self, argv):
Michael Foord086f3082010-11-21 21:28:01 +0000124 if ((len(argv) > 1 and argv[1].lower() == 'discover') or
125 (len(argv) == 1 and self.module is None)):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000126 self._do_discovery(argv[2:])
127 return
128
129 import getopt
Benjamin Petersonb48af542010-04-11 20:43:16 +0000130 long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000131 try:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000132 options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000133 for opt, value in options:
134 if opt in ('-h','-H','--help'):
135 self.usageExit()
136 if opt in ('-q','--quiet'):
137 self.verbosity = 0
138 if opt in ('-v','--verbose'):
139 self.verbosity = 2
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000140 if opt in ('-f','--failfast'):
Michael Foord65b69a12010-03-27 13:25:41 +0000141 if self.failfast is None:
142 self.failfast = True
143 # Should this raise an exception if -f is not valid?
144 if opt in ('-c','--catch'):
145 if self.catchbreak is None:
146 self.catchbreak = True
147 # Should this raise an exception if -c is not valid?
Benjamin Petersonb48af542010-04-11 20:43:16 +0000148 if opt in ('-b','--buffer'):
149 if self.buffer is None:
150 self.buffer = True
151 # Should this raise an exception if -b is not valid?
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000152 if len(args) == 0 and self.defaultTest is None:
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000153 # createTests will load tests from self.module
154 self.testNames = None
155 elif len(args) > 0:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000156 self.testNames = args
157 if __name__ == '__main__':
158 # to support python -m unittest ...
159 self.module = None
160 else:
161 self.testNames = (self.defaultTest,)
162 self.createTests()
163 except getopt.error as msg:
164 self.usageExit(msg)
165
166 def createTests(self):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000167 if self.testNames is None:
168 self.test = self.testLoader.loadTestsFromModule(self.module)
169 else:
170 self.test = self.testLoader.loadTestsFromNames(self.testNames,
171 self.module)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000172
173 def _do_discovery(self, argv, Loader=loader.TestLoader):
174 # handle command line args for test discovery
Michael Foordf707aa72010-05-10 20:23:58 +0000175 self.progName = '%s discover' % self.progName
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000176 import optparse
177 parser = optparse.OptionParser()
Michael Foordf707aa72010-05-10 20:23:58 +0000178 parser.prog = self.progName
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000179 parser.add_option('-v', '--verbose', dest='verbose', default=False,
180 help='Verbose output', action='store_true')
Michael Foord65b69a12010-03-27 13:25:41 +0000181 if self.failfast != False:
182 parser.add_option('-f', '--failfast', dest='failfast', default=False,
183 help='Stop on first fail or error',
184 action='store_true')
185 if self.catchbreak != False:
186 parser.add_option('-c', '--catch', dest='catchbreak', default=False,
187 help='Catch ctrl-C and display results so far',
188 action='store_true')
Benjamin Petersonb48af542010-04-11 20:43:16 +0000189 if self.buffer != False:
190 parser.add_option('-b', '--buffer', dest='buffer', default=False,
191 help='Buffer stdout and stderr during tests',
192 action='store_true')
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000193 parser.add_option('-s', '--start-directory', dest='start', default='.',
194 help="Directory to start discovery ('.' default)")
195 parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
196 help="Pattern to match tests ('test*.py' default)")
197 parser.add_option('-t', '--top-level-directory', dest='top', default=None,
198 help='Top level directory of project (defaults to start directory)')
199
200 options, args = parser.parse_args(argv)
201 if len(args) > 3:
202 self.usageExit()
203
204 for name, value in zip(('start', 'pattern', 'top'), args):
205 setattr(options, name, value)
206
Michael Foord65b69a12010-03-27 13:25:41 +0000207 # 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
Benjamin Petersonb48af542010-04-11 20:43:16 +0000213 if self.buffer is None:
214 self.buffer = options.buffer
Michael Foord65b69a12010-03-27 13:25:41 +0000215
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000216 if options.verbose:
217 self.verbosity = 2
218
219 start_dir = options.start
220 pattern = options.pattern
221 top_level_dir = options.top
222
223 loader = Loader()
224 self.test = loader.discover(start_dir, pattern, top_level_dir)
225
226 def runTests(self):
Michael Foord65b69a12010-03-27 13:25:41 +0000227 if self.catchbreak:
228 installHandler()
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000229 if self.testRunner is None:
230 self.testRunner = runner.TextTestRunner
231 if isinstance(self.testRunner, type):
232 try:
Benjamin Peterson8769fd82010-03-22 01:13:48 +0000233 testRunner = self.testRunner(verbosity=self.verbosity,
Benjamin Petersonb48af542010-04-11 20:43:16 +0000234 failfast=self.failfast,
Ezio Melotti60901872010-12-01 00:56:10 +0000235 buffer=self.buffer,
236 warnings=self.warnings)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000237 except TypeError:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000238 # didn't accept the verbosity, buffer or failfast arguments
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000239 testRunner = self.testRunner()
240 else:
241 # it is assumed to be a TestRunner instance
242 testRunner = self.testRunner
243 self.result = testRunner.run(self.test)
244 if self.exit:
245 sys.exit(not self.result.wasSuccessful())
246
247main = TestProgram