• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import io
2
3import os
4import sys
5import subprocess
6from test import support
7import unittest
8import unittest.test
9from .test_result import BufferedWriter
10
11
12class Test_TestProgram(unittest.TestCase):
13
14    def test_discovery_from_dotted_path(self):
15        loader = unittest.TestLoader()
16
17        tests = [self]
18        expectedPath = os.path.abspath(os.path.dirname(unittest.test.__file__))
19
20        self.wasRun = False
21        def _find_tests(start_dir, pattern):
22            self.wasRun = True
23            self.assertEqual(start_dir, expectedPath)
24            return tests
25        loader._find_tests = _find_tests
26        suite = loader.discover('unittest.test')
27        self.assertTrue(self.wasRun)
28        self.assertEqual(suite._tests, tests)
29
30    # Horrible white box test
31    def testNoExit(self):
32        result = object()
33        test = object()
34
35        class FakeRunner(object):
36            def run(self, test):
37                self.test = test
38                return result
39
40        runner = FakeRunner()
41
42        oldParseArgs = unittest.TestProgram.parseArgs
43        def restoreParseArgs():
44            unittest.TestProgram.parseArgs = oldParseArgs
45        unittest.TestProgram.parseArgs = lambda *args: None
46        self.addCleanup(restoreParseArgs)
47
48        def removeTest():
49            del unittest.TestProgram.test
50        unittest.TestProgram.test = test
51        self.addCleanup(removeTest)
52
53        program = unittest.TestProgram(testRunner=runner, exit=False, verbosity=2)
54
55        self.assertEqual(program.result, result)
56        self.assertEqual(runner.test, test)
57        self.assertEqual(program.verbosity, 2)
58
59    class FooBar(unittest.TestCase):
60        def testPass(self):
61            pass
62        def testFail(self):
63            raise AssertionError
64
65    class FooBarLoader(unittest.TestLoader):
66        """Test loader that returns a suite containing FooBar."""
67        def loadTestsFromModule(self, module):
68            return self.suiteClass(
69                [self.loadTestsFromTestCase(Test_TestProgram.FooBar)])
70
71        def loadTestsFromNames(self, names, module):
72            return self.suiteClass(
73                [self.loadTestsFromTestCase(Test_TestProgram.FooBar)])
74
75    def test_defaultTest_with_string(self):
76        class FakeRunner(object):
77            def run(self, test):
78                self.test = test
79                return True
80
81        old_argv = sys.argv
82        sys.argv = ['faketest']
83        runner = FakeRunner()
84        program = unittest.TestProgram(testRunner=runner, exit=False,
85                                       defaultTest='unittest.test',
86                                       testLoader=self.FooBarLoader())
87        sys.argv = old_argv
88        self.assertEqual(('unittest.test',), program.testNames)
89
90    def test_defaultTest_with_iterable(self):
91        class FakeRunner(object):
92            def run(self, test):
93                self.test = test
94                return True
95
96        old_argv = sys.argv
97        sys.argv = ['faketest']
98        runner = FakeRunner()
99        program = unittest.TestProgram(
100            testRunner=runner, exit=False,
101            defaultTest=['unittest.test', 'unittest.test2'],
102            testLoader=self.FooBarLoader())
103        sys.argv = old_argv
104        self.assertEqual(['unittest.test', 'unittest.test2'],
105                          program.testNames)
106
107    def test_NonExit(self):
108        stream = BufferedWriter()
109        program = unittest.main(exit=False,
110                                argv=["foobar"],
111                                testRunner=unittest.TextTestRunner(stream=stream),
112                                testLoader=self.FooBarLoader())
113        self.assertTrue(hasattr(program, 'result'))
114        self.assertIn('\nFAIL: testFail ', stream.getvalue())
115        self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
116
117
118    def test_Exit(self):
119        stream = BufferedWriter()
120        self.assertRaises(
121            SystemExit,
122            unittest.main,
123            argv=["foobar"],
124            testRunner=unittest.TextTestRunner(stream=stream),
125            exit=True,
126            testLoader=self.FooBarLoader())
127        self.assertIn('\nFAIL: testFail ', stream.getvalue())
128        self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
129
130
131    def test_ExitAsDefault(self):
132        stream = BufferedWriter()
133        self.assertRaises(
134            SystemExit,
135            unittest.main,
136            argv=["foobar"],
137            testRunner=unittest.TextTestRunner(stream=stream),
138            testLoader=self.FooBarLoader())
139        self.assertIn('\nFAIL: testFail ', stream.getvalue())
140        self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
141
142
143class InitialisableProgram(unittest.TestProgram):
144    exit = False
145    result = None
146    verbosity = 1
147    defaultTest = None
148    tb_locals = False
149    testRunner = None
150    testLoader = unittest.defaultTestLoader
151    module = '__main__'
152    progName = 'test'
153    test = 'test'
154    def __init__(self, *args):
155        pass
156
157RESULT = object()
158
159class FakeRunner(object):
160    initArgs = None
161    test = None
162    raiseError = 0
163
164    def __init__(self, **kwargs):
165        FakeRunner.initArgs = kwargs
166        if FakeRunner.raiseError:
167            FakeRunner.raiseError -= 1
168            raise TypeError
169
170    def run(self, test):
171        FakeRunner.test = test
172        return RESULT
173
174
175class TestCommandLineArgs(unittest.TestCase):
176
177    def setUp(self):
178        self.program = InitialisableProgram()
179        self.program.createTests = lambda: None
180        FakeRunner.initArgs = None
181        FakeRunner.test = None
182        FakeRunner.raiseError = 0
183
184    def testVerbosity(self):
185        program = self.program
186
187        for opt in '-q', '--quiet':
188            program.verbosity = 1
189            program.parseArgs([None, opt])
190            self.assertEqual(program.verbosity, 0)
191
192        for opt in '-v', '--verbose':
193            program.verbosity = 1
194            program.parseArgs([None, opt])
195            self.assertEqual(program.verbosity, 2)
196
197    def testBufferCatchFailfast(self):
198        program = self.program
199        for arg, attr in (('buffer', 'buffer'), ('failfast', 'failfast'),
200                      ('catch', 'catchbreak')):
201
202            setattr(program, attr, None)
203            program.parseArgs([None])
204            self.assertIs(getattr(program, attr), False)
205
206            false = []
207            setattr(program, attr, false)
208            program.parseArgs([None])
209            self.assertIs(getattr(program, attr), false)
210
211            true = [42]
212            setattr(program, attr, true)
213            program.parseArgs([None])
214            self.assertIs(getattr(program, attr), true)
215
216            short_opt = '-%s' % arg[0]
217            long_opt = '--%s' % arg
218            for opt in short_opt, long_opt:
219                setattr(program, attr, None)
220                program.parseArgs([None, opt])
221                self.assertIs(getattr(program, attr), True)
222
223                setattr(program, attr, False)
224                with support.captured_stderr() as stderr, \
225                    self.assertRaises(SystemExit) as cm:
226                    program.parseArgs([None, opt])
227                self.assertEqual(cm.exception.args, (2,))
228
229                setattr(program, attr, True)
230                with support.captured_stderr() as stderr, \
231                    self.assertRaises(SystemExit) as cm:
232                    program.parseArgs([None, opt])
233                self.assertEqual(cm.exception.args, (2,))
234
235    def testWarning(self):
236        """Test the warnings argument"""
237        # see #10535
238        class FakeTP(unittest.TestProgram):
239            def parseArgs(self, *args, **kw): pass
240            def runTests(self, *args, **kw): pass
241        warnoptions = sys.warnoptions[:]
242        try:
243            sys.warnoptions[:] = []
244            # no warn options, no arg -> default
245            self.assertEqual(FakeTP().warnings, 'default')
246            # no warn options, w/ arg -> arg value
247            self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore')
248            sys.warnoptions[:] = ['somevalue']
249            # warn options, no arg -> None
250            # warn options, w/ arg -> arg value
251            self.assertEqual(FakeTP().warnings, None)
252            self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore')
253        finally:
254            sys.warnoptions[:] = warnoptions
255
256    def testRunTestsRunnerClass(self):
257        program = self.program
258
259        program.testRunner = FakeRunner
260        program.verbosity = 'verbosity'
261        program.failfast = 'failfast'
262        program.buffer = 'buffer'
263        program.warnings = 'warnings'
264
265        program.runTests()
266
267        self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity',
268                                                'failfast': 'failfast',
269                                                'buffer': 'buffer',
270                                                'tb_locals': False,
271                                                'warnings': 'warnings'})
272        self.assertEqual(FakeRunner.test, 'test')
273        self.assertIs(program.result, RESULT)
274
275    def testRunTestsRunnerInstance(self):
276        program = self.program
277
278        program.testRunner = FakeRunner()
279        FakeRunner.initArgs = None
280
281        program.runTests()
282
283        # A new FakeRunner should not have been instantiated
284        self.assertIsNone(FakeRunner.initArgs)
285
286        self.assertEqual(FakeRunner.test, 'test')
287        self.assertIs(program.result, RESULT)
288
289    def test_locals(self):
290        program = self.program
291
292        program.testRunner = FakeRunner
293        program.parseArgs([None, '--locals'])
294        self.assertEqual(True, program.tb_locals)
295        program.runTests()
296        self.assertEqual(FakeRunner.initArgs, {'buffer': False,
297                                               'failfast': False,
298                                               'tb_locals': True,
299                                               'verbosity': 1,
300                                               'warnings': None})
301
302    def testRunTestsOldRunnerClass(self):
303        program = self.program
304
305        # Two TypeErrors are needed to fall all the way back to old-style
306        # runners - one to fail tb_locals, one to fail buffer etc.
307        FakeRunner.raiseError = 2
308        program.testRunner = FakeRunner
309        program.verbosity = 'verbosity'
310        program.failfast = 'failfast'
311        program.buffer = 'buffer'
312        program.test = 'test'
313
314        program.runTests()
315
316        # If initialising raises a type error it should be retried
317        # without the new keyword arguments
318        self.assertEqual(FakeRunner.initArgs, {})
319        self.assertEqual(FakeRunner.test, 'test')
320        self.assertIs(program.result, RESULT)
321
322    def testCatchBreakInstallsHandler(self):
323        module = sys.modules['unittest.main']
324        original = module.installHandler
325        def restore():
326            module.installHandler = original
327        self.addCleanup(restore)
328
329        self.installed = False
330        def fakeInstallHandler():
331            self.installed = True
332        module.installHandler = fakeInstallHandler
333
334        program = self.program
335        program.catchbreak = True
336
337        program.testRunner = FakeRunner
338
339        program.runTests()
340        self.assertTrue(self.installed)
341
342    def _patch_isfile(self, names, exists=True):
343        def isfile(path):
344            return path in names
345        original = os.path.isfile
346        os.path.isfile = isfile
347        def restore():
348            os.path.isfile = original
349        self.addCleanup(restore)
350
351
352    def testParseArgsFileNames(self):
353        # running tests with filenames instead of module names
354        program = self.program
355        argv = ['progname', 'foo.py', 'bar.Py', 'baz.PY', 'wing.txt']
356        self._patch_isfile(argv)
357
358        program.createTests = lambda: None
359        program.parseArgs(argv)
360
361        # note that 'wing.txt' is not a Python file so the name should
362        # *not* be converted to a module name
363        expected = ['foo', 'bar', 'baz', 'wing.txt']
364        self.assertEqual(program.testNames, expected)
365
366
367    def testParseArgsFilePaths(self):
368        program = self.program
369        argv = ['progname', 'foo/bar/baz.py', 'green\\red.py']
370        self._patch_isfile(argv)
371
372        program.createTests = lambda: None
373        program.parseArgs(argv)
374
375        expected = ['foo.bar.baz', 'green.red']
376        self.assertEqual(program.testNames, expected)
377
378
379    def testParseArgsNonExistentFiles(self):
380        program = self.program
381        argv = ['progname', 'foo/bar/baz.py', 'green\\red.py']
382        self._patch_isfile([])
383
384        program.createTests = lambda: None
385        program.parseArgs(argv)
386
387        self.assertEqual(program.testNames, argv[1:])
388
389    def testParseArgsAbsolutePathsThatCanBeConverted(self):
390        cur_dir = os.getcwd()
391        program = self.program
392        def _join(name):
393            return os.path.join(cur_dir, name)
394        argv = ['progname', _join('foo/bar/baz.py'), _join('green\\red.py')]
395        self._patch_isfile(argv)
396
397        program.createTests = lambda: None
398        program.parseArgs(argv)
399
400        expected = ['foo.bar.baz', 'green.red']
401        self.assertEqual(program.testNames, expected)
402
403    def testParseArgsAbsolutePathsThatCannotBeConverted(self):
404        program = self.program
405        # even on Windows '/...' is considered absolute by os.path.abspath
406        argv = ['progname', '/foo/bar/baz.py', '/green/red.py']
407        self._patch_isfile(argv)
408
409        program.createTests = lambda: None
410        program.parseArgs(argv)
411
412        self.assertEqual(program.testNames, argv[1:])
413
414        # it may be better to use platform specific functions to normalise paths
415        # rather than accepting '.PY' and '\' as file separator on Linux / Mac
416        # it would also be better to check that a filename is a valid module
417        # identifier (we have a regex for this in loader.py)
418        # for invalid filenames should we raise a useful error rather than
419        # leaving the current error message (import of filename fails) in place?
420
421    def testParseArgsSelectedTestNames(self):
422        program = self.program
423        argv = ['progname', '-k', 'foo', '-k', 'bar', '-k', '*pat*']
424
425        program.createTests = lambda: None
426        program.parseArgs(argv)
427
428        self.assertEqual(program.testNamePatterns, ['*foo*', '*bar*', '*pat*'])
429
430    def testSelectedTestNamesFunctionalTest(self):
431        def run_unittest(args):
432            p = subprocess.Popen([sys.executable, '-m', 'unittest'] + args,
433                stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, cwd=os.path.dirname(__file__))
434            with p:
435                _, stderr = p.communicate()
436            return stderr.decode()
437
438        t = '_test_warnings'
439        self.assertIn('Ran 7 tests', run_unittest([t]))
440        self.assertIn('Ran 7 tests', run_unittest(['-k', 'TestWarnings', t]))
441        self.assertIn('Ran 7 tests', run_unittest(['discover', '-p', '*_test*', '-k', 'TestWarnings']))
442        self.assertIn('Ran 2 tests', run_unittest(['-k', 'f', t]))
443        self.assertIn('Ran 7 tests', run_unittest(['-k', 't', t]))
444        self.assertIn('Ran 3 tests', run_unittest(['-k', '*t', t]))
445        self.assertIn('Ran 7 tests', run_unittest(['-k', '*test_warnings.*Warning*', t]))
446        self.assertIn('Ran 1 test', run_unittest(['-k', '*test_warnings.*warning*', t]))
447
448
449if __name__ == '__main__':
450    unittest.main()
451