mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	split unittest.py into a package
This commit is contained in:
		
							parent
							
								
									5fee460bfa
								
							
						
					
					
						commit
						d7b0eebcae
					
				
					 14 changed files with 920 additions and 902 deletions
				
			
		|  | @ -1809,19 +1809,19 @@ def test_DocTestSuite(): | ||||||
|          >>> import test.sample_doctest |          >>> import test.sample_doctest | ||||||
|          >>> suite = doctest.DocTestSuite(test.sample_doctest) |          >>> suite = doctest.DocTestSuite(test.sample_doctest) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=4> |          <unittest.result.TestResult run=9 errors=0 failures=4> | ||||||
| 
 | 
 | ||||||
|        We can also supply the module by name: |        We can also supply the module by name: | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocTestSuite('test.sample_doctest') |          >>> suite = doctest.DocTestSuite('test.sample_doctest') | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=4> |          <unittest.result.TestResult run=9 errors=0 failures=4> | ||||||
| 
 | 
 | ||||||
|        We can use the current module: |        We can use the current module: | ||||||
| 
 | 
 | ||||||
|          >>> suite = test.sample_doctest.test_suite() |          >>> suite = test.sample_doctest.test_suite() | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=4> |          <unittest.result.TestResult run=9 errors=0 failures=4> | ||||||
| 
 | 
 | ||||||
|        We can supply global variables.  If we pass globs, they will be |        We can supply global variables.  If we pass globs, they will be | ||||||
|        used instead of the module globals.  Here we'll pass an empty |        used instead of the module globals.  Here we'll pass an empty | ||||||
|  | @ -1829,7 +1829,7 @@ def test_DocTestSuite(): | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocTestSuite('test.sample_doctest', globs={}) |          >>> suite = doctest.DocTestSuite('test.sample_doctest', globs={}) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=5> |          <unittest.result.TestResult run=9 errors=0 failures=5> | ||||||
| 
 | 
 | ||||||
|        Alternatively, we can provide extra globals.  Here we'll make an |        Alternatively, we can provide extra globals.  Here we'll make an | ||||||
|        error go away by providing an extra global variable: |        error go away by providing an extra global variable: | ||||||
|  | @ -1837,7 +1837,7 @@ def test_DocTestSuite(): | ||||||
|          >>> suite = doctest.DocTestSuite('test.sample_doctest', |          >>> suite = doctest.DocTestSuite('test.sample_doctest', | ||||||
|          ...                              extraglobs={'y': 1}) |          ...                              extraglobs={'y': 1}) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=3> |          <unittest.result.TestResult run=9 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        You can pass option flags.  Here we'll cause an extra error |        You can pass option flags.  Here we'll cause an extra error | ||||||
|        by disabling the blank-line feature: |        by disabling the blank-line feature: | ||||||
|  | @ -1845,7 +1845,7 @@ def test_DocTestSuite(): | ||||||
|          >>> suite = doctest.DocTestSuite('test.sample_doctest', |          >>> suite = doctest.DocTestSuite('test.sample_doctest', | ||||||
|          ...                      optionflags=doctest.DONT_ACCEPT_BLANKLINE) |          ...                      optionflags=doctest.DONT_ACCEPT_BLANKLINE) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=5> |          <unittest.result.TestResult run=9 errors=0 failures=5> | ||||||
| 
 | 
 | ||||||
|        You can supply setUp and tearDown functions: |        You can supply setUp and tearDown functions: | ||||||
| 
 | 
 | ||||||
|  | @ -1862,7 +1862,7 @@ def test_DocTestSuite(): | ||||||
|          >>> suite = doctest.DocTestSuite('test.sample_doctest', |          >>> suite = doctest.DocTestSuite('test.sample_doctest', | ||||||
|          ...      setUp=setUp, tearDown=tearDown) |          ...      setUp=setUp, tearDown=tearDown) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=3> |          <unittest.result.TestResult run=9 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        But the tearDown restores sanity: |        But the tearDown restores sanity: | ||||||
| 
 | 
 | ||||||
|  | @ -1880,7 +1880,7 @@ def test_DocTestSuite(): | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocTestSuite('test.sample_doctest', setUp=setUp) |          >>> suite = doctest.DocTestSuite('test.sample_doctest', setUp=setUp) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=9 errors=0 failures=3> |          <unittest.result.TestResult run=9 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        Here, we didn't need to use a tearDown function because we |        Here, we didn't need to use a tearDown function because we | ||||||
|        modified the test globals, which are a copy of the |        modified the test globals, which are a copy of the | ||||||
|  | @ -1899,7 +1899,7 @@ def test_DocFileSuite(): | ||||||
|          ...                              'test_doctest2.txt', |          ...                              'test_doctest2.txt', | ||||||
|          ...                              'test_doctest4.txt') |          ...                              'test_doctest4.txt') | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=3 errors=0 failures=3> |          <unittest.result.TestResult run=3 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        The test files are looked for in the directory containing the |        The test files are looked for in the directory containing the | ||||||
|        calling module.  A package keyword argument can be provided to |        calling module.  A package keyword argument can be provided to | ||||||
|  | @ -1911,7 +1911,7 @@ def test_DocFileSuite(): | ||||||
|          ...                              'test_doctest4.txt', |          ...                              'test_doctest4.txt', | ||||||
|          ...                              package='test') |          ...                              package='test') | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=3 errors=0 failures=3> |          <unittest.result.TestResult run=3 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        Support for using a package's __loader__.get_data() is also |        Support for using a package's __loader__.get_data() is also | ||||||
|        provided. |        provided. | ||||||
|  | @ -1930,14 +1930,14 @@ def test_DocFileSuite(): | ||||||
|          ... finally: |          ... finally: | ||||||
|          ...     if added_loader: |          ...     if added_loader: | ||||||
|          ...         del test.__loader__ |          ...         del test.__loader__ | ||||||
|          <unittest.TestResult run=3 errors=0 failures=3> |          <unittest.result.TestResult run=3 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        '/' should be used as a path separator.  It will be converted |        '/' should be used as a path separator.  It will be converted | ||||||
|        to a native separator at run time: |        to a native separator at run time: | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocFileSuite('../test/test_doctest.txt') |          >>> suite = doctest.DocFileSuite('../test/test_doctest.txt') | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=1 errors=0 failures=1> |          <unittest.result.TestResult run=1 errors=0 failures=1> | ||||||
| 
 | 
 | ||||||
|        If DocFileSuite is used from an interactive session, then files |        If DocFileSuite is used from an interactive session, then files | ||||||
|        are resolved relative to the directory of sys.argv[0]: |        are resolved relative to the directory of sys.argv[0]: | ||||||
|  | @ -1962,7 +1962,7 @@ def test_DocFileSuite(): | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocFileSuite(test_file, module_relative=False) |          >>> suite = doctest.DocFileSuite(test_file, module_relative=False) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=1 errors=0 failures=1> |          <unittest.result.TestResult run=1 errors=0 failures=1> | ||||||
| 
 | 
 | ||||||
|        It is an error to specify `package` when `module_relative=False`: |        It is an error to specify `package` when `module_relative=False`: | ||||||
| 
 | 
 | ||||||
|  | @ -1978,7 +1978,7 @@ def test_DocFileSuite(): | ||||||
|          ...                              'test_doctest4.txt', |          ...                              'test_doctest4.txt', | ||||||
|          ...                              globs={'favorite_color': 'blue'}) |          ...                              globs={'favorite_color': 'blue'}) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=3 errors=0 failures=2> |          <unittest.result.TestResult run=3 errors=0 failures=2> | ||||||
| 
 | 
 | ||||||
|        In this case, we supplied a missing favorite color. You can |        In this case, we supplied a missing favorite color. You can | ||||||
|        provide doctest options: |        provide doctest options: | ||||||
|  | @ -1989,7 +1989,7 @@ def test_DocFileSuite(): | ||||||
|          ...                         optionflags=doctest.DONT_ACCEPT_BLANKLINE, |          ...                         optionflags=doctest.DONT_ACCEPT_BLANKLINE, | ||||||
|          ...                              globs={'favorite_color': 'blue'}) |          ...                              globs={'favorite_color': 'blue'}) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=3 errors=0 failures=3> |          <unittest.result.TestResult run=3 errors=0 failures=3> | ||||||
| 
 | 
 | ||||||
|        And, you can provide setUp and tearDown functions: |        And, you can provide setUp and tearDown functions: | ||||||
| 
 | 
 | ||||||
|  | @ -2008,7 +2008,7 @@ def test_DocFileSuite(): | ||||||
|          ...                              'test_doctest4.txt', |          ...                              'test_doctest4.txt', | ||||||
|          ...                              setUp=setUp, tearDown=tearDown) |          ...                              setUp=setUp, tearDown=tearDown) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=3 errors=0 failures=2> |          <unittest.result.TestResult run=3 errors=0 failures=2> | ||||||
| 
 | 
 | ||||||
|        But the tearDown restores sanity: |        But the tearDown restores sanity: | ||||||
| 
 | 
 | ||||||
|  | @ -2027,7 +2027,7 @@ def test_DocFileSuite(): | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocFileSuite('test_doctest.txt', setUp=setUp) |          >>> suite = doctest.DocFileSuite('test_doctest.txt', setUp=setUp) | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=1 errors=0 failures=0> |          <unittest.result.TestResult run=1 errors=0 failures=0> | ||||||
| 
 | 
 | ||||||
|        Here, we didn't need to use a tearDown function because we |        Here, we didn't need to use a tearDown function because we | ||||||
|        modified the test globals.  The test globals are |        modified the test globals.  The test globals are | ||||||
|  | @ -2039,7 +2039,7 @@ def test_DocFileSuite(): | ||||||
| 
 | 
 | ||||||
|          >>> suite = doctest.DocFileSuite('test_doctest3.txt') |          >>> suite = doctest.DocFileSuite('test_doctest3.txt') | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=1 errors=0 failures=0> |          <unittest.result.TestResult run=1 errors=0 failures=0> | ||||||
| 
 | 
 | ||||||
|        If the tests contain non-ASCII characters, we have to specify which |        If the tests contain non-ASCII characters, we have to specify which | ||||||
|        encoding the file is encoded with. We do so by using the `encoding` |        encoding the file is encoded with. We do so by using the `encoding` | ||||||
|  | @ -2050,7 +2050,7 @@ def test_DocFileSuite(): | ||||||
|          ...                              'test_doctest4.txt', |          ...                              'test_doctest4.txt', | ||||||
|          ...                              encoding='utf-8') |          ...                              encoding='utf-8') | ||||||
|          >>> suite.run(unittest.TestResult()) |          >>> suite.run(unittest.TestResult()) | ||||||
|          <unittest.TestResult run=3 errors=0 failures=2> |          <unittest.result.TestResult run=3 errors=0 failures=2> | ||||||
| 
 | 
 | ||||||
|        """ |        """ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
| TESTS = 'cjkencodings_test inspect_fodder inspect_fodder2 mapping_tests' | TESTS = 'cjkencodings_test inspect_fodder inspect_fodder2 mapping_tests' | ||||||
| TESTS = TESTS.split() | TESTS = TESTS.split() | ||||||
| TEST_PATH = os.path.dirname(support.__file__) | TEST_PATH = os.path.dirname(support.__file__) | ||||||
| MODULES = "linecache unittest".split() | MODULES = "linecache abc".split() | ||||||
| MODULE_PATH = os.path.dirname(FILENAME) | MODULE_PATH = os.path.dirname(FILENAME) | ||||||
| 
 | 
 | ||||||
| SOURCE_1 = ''' | SOURCE_1 = ''' | ||||||
|  |  | ||||||
|  | @ -148,7 +148,7 @@ def defined_in(item, module): | ||||||
| 
 | 
 | ||||||
|     def test_easy(self): |     def test_easy(self): | ||||||
|         self.checkModule('pyclbr') |         self.checkModule('pyclbr') | ||||||
|         self.checkModule('doctest') |         self.checkModule('doctest', ignore=("DocTestCase",)) | ||||||
|         self.checkModule('rfc822') |         self.checkModule('rfc822') | ||||||
|         self.checkModule('difflib') |         self.checkModule('difflib') | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| from StringIO import StringIO | from StringIO import StringIO | ||||||
|  | import __builtin__ | ||||||
| import os | import os | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
|  | @ -3410,9 +3411,10 @@ class TestDiscovery(TestCase): | ||||||
|     def test_get_module_from_path(self): |     def test_get_module_from_path(self): | ||||||
|         loader = unittest.TestLoader() |         loader = unittest.TestLoader() | ||||||
| 
 | 
 | ||||||
|  |         old_import = __import__ | ||||||
|         def restore_import(): |         def restore_import(): | ||||||
|             unittest.__import__ = __import__ |             __builtin__.__import__ = old_import | ||||||
|         unittest.__import__ = lambda *_: None |         __builtin__.__import__ = lambda *_: None | ||||||
|         self.addCleanup(restore_import) |         self.addCleanup(restore_import) | ||||||
| 
 | 
 | ||||||
|         expected_module = object() |         expected_module = object() | ||||||
|  |  | ||||||
							
								
								
									
										63
									
								
								Lib/unittest/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Lib/unittest/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | """ | ||||||
|  | Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's | ||||||
|  | Smalltalk testing framework. | ||||||
|  | 
 | ||||||
|  | This module contains the core framework classes that form the basis of | ||||||
|  | specific test cases and suites (TestCase, TestSuite etc.), and also a | ||||||
|  | text-based utility class for running the tests and reporting the results | ||||||
|  |  (TextTestRunner). | ||||||
|  | 
 | ||||||
|  | Simple usage: | ||||||
|  | 
 | ||||||
|  |     import unittest | ||||||
|  | 
 | ||||||
|  |     class IntegerArithmenticTestCase(unittest.TestCase): | ||||||
|  |         def testAdd(self):  ## test method names begin 'test*' | ||||||
|  |             self.assertEqual((1 + 2), 3) | ||||||
|  |             self.assertEqual(0 + 1, 1) | ||||||
|  |         def testMultiply(self): | ||||||
|  |             self.assertEqual((0 * 10), 0) | ||||||
|  |             self.assertEqual((5 * 8), 40) | ||||||
|  | 
 | ||||||
|  |     if __name__ == '__main__': | ||||||
|  |         unittest.main() | ||||||
|  | 
 | ||||||
|  | Further information is available in the bundled documentation, and from | ||||||
|  | 
 | ||||||
|  |   http://docs.python.org/library/unittest.html | ||||||
|  | 
 | ||||||
|  | Copyright (c) 1999-2003 Steve Purcell | ||||||
|  | Copyright (c) 2003-2009 Python Software Foundation | ||||||
|  | This module is free software, and you may redistribute it and/or modify | ||||||
|  | it under the same terms as Python itself, so long as this copyright message | ||||||
|  | and disclaimer are retained in their original form. | ||||||
|  | 
 | ||||||
|  | IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | ||||||
|  | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF | ||||||
|  | THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||||
|  | DAMAGE. | ||||||
|  | 
 | ||||||
|  | THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||||||
|  | PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, | ||||||
|  | AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | ||||||
|  | SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | __all__ = ['TestResult', 'TestCase', 'TestSuite', | ||||||
|  |            'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main', | ||||||
|  |            'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless', | ||||||
|  |            'expectedFailure'] | ||||||
|  | 
 | ||||||
|  | # Expose obsolete functions for backwards compatibility | ||||||
|  | __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | from .result import TestResult | ||||||
|  | from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf, | ||||||
|  |                    skipUnless, expectedFailure) | ||||||
|  | from .suite import TestSuite | ||||||
|  | from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames, | ||||||
|  |                      findTestCases) | ||||||
|  | from .main import TestProgram, main | ||||||
|  | from .runner import TextTestRunner | ||||||
							
								
								
									
										8
									
								
								Lib/unittest/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Lib/unittest/__main__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | """Main entry point""" | ||||||
|  | 
 | ||||||
|  | import sys | ||||||
|  | if sys.argv[0].endswith("__main__.py"): | ||||||
|  |     sys.argv[0] = "unittest" | ||||||
|  | 
 | ||||||
|  | from .main import main | ||||||
|  | main(module=None) | ||||||
|  | @ -1,95 +1,13 @@ | ||||||
| #!/usr/bin/env python | """Test case implementation""" | ||||||
| ''' |  | ||||||
| Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's |  | ||||||
| Smalltalk testing framework. |  | ||||||
| 
 | 
 | ||||||
| This module contains the core framework classes that form the basis of | import sys | ||||||
| specific test cases and suites (TestCase, TestSuite etc.), and also a |  | ||||||
| text-based utility class for running the tests and reporting the results |  | ||||||
|  (TextTestRunner). |  | ||||||
| 
 |  | ||||||
| Simple usage: |  | ||||||
| 
 |  | ||||||
|     import unittest |  | ||||||
| 
 |  | ||||||
|     class IntegerArithmenticTestCase(unittest.TestCase): |  | ||||||
|         def testAdd(self):  ## test method names begin 'test*' |  | ||||||
|             self.assertEqual((1 + 2), 3) |  | ||||||
|             self.assertEqual(0 + 1, 1) |  | ||||||
|         def testMultiply(self): |  | ||||||
|             self.assertEqual((0 * 10), 0) |  | ||||||
|             self.assertEqual((5 * 8), 40) |  | ||||||
| 
 |  | ||||||
|     if __name__ == '__main__': |  | ||||||
|         unittest.main() |  | ||||||
| 
 |  | ||||||
| Further information is available in the bundled documentation, and from |  | ||||||
| 
 |  | ||||||
|   http://docs.python.org/library/unittest.html |  | ||||||
| 
 |  | ||||||
| Copyright (c) 1999-2003 Steve Purcell |  | ||||||
| Copyright (c) 2003-2009 Python Software Foundation |  | ||||||
| This module is free software, and you may redistribute it and/or modify |  | ||||||
| it under the same terms as Python itself, so long as this copyright message |  | ||||||
| and disclaimer are retained in their original form. |  | ||||||
| 
 |  | ||||||
| IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, |  | ||||||
| SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF |  | ||||||
| THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |  | ||||||
| DAMAGE. |  | ||||||
| 
 |  | ||||||
| THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |  | ||||||
| PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, |  | ||||||
| AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |  | ||||||
| SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |  | ||||||
| ''' |  | ||||||
| 
 |  | ||||||
| import difflib |  | ||||||
| import functools | import functools | ||||||
| import os | import difflib | ||||||
| import pprint | import pprint | ||||||
| import re | import re | ||||||
| import sys |  | ||||||
| import time |  | ||||||
| import traceback |  | ||||||
| import types |  | ||||||
| import warnings | import warnings | ||||||
| 
 | 
 | ||||||
| from fnmatch import fnmatch | from . import result, util | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Exported classes and functions |  | ||||||
| ############################################################################## |  | ||||||
| __all__ = ['TestResult', 'TestCase', 'TestSuite', |  | ||||||
|            'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main', |  | ||||||
|            'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless', |  | ||||||
|            'expectedFailure'] |  | ||||||
| 
 |  | ||||||
| # Expose obsolete functions for backwards compatibility |  | ||||||
| __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Backward compatibility |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| def _CmpToKey(mycmp): |  | ||||||
|     'Convert a cmp= function into a key= function' |  | ||||||
|     class K(object): |  | ||||||
|         def __init__(self, obj): |  | ||||||
|             self.obj = obj |  | ||||||
|         def __lt__(self, other): |  | ||||||
|             return mycmp(self.obj, other.obj) == -1 |  | ||||||
|     return K |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Test framework core |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| def _strclass(cls): |  | ||||||
|     return "%s.%s" % (cls.__module__, cls.__name__) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class SkipTest(Exception): | class SkipTest(Exception): | ||||||
|  | @ -163,111 +81,6 @@ def wrapper(*args, **kwargs): | ||||||
|         raise _UnexpectedSuccess |         raise _UnexpectedSuccess | ||||||
|     return wrapper |     return wrapper | ||||||
| 
 | 
 | ||||||
| __unittest = 1 |  | ||||||
| 
 |  | ||||||
| class TestResult(object): |  | ||||||
|     """Holder for test result information. |  | ||||||
| 
 |  | ||||||
|     Test results are automatically managed by the TestCase and TestSuite |  | ||||||
|     classes, and do not need to be explicitly manipulated by writers of tests. |  | ||||||
| 
 |  | ||||||
|     Each instance holds the total number of tests run, and collections of |  | ||||||
|     failures and errors that occurred among those test runs. The collections |  | ||||||
|     contain tuples of (testcase, exceptioninfo), where exceptioninfo is the |  | ||||||
|     formatted traceback of the error that occurred. |  | ||||||
|     """ |  | ||||||
|     def __init__(self): |  | ||||||
|         self.failures = [] |  | ||||||
|         self.errors = [] |  | ||||||
|         self.testsRun = 0 |  | ||||||
|         self.skipped = [] |  | ||||||
|         self.expectedFailures = [] |  | ||||||
|         self.unexpectedSuccesses = [] |  | ||||||
|         self.shouldStop = False |  | ||||||
| 
 |  | ||||||
|     def startTest(self, test): |  | ||||||
|         "Called when the given test is about to be run" |  | ||||||
|         self.testsRun = self.testsRun + 1 |  | ||||||
| 
 |  | ||||||
|     def startTestRun(self): |  | ||||||
|         """Called once before any tests are executed. |  | ||||||
| 
 |  | ||||||
|         See startTest for a method called before each test. |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|     def stopTest(self, test): |  | ||||||
|         "Called when the given test has been run" |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     def stopTestRun(self): |  | ||||||
|         """Called once after all tests are executed. |  | ||||||
| 
 |  | ||||||
|         See stopTest for a method called after each test. |  | ||||||
|         """ |  | ||||||
| 
 |  | ||||||
|     def addError(self, test, err): |  | ||||||
|         """Called when an error has occurred. 'err' is a tuple of values as |  | ||||||
|         returned by sys.exc_info(). |  | ||||||
|         """ |  | ||||||
|         self.errors.append((test, self._exc_info_to_string(err, test))) |  | ||||||
| 
 |  | ||||||
|     def addFailure(self, test, err): |  | ||||||
|         """Called when an error has occurred. 'err' is a tuple of values as |  | ||||||
|         returned by sys.exc_info().""" |  | ||||||
|         self.failures.append((test, self._exc_info_to_string(err, test))) |  | ||||||
| 
 |  | ||||||
|     def addSuccess(self, test): |  | ||||||
|         "Called when a test has completed successfully" |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     def addSkip(self, test, reason): |  | ||||||
|         """Called when a test is skipped.""" |  | ||||||
|         self.skipped.append((test, reason)) |  | ||||||
| 
 |  | ||||||
|     def addExpectedFailure(self, test, err): |  | ||||||
|         """Called when an expected failure/error occured.""" |  | ||||||
|         self.expectedFailures.append( |  | ||||||
|             (test, self._exc_info_to_string(err, test))) |  | ||||||
| 
 |  | ||||||
|     def addUnexpectedSuccess(self, test): |  | ||||||
|         """Called when a test was expected to fail, but succeed.""" |  | ||||||
|         self.unexpectedSuccesses.append(test) |  | ||||||
| 
 |  | ||||||
|     def wasSuccessful(self): |  | ||||||
|         "Tells whether or not this result was a success" |  | ||||||
|         return len(self.failures) == len(self.errors) == 0 |  | ||||||
| 
 |  | ||||||
|     def stop(self): |  | ||||||
|         "Indicates that the tests should be aborted" |  | ||||||
|         self.shouldStop = True |  | ||||||
| 
 |  | ||||||
|     def _exc_info_to_string(self, err, test): |  | ||||||
|         """Converts a sys.exc_info()-style tuple of values into a string.""" |  | ||||||
|         exctype, value, tb = err |  | ||||||
|         # Skip test runner traceback levels |  | ||||||
|         while tb and self._is_relevant_tb_level(tb): |  | ||||||
|             tb = tb.tb_next |  | ||||||
|         if exctype is test.failureException: |  | ||||||
|             # Skip assert*() traceback levels |  | ||||||
|             length = self._count_relevant_tb_levels(tb) |  | ||||||
|             return ''.join(traceback.format_exception(exctype, value, tb, length)) |  | ||||||
|         return ''.join(traceback.format_exception(exctype, value, tb)) |  | ||||||
| 
 |  | ||||||
|     def _is_relevant_tb_level(self, tb): |  | ||||||
|         return '__unittest' in tb.tb_frame.f_globals |  | ||||||
| 
 |  | ||||||
|     def _count_relevant_tb_levels(self, tb): |  | ||||||
|         length = 0 |  | ||||||
|         while tb and not self._is_relevant_tb_level(tb): |  | ||||||
|             length += 1 |  | ||||||
|             tb = tb.tb_next |  | ||||||
|         return length |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return "<%s run=%i errors=%i failures=%i>" % \ |  | ||||||
|                (_strclass(self.__class__), self.testsRun, len(self.errors), |  | ||||||
|                 len(self.failures)) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class _AssertRaisesContext(object): | class _AssertRaisesContext(object): | ||||||
|     """A context manager used to implement TestCase.assertRaises* methods.""" |     """A context manager used to implement TestCase.assertRaises* methods.""" | ||||||
|  | @ -409,7 +222,7 @@ def countTestCases(self): | ||||||
|         return 1 |         return 1 | ||||||
| 
 | 
 | ||||||
|     def defaultTestResult(self): |     def defaultTestResult(self): | ||||||
|         return TestResult() |         return result.TestResult() | ||||||
| 
 | 
 | ||||||
|     def shortDescription(self): |     def shortDescription(self): | ||||||
|         """Returns both the test method name and first line of its docstring. |         """Returns both the test method name and first line of its docstring. | ||||||
|  | @ -430,7 +243,7 @@ def shortDescription(self): | ||||||
|         return desc |         return desc | ||||||
| 
 | 
 | ||||||
|     def id(self): |     def id(self): | ||||||
|         return "%s.%s" % (_strclass(self.__class__), self._testMethodName) |         return "%s.%s" % (util.strclass(self.__class__), self._testMethodName) | ||||||
| 
 | 
 | ||||||
|     def __eq__(self, other): |     def __eq__(self, other): | ||||||
|         if type(self) is not type(other): |         if type(self) is not type(other): | ||||||
|  | @ -445,11 +258,11 @@ def __hash__(self): | ||||||
|         return hash((type(self), self._testMethodName)) |         return hash((type(self), self._testMethodName)) | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return "%s (%s)" % (self._testMethodName, _strclass(self.__class__)) |         return "%s (%s)" % (self._testMethodName, util.strclass(self.__class__)) | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "<%s testMethod=%s>" % \ |         return "<%s testMethod=%s>" % \ | ||||||
|                (_strclass(self.__class__), self._testMethodName) |                (util.strclass(self.__class__), self._testMethodName) | ||||||
| 
 | 
 | ||||||
|     def run(self, result=None): |     def run(self, result=None): | ||||||
|         orig_result = result |         orig_result = result | ||||||
|  | @ -935,7 +748,7 @@ def assertSameElements(self, expected_seq, actual_seq, msg=None): | ||||||
|             actual = list(actual_seq) |             actual = list(actual_seq) | ||||||
|             expected.sort() |             expected.sort() | ||||||
|             actual.sort() |             actual.sort() | ||||||
|             missing, unexpected = _SortedListDifference(expected, actual) |             missing, unexpected = util.sorted_list_difference(expected, actual) | ||||||
|         errors = [] |         errors = [] | ||||||
|         if missing: |         if missing: | ||||||
|             errors.append('Expected, but missing:\n    %r' % missing) |             errors.append('Expected, but missing:\n    %r' % missing) | ||||||
|  | @ -1019,114 +832,6 @@ def assertRegexpMatches(self, text, expected_regex, msg=None): | ||||||
|             raise self.failureException(msg) |             raise self.failureException(msg) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _SortedListDifference(expected, actual): |  | ||||||
|     """Finds elements in only one or the other of two, sorted input lists. |  | ||||||
| 
 |  | ||||||
|     Returns a two-element tuple of lists.    The first list contains those |  | ||||||
|     elements in the "expected" list but not in the "actual" list, and the |  | ||||||
|     second contains those elements in the "actual" list but not in the |  | ||||||
|     "expected" list.    Duplicate elements in either input list are ignored. |  | ||||||
|     """ |  | ||||||
|     i = j = 0 |  | ||||||
|     missing = [] |  | ||||||
|     unexpected = [] |  | ||||||
|     while True: |  | ||||||
|         try: |  | ||||||
|             e = expected[i] |  | ||||||
|             a = actual[j] |  | ||||||
|             if e < a: |  | ||||||
|                 missing.append(e) |  | ||||||
|                 i += 1 |  | ||||||
|                 while expected[i] == e: |  | ||||||
|                     i += 1 |  | ||||||
|             elif e > a: |  | ||||||
|                 unexpected.append(a) |  | ||||||
|                 j += 1 |  | ||||||
|                 while actual[j] == a: |  | ||||||
|                     j += 1 |  | ||||||
|             else: |  | ||||||
|                 i += 1 |  | ||||||
|                 try: |  | ||||||
|                     while expected[i] == e: |  | ||||||
|                         i += 1 |  | ||||||
|                 finally: |  | ||||||
|                     j += 1 |  | ||||||
|                     while actual[j] == a: |  | ||||||
|                         j += 1 |  | ||||||
|         except IndexError: |  | ||||||
|             missing.extend(expected[i:]) |  | ||||||
|             unexpected.extend(actual[j:]) |  | ||||||
|             break |  | ||||||
|     return missing, unexpected |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestSuite(object): |  | ||||||
|     """A test suite is a composite test consisting of a number of TestCases. |  | ||||||
| 
 |  | ||||||
|     For use, create an instance of TestSuite, then add test case instances. |  | ||||||
|     When all tests have been added, the suite can be passed to a test |  | ||||||
|     runner, such as TextTestRunner. It will run the individual test cases |  | ||||||
|     in the order in which they were added, aggregating the results. When |  | ||||||
|     subclassing, do not forget to call the base class constructor. |  | ||||||
|     """ |  | ||||||
|     def __init__(self, tests=()): |  | ||||||
|         self._tests = [] |  | ||||||
|         self.addTests(tests) |  | ||||||
| 
 |  | ||||||
|     def __repr__(self): |  | ||||||
|         return "<%s tests=%s>" % (_strclass(self.__class__), list(self)) |  | ||||||
| 
 |  | ||||||
|     def __eq__(self, other): |  | ||||||
|         if not isinstance(other, self.__class__): |  | ||||||
|             return NotImplemented |  | ||||||
|         return list(self) == list(other) |  | ||||||
| 
 |  | ||||||
|     def __ne__(self, other): |  | ||||||
|         return not self == other |  | ||||||
| 
 |  | ||||||
|     # Can't guarantee hash invariant, so flag as unhashable |  | ||||||
|     __hash__ = None |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         return iter(self._tests) |  | ||||||
| 
 |  | ||||||
|     def countTestCases(self): |  | ||||||
|         cases = 0 |  | ||||||
|         for test in self: |  | ||||||
|             cases += test.countTestCases() |  | ||||||
|         return cases |  | ||||||
| 
 |  | ||||||
|     def addTest(self, test): |  | ||||||
|         # sanity checks |  | ||||||
|         if not hasattr(test, '__call__'): |  | ||||||
|             raise TypeError("the test to add must be callable") |  | ||||||
|         if isinstance(test, type) and issubclass(test, (TestCase, TestSuite)): |  | ||||||
|             raise TypeError("TestCases and TestSuites must be instantiated " |  | ||||||
|                             "before passing them to addTest()") |  | ||||||
|         self._tests.append(test) |  | ||||||
| 
 |  | ||||||
|     def addTests(self, tests): |  | ||||||
|         if isinstance(tests, basestring): |  | ||||||
|             raise TypeError("tests must be an iterable of tests, not a string") |  | ||||||
|         for test in tests: |  | ||||||
|             self.addTest(test) |  | ||||||
| 
 |  | ||||||
|     def run(self, result): |  | ||||||
|         for test in self: |  | ||||||
|             if result.shouldStop: |  | ||||||
|                 break |  | ||||||
|             test(result) |  | ||||||
|         return result |  | ||||||
| 
 |  | ||||||
|     def __call__(self, *args, **kwds): |  | ||||||
|         return self.run(*args, **kwds) |  | ||||||
| 
 |  | ||||||
|     def debug(self): |  | ||||||
|         """Run the tests without collecting errors in a TestResult""" |  | ||||||
|         for test in self: |  | ||||||
|             test.debug() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class FunctionTestCase(TestCase): | class FunctionTestCase(TestCase): | ||||||
|     """A test case that wraps a test function. |     """A test case that wraps a test function. | ||||||
| 
 | 
 | ||||||
|  | @ -1174,586 +879,15 @@ def __hash__(self): | ||||||
|                      self._testFunc, self._description)) |                      self._testFunc, self._description)) | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return "%s (%s)" % (_strclass(self.__class__), self._testFunc.__name__) |         return "%s (%s)" % (util.strclass(self.__class__), | ||||||
|  |                             self._testFunc.__name__) | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "<%s testFunc=%s>" % (_strclass(self.__class__), self._testFunc) |         return "<%s testFunc=%s>" % (util.strclass(self.__class__), | ||||||
|  |                                      self._testFunc) | ||||||
| 
 | 
 | ||||||
|     def shortDescription(self): |     def shortDescription(self): | ||||||
|         if self._description is not None: |         if self._description is not None: | ||||||
|             return self._description |             return self._description | ||||||
|         doc = self._testFunc.__doc__ |         doc = self._testFunc.__doc__ | ||||||
|         return doc and doc.split("\n")[0].strip() or None |         return doc and doc.split("\n")[0].strip() or None | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Locating and loading tests |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| class TestLoader(object): |  | ||||||
|     """ |  | ||||||
|     This class is responsible for loading tests according to various criteria |  | ||||||
|     and returning them wrapped in a TestSuite |  | ||||||
|     """ |  | ||||||
|     testMethodPrefix = 'test' |  | ||||||
|     sortTestMethodsUsing = cmp |  | ||||||
|     suiteClass = TestSuite |  | ||||||
|     _top_level_dir = None |  | ||||||
| 
 |  | ||||||
|     def loadTestsFromTestCase(self, testCaseClass): |  | ||||||
|         """Return a suite of all tests cases contained in testCaseClass""" |  | ||||||
|         if issubclass(testCaseClass, TestSuite): |  | ||||||
|             raise TypeError("Test cases should not be derived from TestSuite." \ |  | ||||||
|                                 " Maybe you meant to derive from TestCase?") |  | ||||||
|         testCaseNames = self.getTestCaseNames(testCaseClass) |  | ||||||
|         if not testCaseNames and hasattr(testCaseClass, 'runTest'): |  | ||||||
|             testCaseNames = ['runTest'] |  | ||||||
|         suite = self.suiteClass(map(testCaseClass, testCaseNames)) |  | ||||||
|         return suite |  | ||||||
| 
 |  | ||||||
|     def loadTestsFromModule(self, module, use_load_tests=True): |  | ||||||
|         """Return a suite of all tests cases contained in the given module""" |  | ||||||
|         tests = [] |  | ||||||
|         for name in dir(module): |  | ||||||
|             obj = getattr(module, name) |  | ||||||
|             if isinstance(obj, type) and issubclass(obj, TestCase): |  | ||||||
|                 tests.append(self.loadTestsFromTestCase(obj)) |  | ||||||
| 
 |  | ||||||
|         load_tests = getattr(module, 'load_tests', None) |  | ||||||
|         if use_load_tests and load_tests is not None: |  | ||||||
|             return load_tests(self, tests, None) |  | ||||||
|         return self.suiteClass(tests) |  | ||||||
| 
 |  | ||||||
|     def loadTestsFromName(self, name, module=None): |  | ||||||
|         """Return a suite of all tests cases given a string specifier. |  | ||||||
| 
 |  | ||||||
|         The name may resolve either to a module, a test case class, a |  | ||||||
|         test method within a test case class, or a callable object which |  | ||||||
|         returns a TestCase or TestSuite instance. |  | ||||||
| 
 |  | ||||||
|         The method optionally resolves the names relative to a given module. |  | ||||||
|         """ |  | ||||||
|         parts = name.split('.') |  | ||||||
|         if module is None: |  | ||||||
|             parts_copy = parts[:] |  | ||||||
|             while parts_copy: |  | ||||||
|                 try: |  | ||||||
|                     module = __import__('.'.join(parts_copy)) |  | ||||||
|                     break |  | ||||||
|                 except ImportError: |  | ||||||
|                     del parts_copy[-1] |  | ||||||
|                     if not parts_copy: |  | ||||||
|                         raise |  | ||||||
|             parts = parts[1:] |  | ||||||
|         obj = module |  | ||||||
|         for part in parts: |  | ||||||
|             parent, obj = obj, getattr(obj, part) |  | ||||||
| 
 |  | ||||||
|         if isinstance(obj, types.ModuleType): |  | ||||||
|             return self.loadTestsFromModule(obj) |  | ||||||
|         elif isinstance(obj, type) and issubclass(obj, TestCase): |  | ||||||
|             return self.loadTestsFromTestCase(obj) |  | ||||||
|         elif (isinstance(obj, types.UnboundMethodType) and |  | ||||||
|               isinstance(parent, type) and |  | ||||||
|               issubclass(parent, TestCase)): |  | ||||||
|             return TestSuite([parent(obj.__name__)]) |  | ||||||
|         elif isinstance(obj, TestSuite): |  | ||||||
|             return obj |  | ||||||
|         elif hasattr(obj, '__call__'): |  | ||||||
|             test = obj() |  | ||||||
|             if isinstance(test, TestSuite): |  | ||||||
|                 return test |  | ||||||
|             elif isinstance(test, TestCase): |  | ||||||
|                 return TestSuite([test]) |  | ||||||
|             else: |  | ||||||
|                 raise TypeError("calling %s returned %s, not a test" % |  | ||||||
|                                 (obj, test)) |  | ||||||
|         else: |  | ||||||
|             raise TypeError("don't know how to make test from: %s" % obj) |  | ||||||
| 
 |  | ||||||
|     def loadTestsFromNames(self, names, module=None): |  | ||||||
|         """Return a suite of all tests cases found using the given sequence |  | ||||||
|         of string specifiers. See 'loadTestsFromName()'. |  | ||||||
|         """ |  | ||||||
|         suites = [self.loadTestsFromName(name, module) for name in names] |  | ||||||
|         return self.suiteClass(suites) |  | ||||||
| 
 |  | ||||||
|     def getTestCaseNames(self, testCaseClass): |  | ||||||
|         """Return a sorted sequence of method names found within testCaseClass |  | ||||||
|         """ |  | ||||||
|         def isTestMethod(attrname, testCaseClass=testCaseClass, |  | ||||||
|                          prefix=self.testMethodPrefix): |  | ||||||
|             return attrname.startswith(prefix) and \ |  | ||||||
|                 hasattr(getattr(testCaseClass, attrname), '__call__') |  | ||||||
|         testFnNames = filter(isTestMethod, dir(testCaseClass)) |  | ||||||
|         if self.sortTestMethodsUsing: |  | ||||||
|             testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing)) |  | ||||||
|         return testFnNames |  | ||||||
| 
 |  | ||||||
|     def discover(self, start_dir, pattern='test*.py', top_level_dir=None): |  | ||||||
|         """Find and return all test modules from the specified start |  | ||||||
|         directory, recursing into subdirectories to find them. Only test files |  | ||||||
|         that match the pattern will be loaded. (Using shell style pattern |  | ||||||
|         matching.) |  | ||||||
| 
 |  | ||||||
|         All test modules must be importable from the top level of the project. |  | ||||||
|         If the start directory is not the top level directory then the top |  | ||||||
|         level directory must be specified separately. |  | ||||||
| 
 |  | ||||||
|         If a test package name (directory with '__init__.py') matches the |  | ||||||
|         pattern then the package will be checked for a 'load_tests' function. If |  | ||||||
|         this exists then it will be called with loader, tests, pattern. |  | ||||||
| 
 |  | ||||||
|         If load_tests exists then discovery does  *not* recurse into the package, |  | ||||||
|         load_tests is responsible for loading all tests in the package. |  | ||||||
| 
 |  | ||||||
|         The pattern is deliberately not stored as a loader attribute so that |  | ||||||
|         packages can continue discovery themselves. top_level_dir is stored so |  | ||||||
|         load_tests does not need to pass this argument in to loader.discover(). |  | ||||||
|         """ |  | ||||||
|         if top_level_dir is None and self._top_level_dir is not None: |  | ||||||
|             # make top_level_dir optional if called from load_tests in a package |  | ||||||
|             top_level_dir = self._top_level_dir |  | ||||||
|         elif top_level_dir is None: |  | ||||||
|             top_level_dir = start_dir |  | ||||||
| 
 |  | ||||||
|         top_level_dir = os.path.abspath(os.path.normpath(top_level_dir)) |  | ||||||
|         start_dir = os.path.abspath(os.path.normpath(start_dir)) |  | ||||||
| 
 |  | ||||||
|         if not top_level_dir in sys.path: |  | ||||||
|             # all test modules must be importable from the top level directory |  | ||||||
|             sys.path.append(top_level_dir) |  | ||||||
|         self._top_level_dir = top_level_dir |  | ||||||
| 
 |  | ||||||
|         if start_dir != top_level_dir and not os.path.isfile(os.path.join(start_dir, '__init__.py')): |  | ||||||
|             # what about __init__.pyc or pyo (etc) |  | ||||||
|             raise ImportError('Start directory is not importable: %r' % start_dir) |  | ||||||
| 
 |  | ||||||
|         tests = list(self._find_tests(start_dir, pattern)) |  | ||||||
|         return self.suiteClass(tests) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     def _get_module_from_path(self, path): |  | ||||||
|         """Load a module from a path relative to the top-level directory |  | ||||||
|         of a project. Used by discovery.""" |  | ||||||
|         path = os.path.splitext(os.path.normpath(path))[0] |  | ||||||
| 
 |  | ||||||
|         relpath = os.path.relpath(path, self._top_level_dir) |  | ||||||
|         assert not os.path.isabs(relpath), "Path must be within the project" |  | ||||||
|         assert not relpath.startswith('..'), "Path must be within the project" |  | ||||||
| 
 |  | ||||||
|         name = relpath.replace(os.path.sep, '.') |  | ||||||
|         __import__(name) |  | ||||||
|         return sys.modules[name] |  | ||||||
| 
 |  | ||||||
|     def _find_tests(self, start_dir, pattern): |  | ||||||
|         """Used by discovery. Yields test suites it loads.""" |  | ||||||
|         paths = os.listdir(start_dir) |  | ||||||
| 
 |  | ||||||
|         for path in paths: |  | ||||||
|             full_path = os.path.join(start_dir, path) |  | ||||||
|             # what about __init__.pyc or pyo (etc) |  | ||||||
|             # we would need to avoid loading the same tests multiple times |  | ||||||
|             # from '.py', '.pyc' *and* '.pyo' |  | ||||||
|             if os.path.isfile(full_path) and path.lower().endswith('.py'): |  | ||||||
|                 if fnmatch(path, pattern): |  | ||||||
|                     # if the test file matches, load it |  | ||||||
|                     module = self._get_module_from_path(full_path) |  | ||||||
|                     yield self.loadTestsFromModule(module) |  | ||||||
|             elif os.path.isdir(full_path): |  | ||||||
|                 if not os.path.isfile(os.path.join(full_path, '__init__.py')): |  | ||||||
|                     continue |  | ||||||
| 
 |  | ||||||
|                 load_tests = None |  | ||||||
|                 tests = None |  | ||||||
|                 if fnmatch(path, pattern): |  | ||||||
|                     # only check load_tests if the package directory itself matches the filter |  | ||||||
|                     package = self._get_module_from_path(full_path) |  | ||||||
|                     load_tests = getattr(package, 'load_tests', None) |  | ||||||
|                     tests = self.loadTestsFromModule(package, use_load_tests=False) |  | ||||||
| 
 |  | ||||||
|                 if load_tests is None: |  | ||||||
|                     if tests is not None: |  | ||||||
|                         # tests loaded from package file |  | ||||||
|                         yield tests |  | ||||||
|                     # recurse into the package |  | ||||||
|                     for test in self._find_tests(full_path, pattern): |  | ||||||
|                         yield test |  | ||||||
|                 else: |  | ||||||
|                     yield load_tests(self, tests, pattern) |  | ||||||
| 
 |  | ||||||
| defaultTestLoader = TestLoader() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Patches for old functions: these functions should be considered obsolete |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| def _makeLoader(prefix, sortUsing, suiteClass=None): |  | ||||||
|     loader = TestLoader() |  | ||||||
|     loader.sortTestMethodsUsing = sortUsing |  | ||||||
|     loader.testMethodPrefix = prefix |  | ||||||
|     if suiteClass: loader.suiteClass = suiteClass |  | ||||||
|     return loader |  | ||||||
| 
 |  | ||||||
| def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): |  | ||||||
|     return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) |  | ||||||
| 
 |  | ||||||
| def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite): |  | ||||||
|     return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) |  | ||||||
| 
 |  | ||||||
| def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite): |  | ||||||
|     return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Text UI |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| class _WritelnDecorator(object): |  | ||||||
|     """Used to decorate file-like objects with a handy 'writeln' method""" |  | ||||||
|     def __init__(self,stream): |  | ||||||
|         self.stream = stream |  | ||||||
| 
 |  | ||||||
|     def __getattr__(self, attr): |  | ||||||
|         return getattr(self.stream,attr) |  | ||||||
| 
 |  | ||||||
|     def writeln(self, arg=None): |  | ||||||
|         if arg: |  | ||||||
|             self.write(arg) |  | ||||||
|         self.write('\n') # text-mode streams translate to \r\n if needed |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class _TextTestResult(TestResult): |  | ||||||
|     """A test result class that can print formatted text results to a stream. |  | ||||||
| 
 |  | ||||||
|     Used by TextTestRunner. |  | ||||||
|     """ |  | ||||||
|     separator1 = '=' * 70 |  | ||||||
|     separator2 = '-' * 70 |  | ||||||
| 
 |  | ||||||
|     def __init__(self, stream, descriptions, verbosity): |  | ||||||
|         super(_TextTestResult, self).__init__() |  | ||||||
|         self.stream = stream |  | ||||||
|         self.showAll = verbosity > 1 |  | ||||||
|         self.dots = verbosity == 1 |  | ||||||
|         self.descriptions = descriptions |  | ||||||
| 
 |  | ||||||
|     def getDescription(self, test): |  | ||||||
|         if self.descriptions: |  | ||||||
|             return test.shortDescription() or str(test) |  | ||||||
|         else: |  | ||||||
|             return str(test) |  | ||||||
| 
 |  | ||||||
|     def startTest(self, test): |  | ||||||
|         super(_TextTestResult, self).startTest(test) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.write(self.getDescription(test)) |  | ||||||
|             self.stream.write(" ... ") |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def addSuccess(self, test): |  | ||||||
|         super(_TextTestResult, self).addSuccess(test) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.writeln("ok") |  | ||||||
|         elif self.dots: |  | ||||||
|             self.stream.write('.') |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def addError(self, test, err): |  | ||||||
|         super(_TextTestResult, self).addError(test, err) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.writeln("ERROR") |  | ||||||
|         elif self.dots: |  | ||||||
|             self.stream.write('E') |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def addFailure(self, test, err): |  | ||||||
|         super(_TextTestResult, self).addFailure(test, err) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.writeln("FAIL") |  | ||||||
|         elif self.dots: |  | ||||||
|             self.stream.write('F') |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def addSkip(self, test, reason): |  | ||||||
|         super(_TextTestResult, self).addSkip(test, reason) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.writeln("skipped {0!r}".format(reason)) |  | ||||||
|         elif self.dots: |  | ||||||
|             self.stream.write("s") |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def addExpectedFailure(self, test, err): |  | ||||||
|         super(_TextTestResult, self).addExpectedFailure(test, err) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.writeln("expected failure") |  | ||||||
|         elif self.dots: |  | ||||||
|             self.stream.write("x") |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def addUnexpectedSuccess(self, test): |  | ||||||
|         super(_TextTestResult, self).addUnexpectedSuccess(test) |  | ||||||
|         if self.showAll: |  | ||||||
|             self.stream.writeln("unexpected success") |  | ||||||
|         elif self.dots: |  | ||||||
|             self.stream.write("u") |  | ||||||
|             self.stream.flush() |  | ||||||
| 
 |  | ||||||
|     def printErrors(self): |  | ||||||
|         if self.dots or self.showAll: |  | ||||||
|             self.stream.writeln() |  | ||||||
|         self.printErrorList('ERROR', self.errors) |  | ||||||
|         self.printErrorList('FAIL', self.failures) |  | ||||||
| 
 |  | ||||||
|     def printErrorList(self, flavour, errors): |  | ||||||
|         for test, err in errors: |  | ||||||
|             self.stream.writeln(self.separator1) |  | ||||||
|             self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) |  | ||||||
|             self.stream.writeln(self.separator2) |  | ||||||
|             self.stream.writeln("%s" % err) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TextTestRunner(object): |  | ||||||
|     """A test runner class that displays results in textual form. |  | ||||||
| 
 |  | ||||||
|     It prints out the names of tests as they are run, errors as they |  | ||||||
|     occur, and a summary of the results at the end of the test run. |  | ||||||
|     """ |  | ||||||
|     def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): |  | ||||||
|         self.stream = _WritelnDecorator(stream) |  | ||||||
|         self.descriptions = descriptions |  | ||||||
|         self.verbosity = verbosity |  | ||||||
| 
 |  | ||||||
|     def _makeResult(self): |  | ||||||
|         return _TextTestResult(self.stream, self.descriptions, self.verbosity) |  | ||||||
| 
 |  | ||||||
|     def run(self, test): |  | ||||||
|         "Run the given test case or test suite." |  | ||||||
|         result = self._makeResult() |  | ||||||
|         startTime = time.time() |  | ||||||
|         startTestRun = getattr(result, 'startTestRun', None) |  | ||||||
|         if startTestRun is not None: |  | ||||||
|             startTestRun() |  | ||||||
|         try: |  | ||||||
|             test(result) |  | ||||||
|         finally: |  | ||||||
|             stopTestRun = getattr(result, 'stopTestRun', None) |  | ||||||
|             if stopTestRun is not None: |  | ||||||
|                 stopTestRun() |  | ||||||
|         stopTime = time.time() |  | ||||||
|         timeTaken = stopTime - startTime |  | ||||||
|         result.printErrors() |  | ||||||
|         self.stream.writeln(result.separator2) |  | ||||||
|         run = result.testsRun |  | ||||||
|         self.stream.writeln("Ran %d test%s in %.3fs" % |  | ||||||
|                             (run, run != 1 and "s" or "", timeTaken)) |  | ||||||
|         self.stream.writeln() |  | ||||||
|         results = map(len, (result.expectedFailures, |  | ||||||
|                             result.unexpectedSuccesses, |  | ||||||
|                             result.skipped)) |  | ||||||
|         expectedFails, unexpectedSuccesses, skipped = results |  | ||||||
|         infos = [] |  | ||||||
|         if not result.wasSuccessful(): |  | ||||||
|             self.stream.write("FAILED") |  | ||||||
|             failed, errored = map(len, (result.failures, result.errors)) |  | ||||||
|             if failed: |  | ||||||
|                 infos.append("failures=%d" % failed) |  | ||||||
|             if errored: |  | ||||||
|                 infos.append("errors=%d" % errored) |  | ||||||
|         else: |  | ||||||
|             self.stream.write("OK") |  | ||||||
|         if skipped: |  | ||||||
|             infos.append("skipped=%d" % skipped) |  | ||||||
|         if expectedFails: |  | ||||||
|             infos.append("expected failures=%d" % expectedFails) |  | ||||||
|         if unexpectedSuccesses: |  | ||||||
|             infos.append("unexpected successes=%d" % unexpectedSuccesses) |  | ||||||
|         if infos: |  | ||||||
|             self.stream.writeln(" (%s)" % (", ".join(infos),)) |  | ||||||
|         else: |  | ||||||
|             self.stream.write("\n") |  | ||||||
|         return result |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Facilities for running tests from the command line |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| USAGE_AS_MAIN = """\ |  | ||||||
| Usage: %(progName)s [options] [tests] |  | ||||||
| 
 |  | ||||||
| Options: |  | ||||||
|   -h, --help       Show this message |  | ||||||
|   -v, --verbose    Verbose output |  | ||||||
|   -q, --quiet      Minimal output |  | ||||||
| 
 |  | ||||||
| Examples: |  | ||||||
|   %(progName)s test_module                       - run tests from test_module |  | ||||||
|   %(progName)s test_module.TestClass             - run tests from |  | ||||||
|                                                    test_module.TestClass |  | ||||||
|   %(progName)s test_module.TestClass.test_method - run specified test method |  | ||||||
| 
 |  | ||||||
| [tests] can be a list of any number of test modules, classes and test |  | ||||||
| methods. |  | ||||||
| 
 |  | ||||||
| Alternative Usage: %(progName)s discover [options] |  | ||||||
| 
 |  | ||||||
| Options: |  | ||||||
|   -v, --verbose    Verbose output |  | ||||||
|   -s directory     Directory to start discovery ('.' default) |  | ||||||
|   -p pattern       Pattern to match test files ('test*.py' default) |  | ||||||
|   -t directory     Top level directory of project (default to |  | ||||||
|                    start directory) |  | ||||||
| 
 |  | ||||||
| For test discovery all test modules must be importable from the top |  | ||||||
| level directory of the project. |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| USAGE_FROM_MODULE = """\ |  | ||||||
| Usage: %(progName)s [options] [test] [...] |  | ||||||
| 
 |  | ||||||
| Options: |  | ||||||
|   -h, --help       Show this message |  | ||||||
|   -v, --verbose    Verbose output |  | ||||||
|   -q, --quiet      Minimal output |  | ||||||
| 
 |  | ||||||
| Examples: |  | ||||||
|   %(progName)s                               - run default set of tests |  | ||||||
|   %(progName)s MyTestSuite                   - run suite 'MyTestSuite' |  | ||||||
|   %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething |  | ||||||
|   %(progName)s MyTestCase                    - run all 'test*' test methods |  | ||||||
|                                                in MyTestCase |  | ||||||
| """ |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     USAGE = USAGE_AS_MAIN |  | ||||||
| else: |  | ||||||
|     USAGE = USAGE_FROM_MODULE |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class TestProgram(object): |  | ||||||
|     """A command-line program that runs a set of tests; this is primarily |  | ||||||
|        for making test modules conveniently executable. |  | ||||||
|     """ |  | ||||||
|     USAGE = USAGE |  | ||||||
|     def __init__(self, module='__main__', defaultTest=None, |  | ||||||
|                  argv=None, testRunner=None, |  | ||||||
|                  testLoader=defaultTestLoader, exit=True, |  | ||||||
|                  verbosity=1): |  | ||||||
|         if isinstance(module, basestring): |  | ||||||
|             self.module = __import__(module) |  | ||||||
|             for part in module.split('.')[1:]: |  | ||||||
|                 self.module = getattr(self.module, part) |  | ||||||
|         else: |  | ||||||
|             self.module = module |  | ||||||
|         if argv is None: |  | ||||||
|             argv = sys.argv |  | ||||||
| 
 |  | ||||||
|         self.exit = exit |  | ||||||
|         self.verbosity = verbosity |  | ||||||
|         self.defaultTest = defaultTest |  | ||||||
|         self.testRunner = testRunner |  | ||||||
|         self.testLoader = testLoader |  | ||||||
|         self.progName = os.path.basename(argv[0]) |  | ||||||
|         self.parseArgs(argv) |  | ||||||
|         self.runTests() |  | ||||||
| 
 |  | ||||||
|     def usageExit(self, msg=None): |  | ||||||
|         if msg: |  | ||||||
|             print msg |  | ||||||
|         print self.USAGE % self.__dict__ |  | ||||||
|         sys.exit(2) |  | ||||||
| 
 |  | ||||||
|     def parseArgs(self, argv): |  | ||||||
|         if len(argv) > 1 and argv[1].lower() == 'discover': |  | ||||||
|             self._do_discovery(argv[2:]) |  | ||||||
|             return |  | ||||||
| 
 |  | ||||||
|         import getopt |  | ||||||
|         long_opts = ['help','verbose','quiet'] |  | ||||||
|         try: |  | ||||||
|             options, args = getopt.getopt(argv[1:], 'hHvq', long_opts) |  | ||||||
|             for opt, value in options: |  | ||||||
|                 if opt in ('-h','-H','--help'): |  | ||||||
|                     self.usageExit() |  | ||||||
|                 if opt in ('-q','--quiet'): |  | ||||||
|                     self.verbosity = 0 |  | ||||||
|                 if opt in ('-v','--verbose'): |  | ||||||
|                     self.verbosity = 2 |  | ||||||
|             if len(args) == 0 and self.defaultTest is None: |  | ||||||
|                 self.test = self.testLoader.loadTestsFromModule(self.module) |  | ||||||
|                 return |  | ||||||
|             if len(args) > 0: |  | ||||||
|                 self.testNames = args |  | ||||||
|                 if __name__ == '__main__': |  | ||||||
|                     # to support python -m unittest ... |  | ||||||
|                     self.module = None |  | ||||||
|             else: |  | ||||||
|                 self.testNames = (self.defaultTest,) |  | ||||||
|             self.createTests() |  | ||||||
|         except getopt.error, msg: |  | ||||||
|             self.usageExit(msg) |  | ||||||
| 
 |  | ||||||
|     def createTests(self): |  | ||||||
|         self.test = self.testLoader.loadTestsFromNames(self.testNames, |  | ||||||
|                                                        self.module) |  | ||||||
| 
 |  | ||||||
|     def _do_discovery(self, argv, Loader=TestLoader): |  | ||||||
|         # handle command line args for test discovery |  | ||||||
|         import optparse |  | ||||||
|         parser = optparse.OptionParser() |  | ||||||
|         parser.add_option('-v', '--verbose', dest='verbose', default=False, |  | ||||||
|                           help='Verbose output', action='store_true') |  | ||||||
|         parser.add_option('-s', '--start-directory', dest='start', default='.', |  | ||||||
|                           help="Directory to start discovery ('.' default)") |  | ||||||
|         parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', |  | ||||||
|                           help="Pattern to match tests ('test*.py' default)") |  | ||||||
|         parser.add_option('-t', '--top-level-directory', dest='top', default=None, |  | ||||||
|                           help='Top level directory of project (defaults to start directory)') |  | ||||||
| 
 |  | ||||||
|         options, args = parser.parse_args(argv) |  | ||||||
|         if len(args) > 3: |  | ||||||
|             self.usageExit() |  | ||||||
| 
 |  | ||||||
|         for name, value in zip(('start', 'pattern', 'top'), args): |  | ||||||
|             setattr(options, name, value) |  | ||||||
| 
 |  | ||||||
|         if options.verbose: |  | ||||||
|             self.verbosity = 2 |  | ||||||
| 
 |  | ||||||
|         start_dir = options.start |  | ||||||
|         pattern = options.pattern |  | ||||||
|         top_level_dir = options.top |  | ||||||
| 
 |  | ||||||
|         loader = Loader() |  | ||||||
|         self.test = loader.discover(start_dir, pattern, top_level_dir) |  | ||||||
| 
 |  | ||||||
|     def runTests(self): |  | ||||||
|         if self.testRunner is None: |  | ||||||
|             self.testRunner = TextTestRunner |  | ||||||
|         if isinstance(self.testRunner, (type, types.ClassType)): |  | ||||||
|             try: |  | ||||||
|                 testRunner = self.testRunner(verbosity=self.verbosity) |  | ||||||
|             except TypeError: |  | ||||||
|                 # didn't accept the verbosity argument |  | ||||||
|                 testRunner = self.testRunner() |  | ||||||
|         else: |  | ||||||
|             # it is assumed to be a TestRunner instance |  | ||||||
|             testRunner = self.testRunner |  | ||||||
|         self.result = testRunner.run(self.test) |  | ||||||
|         if self.exit: |  | ||||||
|             sys.exit(not self.result.wasSuccessful()) |  | ||||||
| 
 |  | ||||||
| main = TestProgram |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ############################################################################## |  | ||||||
| # Executing this module from the command line |  | ||||||
| ############################################################################## |  | ||||||
| 
 |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     sys.modules['unittest'] = sys.modules['__main__'] |  | ||||||
|     main(module=None) |  | ||||||
							
								
								
									
										234
									
								
								Lib/unittest/loader.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								Lib/unittest/loader.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,234 @@ | ||||||
|  | """Loading unittests.""" | ||||||
|  | 
 | ||||||
|  | import os | ||||||
|  | import sys | ||||||
|  | import types | ||||||
|  | 
 | ||||||
|  | from fnmatch import fnmatch | ||||||
|  | 
 | ||||||
|  | from . import case, suite | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def _CmpToKey(mycmp): | ||||||
|  |     'Convert a cmp= function into a key= function' | ||||||
|  |     class K(object): | ||||||
|  |         def __init__(self, obj): | ||||||
|  |             self.obj = obj | ||||||
|  |         def __lt__(self, other): | ||||||
|  |             return mycmp(self.obj, other.obj) == -1 | ||||||
|  |     return K | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestLoader(object): | ||||||
|  |     """ | ||||||
|  |     This class is responsible for loading tests according to various criteria | ||||||
|  |     and returning them wrapped in a TestSuite | ||||||
|  |     """ | ||||||
|  |     testMethodPrefix = 'test' | ||||||
|  |     sortTestMethodsUsing = cmp | ||||||
|  |     suiteClass = suite.TestSuite | ||||||
|  |     _top_level_dir = None | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromTestCase(self, testCaseClass): | ||||||
|  |         """Return a suite of all tests cases contained in testCaseClass""" | ||||||
|  |         if issubclass(testCaseClass, suite.TestSuite): | ||||||
|  |             raise TypeError("Test cases should not be derived from TestSuite." \ | ||||||
|  |                                 " Maybe you meant to derive from TestCase?") | ||||||
|  |         testCaseNames = self.getTestCaseNames(testCaseClass) | ||||||
|  |         if not testCaseNames and hasattr(testCaseClass, 'runTest'): | ||||||
|  |             testCaseNames = ['runTest'] | ||||||
|  |         loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) | ||||||
|  |         return loaded_suite | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromModule(self, module, use_load_tests=True): | ||||||
|  |         """Return a suite of all tests cases contained in the given module""" | ||||||
|  |         tests = [] | ||||||
|  |         for name in dir(module): | ||||||
|  |             obj = getattr(module, name) | ||||||
|  |             if isinstance(obj, type) and issubclass(obj, case.TestCase): | ||||||
|  |                 tests.append(self.loadTestsFromTestCase(obj)) | ||||||
|  | 
 | ||||||
|  |         load_tests = getattr(module, 'load_tests', None) | ||||||
|  |         if use_load_tests and load_tests is not None: | ||||||
|  |             return load_tests(self, tests, None) | ||||||
|  |         return self.suiteClass(tests) | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromName(self, name, module=None): | ||||||
|  |         """Return a suite of all tests cases given a string specifier. | ||||||
|  | 
 | ||||||
|  |         The name may resolve either to a module, a test case class, a | ||||||
|  |         test method within a test case class, or a callable object which | ||||||
|  |         returns a TestCase or TestSuite instance. | ||||||
|  | 
 | ||||||
|  |         The method optionally resolves the names relative to a given module. | ||||||
|  |         """ | ||||||
|  |         parts = name.split('.') | ||||||
|  |         if module is None: | ||||||
|  |             parts_copy = parts[:] | ||||||
|  |             while parts_copy: | ||||||
|  |                 try: | ||||||
|  |                     module = __import__('.'.join(parts_copy)) | ||||||
|  |                     break | ||||||
|  |                 except ImportError: | ||||||
|  |                     del parts_copy[-1] | ||||||
|  |                     if not parts_copy: | ||||||
|  |                         raise | ||||||
|  |             parts = parts[1:] | ||||||
|  |         obj = module | ||||||
|  |         for part in parts: | ||||||
|  |             parent, obj = obj, getattr(obj, part) | ||||||
|  | 
 | ||||||
|  |         if isinstance(obj, types.ModuleType): | ||||||
|  |             return self.loadTestsFromModule(obj) | ||||||
|  |         elif isinstance(obj, type) and issubclass(obj, case.TestCase): | ||||||
|  |             return self.loadTestsFromTestCase(obj) | ||||||
|  |         elif (isinstance(obj, types.UnboundMethodType) and | ||||||
|  |               isinstance(parent, type) and | ||||||
|  |               issubclass(parent, case.TestCase)): | ||||||
|  |             return suite.TestSuite([parent(obj.__name__)]) | ||||||
|  |         elif isinstance(obj, suite.TestSuite): | ||||||
|  |             return obj | ||||||
|  |         elif hasattr(obj, '__call__'): | ||||||
|  |             test = obj() | ||||||
|  |             if isinstance(test, suite.TestSuite): | ||||||
|  |                 return test | ||||||
|  |             elif isinstance(test, case.TestCase): | ||||||
|  |                 return suite.TestSuite([test]) | ||||||
|  |             else: | ||||||
|  |                 raise TypeError("calling %s returned %s, not a test" % | ||||||
|  |                                 (obj, test)) | ||||||
|  |         else: | ||||||
|  |             raise TypeError("don't know how to make test from: %s" % obj) | ||||||
|  | 
 | ||||||
|  |     def loadTestsFromNames(self, names, module=None): | ||||||
|  |         """Return a suite of all tests cases found using the given sequence | ||||||
|  |         of string specifiers. See 'loadTestsFromName()'. | ||||||
|  |         """ | ||||||
|  |         suites = [self.loadTestsFromName(name, module) for name in names] | ||||||
|  |         return self.suiteClass(suites) | ||||||
|  | 
 | ||||||
|  |     def getTestCaseNames(self, testCaseClass): | ||||||
|  |         """Return a sorted sequence of method names found within testCaseClass | ||||||
|  |         """ | ||||||
|  |         def isTestMethod(attrname, testCaseClass=testCaseClass, | ||||||
|  |                          prefix=self.testMethodPrefix): | ||||||
|  |             return attrname.startswith(prefix) and \ | ||||||
|  |                 hasattr(getattr(testCaseClass, attrname), '__call__') | ||||||
|  |         testFnNames = filter(isTestMethod, dir(testCaseClass)) | ||||||
|  |         if self.sortTestMethodsUsing: | ||||||
|  |             testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing)) | ||||||
|  |         return testFnNames | ||||||
|  | 
 | ||||||
|  |     def discover(self, start_dir, pattern='test*.py', top_level_dir=None): | ||||||
|  |         """Find and return all test modules from the specified start | ||||||
|  |         directory, recursing into subdirectories to find them. Only test files | ||||||
|  |         that match the pattern will be loaded. (Using shell style pattern | ||||||
|  |         matching.) | ||||||
|  | 
 | ||||||
|  |         All test modules must be importable from the top level of the project. | ||||||
|  |         If the start directory is not the top level directory then the top | ||||||
|  |         level directory must be specified separately. | ||||||
|  | 
 | ||||||
|  |         If a test package name (directory with '__init__.py') matches the | ||||||
|  |         pattern then the package will be checked for a 'load_tests' function. If | ||||||
|  |         this exists then it will be called with loader, tests, pattern. | ||||||
|  | 
 | ||||||
|  |         If load_tests exists then discovery does  *not* recurse into the package, | ||||||
|  |         load_tests is responsible for loading all tests in the package. | ||||||
|  | 
 | ||||||
|  |         The pattern is deliberately not stored as a loader attribute so that | ||||||
|  |         packages can continue discovery themselves. top_level_dir is stored so | ||||||
|  |         load_tests does not need to pass this argument in to loader.discover(). | ||||||
|  |         """ | ||||||
|  |         if top_level_dir is None and self._top_level_dir is not None: | ||||||
|  |             # make top_level_dir optional if called from load_tests in a package | ||||||
|  |             top_level_dir = self._top_level_dir | ||||||
|  |         elif top_level_dir is None: | ||||||
|  |             top_level_dir = start_dir | ||||||
|  | 
 | ||||||
|  |         top_level_dir = os.path.abspath(os.path.normpath(top_level_dir)) | ||||||
|  |         start_dir = os.path.abspath(os.path.normpath(start_dir)) | ||||||
|  | 
 | ||||||
|  |         if not top_level_dir in sys.path: | ||||||
|  |             # all test modules must be importable from the top level directory | ||||||
|  |             sys.path.append(top_level_dir) | ||||||
|  |         self._top_level_dir = top_level_dir | ||||||
|  | 
 | ||||||
|  |         if start_dir != top_level_dir and not os.path.isfile(os.path.join(start_dir, '__init__.py')): | ||||||
|  |             # what about __init__.pyc or pyo (etc) | ||||||
|  |             raise ImportError('Start directory is not importable: %r' % start_dir) | ||||||
|  | 
 | ||||||
|  |         tests = list(self._find_tests(start_dir, pattern)) | ||||||
|  |         return self.suiteClass(tests) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def _get_module_from_path(self, path): | ||||||
|  |         """Load a module from a path relative to the top-level directory | ||||||
|  |         of a project. Used by discovery.""" | ||||||
|  |         path = os.path.splitext(os.path.normpath(path))[0] | ||||||
|  | 
 | ||||||
|  |         relpath = os.path.relpath(path, self._top_level_dir) | ||||||
|  |         assert not os.path.isabs(relpath), "Path must be within the project" | ||||||
|  |         assert not relpath.startswith('..'), "Path must be within the project" | ||||||
|  | 
 | ||||||
|  |         name = relpath.replace(os.path.sep, '.') | ||||||
|  |         __import__(name) | ||||||
|  |         return sys.modules[name] | ||||||
|  | 
 | ||||||
|  |     def _find_tests(self, start_dir, pattern): | ||||||
|  |         """Used by discovery. Yields test suites it loads.""" | ||||||
|  |         paths = os.listdir(start_dir) | ||||||
|  | 
 | ||||||
|  |         for path in paths: | ||||||
|  |             full_path = os.path.join(start_dir, path) | ||||||
|  |             # what about __init__.pyc or pyo (etc) | ||||||
|  |             # we would need to avoid loading the same tests multiple times | ||||||
|  |             # from '.py', '.pyc' *and* '.pyo' | ||||||
|  |             if os.path.isfile(full_path) and path.lower().endswith('.py'): | ||||||
|  |                 if fnmatch(path, pattern): | ||||||
|  |                     # if the test file matches, load it | ||||||
|  |                     module = self._get_module_from_path(full_path) | ||||||
|  |                     yield self.loadTestsFromModule(module) | ||||||
|  |             elif os.path.isdir(full_path): | ||||||
|  |                 if not os.path.isfile(os.path.join(full_path, '__init__.py')): | ||||||
|  |                     continue | ||||||
|  | 
 | ||||||
|  |                 load_tests = None | ||||||
|  |                 tests = None | ||||||
|  |                 if fnmatch(path, pattern): | ||||||
|  |                     # only check load_tests if the package directory itself matches the filter | ||||||
|  |                     package = self._get_module_from_path(full_path) | ||||||
|  |                     load_tests = getattr(package, 'load_tests', None) | ||||||
|  |                     tests = self.loadTestsFromModule(package, use_load_tests=False) | ||||||
|  | 
 | ||||||
|  |                 if load_tests is None: | ||||||
|  |                     if tests is not None: | ||||||
|  |                         # tests loaded from package file | ||||||
|  |                         yield tests | ||||||
|  |                     # recurse into the package | ||||||
|  |                     for test in self._find_tests(full_path, pattern): | ||||||
|  |                         yield test | ||||||
|  |                 else: | ||||||
|  |                     yield load_tests(self, tests, pattern) | ||||||
|  | 
 | ||||||
|  | defaultTestLoader = TestLoader() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def _makeLoader(prefix, sortUsing, suiteClass=None): | ||||||
|  |     loader = TestLoader() | ||||||
|  |     loader.sortTestMethodsUsing = sortUsing | ||||||
|  |     loader.testMethodPrefix = prefix | ||||||
|  |     if suiteClass: | ||||||
|  |         loader.suiteClass = suiteClass | ||||||
|  |     return loader | ||||||
|  | 
 | ||||||
|  | def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): | ||||||
|  |     return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) | ||||||
|  | 
 | ||||||
|  | def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, | ||||||
|  |               suiteClass=suite.TestSuite): | ||||||
|  |     return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) | ||||||
|  | 
 | ||||||
|  | def findTestCases(module, prefix='test', sortUsing=cmp, | ||||||
|  |                   suiteClass=suite.TestSuite): | ||||||
|  |     return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) | ||||||
							
								
								
									
										175
									
								
								Lib/unittest/main.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								Lib/unittest/main.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,175 @@ | ||||||
|  | """Unittest main program""" | ||||||
|  | 
 | ||||||
|  | import sys | ||||||
|  | import os | ||||||
|  | import types | ||||||
|  | 
 | ||||||
|  | from . import loader, runner | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | USAGE_AS_MAIN = """\ | ||||||
|  | Usage: %(progName)s [options] [tests] | ||||||
|  | 
 | ||||||
|  | Options: | ||||||
|  |   -h, --help       Show this message | ||||||
|  |   -v, --verbose    Verbose output | ||||||
|  |   -q, --quiet      Minimal output | ||||||
|  | 
 | ||||||
|  | Examples: | ||||||
|  |   %(progName)s test_module                       - run tests from test_module | ||||||
|  |   %(progName)s test_module.TestClass             - run tests from | ||||||
|  |                                                    test_module.TestClass | ||||||
|  |   %(progName)s test_module.TestClass.test_method - run specified test method | ||||||
|  | 
 | ||||||
|  | [tests] can be a list of any number of test modules, classes and test | ||||||
|  | methods. | ||||||
|  | 
 | ||||||
|  | Alternative Usage: %(progName)s discover [options] | ||||||
|  | 
 | ||||||
|  | Options: | ||||||
|  |   -v, --verbose    Verbose output | ||||||
|  |   -s directory     Directory to start discovery ('.' default) | ||||||
|  |   -p pattern       Pattern to match test files ('test*.py' default) | ||||||
|  |   -t directory     Top level directory of project (default to | ||||||
|  |                    start directory) | ||||||
|  | 
 | ||||||
|  | For test discovery all test modules must be importable from the top | ||||||
|  | level directory of the project. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | USAGE_FROM_MODULE = """\ | ||||||
|  | Usage: %(progName)s [options] [test] [...] | ||||||
|  | 
 | ||||||
|  | Options: | ||||||
|  |   -h, --help       Show this message | ||||||
|  |   -v, --verbose    Verbose output | ||||||
|  |   -q, --quiet      Minimal output | ||||||
|  | 
 | ||||||
|  | Examples: | ||||||
|  |   %(progName)s                               - run default set of tests | ||||||
|  |   %(progName)s MyTestSuite                   - run suite 'MyTestSuite' | ||||||
|  |   %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething | ||||||
|  |   %(progName)s MyTestCase                    - run all 'test*' test methods | ||||||
|  |                                                in MyTestCase | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     USAGE = USAGE_AS_MAIN | ||||||
|  | else: | ||||||
|  |     USAGE = USAGE_FROM_MODULE | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestProgram(object): | ||||||
|  |     """A command-line program that runs a set of tests; this is primarily | ||||||
|  |        for making test modules conveniently executable. | ||||||
|  |     """ | ||||||
|  |     USAGE = USAGE | ||||||
|  |     def __init__(self, module='__main__', defaultTest=None, | ||||||
|  |                  argv=None, testRunner=None, | ||||||
|  |                  testLoader=loader.defaultTestLoader, exit=True, | ||||||
|  |                  verbosity=1): | ||||||
|  |         if isinstance(module, basestring): | ||||||
|  |             self.module = __import__(module) | ||||||
|  |             for part in module.split('.')[1:]: | ||||||
|  |                 self.module = getattr(self.module, part) | ||||||
|  |         else: | ||||||
|  |             self.module = module | ||||||
|  |         if argv is None: | ||||||
|  |             argv = sys.argv | ||||||
|  | 
 | ||||||
|  |         self.exit = exit | ||||||
|  |         self.verbosity = verbosity | ||||||
|  |         self.defaultTest = defaultTest | ||||||
|  |         self.testRunner = testRunner | ||||||
|  |         self.testLoader = testLoader | ||||||
|  |         self.progName = os.path.basename(argv[0]) | ||||||
|  |         self.parseArgs(argv) | ||||||
|  |         self.runTests() | ||||||
|  | 
 | ||||||
|  |     def usageExit(self, msg=None): | ||||||
|  |         if msg: | ||||||
|  |             print msg | ||||||
|  |         print self.USAGE % self.__dict__ | ||||||
|  |         sys.exit(2) | ||||||
|  | 
 | ||||||
|  |     def parseArgs(self, argv): | ||||||
|  |         if len(argv) > 1 and argv[1].lower() == 'discover': | ||||||
|  |             self._do_discovery(argv[2:]) | ||||||
|  |             return | ||||||
|  | 
 | ||||||
|  |         import getopt | ||||||
|  |         long_opts = ['help','verbose','quiet'] | ||||||
|  |         try: | ||||||
|  |             options, args = getopt.getopt(argv[1:], 'hHvq', long_opts) | ||||||
|  |             for opt, value in options: | ||||||
|  |                 if opt in ('-h','-H','--help'): | ||||||
|  |                     self.usageExit() | ||||||
|  |                 if opt in ('-q','--quiet'): | ||||||
|  |                     self.verbosity = 0 | ||||||
|  |                 if opt in ('-v','--verbose'): | ||||||
|  |                     self.verbosity = 2 | ||||||
|  |             if len(args) == 0 and self.defaultTest is None: | ||||||
|  |                 self.test = self.testLoader.loadTestsFromModule(self.module) | ||||||
|  |                 return | ||||||
|  |             if len(args) > 0: | ||||||
|  |                 self.testNames = args | ||||||
|  |                 if __name__ == '__main__': | ||||||
|  |                     # to support python -m unittest ... | ||||||
|  |                     self.module = None | ||||||
|  |             else: | ||||||
|  |                 self.testNames = (self.defaultTest,) | ||||||
|  |             self.createTests() | ||||||
|  |         except getopt.error, msg: | ||||||
|  |             self.usageExit(msg) | ||||||
|  | 
 | ||||||
|  |     def createTests(self): | ||||||
|  |         self.test = self.testLoader.loadTestsFromNames(self.testNames, | ||||||
|  |                                                        self.module) | ||||||
|  | 
 | ||||||
|  |     def _do_discovery(self, argv, Loader=loader.TestLoader): | ||||||
|  |         # handle command line args for test discovery | ||||||
|  |         import optparse | ||||||
|  |         parser = optparse.OptionParser() | ||||||
|  |         parser.add_option('-v', '--verbose', dest='verbose', default=False, | ||||||
|  |                           help='Verbose output', action='store_true') | ||||||
|  |         parser.add_option('-s', '--start-directory', dest='start', default='.', | ||||||
|  |                           help="Directory to start discovery ('.' default)") | ||||||
|  |         parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', | ||||||
|  |                           help="Pattern to match tests ('test*.py' default)") | ||||||
|  |         parser.add_option('-t', '--top-level-directory', dest='top', default=None, | ||||||
|  |                           help='Top level directory of project (defaults to start directory)') | ||||||
|  | 
 | ||||||
|  |         options, args = parser.parse_args(argv) | ||||||
|  |         if len(args) > 3: | ||||||
|  |             self.usageExit() | ||||||
|  | 
 | ||||||
|  |         for name, value in zip(('start', 'pattern', 'top'), args): | ||||||
|  |             setattr(options, name, value) | ||||||
|  | 
 | ||||||
|  |         if options.verbose: | ||||||
|  |             self.verbosity = 2 | ||||||
|  | 
 | ||||||
|  |         start_dir = options.start | ||||||
|  |         pattern = options.pattern | ||||||
|  |         top_level_dir = options.top | ||||||
|  | 
 | ||||||
|  |         loader = Loader() | ||||||
|  |         self.test = loader.discover(start_dir, pattern, top_level_dir) | ||||||
|  | 
 | ||||||
|  |     def runTests(self): | ||||||
|  |         if self.testRunner is None: | ||||||
|  |             self.testRunner = runner.TextTestRunner | ||||||
|  |         if isinstance(self.testRunner, (type, types.ClassType)): | ||||||
|  |             try: | ||||||
|  |                 testRunner = self.testRunner(verbosity=self.verbosity) | ||||||
|  |             except TypeError: | ||||||
|  |                 # didn't accept the verbosity argument | ||||||
|  |                 testRunner = self.testRunner() | ||||||
|  |         else: | ||||||
|  |             # it is assumed to be a TestRunner instance | ||||||
|  |             testRunner = self.testRunner | ||||||
|  |         self.result = testRunner.run(self.test) | ||||||
|  |         if self.exit: | ||||||
|  |             sys.exit(not self.result.wasSuccessful()) | ||||||
|  | 
 | ||||||
|  | main = TestProgram | ||||||
							
								
								
									
										113
									
								
								Lib/unittest/result.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Lib/unittest/result.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | ||||||
|  | """Test result object""" | ||||||
|  | 
 | ||||||
|  | import traceback | ||||||
|  | 
 | ||||||
|  | from . import util | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestResult(object): | ||||||
|  |     """Holder for test result information. | ||||||
|  | 
 | ||||||
|  |     Test results are automatically managed by the TestCase and TestSuite | ||||||
|  |     classes, and do not need to be explicitly manipulated by writers of tests. | ||||||
|  | 
 | ||||||
|  |     Each instance holds the total number of tests run, and collections of | ||||||
|  |     failures and errors that occurred among those test runs. The collections | ||||||
|  |     contain tuples of (testcase, exceptioninfo), where exceptioninfo is the | ||||||
|  |     formatted traceback of the error that occurred. | ||||||
|  |     """ | ||||||
|  |     def __init__(self): | ||||||
|  |         self.failures = [] | ||||||
|  |         self.errors = [] | ||||||
|  |         self.testsRun = 0 | ||||||
|  |         self.skipped = [] | ||||||
|  |         self.expectedFailures = [] | ||||||
|  |         self.unexpectedSuccesses = [] | ||||||
|  |         self.shouldStop = False | ||||||
|  | 
 | ||||||
|  |     def startTest(self, test): | ||||||
|  |         "Called when the given test is about to be run" | ||||||
|  |         self.testsRun = self.testsRun + 1 | ||||||
|  | 
 | ||||||
|  |     def startTestRun(self): | ||||||
|  |         """Called once before any tests are executed. | ||||||
|  | 
 | ||||||
|  |         See startTest for a method called before each test. | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |     def stopTest(self, test): | ||||||
|  |         "Called when the given test has been run" | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     def stopTestRun(self): | ||||||
|  |         """Called once after all tests are executed. | ||||||
|  | 
 | ||||||
|  |         See stopTest for a method called after each test. | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |     def addError(self, test, err): | ||||||
|  |         """Called when an error has occurred. 'err' is a tuple of values as | ||||||
|  |         returned by sys.exc_info(). | ||||||
|  |         """ | ||||||
|  |         self.errors.append((test, self._exc_info_to_string(err, test))) | ||||||
|  | 
 | ||||||
|  |     def addFailure(self, test, err): | ||||||
|  |         """Called when an error has occurred. 'err' is a tuple of values as | ||||||
|  |         returned by sys.exc_info().""" | ||||||
|  |         self.failures.append((test, self._exc_info_to_string(err, test))) | ||||||
|  | 
 | ||||||
|  |     def addSuccess(self, test): | ||||||
|  |         "Called when a test has completed successfully" | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     def addSkip(self, test, reason): | ||||||
|  |         """Called when a test is skipped.""" | ||||||
|  |         self.skipped.append((test, reason)) | ||||||
|  | 
 | ||||||
|  |     def addExpectedFailure(self, test, err): | ||||||
|  |         """Called when an expected failure/error occured.""" | ||||||
|  |         self.expectedFailures.append( | ||||||
|  |             (test, self._exc_info_to_string(err, test))) | ||||||
|  | 
 | ||||||
|  |     def addUnexpectedSuccess(self, test): | ||||||
|  |         """Called when a test was expected to fail, but succeed.""" | ||||||
|  |         self.unexpectedSuccesses.append(test) | ||||||
|  | 
 | ||||||
|  |     def wasSuccessful(self): | ||||||
|  |         "Tells whether or not this result was a success" | ||||||
|  |         return len(self.failures) == len(self.errors) == 0 | ||||||
|  | 
 | ||||||
|  |     def stop(self): | ||||||
|  |         "Indicates that the tests should be aborted" | ||||||
|  |         self.shouldStop = True | ||||||
|  | 
 | ||||||
|  |     def _exc_info_to_string(self, err, test): | ||||||
|  |         """Converts a sys.exc_info()-style tuple of values into a string.""" | ||||||
|  |         exctype, value, tb = err | ||||||
|  |         # Skip test runner traceback levels | ||||||
|  |         while tb and self._is_relevant_tb_level(tb): | ||||||
|  |             tb = tb.tb_next | ||||||
|  |         if exctype is test.failureException: | ||||||
|  |             # Skip assert*() traceback levels | ||||||
|  |             length = self._count_relevant_tb_levels(tb) | ||||||
|  |             return ''.join(traceback.format_exception(exctype, value, tb, length)) | ||||||
|  |         return ''.join(traceback.format_exception(exctype, value, tb)) | ||||||
|  | 
 | ||||||
|  |     def _is_relevant_tb_level(self, tb): | ||||||
|  |         globs = tb.tb_frame.f_globals | ||||||
|  |         is_relevant =  '__name__' in globs and \ | ||||||
|  |             globs["__name__"].startswith("unittest") | ||||||
|  |         del globs | ||||||
|  |         return is_relevant | ||||||
|  | 
 | ||||||
|  |     def _count_relevant_tb_levels(self, tb): | ||||||
|  |         length = 0 | ||||||
|  |         while tb and not self._is_relevant_tb_level(tb): | ||||||
|  |             length += 1 | ||||||
|  |             tb = tb.tb_next | ||||||
|  |         return length | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         return "<%s run=%i errors=%i failures=%i>" % \ | ||||||
|  |                (util.strclass(self.__class__), self.testsRun, len(self.errors), | ||||||
|  |                 len(self.failures)) | ||||||
							
								
								
									
										172
									
								
								Lib/unittest/runner.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								Lib/unittest/runner.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,172 @@ | ||||||
|  | """Running tests""" | ||||||
|  | 
 | ||||||
|  | import sys | ||||||
|  | import time | ||||||
|  | 
 | ||||||
|  | from . import result | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class _WritelnDecorator(object): | ||||||
|  |     """Used to decorate file-like objects with a handy 'writeln' method""" | ||||||
|  |     def __init__(self,stream): | ||||||
|  |         self.stream = stream | ||||||
|  | 
 | ||||||
|  |     def __getattr__(self, attr): | ||||||
|  |         return getattr(self.stream,attr) | ||||||
|  | 
 | ||||||
|  |     def writeln(self, arg=None): | ||||||
|  |         if arg: | ||||||
|  |             self.write(arg) | ||||||
|  |         self.write('\n') # text-mode streams translate to \r\n if needed | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class _TextTestResult(result.TestResult): | ||||||
|  |     """A test result class that can print formatted text results to a stream. | ||||||
|  | 
 | ||||||
|  |     Used by TextTestRunner. | ||||||
|  |     """ | ||||||
|  |     separator1 = '=' * 70 | ||||||
|  |     separator2 = '-' * 70 | ||||||
|  | 
 | ||||||
|  |     def __init__(self, stream, descriptions, verbosity): | ||||||
|  |         super(_TextTestResult, self).__init__() | ||||||
|  |         self.stream = stream | ||||||
|  |         self.showAll = verbosity > 1 | ||||||
|  |         self.dots = verbosity == 1 | ||||||
|  |         self.descriptions = descriptions | ||||||
|  | 
 | ||||||
|  |     def getDescription(self, test): | ||||||
|  |         if self.descriptions: | ||||||
|  |             return test.shortDescription() or str(test) | ||||||
|  |         else: | ||||||
|  |             return str(test) | ||||||
|  | 
 | ||||||
|  |     def startTest(self, test): | ||||||
|  |         super(_TextTestResult, self).startTest(test) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.write(self.getDescription(test)) | ||||||
|  |             self.stream.write(" ... ") | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def addSuccess(self, test): | ||||||
|  |         super(_TextTestResult, self).addSuccess(test) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.writeln("ok") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write('.') | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def addError(self, test, err): | ||||||
|  |         super(_TextTestResult, self).addError(test, err) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.writeln("ERROR") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write('E') | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def addFailure(self, test, err): | ||||||
|  |         super(_TextTestResult, self).addFailure(test, err) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.writeln("FAIL") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write('F') | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def addSkip(self, test, reason): | ||||||
|  |         super(_TextTestResult, self).addSkip(test, reason) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.writeln("skipped {0!r}".format(reason)) | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write("s") | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def addExpectedFailure(self, test, err): | ||||||
|  |         super(_TextTestResult, self).addExpectedFailure(test, err) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.writeln("expected failure") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write("x") | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def addUnexpectedSuccess(self, test): | ||||||
|  |         super(_TextTestResult, self).addUnexpectedSuccess(test) | ||||||
|  |         if self.showAll: | ||||||
|  |             self.stream.writeln("unexpected success") | ||||||
|  |         elif self.dots: | ||||||
|  |             self.stream.write("u") | ||||||
|  |             self.stream.flush() | ||||||
|  | 
 | ||||||
|  |     def printErrors(self): | ||||||
|  |         if self.dots or self.showAll: | ||||||
|  |             self.stream.writeln() | ||||||
|  |         self.printErrorList('ERROR', self.errors) | ||||||
|  |         self.printErrorList('FAIL', self.failures) | ||||||
|  | 
 | ||||||
|  |     def printErrorList(self, flavour, errors): | ||||||
|  |         for test, err in errors: | ||||||
|  |             self.stream.writeln(self.separator1) | ||||||
|  |             self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) | ||||||
|  |             self.stream.writeln(self.separator2) | ||||||
|  |             self.stream.writeln("%s" % err) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TextTestRunner(object): | ||||||
|  |     """A test runner class that displays results in textual form. | ||||||
|  | 
 | ||||||
|  |     It prints out the names of tests as they are run, errors as they | ||||||
|  |     occur, and a summary of the results at the end of the test run. | ||||||
|  |     """ | ||||||
|  |     def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): | ||||||
|  |         self.stream = _WritelnDecorator(stream) | ||||||
|  |         self.descriptions = descriptions | ||||||
|  |         self.verbosity = verbosity | ||||||
|  | 
 | ||||||
|  |     def _makeResult(self): | ||||||
|  |         return _TextTestResult(self.stream, self.descriptions, self.verbosity) | ||||||
|  | 
 | ||||||
|  |     def run(self, test): | ||||||
|  |         "Run the given test case or test suite." | ||||||
|  |         result = self._makeResult() | ||||||
|  |         startTime = time.time() | ||||||
|  |         startTestRun = getattr(result, 'startTestRun', None) | ||||||
|  |         if startTestRun is not None: | ||||||
|  |             startTestRun() | ||||||
|  |         try: | ||||||
|  |             test(result) | ||||||
|  |         finally: | ||||||
|  |             stopTestRun = getattr(result, 'stopTestRun', None) | ||||||
|  |             if stopTestRun is not None: | ||||||
|  |                 stopTestRun() | ||||||
|  |         stopTime = time.time() | ||||||
|  |         timeTaken = stopTime - startTime | ||||||
|  |         result.printErrors() | ||||||
|  |         self.stream.writeln(result.separator2) | ||||||
|  |         run = result.testsRun | ||||||
|  |         self.stream.writeln("Ran %d test%s in %.3fs" % | ||||||
|  |                             (run, run != 1 and "s" or "", timeTaken)) | ||||||
|  |         self.stream.writeln() | ||||||
|  |         results = map(len, (result.expectedFailures, | ||||||
|  |                             result.unexpectedSuccesses, | ||||||
|  |                             result.skipped)) | ||||||
|  |         expectedFails, unexpectedSuccesses, skipped = results | ||||||
|  |         infos = [] | ||||||
|  |         if not result.wasSuccessful(): | ||||||
|  |             self.stream.write("FAILED") | ||||||
|  |             failed, errored = map(len, (result.failures, result.errors)) | ||||||
|  |             if failed: | ||||||
|  |                 infos.append("failures=%d" % failed) | ||||||
|  |             if errored: | ||||||
|  |                 infos.append("errors=%d" % errored) | ||||||
|  |         else: | ||||||
|  |             self.stream.write("OK") | ||||||
|  |         if skipped: | ||||||
|  |             infos.append("skipped=%d" % skipped) | ||||||
|  |         if expectedFails: | ||||||
|  |             infos.append("expected failures=%d" % expectedFails) | ||||||
|  |         if unexpectedSuccesses: | ||||||
|  |             infos.append("unexpected successes=%d" % unexpectedSuccesses) | ||||||
|  |         if infos: | ||||||
|  |             self.stream.writeln(" (%s)" % (", ".join(infos),)) | ||||||
|  |         else: | ||||||
|  |             self.stream.write("\n") | ||||||
|  |         return result | ||||||
							
								
								
									
										71
									
								
								Lib/unittest/suite.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Lib/unittest/suite.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | ||||||
|  | """TestSuite""" | ||||||
|  | 
 | ||||||
|  | from . import case | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestSuite(object): | ||||||
|  |     """A test suite is a composite test consisting of a number of TestCases. | ||||||
|  | 
 | ||||||
|  |     For use, create an instance of TestSuite, then add test case instances. | ||||||
|  |     When all tests have been added, the suite can be passed to a test | ||||||
|  |     runner, such as TextTestRunner. It will run the individual test cases | ||||||
|  |     in the order in which they were added, aggregating the results. When | ||||||
|  |     subclassing, do not forget to call the base class constructor. | ||||||
|  |     """ | ||||||
|  |     def __init__(self, tests=()): | ||||||
|  |         self._tests = [] | ||||||
|  |         self.addTests(tests) | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         return "<%s tests=%s>" % (_strclass(self.__class__), list(self)) | ||||||
|  | 
 | ||||||
|  |     def __eq__(self, other): | ||||||
|  |         if not isinstance(other, self.__class__): | ||||||
|  |             return NotImplemented | ||||||
|  |         return list(self) == list(other) | ||||||
|  | 
 | ||||||
|  |     def __ne__(self, other): | ||||||
|  |         return not self == other | ||||||
|  | 
 | ||||||
|  |     # Can't guarantee hash invariant, so flag as unhashable | ||||||
|  |     __hash__ = None | ||||||
|  | 
 | ||||||
|  |     def __iter__(self): | ||||||
|  |         return iter(self._tests) | ||||||
|  | 
 | ||||||
|  |     def countTestCases(self): | ||||||
|  |         cases = 0 | ||||||
|  |         for test in self: | ||||||
|  |             cases += test.countTestCases() | ||||||
|  |         return cases | ||||||
|  | 
 | ||||||
|  |     def addTest(self, test): | ||||||
|  |         # sanity checks | ||||||
|  |         if not hasattr(test, '__call__'): | ||||||
|  |             raise TypeError("the test to add must be callable") | ||||||
|  |         if isinstance(test, type) and issubclass(test, | ||||||
|  |                                                  (case.TestCase, TestSuite)): | ||||||
|  |             raise TypeError("TestCases and TestSuites must be instantiated " | ||||||
|  |                             "before passing them to addTest()") | ||||||
|  |         self._tests.append(test) | ||||||
|  | 
 | ||||||
|  |     def addTests(self, tests): | ||||||
|  |         if isinstance(tests, basestring): | ||||||
|  |             raise TypeError("tests must be an iterable of tests, not a string") | ||||||
|  |         for test in tests: | ||||||
|  |             self.addTest(test) | ||||||
|  | 
 | ||||||
|  |     def run(self, result): | ||||||
|  |         for test in self: | ||||||
|  |             if result.shouldStop: | ||||||
|  |                 break | ||||||
|  |             test(result) | ||||||
|  |         return result | ||||||
|  | 
 | ||||||
|  |     def __call__(self, *args, **kwds): | ||||||
|  |         return self.run(*args, **kwds) | ||||||
|  | 
 | ||||||
|  |     def debug(self): | ||||||
|  |         """Run the tests without collecting errors in a TestResult""" | ||||||
|  |         for test in self: | ||||||
|  |             test.debug() | ||||||
							
								
								
									
										44
									
								
								Lib/unittest/util.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Lib/unittest/util.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | ||||||
|  | """Various utility functions.""" | ||||||
|  | 
 | ||||||
|  | def strclass(cls): | ||||||
|  |     return "%s.%s" % (cls.__module__, cls.__name__) | ||||||
|  | 
 | ||||||
|  | def sorted_list_difference(expected, actual): | ||||||
|  |     """Finds elements in only one or the other of two, sorted input lists. | ||||||
|  | 
 | ||||||
|  |     Returns a two-element tuple of lists.    The first list contains those | ||||||
|  |     elements in the "expected" list but not in the "actual" list, and the | ||||||
|  |     second contains those elements in the "actual" list but not in the | ||||||
|  |     "expected" list.    Duplicate elements in either input list are ignored. | ||||||
|  |     """ | ||||||
|  |     i = j = 0 | ||||||
|  |     missing = [] | ||||||
|  |     unexpected = [] | ||||||
|  |     while True: | ||||||
|  |         try: | ||||||
|  |             e = expected[i] | ||||||
|  |             a = actual[j] | ||||||
|  |             if e < a: | ||||||
|  |                 missing.append(e) | ||||||
|  |                 i += 1 | ||||||
|  |                 while expected[i] == e: | ||||||
|  |                     i += 1 | ||||||
|  |             elif e > a: | ||||||
|  |                 unexpected.append(a) | ||||||
|  |                 j += 1 | ||||||
|  |                 while actual[j] == a: | ||||||
|  |                     j += 1 | ||||||
|  |             else: | ||||||
|  |                 i += 1 | ||||||
|  |                 try: | ||||||
|  |                     while expected[i] == e: | ||||||
|  |                         i += 1 | ||||||
|  |                 finally: | ||||||
|  |                     j += 1 | ||||||
|  |                     while actual[j] == a: | ||||||
|  |                         j += 1 | ||||||
|  |         except IndexError: | ||||||
|  |             missing.extend(expected[i:]) | ||||||
|  |             unexpected.extend(actual[j:]) | ||||||
|  |             break | ||||||
|  |     return missing, unexpected | ||||||
|  | @ -352,6 +352,8 @@ Core and Builtins | ||||||
| Library | Library | ||||||
| ------- | ------- | ||||||
| 
 | 
 | ||||||
|  | - unittest has been split up into a package.  All old names should still work. | ||||||
|  | 
 | ||||||
| - Issue #6431: Make Fraction type return NotImplemented when it doesn't | - Issue #6431: Make Fraction type return NotImplemented when it doesn't | ||||||
|   know how to handle a comparison without loss of precision.  Also add |   know how to handle a comparison without loss of precision.  Also add | ||||||
|   correct handling of infinities and nans for comparisons with float. |   correct handling of infinities and nans for comparisons with float. | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Benjamin Peterson
						Benjamin Peterson