Home | History | Annotate | Download | only in test
      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