1import os 2import re 3import sys 4 5import unittest2 6 7 8class TestDiscovery(unittest2.TestCase): 9 10 # Heavily mocked tests so I can avoid hitting the filesystem 11 def test_get_name_from_path(self): 12 loader = unittest2.TestLoader() 13 14 loader._top_level_dir = '/foo' 15 name = loader._get_name_from_path('/foo/bar/baz.py') 16 self.assertEqual(name, 'bar.baz') 17 18 if not __debug__: 19 # asserts are off 20 return 21 22 self.assertRaises(AssertionError, 23 loader._get_name_from_path, 24 '/bar/baz.py') 25 26 def test_find_tests(self): 27 loader = unittest2.TestLoader() 28 29 original_listdir = os.listdir 30 31 def restore_listdir(): 32 os.listdir = original_listdir 33 original_isfile = os.path.isfile 34 35 def restore_isfile(): 36 os.path.isfile = original_isfile 37 original_isdir = os.path.isdir 38 39 def restore_isdir(): 40 os.path.isdir = original_isdir 41 42 path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir', 43 'test.foo', 'test-not-a-module.py', 'another_dir'], 44 ['test3.py', 'test4.py', ]] 45 os.listdir = lambda path: path_lists.pop(0) 46 self.addCleanup(restore_listdir) 47 48 def isdir(path): 49 return path.endswith('dir') 50 os.path.isdir = isdir 51 self.addCleanup(restore_isdir) 52 53 def isfile(path): 54 # another_dir is not a package and so shouldn't be recursed into 55 return not path.endswith('dir') and not 'another_dir' in path 56 os.path.isfile = isfile 57 self.addCleanup(restore_isfile) 58 59 loader._get_module_from_name = lambda path: path + ' module' 60 loader.loadTestsFromModule = lambda module: module + ' tests' 61 62 top_level = os.path.abspath('/foo') 63 loader._top_level_dir = top_level 64 suite = list(loader._find_tests(top_level, 'test*.py')) 65 66 expected = [name + ' module tests' for name in 67 ('test1', 'test2')] 68 expected.extend([('test_dir.%s' % name) + ' module tests' for name in 69 ('test3', 'test4')]) 70 self.assertEqual(suite, expected) 71 72 def test_find_tests_with_package(self): 73 loader = unittest2.TestLoader() 74 75 original_listdir = os.listdir 76 77 def restore_listdir(): 78 os.listdir = original_listdir 79 original_isfile = os.path.isfile 80 81 def restore_isfile(): 82 os.path.isfile = original_isfile 83 original_isdir = os.path.isdir 84 85 def restore_isdir(): 86 os.path.isdir = original_isdir 87 88 directories = ['a_directory', 'test_directory', 'test_directory2'] 89 path_lists = [directories, [], [], []] 90 os.listdir = lambda path: path_lists.pop(0) 91 self.addCleanup(restore_listdir) 92 93 os.path.isdir = lambda path: True 94 self.addCleanup(restore_isdir) 95 96 os.path.isfile = lambda path: os.path.basename(path) not in directories 97 self.addCleanup(restore_isfile) 98 99 class Module(object): 100 paths = [] 101 load_tests_args = [] 102 103 def __init__(self, path): 104 self.path = path 105 self.paths.append(path) 106 if os.path.basename(path) == 'test_directory': 107 def load_tests(loader, tests, pattern): 108 self.load_tests_args.append((loader, tests, pattern)) 109 return 'load_tests' 110 self.load_tests = load_tests 111 112 def __eq__(self, other): 113 return self.path == other.path 114 115 # Silence py3k warning 116 __hash__ = None 117 118 loader._get_module_from_name = lambda name: Module(name) 119 120 def loadTestsFromModule(module, use_load_tests): 121 if use_load_tests: 122 raise self.failureException( 123 'use_load_tests should be False for packages') 124 return module.path + ' module tests' 125 loader.loadTestsFromModule = loadTestsFromModule 126 127 loader._top_level_dir = '/foo' 128 # this time no '.py' on the pattern so that it can match 129 # a test package 130 suite = list(loader._find_tests('/foo', 'test*')) 131 132 # We should have loaded tests from the test_directory package by calling load_tests 133 # and directly from the test_directory2 package 134 self.assertEqual(suite, 135 ['load_tests', 'test_directory2' + ' module tests']) 136 self.assertEqual(Module.paths, ['test_directory', 'test_directory2']) 137 138 # load_tests should have been called once with loader, tests and 139 # pattern 140 self.assertEqual( 141 Module.load_tests_args, [ 142 (loader, 'test_directory' + ' module tests', 'test*')]) 143 144 def test_discover(self): 145 loader = unittest2.TestLoader() 146 147 original_isfile = os.path.isfile 148 original_isdir = os.path.isdir 149 150 def restore_isfile(): 151 os.path.isfile = original_isfile 152 153 os.path.isfile = lambda path: False 154 self.addCleanup(restore_isfile) 155 156 orig_sys_path = sys.path[:] 157 158 def restore_path(): 159 sys.path[:] = orig_sys_path 160 self.addCleanup(restore_path) 161 162 full_path = os.path.abspath(os.path.normpath('/foo')) 163 self.assertRaises(ImportError, 164 loader.discover, 165 '/foo/bar', top_level_dir='/foo') 166 167 self.assertEqual(loader._top_level_dir, full_path) 168 self.assertIn(full_path, sys.path) 169 170 os.path.isfile = lambda path: True 171 os.path.isdir = lambda path: True 172 173 def restore_isdir(): 174 os.path.isdir = original_isdir 175 self.addCleanup(restore_isdir) 176 177 _find_tests_args = [] 178 179 def _find_tests(start_dir, pattern): 180 _find_tests_args.append((start_dir, pattern)) 181 return ['tests'] 182 loader._find_tests = _find_tests 183 loader.suiteClass = str 184 185 suite = loader.discover('/foo/bar/baz', 'pattern', '/foo/bar') 186 187 top_level_dir = os.path.abspath(os.path.normpath('/foo/bar')) 188 start_dir = os.path.abspath(os.path.normpath('/foo/bar/baz')) 189 self.assertEqual(suite, "['tests']") 190 self.assertEqual(loader._top_level_dir, top_level_dir) 191 self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) 192 self.assertIn(top_level_dir, sys.path) 193 194 def test_discover_with_modules_that_fail_to_import(self): 195 loader = unittest2.TestLoader() 196 197 listdir = os.listdir 198 os.listdir = lambda _: ['test_this_does_not_exist.py'] 199 isfile = os.path.isfile 200 os.path.isfile = lambda _: True 201 orig_sys_path = sys.path[:] 202 203 def restore(): 204 os.path.isfile = isfile 205 os.listdir = listdir 206 sys.path[:] = orig_sys_path 207 self.addCleanup(restore) 208 209 suite = loader.discover('.') 210 self.assertIn(os.getcwd(), sys.path) 211 self.assertEqual(suite.countTestCases(), 1) 212 test = list(list(suite)[0])[0] # extract test from suite 213 214 self.assertRaises(ImportError, 215 lambda: test.test_this_does_not_exist()) 216 217 def test_command_line_handling_parseArgs(self): 218 # Haha - take that uninstantiable class 219 program = object.__new__(unittest2.TestProgram) 220 221 args = [] 222 223 def do_discovery(argv): 224 args.extend(argv) 225 program._do_discovery = do_discovery 226 program.parseArgs(['something', 'discover']) 227 self.assertEqual(args, []) 228 229 program.parseArgs(['something', 'discover', 'foo', 'bar']) 230 self.assertEqual(args, ['foo', 'bar']) 231 232 def test_command_line_handling_do_discovery_too_many_arguments(self): 233 class Stop(Exception): 234 pass 235 236 def usageExit(): 237 raise Stop 238 239 program = object.__new__(unittest2.TestProgram) 240 program.usageExit = usageExit 241 242 self.assertRaises(Stop, 243 # too many args 244 lambda: program._do_discovery(['one', 'two', 'three', 'four'])) 245 246 def test_command_line_handling_do_discovery_calls_loader(self): 247 program = object.__new__(unittest2.TestProgram) 248 249 class Loader(object): 250 args = [] 251 252 def discover(self, start_dir, pattern, top_level_dir): 253 self.args.append((start_dir, pattern, top_level_dir)) 254 return 'tests' 255 256 program._do_discovery(['-v'], Loader=Loader) 257 self.assertEqual(program.verbosity, 2) 258 self.assertEqual(program.test, 'tests') 259 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 260 261 Loader.args = [] 262 program = object.__new__(unittest2.TestProgram) 263 program._do_discovery(['--verbose'], Loader=Loader) 264 self.assertEqual(program.test, 'tests') 265 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 266 267 Loader.args = [] 268 program = object.__new__(unittest2.TestProgram) 269 program._do_discovery([], Loader=Loader) 270 self.assertEqual(program.test, 'tests') 271 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 272 273 Loader.args = [] 274 program = object.__new__(unittest2.TestProgram) 275 program._do_discovery(['fish'], Loader=Loader) 276 self.assertEqual(program.test, 'tests') 277 self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) 278 279 Loader.args = [] 280 program = object.__new__(unittest2.TestProgram) 281 program._do_discovery(['fish', 'eggs'], Loader=Loader) 282 self.assertEqual(program.test, 'tests') 283 self.assertEqual(Loader.args, [('fish', 'eggs', None)]) 284 285 Loader.args = [] 286 program = object.__new__(unittest2.TestProgram) 287 program._do_discovery(['fish', 'eggs', 'ham'], Loader=Loader) 288 self.assertEqual(program.test, 'tests') 289 self.assertEqual(Loader.args, [('fish', 'eggs', 'ham')]) 290 291 Loader.args = [] 292 program = object.__new__(unittest2.TestProgram) 293 program._do_discovery(['-s', 'fish'], Loader=Loader) 294 self.assertEqual(program.test, 'tests') 295 self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) 296 297 Loader.args = [] 298 program = object.__new__(unittest2.TestProgram) 299 program._do_discovery(['-t', 'fish'], Loader=Loader) 300 self.assertEqual(program.test, 'tests') 301 self.assertEqual(Loader.args, [('.', 'test*.py', 'fish')]) 302 303 Loader.args = [] 304 program = object.__new__(unittest2.TestProgram) 305 program._do_discovery(['-p', 'fish'], Loader=Loader) 306 self.assertEqual(program.test, 'tests') 307 self.assertEqual(Loader.args, [('.', 'fish', None)]) 308 self.assertFalse(program.failfast) 309 self.assertFalse(program.catchbreak) 310 311 args = ['-p', 'eggs', '-s', 'fish', '-v', '-f'] 312 try: 313 import signal 314 except ImportError: 315 signal = None 316 else: 317 args.append('-c') 318 Loader.args = [] 319 program = object.__new__(unittest2.TestProgram) 320 program._do_discovery(args, Loader=Loader) 321 self.assertEqual(program.test, 'tests') 322 self.assertEqual(Loader.args, [('fish', 'eggs', None)]) 323 self.assertEqual(program.verbosity, 2) 324 self.assertTrue(program.failfast) 325 if signal is not None: 326 self.assertTrue(program.catchbreak) 327 328 def test_detect_module_clash(self): 329 class Module(object): 330 __file__ = 'bar/foo.py' 331 sys.modules['foo'] = Module 332 full_path = os.path.abspath('foo') 333 original_listdir = os.listdir 334 original_isfile = os.path.isfile 335 original_isdir = os.path.isdir 336 337 def cleanup(): 338 os.listdir = original_listdir 339 os.path.isfile = original_isfile 340 os.path.isdir = original_isdir 341 del sys.modules['foo'] 342 if full_path in sys.path: 343 sys.path.remove(full_path) 344 self.addCleanup(cleanup) 345 346 def listdir(_): 347 return ['foo.py'] 348 349 def isfile(_): 350 return True 351 352 def isdir(_): 353 return True 354 os.listdir = listdir 355 os.path.isfile = isfile 356 os.path.isdir = isdir 357 358 loader = unittest2.TestLoader() 359 360 mod_dir = os.path.abspath('bar') 361 expected_dir = os.path.abspath('foo') 362 msg = re.escape( 363 r"'foo' module incorrectly imported from %r. Expected %r. " 364 "Is this module globally installed?" % 365 (mod_dir, expected_dir)) 366 self.assertRaisesRegexp( 367 ImportError, '^%s$' % msg, loader.discover, 368 start_dir='foo', pattern='foo.py' 369 ) 370 self.assertEqual(sys.path[0], full_path) 371 372 def test_discovery_from_dotted_path(self): 373 loader = unittest2.TestLoader() 374 375 tests = [self] 376 expectedPath = os.path.abspath( 377 os.path.dirname(unittest2.test.__file__)) 378 379 self.wasRun = False 380 381 def _find_tests(start_dir, pattern): 382 self.wasRun = True 383 self.assertEqual(start_dir, expectedPath) 384 return tests 385 loader._find_tests = _find_tests 386 suite = loader.discover('unittest2.test') 387 self.assertTrue(self.wasRun) 388 self.assertEqual(suite._tests, tests) 389 390 391if __name__ == '__main__': 392 unittest2.main() 393