1*cda5da8dSAndroid Build Coastguard Worker"""Loading unittests.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Workerimport os 4*cda5da8dSAndroid Build Coastguard Workerimport re 5*cda5da8dSAndroid Build Coastguard Workerimport sys 6*cda5da8dSAndroid Build Coastguard Workerimport traceback 7*cda5da8dSAndroid Build Coastguard Workerimport types 8*cda5da8dSAndroid Build Coastguard Workerimport functools 9*cda5da8dSAndroid Build Coastguard Workerimport warnings 10*cda5da8dSAndroid Build Coastguard Worker 11*cda5da8dSAndroid Build Coastguard Workerfrom fnmatch import fnmatch, fnmatchcase 12*cda5da8dSAndroid Build Coastguard Worker 13*cda5da8dSAndroid Build Coastguard Workerfrom . import case, suite, util 14*cda5da8dSAndroid Build Coastguard Worker 15*cda5da8dSAndroid Build Coastguard Worker__unittest = True 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Worker# what about .pyc (etc) 18*cda5da8dSAndroid Build Coastguard Worker# we would need to avoid loading the same tests multiple times 19*cda5da8dSAndroid Build Coastguard Worker# from '.py', *and* '.pyc' 20*cda5da8dSAndroid Build Coastguard WorkerVALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE) 21*cda5da8dSAndroid Build Coastguard Worker 22*cda5da8dSAndroid Build Coastguard Worker 23*cda5da8dSAndroid Build Coastguard Workerclass _FailedTest(case.TestCase): 24*cda5da8dSAndroid Build Coastguard Worker _testMethodName = None 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker def __init__(self, method_name, exception): 27*cda5da8dSAndroid Build Coastguard Worker self._exception = exception 28*cda5da8dSAndroid Build Coastguard Worker super(_FailedTest, self).__init__(method_name) 29*cda5da8dSAndroid Build Coastguard Worker 30*cda5da8dSAndroid Build Coastguard Worker def __getattr__(self, name): 31*cda5da8dSAndroid Build Coastguard Worker if name != self._testMethodName: 32*cda5da8dSAndroid Build Coastguard Worker return super(_FailedTest, self).__getattr__(name) 33*cda5da8dSAndroid Build Coastguard Worker def testFailure(): 34*cda5da8dSAndroid Build Coastguard Worker raise self._exception 35*cda5da8dSAndroid Build Coastguard Worker return testFailure 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Worker 38*cda5da8dSAndroid Build Coastguard Workerdef _make_failed_import_test(name, suiteClass): 39*cda5da8dSAndroid Build Coastguard Worker message = 'Failed to import test module: %s\n%s' % ( 40*cda5da8dSAndroid Build Coastguard Worker name, traceback.format_exc()) 41*cda5da8dSAndroid Build Coastguard Worker return _make_failed_test(name, ImportError(message), suiteClass, message) 42*cda5da8dSAndroid Build Coastguard Worker 43*cda5da8dSAndroid Build Coastguard Workerdef _make_failed_load_tests(name, exception, suiteClass): 44*cda5da8dSAndroid Build Coastguard Worker message = 'Failed to call load_tests:\n%s' % (traceback.format_exc(),) 45*cda5da8dSAndroid Build Coastguard Worker return _make_failed_test( 46*cda5da8dSAndroid Build Coastguard Worker name, exception, suiteClass, message) 47*cda5da8dSAndroid Build Coastguard Worker 48*cda5da8dSAndroid Build Coastguard Workerdef _make_failed_test(methodname, exception, suiteClass, message): 49*cda5da8dSAndroid Build Coastguard Worker test = _FailedTest(methodname, exception) 50*cda5da8dSAndroid Build Coastguard Worker return suiteClass((test,)), message 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Workerdef _make_skipped_test(methodname, exception, suiteClass): 53*cda5da8dSAndroid Build Coastguard Worker @case.skip(str(exception)) 54*cda5da8dSAndroid Build Coastguard Worker def testSkipped(self): 55*cda5da8dSAndroid Build Coastguard Worker pass 56*cda5da8dSAndroid Build Coastguard Worker attrs = {methodname: testSkipped} 57*cda5da8dSAndroid Build Coastguard Worker TestClass = type("ModuleSkipped", (case.TestCase,), attrs) 58*cda5da8dSAndroid Build Coastguard Worker return suiteClass((TestClass(methodname),)) 59*cda5da8dSAndroid Build Coastguard Worker 60*cda5da8dSAndroid Build Coastguard Workerdef _jython_aware_splitext(path): 61*cda5da8dSAndroid Build Coastguard Worker if path.lower().endswith('$py.class'): 62*cda5da8dSAndroid Build Coastguard Worker return path[:-9] 63*cda5da8dSAndroid Build Coastguard Worker return os.path.splitext(path)[0] 64*cda5da8dSAndroid Build Coastguard Worker 65*cda5da8dSAndroid Build Coastguard Worker 66*cda5da8dSAndroid Build Coastguard Workerclass TestLoader(object): 67*cda5da8dSAndroid Build Coastguard Worker """ 68*cda5da8dSAndroid Build Coastguard Worker This class is responsible for loading tests according to various criteria 69*cda5da8dSAndroid Build Coastguard Worker and returning them wrapped in a TestSuite 70*cda5da8dSAndroid Build Coastguard Worker """ 71*cda5da8dSAndroid Build Coastguard Worker testMethodPrefix = 'test' 72*cda5da8dSAndroid Build Coastguard Worker sortTestMethodsUsing = staticmethod(util.three_way_cmp) 73*cda5da8dSAndroid Build Coastguard Worker testNamePatterns = None 74*cda5da8dSAndroid Build Coastguard Worker suiteClass = suite.TestSuite 75*cda5da8dSAndroid Build Coastguard Worker _top_level_dir = None 76*cda5da8dSAndroid Build Coastguard Worker 77*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 78*cda5da8dSAndroid Build Coastguard Worker super(TestLoader, self).__init__() 79*cda5da8dSAndroid Build Coastguard Worker self.errors = [] 80*cda5da8dSAndroid Build Coastguard Worker # Tracks packages which we have called into via load_tests, to 81*cda5da8dSAndroid Build Coastguard Worker # avoid infinite re-entrancy. 82*cda5da8dSAndroid Build Coastguard Worker self._loading_packages = set() 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker def loadTestsFromTestCase(self, testCaseClass): 85*cda5da8dSAndroid Build Coastguard Worker """Return a suite of all test cases contained in testCaseClass""" 86*cda5da8dSAndroid Build Coastguard Worker if issubclass(testCaseClass, suite.TestSuite): 87*cda5da8dSAndroid Build Coastguard Worker raise TypeError("Test cases should not be derived from " 88*cda5da8dSAndroid Build Coastguard Worker "TestSuite. Maybe you meant to derive from " 89*cda5da8dSAndroid Build Coastguard Worker "TestCase?") 90*cda5da8dSAndroid Build Coastguard Worker testCaseNames = self.getTestCaseNames(testCaseClass) 91*cda5da8dSAndroid Build Coastguard Worker if not testCaseNames and hasattr(testCaseClass, 'runTest'): 92*cda5da8dSAndroid Build Coastguard Worker testCaseNames = ['runTest'] 93*cda5da8dSAndroid Build Coastguard Worker loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) 94*cda5da8dSAndroid Build Coastguard Worker return loaded_suite 95*cda5da8dSAndroid Build Coastguard Worker 96*cda5da8dSAndroid Build Coastguard Worker # XXX After Python 3.5, remove backward compatibility hacks for 97*cda5da8dSAndroid Build Coastguard Worker # use_load_tests deprecation via *args and **kws. See issue 16662. 98*cda5da8dSAndroid Build Coastguard Worker def loadTestsFromModule(self, module, *args, pattern=None, **kws): 99*cda5da8dSAndroid Build Coastguard Worker """Return a suite of all test cases contained in the given module""" 100*cda5da8dSAndroid Build Coastguard Worker # This method used to take an undocumented and unofficial 101*cda5da8dSAndroid Build Coastguard Worker # use_load_tests argument. For backward compatibility, we still 102*cda5da8dSAndroid Build Coastguard Worker # accept the argument (which can also be the first position) but we 103*cda5da8dSAndroid Build Coastguard Worker # ignore it and issue a deprecation warning if it's present. 104*cda5da8dSAndroid Build Coastguard Worker if len(args) > 0 or 'use_load_tests' in kws: 105*cda5da8dSAndroid Build Coastguard Worker warnings.warn('use_load_tests is deprecated and ignored', 106*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning) 107*cda5da8dSAndroid Build Coastguard Worker kws.pop('use_load_tests', None) 108*cda5da8dSAndroid Build Coastguard Worker if len(args) > 1: 109*cda5da8dSAndroid Build Coastguard Worker # Complain about the number of arguments, but don't forget the 110*cda5da8dSAndroid Build Coastguard Worker # required `module` argument. 111*cda5da8dSAndroid Build Coastguard Worker complaint = len(args) + 1 112*cda5da8dSAndroid Build Coastguard Worker raise TypeError('loadTestsFromModule() takes 1 positional argument but {} were given'.format(complaint)) 113*cda5da8dSAndroid Build Coastguard Worker if len(kws) != 0: 114*cda5da8dSAndroid Build Coastguard Worker # Since the keyword arguments are unsorted (see PEP 468), just 115*cda5da8dSAndroid Build Coastguard Worker # pick the alphabetically sorted first argument to complain about, 116*cda5da8dSAndroid Build Coastguard Worker # if multiple were given. At least the error message will be 117*cda5da8dSAndroid Build Coastguard Worker # predictable. 118*cda5da8dSAndroid Build Coastguard Worker complaint = sorted(kws)[0] 119*cda5da8dSAndroid Build Coastguard Worker raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{}'".format(complaint)) 120*cda5da8dSAndroid Build Coastguard Worker tests = [] 121*cda5da8dSAndroid Build Coastguard Worker for name in dir(module): 122*cda5da8dSAndroid Build Coastguard Worker obj = getattr(module, name) 123*cda5da8dSAndroid Build Coastguard Worker if isinstance(obj, type) and issubclass(obj, case.TestCase): 124*cda5da8dSAndroid Build Coastguard Worker tests.append(self.loadTestsFromTestCase(obj)) 125*cda5da8dSAndroid Build Coastguard Worker 126*cda5da8dSAndroid Build Coastguard Worker load_tests = getattr(module, 'load_tests', None) 127*cda5da8dSAndroid Build Coastguard Worker tests = self.suiteClass(tests) 128*cda5da8dSAndroid Build Coastguard Worker if load_tests is not None: 129*cda5da8dSAndroid Build Coastguard Worker try: 130*cda5da8dSAndroid Build Coastguard Worker return load_tests(self, tests, pattern) 131*cda5da8dSAndroid Build Coastguard Worker except Exception as e: 132*cda5da8dSAndroid Build Coastguard Worker error_case, error_message = _make_failed_load_tests( 133*cda5da8dSAndroid Build Coastguard Worker module.__name__, e, self.suiteClass) 134*cda5da8dSAndroid Build Coastguard Worker self.errors.append(error_message) 135*cda5da8dSAndroid Build Coastguard Worker return error_case 136*cda5da8dSAndroid Build Coastguard Worker return tests 137*cda5da8dSAndroid Build Coastguard Worker 138*cda5da8dSAndroid Build Coastguard Worker def loadTestsFromName(self, name, module=None): 139*cda5da8dSAndroid Build Coastguard Worker """Return a suite of all test cases given a string specifier. 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker The name may resolve either to a module, a test case class, a 142*cda5da8dSAndroid Build Coastguard Worker test method within a test case class, or a callable object which 143*cda5da8dSAndroid Build Coastguard Worker returns a TestCase or TestSuite instance. 144*cda5da8dSAndroid Build Coastguard Worker 145*cda5da8dSAndroid Build Coastguard Worker The method optionally resolves the names relative to a given module. 146*cda5da8dSAndroid Build Coastguard Worker """ 147*cda5da8dSAndroid Build Coastguard Worker parts = name.split('.') 148*cda5da8dSAndroid Build Coastguard Worker error_case, error_message = None, None 149*cda5da8dSAndroid Build Coastguard Worker if module is None: 150*cda5da8dSAndroid Build Coastguard Worker parts_copy = parts[:] 151*cda5da8dSAndroid Build Coastguard Worker while parts_copy: 152*cda5da8dSAndroid Build Coastguard Worker try: 153*cda5da8dSAndroid Build Coastguard Worker module_name = '.'.join(parts_copy) 154*cda5da8dSAndroid Build Coastguard Worker module = __import__(module_name) 155*cda5da8dSAndroid Build Coastguard Worker break 156*cda5da8dSAndroid Build Coastguard Worker except ImportError: 157*cda5da8dSAndroid Build Coastguard Worker next_attribute = parts_copy.pop() 158*cda5da8dSAndroid Build Coastguard Worker # Last error so we can give it to the user if needed. 159*cda5da8dSAndroid Build Coastguard Worker error_case, error_message = _make_failed_import_test( 160*cda5da8dSAndroid Build Coastguard Worker next_attribute, self.suiteClass) 161*cda5da8dSAndroid Build Coastguard Worker if not parts_copy: 162*cda5da8dSAndroid Build Coastguard Worker # Even the top level import failed: report that error. 163*cda5da8dSAndroid Build Coastguard Worker self.errors.append(error_message) 164*cda5da8dSAndroid Build Coastguard Worker return error_case 165*cda5da8dSAndroid Build Coastguard Worker parts = parts[1:] 166*cda5da8dSAndroid Build Coastguard Worker obj = module 167*cda5da8dSAndroid Build Coastguard Worker for part in parts: 168*cda5da8dSAndroid Build Coastguard Worker try: 169*cda5da8dSAndroid Build Coastguard Worker parent, obj = obj, getattr(obj, part) 170*cda5da8dSAndroid Build Coastguard Worker except AttributeError as e: 171*cda5da8dSAndroid Build Coastguard Worker # We can't traverse some part of the name. 172*cda5da8dSAndroid Build Coastguard Worker if (getattr(obj, '__path__', None) is not None 173*cda5da8dSAndroid Build Coastguard Worker and error_case is not None): 174*cda5da8dSAndroid Build Coastguard Worker # This is a package (no __path__ per importlib docs), and we 175*cda5da8dSAndroid Build Coastguard Worker # encountered an error importing something. We cannot tell 176*cda5da8dSAndroid Build Coastguard Worker # the difference between package.WrongNameTestClass and 177*cda5da8dSAndroid Build Coastguard Worker # package.wrong_module_name so we just report the 178*cda5da8dSAndroid Build Coastguard Worker # ImportError - it is more informative. 179*cda5da8dSAndroid Build Coastguard Worker self.errors.append(error_message) 180*cda5da8dSAndroid Build Coastguard Worker return error_case 181*cda5da8dSAndroid Build Coastguard Worker else: 182*cda5da8dSAndroid Build Coastguard Worker # Otherwise, we signal that an AttributeError has occurred. 183*cda5da8dSAndroid Build Coastguard Worker error_case, error_message = _make_failed_test( 184*cda5da8dSAndroid Build Coastguard Worker part, e, self.suiteClass, 185*cda5da8dSAndroid Build Coastguard Worker 'Failed to access attribute:\n%s' % ( 186*cda5da8dSAndroid Build Coastguard Worker traceback.format_exc(),)) 187*cda5da8dSAndroid Build Coastguard Worker self.errors.append(error_message) 188*cda5da8dSAndroid Build Coastguard Worker return error_case 189*cda5da8dSAndroid Build Coastguard Worker 190*cda5da8dSAndroid Build Coastguard Worker if isinstance(obj, types.ModuleType): 191*cda5da8dSAndroid Build Coastguard Worker return self.loadTestsFromModule(obj) 192*cda5da8dSAndroid Build Coastguard Worker elif isinstance(obj, type) and issubclass(obj, case.TestCase): 193*cda5da8dSAndroid Build Coastguard Worker return self.loadTestsFromTestCase(obj) 194*cda5da8dSAndroid Build Coastguard Worker elif (isinstance(obj, types.FunctionType) and 195*cda5da8dSAndroid Build Coastguard Worker isinstance(parent, type) and 196*cda5da8dSAndroid Build Coastguard Worker issubclass(parent, case.TestCase)): 197*cda5da8dSAndroid Build Coastguard Worker name = parts[-1] 198*cda5da8dSAndroid Build Coastguard Worker inst = parent(name) 199*cda5da8dSAndroid Build Coastguard Worker # static methods follow a different path 200*cda5da8dSAndroid Build Coastguard Worker if not isinstance(getattr(inst, name), types.FunctionType): 201*cda5da8dSAndroid Build Coastguard Worker return self.suiteClass([inst]) 202*cda5da8dSAndroid Build Coastguard Worker elif isinstance(obj, suite.TestSuite): 203*cda5da8dSAndroid Build Coastguard Worker return obj 204*cda5da8dSAndroid Build Coastguard Worker if callable(obj): 205*cda5da8dSAndroid Build Coastguard Worker test = obj() 206*cda5da8dSAndroid Build Coastguard Worker if isinstance(test, suite.TestSuite): 207*cda5da8dSAndroid Build Coastguard Worker return test 208*cda5da8dSAndroid Build Coastguard Worker elif isinstance(test, case.TestCase): 209*cda5da8dSAndroid Build Coastguard Worker return self.suiteClass([test]) 210*cda5da8dSAndroid Build Coastguard Worker else: 211*cda5da8dSAndroid Build Coastguard Worker raise TypeError("calling %s returned %s, not a test" % 212*cda5da8dSAndroid Build Coastguard Worker (obj, test)) 213*cda5da8dSAndroid Build Coastguard Worker else: 214*cda5da8dSAndroid Build Coastguard Worker raise TypeError("don't know how to make test from: %s" % obj) 215*cda5da8dSAndroid Build Coastguard Worker 216*cda5da8dSAndroid Build Coastguard Worker def loadTestsFromNames(self, names, module=None): 217*cda5da8dSAndroid Build Coastguard Worker """Return a suite of all test cases found using the given sequence 218*cda5da8dSAndroid Build Coastguard Worker of string specifiers. See 'loadTestsFromName()'. 219*cda5da8dSAndroid Build Coastguard Worker """ 220*cda5da8dSAndroid Build Coastguard Worker suites = [self.loadTestsFromName(name, module) for name in names] 221*cda5da8dSAndroid Build Coastguard Worker return self.suiteClass(suites) 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker def getTestCaseNames(self, testCaseClass): 224*cda5da8dSAndroid Build Coastguard Worker """Return a sorted sequence of method names found within testCaseClass 225*cda5da8dSAndroid Build Coastguard Worker """ 226*cda5da8dSAndroid Build Coastguard Worker def shouldIncludeMethod(attrname): 227*cda5da8dSAndroid Build Coastguard Worker if not attrname.startswith(self.testMethodPrefix): 228*cda5da8dSAndroid Build Coastguard Worker return False 229*cda5da8dSAndroid Build Coastguard Worker testFunc = getattr(testCaseClass, attrname) 230*cda5da8dSAndroid Build Coastguard Worker if not callable(testFunc): 231*cda5da8dSAndroid Build Coastguard Worker return False 232*cda5da8dSAndroid Build Coastguard Worker fullName = f'%s.%s.%s' % ( 233*cda5da8dSAndroid Build Coastguard Worker testCaseClass.__module__, testCaseClass.__qualname__, attrname 234*cda5da8dSAndroid Build Coastguard Worker ) 235*cda5da8dSAndroid Build Coastguard Worker return self.testNamePatterns is None or \ 236*cda5da8dSAndroid Build Coastguard Worker any(fnmatchcase(fullName, pattern) for pattern in self.testNamePatterns) 237*cda5da8dSAndroid Build Coastguard Worker testFnNames = list(filter(shouldIncludeMethod, dir(testCaseClass))) 238*cda5da8dSAndroid Build Coastguard Worker if self.sortTestMethodsUsing: 239*cda5da8dSAndroid Build Coastguard Worker testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing)) 240*cda5da8dSAndroid Build Coastguard Worker return testFnNames 241*cda5da8dSAndroid Build Coastguard Worker 242*cda5da8dSAndroid Build Coastguard Worker def discover(self, start_dir, pattern='test*.py', top_level_dir=None): 243*cda5da8dSAndroid Build Coastguard Worker """Find and return all test modules from the specified start 244*cda5da8dSAndroid Build Coastguard Worker directory, recursing into subdirectories to find them and return all 245*cda5da8dSAndroid Build Coastguard Worker tests found within them. Only test files that match the pattern will 246*cda5da8dSAndroid Build Coastguard Worker be loaded. (Using shell style pattern matching.) 247*cda5da8dSAndroid Build Coastguard Worker 248*cda5da8dSAndroid Build Coastguard Worker All test modules must be importable from the top level of the project. 249*cda5da8dSAndroid Build Coastguard Worker If the start directory is not the top level directory then the top 250*cda5da8dSAndroid Build Coastguard Worker level directory must be specified separately. 251*cda5da8dSAndroid Build Coastguard Worker 252*cda5da8dSAndroid Build Coastguard Worker If a test package name (directory with '__init__.py') matches the 253*cda5da8dSAndroid Build Coastguard Worker pattern then the package will be checked for a 'load_tests' function. If 254*cda5da8dSAndroid Build Coastguard Worker this exists then it will be called with (loader, tests, pattern) unless 255*cda5da8dSAndroid Build Coastguard Worker the package has already had load_tests called from the same discovery 256*cda5da8dSAndroid Build Coastguard Worker invocation, in which case the package module object is not scanned for 257*cda5da8dSAndroid Build Coastguard Worker tests - this ensures that when a package uses discover to further 258*cda5da8dSAndroid Build Coastguard Worker discover child tests that infinite recursion does not happen. 259*cda5da8dSAndroid Build Coastguard Worker 260*cda5da8dSAndroid Build Coastguard Worker If load_tests exists then discovery does *not* recurse into the package, 261*cda5da8dSAndroid Build Coastguard Worker load_tests is responsible for loading all tests in the package. 262*cda5da8dSAndroid Build Coastguard Worker 263*cda5da8dSAndroid Build Coastguard Worker The pattern is deliberately not stored as a loader attribute so that 264*cda5da8dSAndroid Build Coastguard Worker packages can continue discovery themselves. top_level_dir is stored so 265*cda5da8dSAndroid Build Coastguard Worker load_tests does not need to pass this argument in to loader.discover(). 266*cda5da8dSAndroid Build Coastguard Worker 267*cda5da8dSAndroid Build Coastguard Worker Paths are sorted before being imported to ensure reproducible execution 268*cda5da8dSAndroid Build Coastguard Worker order even on filesystems with non-alphabetical ordering like ext3/4. 269*cda5da8dSAndroid Build Coastguard Worker """ 270*cda5da8dSAndroid Build Coastguard Worker set_implicit_top = False 271*cda5da8dSAndroid Build Coastguard Worker if top_level_dir is None and self._top_level_dir is not None: 272*cda5da8dSAndroid Build Coastguard Worker # make top_level_dir optional if called from load_tests in a package 273*cda5da8dSAndroid Build Coastguard Worker top_level_dir = self._top_level_dir 274*cda5da8dSAndroid Build Coastguard Worker elif top_level_dir is None: 275*cda5da8dSAndroid Build Coastguard Worker set_implicit_top = True 276*cda5da8dSAndroid Build Coastguard Worker top_level_dir = start_dir 277*cda5da8dSAndroid Build Coastguard Worker 278*cda5da8dSAndroid Build Coastguard Worker top_level_dir = os.path.abspath(top_level_dir) 279*cda5da8dSAndroid Build Coastguard Worker 280*cda5da8dSAndroid Build Coastguard Worker if not top_level_dir in sys.path: 281*cda5da8dSAndroid Build Coastguard Worker # all test modules must be importable from the top level directory 282*cda5da8dSAndroid Build Coastguard Worker # should we *unconditionally* put the start directory in first 283*cda5da8dSAndroid Build Coastguard Worker # in sys.path to minimise likelihood of conflicts between installed 284*cda5da8dSAndroid Build Coastguard Worker # modules and development versions? 285*cda5da8dSAndroid Build Coastguard Worker sys.path.insert(0, top_level_dir) 286*cda5da8dSAndroid Build Coastguard Worker self._top_level_dir = top_level_dir 287*cda5da8dSAndroid Build Coastguard Worker 288*cda5da8dSAndroid Build Coastguard Worker is_not_importable = False 289*cda5da8dSAndroid Build Coastguard Worker if os.path.isdir(os.path.abspath(start_dir)): 290*cda5da8dSAndroid Build Coastguard Worker start_dir = os.path.abspath(start_dir) 291*cda5da8dSAndroid Build Coastguard Worker if start_dir != top_level_dir: 292*cda5da8dSAndroid Build Coastguard Worker is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py')) 293*cda5da8dSAndroid Build Coastguard Worker else: 294*cda5da8dSAndroid Build Coastguard Worker # support for discovery from dotted module names 295*cda5da8dSAndroid Build Coastguard Worker try: 296*cda5da8dSAndroid Build Coastguard Worker __import__(start_dir) 297*cda5da8dSAndroid Build Coastguard Worker except ImportError: 298*cda5da8dSAndroid Build Coastguard Worker is_not_importable = True 299*cda5da8dSAndroid Build Coastguard Worker else: 300*cda5da8dSAndroid Build Coastguard Worker the_module = sys.modules[start_dir] 301*cda5da8dSAndroid Build Coastguard Worker top_part = start_dir.split('.')[0] 302*cda5da8dSAndroid Build Coastguard Worker try: 303*cda5da8dSAndroid Build Coastguard Worker start_dir = os.path.abspath( 304*cda5da8dSAndroid Build Coastguard Worker os.path.dirname((the_module.__file__))) 305*cda5da8dSAndroid Build Coastguard Worker except AttributeError: 306*cda5da8dSAndroid Build Coastguard Worker if the_module.__name__ in sys.builtin_module_names: 307*cda5da8dSAndroid Build Coastguard Worker # builtin module 308*cda5da8dSAndroid Build Coastguard Worker raise TypeError('Can not use builtin modules ' 309*cda5da8dSAndroid Build Coastguard Worker 'as dotted module names') from None 310*cda5da8dSAndroid Build Coastguard Worker else: 311*cda5da8dSAndroid Build Coastguard Worker raise TypeError( 312*cda5da8dSAndroid Build Coastguard Worker f"don't know how to discover from {the_module!r}" 313*cda5da8dSAndroid Build Coastguard Worker ) from None 314*cda5da8dSAndroid Build Coastguard Worker 315*cda5da8dSAndroid Build Coastguard Worker if set_implicit_top: 316*cda5da8dSAndroid Build Coastguard Worker self._top_level_dir = self._get_directory_containing_module(top_part) 317*cda5da8dSAndroid Build Coastguard Worker sys.path.remove(top_level_dir) 318*cda5da8dSAndroid Build Coastguard Worker 319*cda5da8dSAndroid Build Coastguard Worker if is_not_importable: 320*cda5da8dSAndroid Build Coastguard Worker raise ImportError('Start directory is not importable: %r' % start_dir) 321*cda5da8dSAndroid Build Coastguard Worker 322*cda5da8dSAndroid Build Coastguard Worker tests = list(self._find_tests(start_dir, pattern)) 323*cda5da8dSAndroid Build Coastguard Worker return self.suiteClass(tests) 324*cda5da8dSAndroid Build Coastguard Worker 325*cda5da8dSAndroid Build Coastguard Worker def _get_directory_containing_module(self, module_name): 326*cda5da8dSAndroid Build Coastguard Worker module = sys.modules[module_name] 327*cda5da8dSAndroid Build Coastguard Worker full_path = os.path.abspath(module.__file__) 328*cda5da8dSAndroid Build Coastguard Worker 329*cda5da8dSAndroid Build Coastguard Worker if os.path.basename(full_path).lower().startswith('__init__.py'): 330*cda5da8dSAndroid Build Coastguard Worker return os.path.dirname(os.path.dirname(full_path)) 331*cda5da8dSAndroid Build Coastguard Worker else: 332*cda5da8dSAndroid Build Coastguard Worker # here we have been given a module rather than a package - so 333*cda5da8dSAndroid Build Coastguard Worker # all we can do is search the *same* directory the module is in 334*cda5da8dSAndroid Build Coastguard Worker # should an exception be raised instead 335*cda5da8dSAndroid Build Coastguard Worker return os.path.dirname(full_path) 336*cda5da8dSAndroid Build Coastguard Worker 337*cda5da8dSAndroid Build Coastguard Worker def _get_name_from_path(self, path): 338*cda5da8dSAndroid Build Coastguard Worker if path == self._top_level_dir: 339*cda5da8dSAndroid Build Coastguard Worker return '.' 340*cda5da8dSAndroid Build Coastguard Worker path = _jython_aware_splitext(os.path.normpath(path)) 341*cda5da8dSAndroid Build Coastguard Worker 342*cda5da8dSAndroid Build Coastguard Worker _relpath = os.path.relpath(path, self._top_level_dir) 343*cda5da8dSAndroid Build Coastguard Worker assert not os.path.isabs(_relpath), "Path must be within the project" 344*cda5da8dSAndroid Build Coastguard Worker assert not _relpath.startswith('..'), "Path must be within the project" 345*cda5da8dSAndroid Build Coastguard Worker 346*cda5da8dSAndroid Build Coastguard Worker name = _relpath.replace(os.path.sep, '.') 347*cda5da8dSAndroid Build Coastguard Worker return name 348*cda5da8dSAndroid Build Coastguard Worker 349*cda5da8dSAndroid Build Coastguard Worker def _get_module_from_name(self, name): 350*cda5da8dSAndroid Build Coastguard Worker __import__(name) 351*cda5da8dSAndroid Build Coastguard Worker return sys.modules[name] 352*cda5da8dSAndroid Build Coastguard Worker 353*cda5da8dSAndroid Build Coastguard Worker def _match_path(self, path, full_path, pattern): 354*cda5da8dSAndroid Build Coastguard Worker # override this method to use alternative matching strategy 355*cda5da8dSAndroid Build Coastguard Worker return fnmatch(path, pattern) 356*cda5da8dSAndroid Build Coastguard Worker 357*cda5da8dSAndroid Build Coastguard Worker def _find_tests(self, start_dir, pattern): 358*cda5da8dSAndroid Build Coastguard Worker """Used by discovery. Yields test suites it loads.""" 359*cda5da8dSAndroid Build Coastguard Worker # Handle the __init__ in this package 360*cda5da8dSAndroid Build Coastguard Worker name = self._get_name_from_path(start_dir) 361*cda5da8dSAndroid Build Coastguard Worker # name is '.' when start_dir == top_level_dir (and top_level_dir is by 362*cda5da8dSAndroid Build Coastguard Worker # definition not a package). 363*cda5da8dSAndroid Build Coastguard Worker if name != '.' and name not in self._loading_packages: 364*cda5da8dSAndroid Build Coastguard Worker # name is in self._loading_packages while we have called into 365*cda5da8dSAndroid Build Coastguard Worker # loadTestsFromModule with name. 366*cda5da8dSAndroid Build Coastguard Worker tests, should_recurse = self._find_test_path(start_dir, pattern) 367*cda5da8dSAndroid Build Coastguard Worker if tests is not None: 368*cda5da8dSAndroid Build Coastguard Worker yield tests 369*cda5da8dSAndroid Build Coastguard Worker if not should_recurse: 370*cda5da8dSAndroid Build Coastguard Worker # Either an error occurred, or load_tests was used by the 371*cda5da8dSAndroid Build Coastguard Worker # package. 372*cda5da8dSAndroid Build Coastguard Worker return 373*cda5da8dSAndroid Build Coastguard Worker # Handle the contents. 374*cda5da8dSAndroid Build Coastguard Worker paths = sorted(os.listdir(start_dir)) 375*cda5da8dSAndroid Build Coastguard Worker for path in paths: 376*cda5da8dSAndroid Build Coastguard Worker full_path = os.path.join(start_dir, path) 377*cda5da8dSAndroid Build Coastguard Worker tests, should_recurse = self._find_test_path(full_path, pattern) 378*cda5da8dSAndroid Build Coastguard Worker if tests is not None: 379*cda5da8dSAndroid Build Coastguard Worker yield tests 380*cda5da8dSAndroid Build Coastguard Worker if should_recurse: 381*cda5da8dSAndroid Build Coastguard Worker # we found a package that didn't use load_tests. 382*cda5da8dSAndroid Build Coastguard Worker name = self._get_name_from_path(full_path) 383*cda5da8dSAndroid Build Coastguard Worker self._loading_packages.add(name) 384*cda5da8dSAndroid Build Coastguard Worker try: 385*cda5da8dSAndroid Build Coastguard Worker yield from self._find_tests(full_path, pattern) 386*cda5da8dSAndroid Build Coastguard Worker finally: 387*cda5da8dSAndroid Build Coastguard Worker self._loading_packages.discard(name) 388*cda5da8dSAndroid Build Coastguard Worker 389*cda5da8dSAndroid Build Coastguard Worker def _find_test_path(self, full_path, pattern): 390*cda5da8dSAndroid Build Coastguard Worker """Used by discovery. 391*cda5da8dSAndroid Build Coastguard Worker 392*cda5da8dSAndroid Build Coastguard Worker Loads tests from a single file, or a directories' __init__.py when 393*cda5da8dSAndroid Build Coastguard Worker passed the directory. 394*cda5da8dSAndroid Build Coastguard Worker 395*cda5da8dSAndroid Build Coastguard Worker Returns a tuple (None_or_tests_from_file, should_recurse). 396*cda5da8dSAndroid Build Coastguard Worker """ 397*cda5da8dSAndroid Build Coastguard Worker basename = os.path.basename(full_path) 398*cda5da8dSAndroid Build Coastguard Worker if os.path.isfile(full_path): 399*cda5da8dSAndroid Build Coastguard Worker if not VALID_MODULE_NAME.match(basename): 400*cda5da8dSAndroid Build Coastguard Worker # valid Python identifiers only 401*cda5da8dSAndroid Build Coastguard Worker return None, False 402*cda5da8dSAndroid Build Coastguard Worker if not self._match_path(basename, full_path, pattern): 403*cda5da8dSAndroid Build Coastguard Worker return None, False 404*cda5da8dSAndroid Build Coastguard Worker # if the test file matches, load it 405*cda5da8dSAndroid Build Coastguard Worker name = self._get_name_from_path(full_path) 406*cda5da8dSAndroid Build Coastguard Worker try: 407*cda5da8dSAndroid Build Coastguard Worker module = self._get_module_from_name(name) 408*cda5da8dSAndroid Build Coastguard Worker except case.SkipTest as e: 409*cda5da8dSAndroid Build Coastguard Worker return _make_skipped_test(name, e, self.suiteClass), False 410*cda5da8dSAndroid Build Coastguard Worker except: 411*cda5da8dSAndroid Build Coastguard Worker error_case, error_message = \ 412*cda5da8dSAndroid Build Coastguard Worker _make_failed_import_test(name, self.suiteClass) 413*cda5da8dSAndroid Build Coastguard Worker self.errors.append(error_message) 414*cda5da8dSAndroid Build Coastguard Worker return error_case, False 415*cda5da8dSAndroid Build Coastguard Worker else: 416*cda5da8dSAndroid Build Coastguard Worker mod_file = os.path.abspath( 417*cda5da8dSAndroid Build Coastguard Worker getattr(module, '__file__', full_path)) 418*cda5da8dSAndroid Build Coastguard Worker realpath = _jython_aware_splitext( 419*cda5da8dSAndroid Build Coastguard Worker os.path.realpath(mod_file)) 420*cda5da8dSAndroid Build Coastguard Worker fullpath_noext = _jython_aware_splitext( 421*cda5da8dSAndroid Build Coastguard Worker os.path.realpath(full_path)) 422*cda5da8dSAndroid Build Coastguard Worker if realpath.lower() != fullpath_noext.lower(): 423*cda5da8dSAndroid Build Coastguard Worker module_dir = os.path.dirname(realpath) 424*cda5da8dSAndroid Build Coastguard Worker mod_name = _jython_aware_splitext( 425*cda5da8dSAndroid Build Coastguard Worker os.path.basename(full_path)) 426*cda5da8dSAndroid Build Coastguard Worker expected_dir = os.path.dirname(full_path) 427*cda5da8dSAndroid Build Coastguard Worker msg = ("%r module incorrectly imported from %r. Expected " 428*cda5da8dSAndroid Build Coastguard Worker "%r. Is this module globally installed?") 429*cda5da8dSAndroid Build Coastguard Worker raise ImportError( 430*cda5da8dSAndroid Build Coastguard Worker msg % (mod_name, module_dir, expected_dir)) 431*cda5da8dSAndroid Build Coastguard Worker return self.loadTestsFromModule(module, pattern=pattern), False 432*cda5da8dSAndroid Build Coastguard Worker elif os.path.isdir(full_path): 433*cda5da8dSAndroid Build Coastguard Worker if not os.path.isfile(os.path.join(full_path, '__init__.py')): 434*cda5da8dSAndroid Build Coastguard Worker return None, False 435*cda5da8dSAndroid Build Coastguard Worker 436*cda5da8dSAndroid Build Coastguard Worker load_tests = None 437*cda5da8dSAndroid Build Coastguard Worker tests = None 438*cda5da8dSAndroid Build Coastguard Worker name = self._get_name_from_path(full_path) 439*cda5da8dSAndroid Build Coastguard Worker try: 440*cda5da8dSAndroid Build Coastguard Worker package = self._get_module_from_name(name) 441*cda5da8dSAndroid Build Coastguard Worker except case.SkipTest as e: 442*cda5da8dSAndroid Build Coastguard Worker return _make_skipped_test(name, e, self.suiteClass), False 443*cda5da8dSAndroid Build Coastguard Worker except: 444*cda5da8dSAndroid Build Coastguard Worker error_case, error_message = \ 445*cda5da8dSAndroid Build Coastguard Worker _make_failed_import_test(name, self.suiteClass) 446*cda5da8dSAndroid Build Coastguard Worker self.errors.append(error_message) 447*cda5da8dSAndroid Build Coastguard Worker return error_case, False 448*cda5da8dSAndroid Build Coastguard Worker else: 449*cda5da8dSAndroid Build Coastguard Worker load_tests = getattr(package, 'load_tests', None) 450*cda5da8dSAndroid Build Coastguard Worker # Mark this package as being in load_tests (possibly ;)) 451*cda5da8dSAndroid Build Coastguard Worker self._loading_packages.add(name) 452*cda5da8dSAndroid Build Coastguard Worker try: 453*cda5da8dSAndroid Build Coastguard Worker tests = self.loadTestsFromModule(package, pattern=pattern) 454*cda5da8dSAndroid Build Coastguard Worker if load_tests is not None: 455*cda5da8dSAndroid Build Coastguard Worker # loadTestsFromModule(package) has loaded tests for us. 456*cda5da8dSAndroid Build Coastguard Worker return tests, False 457*cda5da8dSAndroid Build Coastguard Worker return tests, True 458*cda5da8dSAndroid Build Coastguard Worker finally: 459*cda5da8dSAndroid Build Coastguard Worker self._loading_packages.discard(name) 460*cda5da8dSAndroid Build Coastguard Worker else: 461*cda5da8dSAndroid Build Coastguard Worker return None, False 462*cda5da8dSAndroid Build Coastguard Worker 463*cda5da8dSAndroid Build Coastguard Worker 464*cda5da8dSAndroid Build Coastguard WorkerdefaultTestLoader = TestLoader() 465*cda5da8dSAndroid Build Coastguard Worker 466*cda5da8dSAndroid Build Coastguard Worker 467*cda5da8dSAndroid Build Coastguard Worker# These functions are considered obsolete for long time. 468*cda5da8dSAndroid Build Coastguard Worker# They will be removed in Python 3.13. 469*cda5da8dSAndroid Build Coastguard Worker 470*cda5da8dSAndroid Build Coastguard Workerdef _makeLoader(prefix, sortUsing, suiteClass=None, testNamePatterns=None): 471*cda5da8dSAndroid Build Coastguard Worker loader = TestLoader() 472*cda5da8dSAndroid Build Coastguard Worker loader.sortTestMethodsUsing = sortUsing 473*cda5da8dSAndroid Build Coastguard Worker loader.testMethodPrefix = prefix 474*cda5da8dSAndroid Build Coastguard Worker loader.testNamePatterns = testNamePatterns 475*cda5da8dSAndroid Build Coastguard Worker if suiteClass: 476*cda5da8dSAndroid Build Coastguard Worker loader.suiteClass = suiteClass 477*cda5da8dSAndroid Build Coastguard Worker return loader 478*cda5da8dSAndroid Build Coastguard Worker 479*cda5da8dSAndroid Build Coastguard Workerdef getTestCaseNames(testCaseClass, prefix, sortUsing=util.three_way_cmp, testNamePatterns=None): 480*cda5da8dSAndroid Build Coastguard Worker import warnings 481*cda5da8dSAndroid Build Coastguard Worker warnings.warn( 482*cda5da8dSAndroid Build Coastguard Worker "unittest.getTestCaseNames() is deprecated and will be removed in Python 3.13. " 483*cda5da8dSAndroid Build Coastguard Worker "Please use unittest.TestLoader.getTestCaseNames() instead.", 484*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning, stacklevel=2 485*cda5da8dSAndroid Build Coastguard Worker ) 486*cda5da8dSAndroid Build Coastguard Worker return _makeLoader(prefix, sortUsing, testNamePatterns=testNamePatterns).getTestCaseNames(testCaseClass) 487*cda5da8dSAndroid Build Coastguard Worker 488*cda5da8dSAndroid Build Coastguard Workerdef makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp, 489*cda5da8dSAndroid Build Coastguard Worker suiteClass=suite.TestSuite): 490*cda5da8dSAndroid Build Coastguard Worker import warnings 491*cda5da8dSAndroid Build Coastguard Worker warnings.warn( 492*cda5da8dSAndroid Build Coastguard Worker "unittest.makeSuite() is deprecated and will be removed in Python 3.13. " 493*cda5da8dSAndroid Build Coastguard Worker "Please use unittest.TestLoader.loadTestsFromTestCase() instead.", 494*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning, stacklevel=2 495*cda5da8dSAndroid Build Coastguard Worker ) 496*cda5da8dSAndroid Build Coastguard Worker return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase( 497*cda5da8dSAndroid Build Coastguard Worker testCaseClass) 498*cda5da8dSAndroid Build Coastguard Worker 499*cda5da8dSAndroid Build Coastguard Workerdef findTestCases(module, prefix='test', sortUsing=util.three_way_cmp, 500*cda5da8dSAndroid Build Coastguard Worker suiteClass=suite.TestSuite): 501*cda5da8dSAndroid Build Coastguard Worker import warnings 502*cda5da8dSAndroid Build Coastguard Worker warnings.warn( 503*cda5da8dSAndroid Build Coastguard Worker "unittest.findTestCases() is deprecated and will be removed in Python 3.13. " 504*cda5da8dSAndroid Build Coastguard Worker "Please use unittest.TestLoader.loadTestsFromModule() instead.", 505*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning, stacklevel=2 506*cda5da8dSAndroid Build Coastguard Worker ) 507*cda5da8dSAndroid Build Coastguard Worker return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(\ 508*cda5da8dSAndroid Build Coastguard Worker module) 509