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