blob: 1fdf9913c970436f089bcf6d83b335de5455970e [file] [log] [blame]
Michael Foord2560e5c2010-03-27 12:34:21 +00001import os
Michael Foord3b2494f2010-05-07 23:42:40 +00002import re
Michael Foord2560e5c2010-03-27 12:34:21 +00003import sys
4
5import unittest
6
7
Michael Foord086f3082010-11-21 21:28:01 +00008class TestableTestProgram(unittest.TestProgram):
9 module = '__main__'
10 exit = True
11 defaultTest = failfast = catchbreak = buffer = None
12 verbosity = 1
13 progName = ''
14 testRunner = testLoader = None
15
16 def __init__(self):
17 pass
18
19
Michael Foord2560e5c2010-03-27 12:34:21 +000020class TestDiscovery(unittest.TestCase):
21
22 # Heavily mocked tests so I can avoid hitting the filesystem
23 def test_get_name_from_path(self):
24 loader = unittest.TestLoader()
25 loader._top_level_dir = '/foo'
26 name = loader._get_name_from_path('/foo/bar/baz.py')
27 self.assertEqual(name, 'bar.baz')
28
29 if not __debug__:
30 # asserts are off
31 return
32
33 with self.assertRaises(AssertionError):
34 loader._get_name_from_path('/bar/baz.py')
35
36 def test_find_tests(self):
37 loader = unittest.TestLoader()
38
39 original_listdir = os.listdir
40 def restore_listdir():
41 os.listdir = original_listdir
42 original_isfile = os.path.isfile
43 def restore_isfile():
44 os.path.isfile = original_isfile
45 original_isdir = os.path.isdir
46 def restore_isdir():
47 os.path.isdir = original_isdir
48
49 path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir',
50 'test.foo', 'test-not-a-module.py', 'another_dir'],
51 ['test3.py', 'test4.py', ]]
52 os.listdir = lambda path: path_lists.pop(0)
53 self.addCleanup(restore_listdir)
54
55 def isdir(path):
56 return path.endswith('dir')
57 os.path.isdir = isdir
58 self.addCleanup(restore_isdir)
59
60 def isfile(path):
61 # another_dir is not a package and so shouldn't be recursed into
62 return not path.endswith('dir') and not 'another_dir' in path
63 os.path.isfile = isfile
64 self.addCleanup(restore_isfile)
65
66 loader._get_module_from_name = lambda path: path + ' module'
67 loader.loadTestsFromModule = lambda module: module + ' tests'
68
Michael Foord3b2494f2010-05-07 23:42:40 +000069 top_level = os.path.abspath('/foo')
70 loader._top_level_dir = top_level
71 suite = list(loader._find_tests(top_level, 'test*.py'))
Michael Foord2560e5c2010-03-27 12:34:21 +000072
73 expected = [name + ' module tests' for name in
74 ('test1', 'test2')]
75 expected.extend([('test_dir.%s' % name) + ' module tests' for name in
76 ('test3', 'test4')])
77 self.assertEqual(suite, expected)
78
79 def test_find_tests_with_package(self):
80 loader = unittest.TestLoader()
81
82 original_listdir = os.listdir
83 def restore_listdir():
84 os.listdir = original_listdir
85 original_isfile = os.path.isfile
86 def restore_isfile():
87 os.path.isfile = original_isfile
88 original_isdir = os.path.isdir
89 def restore_isdir():
90 os.path.isdir = original_isdir
91
92 directories = ['a_directory', 'test_directory', 'test_directory2']
93 path_lists = [directories, [], [], []]
94 os.listdir = lambda path: path_lists.pop(0)
95 self.addCleanup(restore_listdir)
96
97 os.path.isdir = lambda path: True
98 self.addCleanup(restore_isdir)
99
100 os.path.isfile = lambda path: os.path.basename(path) not in directories
101 self.addCleanup(restore_isfile)
102
103 class Module(object):
104 paths = []
105 load_tests_args = []
106
107 def __init__(self, path):
108 self.path = path
109 self.paths.append(path)
110 if os.path.basename(path) == 'test_directory':
111 def load_tests(loader, tests, pattern):
112 self.load_tests_args.append((loader, tests, pattern))
113 return 'load_tests'
114 self.load_tests = load_tests
115
116 def __eq__(self, other):
117 return self.path == other.path
118
119 loader._get_module_from_name = lambda name: Module(name)
120 def loadTestsFromModule(module, use_load_tests):
121 if use_load_tests:
122 raise self.failureException('use_load_tests should be False for packages')
123 return module.path + ' module tests'
124 loader.loadTestsFromModule = loadTestsFromModule
125
126 loader._top_level_dir = '/foo'
127 # this time no '.py' on the pattern so that it can match
128 # a test package
129 suite = list(loader._find_tests('/foo', 'test*'))
130
131 # We should have loaded tests from the test_directory package by calling load_tests
132 # and directly from the test_directory2 package
133 self.assertEqual(suite,
134 ['load_tests', 'test_directory2' + ' module tests'])
135 self.assertEqual(Module.paths, ['test_directory', 'test_directory2'])
136
137 # load_tests should have been called once with loader, tests and pattern
138 self.assertEqual(Module.load_tests_args,
139 [(loader, 'test_directory' + ' module tests', 'test*')])
140
141 def test_discover(self):
142 loader = unittest.TestLoader()
143
144 original_isfile = os.path.isfile
Benjamin Petersonb48af542010-04-11 20:43:16 +0000145 original_isdir = os.path.isdir
Michael Foord2560e5c2010-03-27 12:34:21 +0000146 def restore_isfile():
147 os.path.isfile = original_isfile
148
149 os.path.isfile = lambda path: False
150 self.addCleanup(restore_isfile)
151
152 orig_sys_path = sys.path[:]
153 def restore_path():
154 sys.path[:] = orig_sys_path
155 self.addCleanup(restore_path)
156
157 full_path = os.path.abspath(os.path.normpath('/foo'))
158 with self.assertRaises(ImportError):
159 loader.discover('/foo/bar', top_level_dir='/foo')
160
161 self.assertEqual(loader._top_level_dir, full_path)
162 self.assertIn(full_path, sys.path)
163
164 os.path.isfile = lambda path: True
Benjamin Petersonb48af542010-04-11 20:43:16 +0000165 os.path.isdir = lambda path: True
166
167 def restore_isdir():
168 os.path.isdir = original_isdir
169 self.addCleanup(restore_isdir)
170
Michael Foord2560e5c2010-03-27 12:34:21 +0000171 _find_tests_args = []
172 def _find_tests(start_dir, pattern):
173 _find_tests_args.append((start_dir, pattern))
174 return ['tests']
175 loader._find_tests = _find_tests
176 loader.suiteClass = str
177
178 suite = loader.discover('/foo/bar/baz', 'pattern', '/foo/bar')
179
Benjamin Petersonb48af542010-04-11 20:43:16 +0000180 top_level_dir = os.path.abspath('/foo/bar')
181 start_dir = os.path.abspath('/foo/bar/baz')
Michael Foord2560e5c2010-03-27 12:34:21 +0000182 self.assertEqual(suite, "['tests']")
183 self.assertEqual(loader._top_level_dir, top_level_dir)
184 self.assertEqual(_find_tests_args, [(start_dir, 'pattern')])
185 self.assertIn(top_level_dir, sys.path)
186
187 def test_discover_with_modules_that_fail_to_import(self):
188 loader = unittest.TestLoader()
189
190 listdir = os.listdir
191 os.listdir = lambda _: ['test_this_does_not_exist.py']
192 isfile = os.path.isfile
193 os.path.isfile = lambda _: True
194 orig_sys_path = sys.path[:]
195 def restore():
196 os.path.isfile = isfile
197 os.listdir = listdir
198 sys.path[:] = orig_sys_path
199 self.addCleanup(restore)
200
201 suite = loader.discover('.')
202 self.assertIn(os.getcwd(), sys.path)
203 self.assertEqual(suite.countTestCases(), 1)
204 test = list(list(suite)[0])[0] # extract test from suite
205
206 with self.assertRaises(ImportError):
207 test.test_this_does_not_exist()
208
209 def test_command_line_handling_parseArgs(self):
Michael Foord086f3082010-11-21 21:28:01 +0000210 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000211
212 args = []
213 def do_discovery(argv):
214 args.extend(argv)
215 program._do_discovery = do_discovery
216 program.parseArgs(['something', 'discover'])
217 self.assertEqual(args, [])
218
219 program.parseArgs(['something', 'discover', 'foo', 'bar'])
220 self.assertEqual(args, ['foo', 'bar'])
221
Michael Foord086f3082010-11-21 21:28:01 +0000222 def test_command_line_handling_discover_by_default(self):
223 program = TestableTestProgram()
224 program.module = None
225
Michael Foordb87ef8f2010-11-22 10:41:27 +0000226 self.called = False
Michael Foord086f3082010-11-21 21:28:01 +0000227 def do_discovery(argv):
Michael Foordb87ef8f2010-11-22 10:41:27 +0000228 self.called = True
229 self.assertEqual(argv, [])
Michael Foord086f3082010-11-21 21:28:01 +0000230 program._do_discovery = do_discovery
231 program.parseArgs(['something'])
Michael Foordb87ef8f2010-11-22 10:41:27 +0000232 self.assertTrue(self.called)
Michael Foord086f3082010-11-21 21:28:01 +0000233
Michael Foordf100dbd2010-12-19 03:59:10 +0000234 def test_command_line_handling_discover_by_default_with_options(self):
235 program = TestableTestProgram()
236 program.module = None
237
238 args = ['something', '-v', '-b', '-v', '-c', '-f']
239 self.called = False
240 def do_discovery(argv):
241 self.called = True
242 self.assertEqual(argv, args[1:])
243 program._do_discovery = do_discovery
244 program.parseArgs(args)
245 self.assertTrue(self.called)
246
Michael Foord086f3082010-11-21 21:28:01 +0000247
Michael Foord2560e5c2010-03-27 12:34:21 +0000248 def test_command_line_handling_do_discovery_too_many_arguments(self):
249 class Stop(Exception):
250 pass
251 def usageExit():
252 raise Stop
253
Michael Foord086f3082010-11-21 21:28:01 +0000254 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000255 program.usageExit = usageExit
Michael Foord8fd396b2013-02-11 00:04:24 +0000256 program.testLoader = None
Michael Foord2560e5c2010-03-27 12:34:21 +0000257
258 with self.assertRaises(Stop):
259 # too many args
260 program._do_discovery(['one', 'two', 'three', 'four'])
261
262
Michael Foord8fd396b2013-02-11 00:04:24 +0000263 def test_command_line_handling_do_discovery_uses_default_loader(self):
264 program = object.__new__(unittest.TestProgram)
265
266 class Loader(object):
267 args = []
268 def discover(self, start_dir, pattern, top_level_dir):
269 self.args.append((start_dir, pattern, top_level_dir))
270 return 'tests'
271
Michael Foordf78f5b12013-02-11 13:20:52 +0000272 program.testLoader = Loader()
Michael Foord8fd396b2013-02-11 00:04:24 +0000273 program._do_discovery(['-v'])
274 self.assertEqual(Loader.args, [('.', 'test*.py', None)])
275
Michael Foord2560e5c2010-03-27 12:34:21 +0000276 def test_command_line_handling_do_discovery_calls_loader(self):
Michael Foord086f3082010-11-21 21:28:01 +0000277 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000278
279 class Loader(object):
280 args = []
281 def discover(self, start_dir, pattern, top_level_dir):
282 self.args.append((start_dir, pattern, top_level_dir))
283 return 'tests'
284
285 program._do_discovery(['-v'], Loader=Loader)
286 self.assertEqual(program.verbosity, 2)
287 self.assertEqual(program.test, 'tests')
288 self.assertEqual(Loader.args, [('.', 'test*.py', None)])
289
290 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000291 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000292 program._do_discovery(['--verbose'], Loader=Loader)
293 self.assertEqual(program.test, 'tests')
294 self.assertEqual(Loader.args, [('.', 'test*.py', None)])
295
296 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000297 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000298 program._do_discovery([], Loader=Loader)
299 self.assertEqual(program.test, 'tests')
300 self.assertEqual(Loader.args, [('.', 'test*.py', None)])
301
302 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000303 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000304 program._do_discovery(['fish'], Loader=Loader)
305 self.assertEqual(program.test, 'tests')
306 self.assertEqual(Loader.args, [('fish', 'test*.py', None)])
307
308 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000309 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000310 program._do_discovery(['fish', 'eggs'], Loader=Loader)
311 self.assertEqual(program.test, 'tests')
312 self.assertEqual(Loader.args, [('fish', 'eggs', None)])
313
314 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000315 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000316 program._do_discovery(['fish', 'eggs', 'ham'], Loader=Loader)
317 self.assertEqual(program.test, 'tests')
318 self.assertEqual(Loader.args, [('fish', 'eggs', 'ham')])
319
320 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000321 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000322 program._do_discovery(['-s', 'fish'], Loader=Loader)
323 self.assertEqual(program.test, 'tests')
324 self.assertEqual(Loader.args, [('fish', 'test*.py', None)])
325
326 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000327 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000328 program._do_discovery(['-t', 'fish'], Loader=Loader)
329 self.assertEqual(program.test, 'tests')
330 self.assertEqual(Loader.args, [('.', 'test*.py', 'fish')])
331
332 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000333 program = TestableTestProgram()
Michael Foord2560e5c2010-03-27 12:34:21 +0000334 program._do_discovery(['-p', 'fish'], Loader=Loader)
335 self.assertEqual(program.test, 'tests')
336 self.assertEqual(Loader.args, [('.', 'fish', None)])
337 self.assertFalse(program.failfast)
Michael Foord65b69a12010-03-27 13:25:41 +0000338 self.assertFalse(program.catchbreak)
Michael Foord2560e5c2010-03-27 12:34:21 +0000339
340 Loader.args = []
Michael Foord086f3082010-11-21 21:28:01 +0000341 program = TestableTestProgram()
Michael Foord65b69a12010-03-27 13:25:41 +0000342 program._do_discovery(['-p', 'eggs', '-s', 'fish', '-v', '-f', '-c'],
343 Loader=Loader)
Michael Foord2560e5c2010-03-27 12:34:21 +0000344 self.assertEqual(program.test, 'tests')
345 self.assertEqual(Loader.args, [('fish', 'eggs', None)])
346 self.assertEqual(program.verbosity, 2)
347 self.assertTrue(program.failfast)
Michael Foord65b69a12010-03-27 13:25:41 +0000348 self.assertTrue(program.catchbreak)
349
Michael Foord3b2494f2010-05-07 23:42:40 +0000350 def test_detect_module_clash(self):
351 class Module(object):
352 __file__ = 'bar/foo.py'
353 sys.modules['foo'] = Module
354 full_path = os.path.abspath('foo')
355 original_listdir = os.listdir
356 original_isfile = os.path.isfile
357 original_isdir = os.path.isdir
358
359 def cleanup():
360 os.listdir = original_listdir
361 os.path.isfile = original_isfile
362 os.path.isdir = original_isdir
363 del sys.modules['foo']
364 if full_path in sys.path:
365 sys.path.remove(full_path)
366 self.addCleanup(cleanup)
367
368 def listdir(_):
369 return ['foo.py']
370 def isfile(_):
371 return True
372 def isdir(_):
373 return True
374 os.listdir = listdir
375 os.path.isfile = isfile
376 os.path.isdir = isdir
377
378 loader = unittest.TestLoader()
379
380 mod_dir = os.path.abspath('bar')
381 expected_dir = os.path.abspath('foo')
382 msg = re.escape(r"'foo' module incorrectly imported from %r. Expected %r. "
383 "Is this module globally installed?" % (mod_dir, expected_dir))
Ezio Melottied3a7d22010-12-01 02:32:32 +0000384 self.assertRaisesRegex(
Michael Foord3b2494f2010-05-07 23:42:40 +0000385 ImportError, '^%s$' % msg, loader.discover,
386 start_dir='foo', pattern='foo.py'
387 )
388 self.assertEqual(sys.path[0], full_path)
389
Michael Foord65b69a12010-03-27 13:25:41 +0000390
Michael Foord161b0242010-05-08 13:23:31 +0000391 def test_discovery_from_dotted_path(self):
392 loader = unittest.TestLoader()
393
394 tests = [self]
395 expectedPath = os.path.abspath(os.path.dirname(unittest.test.__file__))
396
397 self.wasRun = False
398 def _find_tests(start_dir, pattern):
399 self.wasRun = True
400 self.assertEqual(start_dir, expectedPath)
401 return tests
402 loader._find_tests = _find_tests
403 suite = loader.discover('unittest.test')
404 self.assertTrue(self.wasRun)
405 self.assertEqual(suite._tests, tests)
406
407
Michael Foord65b69a12010-03-27 13:25:41 +0000408if __name__ == '__main__':
409 unittest.main()