1import io 2 3import os 4import sys 5import subprocess 6from test import support 7import unittest 8import unittest.test 9 10 11class Test_TestProgram(unittest.TestCase): 12 13 def test_discovery_from_dotted_path(self): 14 loader = unittest.TestLoader() 15 16 tests = [self] 17 expectedPath = os.path.abspath(os.path.dirname(unittest.test.__file__)) 18 19 self.wasRun = False 20 def _find_tests(start_dir, pattern): 21 self.wasRun = True 22 self.assertEqual(start_dir, expectedPath) 23 return tests 24 loader._find_tests = _find_tests 25 suite = loader.discover('unittest.test') 26 self.assertTrue(self.wasRun) 27 self.assertEqual(suite._tests, tests) 28 29 # Horrible white box test 30 def testNoExit(self): 31 result = object() 32 test = object() 33 34 class FakeRunner(object): 35 def run(self, test): 36 self.test = test 37 return result 38 39 runner = FakeRunner() 40 41 oldParseArgs = unittest.TestProgram.parseArgs 42 def restoreParseArgs(): 43 unittest.TestProgram.parseArgs = oldParseArgs 44 unittest.TestProgram.parseArgs = lambda *args: None 45 self.addCleanup(restoreParseArgs) 46 47 def removeTest(): 48 del unittest.TestProgram.test 49 unittest.TestProgram.test = test 50 self.addCleanup(removeTest) 51 52 program = unittest.TestProgram(testRunner=runner, exit=False, verbosity=2) 53 54 self.assertEqual(program.result, result) 55 self.assertEqual(runner.test, test) 56 self.assertEqual(program.verbosity, 2) 57 58 class FooBar(unittest.TestCase): 59 def testPass(self): 60 assert True 61 def testFail(self): 62 assert False 63 64 class FooBarLoader(unittest.TestLoader): 65 """Test loader that returns a suite containing FooBar.""" 66 def loadTestsFromModule(self, module): 67 return self.suiteClass( 68 [self.loadTestsFromTestCase(Test_TestProgram.FooBar)]) 69 70 def loadTestsFromNames(self, names, module): 71 return self.suiteClass( 72 [self.loadTestsFromTestCase(Test_TestProgram.FooBar)]) 73 74 def test_defaultTest_with_string(self): 75 class FakeRunner(object): 76 def run(self, test): 77 self.test = test 78 return True 79 80 old_argv = sys.argv 81 sys.argv = ['faketest'] 82 runner = FakeRunner() 83 program = unittest.TestProgram(testRunner=runner, exit=False, 84 defaultTest='unittest.test', 85 testLoader=self.FooBarLoader()) 86 sys.argv = old_argv 87 self.assertEqual(('unittest.test',), program.testNames) 88 89 def test_defaultTest_with_iterable(self): 90 class FakeRunner(object): 91 def run(self, test): 92 self.test = test 93 return True 94 95 old_argv = sys.argv 96 sys.argv = ['faketest'] 97 runner = FakeRunner() 98 program = unittest.TestProgram( 99 testRunner=runner, exit=False, 100 defaultTest=['unittest.test', 'unittest.test2'], 101 testLoader=self.FooBarLoader()) 102 sys.argv = old_argv 103 self.assertEqual(['unittest.test', 'unittest.test2'], 104 program.testNames) 105 106 def test_NonExit(self): 107 program = unittest.main(exit=False, 108 argv=["foobar"], 109 testRunner=unittest.TextTestRunner(stream=io.StringIO()), 110 testLoader=self.FooBarLoader()) 111 self.assertTrue(hasattr(program, 'result')) 112 113 114 def test_Exit(self): 115 self.assertRaises( 116 SystemExit, 117 unittest.main, 118 argv=["foobar"], 119 testRunner=unittest.TextTestRunner(stream=io.StringIO()), 120 exit=True, 121 testLoader=self.FooBarLoader()) 122 123 124 def test_ExitAsDefault(self): 125 self.assertRaises( 126 SystemExit, 127 unittest.main, 128 argv=["foobar"], 129 testRunner=unittest.TextTestRunner(stream=io.StringIO()), 130 testLoader=self.FooBarLoader()) 131 132 133class InitialisableProgram(unittest.TestProgram): 134 exit = False 135 result = None 136 verbosity = 1 137 defaultTest = None 138 tb_locals = False 139 testRunner = None 140 testLoader = unittest.defaultTestLoader 141 module = '__main__' 142 progName = 'test' 143 test = 'test' 144 def __init__(self, *args): 145 pass 146 147RESULT = object() 148 149class FakeRunner(object): 150 initArgs = None 151 test = None 152 raiseError = 0 153 154 def __init__(self, **kwargs): 155 FakeRunner.initArgs = kwargs 156 if FakeRunner.raiseError: 157 FakeRunner.raiseError -= 1 158 raise TypeError 159 160 def run(self, test): 161 FakeRunner.test = test 162 return RESULT 163 164 165class TestCommandLineArgs(unittest.TestCase): 166 167 def setUp(self): 168 self.program = InitialisableProgram() 169 self.program.createTests = lambda: None 170 FakeRunner.initArgs = None 171 FakeRunner.test = None 172 FakeRunner.raiseError = 0 173 174 def testVerbosity(self): 175 program = self.program 176 177 for opt in '-q', '--quiet': 178 program.verbosity = 1 179 program.parseArgs([None, opt]) 180 self.assertEqual(program.verbosity, 0) 181 182 for opt in '-v', '--verbose': 183 program.verbosity = 1 184 program.parseArgs([None, opt]) 185 self.assertEqual(program.verbosity, 2) 186 187 def testBufferCatchFailfast(self): 188 program = self.program 189 for arg, attr in (('buffer', 'buffer'), ('failfast', 'failfast'), 190 ('catch', 'catchbreak')): 191 if attr == 'catch' and not hasInstallHandler: 192 continue 193 194 setattr(program, attr, None) 195 program.parseArgs([None]) 196 self.assertIs(getattr(program, attr), False) 197 198 false = [] 199 setattr(program, attr, false) 200 program.parseArgs([None]) 201 self.assertIs(getattr(program, attr), false) 202 203 true = [42] 204 setattr(program, attr, true) 205 program.parseArgs([None]) 206 self.assertIs(getattr(program, attr), true) 207 208 short_opt = '-%s' % arg[0] 209 long_opt = '--%s' % arg 210 for opt in short_opt, long_opt: 211 setattr(program, attr, None) 212 program.parseArgs([None, opt]) 213 self.assertIs(getattr(program, attr), True) 214 215 setattr(program, attr, False) 216 with support.captured_stderr() as stderr, \ 217 self.assertRaises(SystemExit) as cm: 218 program.parseArgs([None, opt]) 219 self.assertEqual(cm.exception.args, (2,)) 220 221 setattr(program, attr, True) 222 with support.captured_stderr() as stderr, \ 223 self.assertRaises(SystemExit) as cm: 224 program.parseArgs([None, opt]) 225 self.assertEqual(cm.exception.args, (2,)) 226 227 def testWarning(self): 228 """Test the warnings argument""" 229 # see #10535 230 class FakeTP(unittest.TestProgram): 231 def parseArgs(self, *args, **kw): pass 232 def runTests(self, *args, **kw): pass 233 warnoptions = sys.warnoptions[:] 234 try: 235 sys.warnoptions[:] = [] 236 # no warn options, no arg -> default 237 self.assertEqual(FakeTP().warnings, 'default') 238 # no warn options, w/ arg -> arg value 239 self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore') 240 sys.warnoptions[:] = ['somevalue'] 241 # warn options, no arg -> None 242 # warn options, w/ arg -> arg value 243 self.assertEqual(FakeTP().warnings, None) 244 self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore') 245 finally: 246 sys.warnoptions[:] = warnoptions 247 248 def testRunTestsRunnerClass(self): 249 program = self.program 250 251 program.testRunner = FakeRunner 252 program.verbosity = 'verbosity' 253 program.failfast = 'failfast' 254 program.buffer = 'buffer' 255 program.warnings = 'warnings' 256 257 program.runTests() 258 259 self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity', 260 'failfast': 'failfast', 261 'buffer': 'buffer', 262 'tb_locals': False, 263 'warnings': 'warnings'}) 264 self.assertEqual(FakeRunner.test, 'test') 265 self.assertIs(program.result, RESULT) 266 267 def testRunTestsRunnerInstance(self): 268 program = self.program 269 270 program.testRunner = FakeRunner() 271 FakeRunner.initArgs = None 272 273 program.runTests() 274 275 # A new FakeRunner should not have been instantiated 276 self.assertIsNone(FakeRunner.initArgs) 277 278 self.assertEqual(FakeRunner.test, 'test') 279 self.assertIs(program.result, RESULT) 280 281 def test_locals(self): 282 program = self.program 283 284 program.testRunner = FakeRunner 285 program.parseArgs([None, '--locals']) 286 self.assertEqual(True, program.tb_locals) 287 program.runTests() 288 self.assertEqual(FakeRunner.initArgs, {'buffer': False, 289 'failfast': False, 290 'tb_locals': True, 291 'verbosity': 1, 292 'warnings': None}) 293 294 def testRunTestsOldRunnerClass(self): 295 program = self.program 296 297 # Two TypeErrors are needed to fall all the way back to old-style 298 # runners - one to fail tb_locals, one to fail buffer etc. 299 FakeRunner.raiseError = 2 300 program.testRunner = FakeRunner 301 program.verbosity = 'verbosity' 302 program.failfast = 'failfast' 303 program.buffer = 'buffer' 304 program.test = 'test' 305 306 program.runTests() 307 308 # If initialising raises a type error it should be retried 309 # without the new keyword arguments 310 self.assertEqual(FakeRunner.initArgs, {}) 311 self.assertEqual(FakeRunner.test, 'test') 312 self.assertIs(program.result, RESULT) 313 314 def testCatchBreakInstallsHandler(self): 315 module = sys.modules['unittest.main'] 316 original = module.installHandler 317 def restore(): 318 module.installHandler = original 319 self.addCleanup(restore) 320 321 self.installed = False 322 def fakeInstallHandler(): 323 self.installed = True 324 module.installHandler = fakeInstallHandler 325 326 program = self.program 327 program.catchbreak = True 328 329 program.testRunner = FakeRunner 330 331 program.runTests() 332 self.assertTrue(self.installed) 333 334 def _patch_isfile(self, names, exists=True): 335 def isfile(path): 336 return path in names 337 original = os.path.isfile 338 os.path.isfile = isfile 339 def restore(): 340 os.path.isfile = original 341 self.addCleanup(restore) 342 343 344 def testParseArgsFileNames(self): 345 # running tests with filenames instead of module names 346 program = self.program 347 argv = ['progname', 'foo.py', 'bar.Py', 'baz.PY', 'wing.txt'] 348 self._patch_isfile(argv) 349 350 program.createTests = lambda: None 351 program.parseArgs(argv) 352 353 # note that 'wing.txt' is not a Python file so the name should 354 # *not* be converted to a module name 355 expected = ['foo', 'bar', 'baz', 'wing.txt'] 356 self.assertEqual(program.testNames, expected) 357 358 359 def testParseArgsFilePaths(self): 360 program = self.program 361 argv = ['progname', 'foo/bar/baz.py', 'green\\red.py'] 362 self._patch_isfile(argv) 363 364 program.createTests = lambda: None 365 program.parseArgs(argv) 366 367 expected = ['foo.bar.baz', 'green.red'] 368 self.assertEqual(program.testNames, expected) 369 370 371 def testParseArgsNonExistentFiles(self): 372 program = self.program 373 argv = ['progname', 'foo/bar/baz.py', 'green\\red.py'] 374 self._patch_isfile([]) 375 376 program.createTests = lambda: None 377 program.parseArgs(argv) 378 379 self.assertEqual(program.testNames, argv[1:]) 380 381 def testParseArgsAbsolutePathsThatCanBeConverted(self): 382 cur_dir = os.getcwd() 383 program = self.program 384 def _join(name): 385 return os.path.join(cur_dir, name) 386 argv = ['progname', _join('foo/bar/baz.py'), _join('green\\red.py')] 387 self._patch_isfile(argv) 388 389 program.createTests = lambda: None 390 program.parseArgs(argv) 391 392 expected = ['foo.bar.baz', 'green.red'] 393 self.assertEqual(program.testNames, expected) 394 395 def testParseArgsAbsolutePathsThatCannotBeConverted(self): 396 program = self.program 397 # even on Windows '/...' is considered absolute by os.path.abspath 398 argv = ['progname', '/foo/bar/baz.py', '/green/red.py'] 399 self._patch_isfile(argv) 400 401 program.createTests = lambda: None 402 program.parseArgs(argv) 403 404 self.assertEqual(program.testNames, argv[1:]) 405 406 # it may be better to use platform specific functions to normalise paths 407 # rather than accepting '.PY' and '\' as file separator on Linux / Mac 408 # it would also be better to check that a filename is a valid module 409 # identifier (we have a regex for this in loader.py) 410 # for invalid filenames should we raise a useful error rather than 411 # leaving the current error message (import of filename fails) in place? 412 413 def testParseArgsSelectedTestNames(self): 414 program = self.program 415 argv = ['progname', '-k', 'foo', '-k', 'bar', '-k', '*pat*'] 416 417 program.createTests = lambda: None 418 program.parseArgs(argv) 419 420 self.assertEqual(program.testNamePatterns, ['*foo*', '*bar*', '*pat*']) 421 422 def testSelectedTestNamesFunctionalTest(self): 423 def run_unittest(args): 424 p = subprocess.Popen([sys.executable, '-m', 'unittest'] + args, 425 stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, cwd=os.path.dirname(__file__)) 426 with p: 427 _, stderr = p.communicate() 428 return stderr.decode() 429 430 t = '_test_warnings' 431 self.assertIn('Ran 7 tests', run_unittest([t])) 432 self.assertIn('Ran 7 tests', run_unittest(['-k', 'TestWarnings', t])) 433 self.assertIn('Ran 7 tests', run_unittest(['discover', '-p', '*_test*', '-k', 'TestWarnings'])) 434 self.assertIn('Ran 2 tests', run_unittest(['-k', 'f', t])) 435 self.assertIn('Ran 7 tests', run_unittest(['-k', 't', t])) 436 self.assertIn('Ran 3 tests', run_unittest(['-k', '*t', t])) 437 self.assertIn('Ran 7 tests', run_unittest(['-k', '*test_warnings.*Warning*', t])) 438 self.assertIn('Ran 1 test', run_unittest(['-k', '*test_warnings.*warning*', t])) 439 440 441if __name__ == '__main__': 442 unittest.main() 443