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