1 import os.path 2 from os.path import abspath 3 import re 4 import sys 5 import types 6 import pickle 7 import builtins 8 from test import support 9 10 import unittest 11 import unittest.test 12 13 14 class TestableTestProgram(unittest.TestProgram): 15 module = None 16 exit = True 17 defaultTest = failfast = catchbreak = buffer = None 18 verbosity = 1 19 progName = '' 20 testRunner = testLoader = None 21 22 def __init__(self): 23 pass 24 25 26 class TestDiscovery(unittest.TestCase): 27 28 # Heavily mocked tests so I can avoid hitting the filesystem 29 def test_get_name_from_path(self): 30 loader = unittest.TestLoader() 31 loader._top_level_dir = '/foo' 32 name = loader._get_name_from_path('/foo/bar/baz.py') 33 self.assertEqual(name, 'bar.baz') 34 35 if not __debug__: 36 # asserts are off 37 return 38 39 with self.assertRaises(AssertionError): 40 loader._get_name_from_path('/bar/baz.py') 41 42 def test_find_tests(self): 43 loader = unittest.TestLoader() 44 45 original_listdir = os.listdir 46 def restore_listdir(): 47 os.listdir = original_listdir 48 original_isfile = os.path.isfile 49 def restore_isfile(): 50 os.path.isfile = original_isfile 51 original_isdir = os.path.isdir 52 def restore_isdir(): 53 os.path.isdir = original_isdir 54 55 path_lists = [['test2.py', 'test1.py', 'not_a_test.py', 'test_dir', 56 'test.foo', 'test-not-a-module.py', 'another_dir'], 57 ['test4.py', 'test3.py', ]] 58 os.listdir = lambda path: path_lists.pop(0) 59 self.addCleanup(restore_listdir) 60 61 def isdir(path): 62 return path.endswith('dir') 63 os.path.isdir = isdir 64 self.addCleanup(restore_isdir) 65 66 def isfile(path): 67 # another_dir is not a package and so shouldn't be recursed into 68 return not path.endswith('dir') and not 'another_dir' in path 69 os.path.isfile = isfile 70 self.addCleanup(restore_isfile) 71 72 loader._get_module_from_name = lambda path: path + ' module' 73 orig_load_tests = loader.loadTestsFromModule 74 def loadTestsFromModule(module, pattern=None): 75 # This is where load_tests is called. 76 base = orig_load_tests(module, pattern=pattern) 77 return base + [module + ' tests'] 78 loader.loadTestsFromModule = loadTestsFromModule 79 loader.suiteClass = lambda thing: thing 80 81 top_level = os.path.abspath('/foo') 82 loader._top_level_dir = top_level 83 suite = list(loader._find_tests(top_level, 'test*.py')) 84 85 # The test suites found should be sorted alphabetically for reliable 86 # execution order. 87 expected = [[name + ' module tests'] for name in 88 ('test1', 'test2', 'test_dir')] 89 expected.extend([[('test_dir.%s' % name) + ' module tests'] for name in 90 ('test3', 'test4')]) 91 self.assertEqual(suite, expected) 92 93 def test_find_tests_socket(self): 94 # A socket is neither a directory nor a regular file. 95 # https://bugs.python.org/issue25320 96 loader = unittest.TestLoader() 97 98 original_listdir = os.listdir 99 def restore_listdir(): 100 os.listdir = original_listdir 101 original_isfile = os.path.isfile 102 def restore_isfile(): 103 os.path.isfile = original_isfile 104 original_isdir = os.path.isdir 105 def restore_isdir(): 106 os.path.isdir = original_isdir 107 108 path_lists = [['socket']] 109 os.listdir = lambda path: path_lists.pop(0) 110 self.addCleanup(restore_listdir) 111 112 os.path.isdir = lambda path: False 113 self.addCleanup(restore_isdir) 114 115 os.path.isfile = lambda path: False 116 self.addCleanup(restore_isfile) 117 118 loader._get_module_from_name = lambda path: path + ' module' 119 orig_load_tests = loader.loadTestsFromModule 120 def loadTestsFromModule(module, pattern=None): 121 # This is where load_tests is called. 122 base = orig_load_tests(module, pattern=pattern) 123 return base + [module + ' tests'] 124 loader.loadTestsFromModule = loadTestsFromModule 125 loader.suiteClass = lambda thing: thing 126 127 top_level = os.path.abspath('/foo') 128 loader._top_level_dir = top_level 129 suite = list(loader._find_tests(top_level, 'test*.py')) 130 131 self.assertEqual(suite, []) 132 133 def test_find_tests_with_package(self): 134 loader = unittest.TestLoader() 135 136 original_listdir = os.listdir 137 def restore_listdir(): 138 os.listdir = original_listdir 139 original_isfile = os.path.isfile 140 def restore_isfile(): 141 os.path.isfile = original_isfile 142 original_isdir = os.path.isdir 143 def restore_isdir(): 144 os.path.isdir = original_isdir 145 146 directories = ['a_directory', 'test_directory', 'test_directory2'] 147 path_lists = [directories, [], [], []] 148 os.listdir = lambda path: path_lists.pop(0) 149 self.addCleanup(restore_listdir) 150 151 os.path.isdir = lambda path: True 152 self.addCleanup(restore_isdir) 153 154 os.path.isfile = lambda path: os.path.basename(path) not in directories 155 self.addCleanup(restore_isfile) 156 157 class Module(object): 158 paths = [] 159 load_tests_args = [] 160 161 def __init__(self, path): 162 self.path = path 163 self.paths.append(path) 164 if os.path.basename(path) == 'test_directory': 165 def load_tests(loader, tests, pattern): 166 self.load_tests_args.append((loader, tests, pattern)) 167 return [self.path + ' load_tests'] 168 self.load_tests = load_tests 169 170 def __eq__(self, other): 171 return self.path == other.path 172 173 loader._get_module_from_name = lambda name: Module(name) 174 orig_load_tests = loader.loadTestsFromModule 175 def loadTestsFromModule(module, pattern=None): 176 # This is where load_tests is called. 177 base = orig_load_tests(module, pattern=pattern) 178 return base + [module.path + ' module tests'] 179 loader.loadTestsFromModule = loadTestsFromModule 180 loader.suiteClass = lambda thing: thing 181 182 loader._top_level_dir = '/foo' 183 # this time no '.py' on the pattern so that it can match 184 # a test package 185 suite = list(loader._find_tests('/foo', 'test*')) 186 187 # We should have loaded tests from the a_directory and test_directory2 188 # directly and via load_tests for the test_directory package, which 189 # still calls the baseline module loader. 190 self.assertEqual(suite, 191 [['a_directory module tests'], 192 ['test_directory load_tests', 193 'test_directory module tests'], 194 ['test_directory2 module tests']]) 195 196 197 # The test module paths should be sorted for reliable execution order 198 self.assertEqual(Module.paths, 199 ['a_directory', 'test_directory', 'test_directory2']) 200 201 # load_tests should have been called once with loader, tests and pattern 202 # (but there are no tests in our stub module itself, so thats [] at the 203 # time of call. 204 self.assertEqual(Module.load_tests_args, 205 [(loader, [], 'test*')]) 206 207 def test_find_tests_default_calls_package_load_tests(self): 208 loader = unittest.TestLoader() 209 210 original_listdir = os.listdir 211 def restore_listdir(): 212 os.listdir = original_listdir 213 original_isfile = os.path.isfile 214 def restore_isfile(): 215 os.path.isfile = original_isfile 216 original_isdir = os.path.isdir 217 def restore_isdir(): 218 os.path.isdir = original_isdir 219 220 directories = ['a_directory', 'test_directory', 'test_directory2'] 221 path_lists = [directories, [], [], []] 222 os.listdir = lambda path: path_lists.pop(0) 223 self.addCleanup(restore_listdir) 224 225 os.path.isdir = lambda path: True 226 self.addCleanup(restore_isdir) 227 228 os.path.isfile = lambda path: os.path.basename(path) not in directories 229 self.addCleanup(restore_isfile) 230 231 class Module(object): 232 paths = [] 233 load_tests_args = [] 234 235 def __init__(self, path): 236 self.path = path 237 self.paths.append(path) 238 if os.path.basename(path) == 'test_directory': 239 def load_tests(loader, tests, pattern): 240 self.load_tests_args.append((loader, tests, pattern)) 241 return [self.path + ' load_tests'] 242 self.load_tests = load_tests 243 244 def __eq__(self, other): 245 return self.path == other.path 246 247 loader._get_module_from_name = lambda name: Module(name) 248 orig_load_tests = loader.loadTestsFromModule 249 def loadTestsFromModule(module, pattern=None): 250 # This is where load_tests is called. 251 base = orig_load_tests(module, pattern=pattern) 252 return base + [module.path + ' module tests'] 253 loader.loadTestsFromModule = loadTestsFromModule 254 loader.suiteClass = lambda thing: thing 255 256 loader._top_level_dir = '/foo' 257 # this time no '.py' on the pattern so that it can match 258 # a test package 259 suite = list(loader._find_tests('/foo', 'test*.py')) 260 261 # We should have loaded tests from the a_directory and test_directory2 262 # directly and via load_tests for the test_directory package, which 263 # still calls the baseline module loader. 264 self.assertEqual(suite, 265 [['a_directory module tests'], 266 ['test_directory load_tests', 267 'test_directory module tests'], 268 ['test_directory2 module tests']]) 269 # The test module paths should be sorted for reliable execution order 270 self.assertEqual(Module.paths, 271 ['a_directory', 'test_directory', 'test_directory2']) 272 273 274 # load_tests should have been called once with loader, tests and pattern 275 self.assertEqual(Module.load_tests_args, 276 [(loader, [], 'test*.py')]) 277 278 def test_find_tests_customize_via_package_pattern(self): 279 # This test uses the example 'do-nothing' load_tests from 280 # https://docs.python.org/3/library/unittest.html#load-tests-protocol 281 # to make sure that that actually works. 282 # Housekeeping 283 original_listdir = os.listdir 284 def restore_listdir(): 285 os.listdir = original_listdir 286 self.addCleanup(restore_listdir) 287 original_isfile = os.path.isfile 288 def restore_isfile(): 289 os.path.isfile = original_isfile 290 self.addCleanup(restore_isfile) 291 original_isdir = os.path.isdir 292 def restore_isdir(): 293 os.path.isdir = original_isdir 294 self.addCleanup(restore_isdir) 295 self.addCleanup(sys.path.remove, abspath('/foo')) 296 297 # Test data: we expect the following: 298 # a listdir to find our package, and isfile and isdir checks on it. 299 # a module-from-name call to turn that into a module 300 # followed by load_tests. 301 # then our load_tests will call discover() which is messy 302 # but that finally chains into find_tests again for the child dir - 303 # which is why we don't have an infinite loop. 304 # We expect to see: 305 # the module load tests for both package and plain module called, 306 # and the plain module result nested by the package module load_tests 307 # indicating that it was processed and could have been mutated. 308 vfs = {abspath('/foo'): ['my_package'], 309 abspath('/foo/my_package'): ['__init__.py', 'test_module.py']} 310 def list_dir(path): 311 return list(vfs[path]) 312 os.listdir = list_dir 313 os.path.isdir = lambda path: not path.endswith('.py') 314 os.path.isfile = lambda path: path.endswith('.py') 315 316 class Module(object): 317 paths = [] 318 load_tests_args = [] 319 320 def __init__(self, path): 321 self.path = path 322 self.paths.append(path) 323 if path.endswith('test_module'): 324 def load_tests(loader, tests, pattern): 325 self.load_tests_args.append((loader, tests, pattern)) 326 return [self.path + ' load_tests'] 327 else: 328 def load_tests(loader, tests, pattern): 329 self.load_tests_args.append((loader, tests, pattern)) 330 # top level directory cached on loader instance 331 __file__ = '/foo/my_package/__init__.py' 332 this_dir = os.path.dirname(__file__) 333 pkg_tests = loader.discover( 334 start_dir=this_dir, pattern=pattern) 335 return [self.path + ' load_tests', tests 336 ] + pkg_tests 337 self.load_tests = load_tests 338 339 def __eq__(self, other): 340 return self.path == other.path 341 342 loader = unittest.TestLoader() 343 loader._get_module_from_name = lambda name: Module(name) 344 loader.suiteClass = lambda thing: thing 345 346 loader._top_level_dir = abspath('/foo') 347 # this time no '.py' on the pattern so that it can match 348 # a test package 349 suite = list(loader._find_tests(abspath('/foo'), 'test*.py')) 350 351 # We should have loaded tests from both my_package and 352 # my_package.test_module, and also run the load_tests hook in both. 353 # (normally this would be nested TestSuites.) 354 self.assertEqual(suite, 355 [['my_package load_tests', [], 356 ['my_package.test_module load_tests']]]) 357 # Parents before children. 358 self.assertEqual(Module.paths, 359 ['my_package', 'my_package.test_module']) 360 361 # load_tests should have been called twice with loader, tests and pattern 362 self.assertEqual(Module.load_tests_args, 363 [(loader, [], 'test*.py'), 364 (loader, [], 'test*.py')]) 365 366 def test_discover(self): 367 loader = unittest.TestLoader() 368 369 original_isfile = os.path.isfile 370 original_isdir = os.path.isdir 371 def restore_isfile(): 372 os.path.isfile = original_isfile 373 374 os.path.isfile = lambda path: False 375 self.addCleanup(restore_isfile) 376 377 orig_sys_path = sys.path[:] 378 def restore_path(): 379 sys.path[:] = orig_sys_path 380 self.addCleanup(restore_path) 381 382 full_path = os.path.abspath(os.path.normpath('/foo')) 383 with self.assertRaises(ImportError): 384 loader.discover('/foo/bar', top_level_dir='/foo') 385 386 self.assertEqual(loader._top_level_dir, full_path) 387 self.assertIn(full_path, sys.path) 388 389 os.path.isfile = lambda path: True 390 os.path.isdir = lambda path: True 391 392 def restore_isdir(): 393 os.path.isdir = original_isdir 394 self.addCleanup(restore_isdir) 395 396 _find_tests_args = [] 397 def _find_tests(start_dir, pattern, namespace=None): 398 _find_tests_args.append((start_dir, pattern)) 399 return ['tests'] 400 loader._find_tests = _find_tests 401 loader.suiteClass = str 402 403 suite = loader.discover('/foo/bar/baz', 'pattern', '/foo/bar') 404 405 top_level_dir = os.path.abspath('/foo/bar') 406 start_dir = os.path.abspath('/foo/bar/baz') 407 self.assertEqual(suite, "['tests']") 408 self.assertEqual(loader._top_level_dir, top_level_dir) 409 self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) 410 self.assertIn(top_level_dir, sys.path) 411 412 def test_discover_start_dir_is_package_calls_package_load_tests(self): 413 # This test verifies that the package load_tests in a package is indeed 414 # invoked when the start_dir is a package (and not the top level). 415 # http://bugs.python.org/issue22457 416 417 # Test data: we expect the following: 418 # an isfile to verify the package, then importing and scanning 419 # as per _find_tests' normal behaviour. 420 # We expect to see our load_tests hook called once. 421 vfs = {abspath('/toplevel'): ['startdir'], 422 abspath('/toplevel/startdir'): ['__init__.py']} 423 def list_dir(path): 424 return list(vfs[path]) 425 self.addCleanup(setattr, os, 'listdir', os.listdir) 426 os.listdir = list_dir 427 self.addCleanup(setattr, os.path, 'isfile', os.path.isfile) 428 os.path.isfile = lambda path: path.endswith('.py') 429 self.addCleanup(setattr, os.path, 'isdir', os.path.isdir) 430 os.path.isdir = lambda path: not path.endswith('.py') 431 self.addCleanup(sys.path.remove, abspath('/toplevel')) 432 433 class Module(object): 434 paths = [] 435 load_tests_args = [] 436 437 def __init__(self, path): 438 self.path = path 439 440 def load_tests(self, loader, tests, pattern): 441 return ['load_tests called ' + self.path] 442 443 def __eq__(self, other): 444 return self.path == other.path 445 446 loader = unittest.TestLoader() 447 loader._get_module_from_name = lambda name: Module(name) 448 loader.suiteClass = lambda thing: thing 449 450 suite = loader.discover('/toplevel/startdir', top_level_dir='/toplevel') 451 452 # We should have loaded tests from the package __init__. 453 # (normally this would be nested TestSuites.) 454 self.assertEqual(suite, 455 [['load_tests called startdir']]) 456 457 def setup_import_issue_tests(self, fakefile): 458 listdir = os.listdir 459 os.listdir = lambda _: [fakefile] 460 isfile = os.path.isfile 461 os.path.isfile = lambda _: True 462 orig_sys_path = sys.path[:] 463 def restore(): 464 os.path.isfile = isfile 465 os.listdir = listdir 466 sys.path[:] = orig_sys_path 467 self.addCleanup(restore) 468 469 def setup_import_issue_package_tests(self, vfs): 470 self.addCleanup(setattr, os, 'listdir', os.listdir) 471 self.addCleanup(setattr, os.path, 'isfile', os.path.isfile) 472 self.addCleanup(setattr, os.path, 'isdir', os.path.isdir) 473 self.addCleanup(sys.path.__setitem__, slice(None), list(sys.path)) 474 def list_dir(path): 475 return list(vfs[path]) 476 os.listdir = list_dir 477 os.path.isdir = lambda path: not path.endswith('.py') 478 os.path.isfile = lambda path: path.endswith('.py') 479 480 def test_discover_with_modules_that_fail_to_import(self): 481 loader = unittest.TestLoader() 482 483 self.setup_import_issue_tests('test_this_does_not_exist.py') 484 485 suite = loader.discover('.') 486 self.assertIn(os.getcwd(), sys.path) 487 self.assertEqual(suite.countTestCases(), 1) 488 # Errors loading the suite are also captured for introspection. 489 self.assertNotEqual([], loader.errors) 490 self.assertEqual(1, len(loader.errors)) 491 error = loader.errors[0] 492 self.assertTrue( 493 'Failed to import test module: test_this_does_not_exist' in error, 494 'missing error string in %r' % error) 495 test = list(list(suite)[0])[0] # extract test from suite 496 497 with self.assertRaises(ImportError): 498 test.test_this_does_not_exist() 499 500 def test_discover_with_init_modules_that_fail_to_import(self): 501 vfs = {abspath('/foo'): ['my_package'], 502 abspath('/foo/my_package'): ['__init__.py', 'test_module.py']} 503 self.setup_import_issue_package_tests(vfs) 504 import_calls = [] 505 def _get_module_from_name(name): 506 import_calls.append(name) 507 raise ImportError("Cannot import Name") 508 loader = unittest.TestLoader() 509 loader._get_module_from_name = _get_module_from_name 510 suite = loader.discover(abspath('/foo')) 511 512 self.assertIn(abspath('/foo'), sys.path) 513 self.assertEqual(suite.countTestCases(), 1) 514 # Errors loading the suite are also captured for introspection. 515 self.assertNotEqual([], loader.errors) 516 self.assertEqual(1, len(loader.errors)) 517 error = loader.errors[0] 518 self.assertTrue( 519 'Failed to import test module: my_package' in error, 520 'missing error string in %r' % error) 521 test = list(list(suite)[0])[0] # extract test from suite 522 with self.assertRaises(ImportError): 523 test.my_package() 524 self.assertEqual(import_calls, ['my_package']) 525 526 # Check picklability 527 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 528 pickle.loads(pickle.dumps(test, proto)) 529 530 def test_discover_with_module_that_raises_SkipTest_on_import(self): 531 loader = unittest.TestLoader() 532 533 def _get_module_from_name(name): 534 raise unittest.SkipTest('skipperoo') 535 loader._get_module_from_name = _get_module_from_name 536 537 self.setup_import_issue_tests('test_skip_dummy.py') 538 539 suite = loader.discover('.') 540 self.assertEqual(suite.countTestCases(), 1) 541 542 result = unittest.TestResult() 543 suite.run(result) 544 self.assertEqual(len(result.skipped), 1) 545 546 # Check picklability 547 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 548 pickle.loads(pickle.dumps(suite, proto)) 549 550 def test_discover_with_init_module_that_raises_SkipTest_on_import(self): 551 vfs = {abspath('/foo'): ['my_package'], 552 abspath('/foo/my_package'): ['__init__.py', 'test_module.py']} 553 self.setup_import_issue_package_tests(vfs) 554 import_calls = [] 555 def _get_module_from_name(name): 556 import_calls.append(name) 557 raise unittest.SkipTest('skipperoo') 558 loader = unittest.TestLoader() 559 loader._get_module_from_name = _get_module_from_name 560 suite = loader.discover(abspath('/foo')) 561 562 self.assertIn(abspath('/foo'), sys.path) 563 self.assertEqual(suite.countTestCases(), 1) 564 result = unittest.TestResult() 565 suite.run(result) 566 self.assertEqual(len(result.skipped), 1) 567 self.assertEqual(result.testsRun, 1) 568 self.assertEqual(import_calls, ['my_package']) 569 570 # Check picklability 571 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 572 pickle.loads(pickle.dumps(suite, proto)) 573 574 def test_command_line_handling_parseArgs(self): 575 program = TestableTestProgram() 576 577 args = [] 578 program._do_discovery = args.append 579 program.parseArgs(['something', 'discover']) 580 self.assertEqual(args, [[]]) 581 582 args[:] = [] 583 program.parseArgs(['something', 'discover', 'foo', 'bar']) 584 self.assertEqual(args, [['foo', 'bar']]) 585 586 def test_command_line_handling_discover_by_default(self): 587 program = TestableTestProgram() 588 589 args = [] 590 program._do_discovery = args.append 591 program.parseArgs(['something']) 592 self.assertEqual(args, [[]]) 593 self.assertEqual(program.verbosity, 1) 594 self.assertIs(program.buffer, False) 595 self.assertIs(program.catchbreak, False) 596 self.assertIs(program.failfast, False) 597 598 def test_command_line_handling_discover_by_default_with_options(self): 599 program = TestableTestProgram() 600 601 args = [] 602 program._do_discovery = args.append 603 program.parseArgs(['something', '-v', '-b', '-v', '-c', '-f']) 604 self.assertEqual(args, [[]]) 605 self.assertEqual(program.verbosity, 2) 606 self.assertIs(program.buffer, True) 607 self.assertIs(program.catchbreak, True) 608 self.assertIs(program.failfast, True) 609 610 611 def test_command_line_handling_do_discovery_too_many_arguments(self): 612 program = TestableTestProgram() 613 program.testLoader = None 614 615 with support.captured_stderr() as stderr, \ 616 self.assertRaises(SystemExit) as cm: 617 # too many args 618 program._do_discovery(['one', 'two', 'three', 'four']) 619 self.assertEqual(cm.exception.args, (2,)) 620 self.assertIn('usage:', stderr.getvalue()) 621 622 623 def test_command_line_handling_do_discovery_uses_default_loader(self): 624 program = object.__new__(unittest.TestProgram) 625 program._initArgParsers() 626 627 class Loader(object): 628 args = [] 629 def discover(self, start_dir, pattern, top_level_dir): 630 self.args.append((start_dir, pattern, top_level_dir)) 631 return 'tests' 632 633 program.testLoader = Loader() 634 program._do_discovery(['-v']) 635 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 636 637 def test_command_line_handling_do_discovery_calls_loader(self): 638 program = TestableTestProgram() 639 640 class Loader(object): 641 args = [] 642 def discover(self, start_dir, pattern, top_level_dir): 643 self.args.append((start_dir, pattern, top_level_dir)) 644 return 'tests' 645 646 program._do_discovery(['-v'], Loader=Loader) 647 self.assertEqual(program.verbosity, 2) 648 self.assertEqual(program.test, 'tests') 649 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 650 651 Loader.args = [] 652 program = TestableTestProgram() 653 program._do_discovery(['--verbose'], Loader=Loader) 654 self.assertEqual(program.test, 'tests') 655 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 656 657 Loader.args = [] 658 program = TestableTestProgram() 659 program._do_discovery([], Loader=Loader) 660 self.assertEqual(program.test, 'tests') 661 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 662 663 Loader.args = [] 664 program = TestableTestProgram() 665 program._do_discovery(['fish'], Loader=Loader) 666 self.assertEqual(program.test, 'tests') 667 self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) 668 669 Loader.args = [] 670 program = TestableTestProgram() 671 program._do_discovery(['fish', 'eggs'], Loader=Loader) 672 self.assertEqual(program.test, 'tests') 673 self.assertEqual(Loader.args, [('fish', 'eggs', None)]) 674 675 Loader.args = [] 676 program = TestableTestProgram() 677 program._do_discovery(['fish', 'eggs', 'ham'], Loader=Loader) 678 self.assertEqual(program.test, 'tests') 679 self.assertEqual(Loader.args, [('fish', 'eggs', 'ham')]) 680 681 Loader.args = [] 682 program = TestableTestProgram() 683 program._do_discovery(['-s', 'fish'], Loader=Loader) 684 self.assertEqual(program.test, 'tests') 685 self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) 686 687 Loader.args = [] 688 program = TestableTestProgram() 689 program._do_discovery(['-t', 'fish'], Loader=Loader) 690 self.assertEqual(program.test, 'tests') 691 self.assertEqual(Loader.args, [('.', 'test*.py', 'fish')]) 692 693 Loader.args = [] 694 program = TestableTestProgram() 695 program._do_discovery(['-p', 'fish'], Loader=Loader) 696 self.assertEqual(program.test, 'tests') 697 self.assertEqual(Loader.args, [('.', 'fish', None)]) 698 self.assertFalse(program.failfast) 699 self.assertFalse(program.catchbreak) 700 701 Loader.args = [] 702 program = TestableTestProgram() 703 program._do_discovery(['-p', 'eggs', '-s', 'fish', '-v', '-f', '-c'], 704 Loader=Loader) 705 self.assertEqual(program.test, 'tests') 706 self.assertEqual(Loader.args, [('fish', 'eggs', None)]) 707 self.assertEqual(program.verbosity, 2) 708 self.assertTrue(program.failfast) 709 self.assertTrue(program.catchbreak) 710 711 def setup_module_clash(self): 712 class Module(object): 713 __file__ = 'bar/foo.py' 714 sys.modules['foo'] = Module 715 full_path = os.path.abspath('foo') 716 original_listdir = os.listdir 717 original_isfile = os.path.isfile 718 original_isdir = os.path.isdir 719 720 def cleanup(): 721 os.listdir = original_listdir 722 os.path.isfile = original_isfile 723 os.path.isdir = original_isdir 724 del sys.modules['foo'] 725 if full_path in sys.path: 726 sys.path.remove(full_path) 727 self.addCleanup(cleanup) 728 729 def listdir(_): 730 return ['foo.py'] 731 def isfile(_): 732 return True 733 def isdir(_): 734 return True 735 os.listdir = listdir 736 os.path.isfile = isfile 737 os.path.isdir = isdir 738 return full_path 739 740 def test_detect_module_clash(self): 741 full_path = self.setup_module_clash() 742 loader = unittest.TestLoader() 743 744 mod_dir = os.path.abspath('bar') 745 expected_dir = os.path.abspath('foo') 746 msg = re.escape(r"'foo' module incorrectly imported from %r. Expected %r. " 747 "Is this module globally installed?" % (mod_dir, expected_dir)) 748 self.assertRaisesRegex( 749 ImportError, '^%s$' % msg, loader.discover, 750 start_dir='foo', pattern='foo.py' 751 ) 752 self.assertEqual(sys.path[0], full_path) 753 754 def test_module_symlink_ok(self): 755 full_path = self.setup_module_clash() 756 757 original_realpath = os.path.realpath 758 759 mod_dir = os.path.abspath('bar') 760 expected_dir = os.path.abspath('foo') 761 762 def cleanup(): 763 os.path.realpath = original_realpath 764 self.addCleanup(cleanup) 765 766 def realpath(path): 767 if path == os.path.join(mod_dir, 'foo.py'): 768 return os.path.join(expected_dir, 'foo.py') 769 return path 770 os.path.realpath = realpath 771 loader = unittest.TestLoader() 772 loader.discover(start_dir='foo', pattern='foo.py') 773 774 def test_discovery_from_dotted_path(self): 775 loader = unittest.TestLoader() 776 777 tests = [self] 778 expectedPath = os.path.abspath(os.path.dirname(unittest.test.__file__)) 779 780 self.wasRun = False 781 def _find_tests(start_dir, pattern, namespace=None): 782 self.wasRun = True 783 self.assertEqual(start_dir, expectedPath) 784 return tests 785 loader._find_tests = _find_tests 786 suite = loader.discover('unittest.test') 787 self.assertTrue(self.wasRun) 788 self.assertEqual(suite._tests, tests) 789 790 791 def test_discovery_from_dotted_path_builtin_modules(self): 792 793 loader = unittest.TestLoader() 794 795 listdir = os.listdir 796 os.listdir = lambda _: ['test_this_does_not_exist.py'] 797 isfile = os.path.isfile 798 isdir = os.path.isdir 799 os.path.isdir = lambda _: False 800 orig_sys_path = sys.path[:] 801 def restore(): 802 os.path.isfile = isfile 803 os.path.isdir = isdir 804 os.listdir = listdir 805 sys.path[:] = orig_sys_path 806 self.addCleanup(restore) 807 808 with self.assertRaises(TypeError) as cm: 809 loader.discover('sys') 810 self.assertEqual(str(cm.exception), 811 'Can not use builtin modules ' 812 'as dotted module names') 813 814 def test_discovery_from_dotted_namespace_packages(self): 815 loader = unittest.TestLoader() 816 817 orig_import = __import__ 818 package = types.ModuleType('package') 819 package.__path__ = ['/a', '/b'] 820 package.__spec__ = types.SimpleNamespace( 821 loader=None, 822 submodule_search_locations=['/a', '/b'] 823 ) 824 825 def _import(packagename, *args, **kwargs): 826 sys.modules[packagename] = package 827 return package 828 829 def cleanup(): 830 builtins.__import__ = orig_import 831 self.addCleanup(cleanup) 832 builtins.__import__ = _import 833 834 _find_tests_args = [] 835 def _find_tests(start_dir, pattern, namespace=None): 836 _find_tests_args.append((start_dir, pattern)) 837 return ['%s/tests' % start_dir] 838 839 loader._find_tests = _find_tests 840 loader.suiteClass = list 841 suite = loader.discover('package') 842 self.assertEqual(suite, ['/a/tests', '/b/tests']) 843 844 def test_discovery_failed_discovery(self): 845 loader = unittest.TestLoader() 846 package = types.ModuleType('package') 847 orig_import = __import__ 848 849 def _import(packagename, *args, **kwargs): 850 sys.modules[packagename] = package 851 return package 852 853 def cleanup(): 854 builtins.__import__ = orig_import 855 self.addCleanup(cleanup) 856 builtins.__import__ = _import 857 858 with self.assertRaises(TypeError) as cm: 859 loader.discover('package') 860 self.assertEqual(str(cm.exception), 861 'don\'t know how to discover from {!r}' 862 .format(package)) 863 864 865 if __name__ == '__main__': 866 unittest.main() 867