1""" 2Test discovery functions. 3""" 4 5import os 6import sys 7 8from lit.TestingConfig import TestingConfig 9from lit import LitConfig, Test 10 11def dirContainsTestSuite(path, lit_config): 12 cfgpath = os.path.join(path, lit_config.site_config_name) 13 if os.path.exists(cfgpath): 14 return cfgpath 15 cfgpath = os.path.join(path, lit_config.config_name) 16 if os.path.exists(cfgpath): 17 return cfgpath 18 19def getTestSuite(item, litConfig, cache): 20 """getTestSuite(item, litConfig, cache) -> (suite, relative_path) 21 22 Find the test suite containing @arg item. 23 24 @retval (None, ...) - Indicates no test suite contains @arg item. 25 @retval (suite, relative_path) - The suite that @arg item is in, and its 26 relative path inside that suite. 27 """ 28 def search1(path): 29 # Check for a site config or a lit config. 30 cfgpath = dirContainsTestSuite(path, litConfig) 31 32 # If we didn't find a config file, keep looking. 33 if not cfgpath: 34 parent,base = os.path.split(path) 35 if parent == path: 36 return (None, ()) 37 38 ts, relative = search(parent) 39 return (ts, relative + (base,)) 40 41 # We found a config file, load it. 42 if litConfig.debug: 43 litConfig.note('loading suite config %r' % cfgpath) 44 45 cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True) 46 source_root = os.path.realpath(cfg.test_source_root or path) 47 exec_root = os.path.realpath(cfg.test_exec_root or path) 48 return Test.TestSuite(cfg.name, source_root, exec_root, cfg), () 49 50 def search(path): 51 # Check for an already instantiated test suite. 52 res = cache.get(path) 53 if res is None: 54 cache[path] = res = search1(path) 55 return res 56 57 # Canonicalize the path. 58 item = os.path.realpath(item) 59 60 # Skip files and virtual components. 61 components = [] 62 while not os.path.isdir(item): 63 parent,base = os.path.split(item) 64 if parent == item: 65 return (None, ()) 66 components.append(base) 67 item = parent 68 components.reverse() 69 70 ts, relative = search(item) 71 return ts, tuple(relative + tuple(components)) 72 73def getLocalConfig(ts, path_in_suite, litConfig, cache): 74 def search1(path_in_suite): 75 # Get the parent config. 76 if not path_in_suite: 77 parent = ts.config 78 else: 79 parent = search(path_in_suite[:-1]) 80 81 # Load the local configuration. 82 source_path = ts.getSourcePath(path_in_suite) 83 cfgpath = os.path.join(source_path, litConfig.local_config_name) 84 if litConfig.debug: 85 litConfig.note('loading local config %r' % cfgpath) 86 return TestingConfig.frompath(cfgpath, parent, litConfig, 87 mustExist = False, 88 config = parent.clone(cfgpath)) 89 90 def search(path_in_suite): 91 key = (ts, path_in_suite) 92 res = cache.get(key) 93 if res is None: 94 cache[key] = res = search1(path_in_suite) 95 return res 96 97 return search(path_in_suite) 98 99def getTests(path, litConfig, testSuiteCache, localConfigCache): 100 # Find the test suite for this input and its relative path. 101 ts,path_in_suite = getTestSuite(path, litConfig, testSuiteCache) 102 if ts is None: 103 litConfig.warning('unable to find test suite for %r' % path) 104 return (),() 105 106 if litConfig.debug: 107 litConfig.note('resolved input %r to %r::%r' % (path, ts.name, 108 path_in_suite)) 109 110 return ts, getTestsInSuite(ts, path_in_suite, litConfig, 111 testSuiteCache, localConfigCache) 112 113def getTestsInSuite(ts, path_in_suite, litConfig, 114 testSuiteCache, localConfigCache): 115 # Check that the source path exists (errors here are reported by the 116 # caller). 117 source_path = ts.getSourcePath(path_in_suite) 118 if not os.path.exists(source_path): 119 return 120 121 # Check if the user named a test directly. 122 if not os.path.isdir(source_path): 123 lc = getLocalConfig(ts, path_in_suite[:-1], litConfig, localConfigCache) 124 yield Test.Test(ts, path_in_suite, lc) 125 return 126 127 # Otherwise we have a directory to search for tests, start by getting the 128 # local configuration. 129 lc = getLocalConfig(ts, path_in_suite, litConfig, localConfigCache) 130 131 # Search for tests. 132 if lc.test_format is not None: 133 for res in lc.test_format.getTestsInDirectory(ts, path_in_suite, 134 litConfig, lc): 135 yield res 136 137 # Search subdirectories. 138 for filename in os.listdir(source_path): 139 # FIXME: This doesn't belong here? 140 if filename in ('Output', '.svn', '.git') or filename in lc.excludes: 141 continue 142 143 # Ignore non-directories. 144 file_sourcepath = os.path.join(source_path, filename) 145 if not os.path.isdir(file_sourcepath): 146 continue 147 148 # Check for nested test suites, first in the execpath in case there is a 149 # site configuration and then in the source path. 150 subpath = path_in_suite + (filename,) 151 file_execpath = ts.getExecPath(subpath) 152 if dirContainsTestSuite(file_execpath, litConfig): 153 sub_ts, subpath_in_suite = getTestSuite(file_execpath, litConfig, 154 testSuiteCache) 155 elif dirContainsTestSuite(file_sourcepath, litConfig): 156 sub_ts, subpath_in_suite = getTestSuite(file_sourcepath, litConfig, 157 testSuiteCache) 158 else: 159 sub_ts = None 160 161 # If the this directory recursively maps back to the current test suite, 162 # disregard it (this can happen if the exec root is located inside the 163 # current test suite, for example). 164 if sub_ts is ts: 165 continue 166 167 # Otherwise, load from the nested test suite, if present. 168 if sub_ts is not None: 169 subiter = getTestsInSuite(sub_ts, subpath_in_suite, litConfig, 170 testSuiteCache, localConfigCache) 171 else: 172 subiter = getTestsInSuite(ts, subpath, litConfig, testSuiteCache, 173 localConfigCache) 174 175 N = 0 176 for res in subiter: 177 N += 1 178 yield res 179 if sub_ts and not N: 180 litConfig.warning('test suite %r contained no tests' % sub_ts.name) 181 182def find_tests_for_inputs(lit_config, inputs): 183 """ 184 find_tests_for_inputs(lit_config, inputs) -> [Test] 185 186 Given a configuration object and a list of input specifiers, find all the 187 tests to execute. 188 """ 189 190 # Expand '@...' form in inputs. 191 actual_inputs = [] 192 for input in inputs: 193 if os.path.exists(input) or not input.startswith('@'): 194 actual_inputs.append(input) 195 else: 196 f = open(input[1:]) 197 try: 198 for ln in f: 199 ln = ln.strip() 200 if ln: 201 actual_inputs.append(ln) 202 finally: 203 f.close() 204 205 # Load the tests from the inputs. 206 tests = [] 207 test_suite_cache = {} 208 local_config_cache = {} 209 for input in actual_inputs: 210 prev = len(tests) 211 tests.extend(getTests(input, lit_config, 212 test_suite_cache, local_config_cache)[1]) 213 if prev == len(tests): 214 lit_config.warning('input %r contained no tests' % input) 215 216 # If there were any errors during test discovery, exit now. 217 if lit_config.numErrors: 218 sys.stderr.write('%d errors, exiting.\n' % lit_config.numErrors) 219 sys.exit(2) 220 221 return tests 222 223def load_test_suite(inputs): 224 import platform 225 import unittest 226 from lit.LitTestCase import LitTestCase 227 228 # Create the global config object. 229 litConfig = LitConfig.LitConfig(progname = 'lit', 230 path = [], 231 quiet = False, 232 useValgrind = False, 233 valgrindLeakCheck = False, 234 valgrindArgs = [], 235 noExecute = False, 236 debug = False, 237 isWindows = (platform.system()=='Windows'), 238 params = {}) 239 240 tests = find_tests_for_inputs(litConfig, inputs) 241 242 # Return a unittest test suite which just runs the tests in order. 243 return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests]) 244