2 Test discovery functions.
8 from lit.TestingConfig import TestingConfig
9 from lit import LitConfig, Test
11 def dirContainsTestSuite(path, lit_config):
12 cfgpath = os.path.join(path, lit_config.site_config_name)
13 if os.path.exists(cfgpath):
15 cfgpath = os.path.join(path, lit_config.config_name)
16 if os.path.exists(cfgpath):
19 def getTestSuite(item, litConfig, cache):
20 """getTestSuite(item, litConfig, cache) -> (suite, relative_path)
22 Find the test suite containing @arg item.
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.
29 # Check for a site config or a lit config.
30 cfgpath = dirContainsTestSuite(path, litConfig)
32 # If we didn't find a config file, keep looking.
34 parent,base = os.path.split(path)
38 ts, relative = search(parent)
39 return (ts, relative + (base,))
41 # We found a config file, load it.
43 litConfig.note('loading suite config %r' % cfgpath)
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), ()
51 # Check for an already instantiated test suite.
54 cache[path] = res = search1(path)
57 # Canonicalize the path.
58 item = os.path.realpath(item)
60 # Skip files and virtual components.
62 while not os.path.isdir(item):
63 parent,base = os.path.split(item)
66 components.append(base)
70 ts, relative = search(item)
71 return ts, tuple(relative + tuple(components))
73 def getLocalConfig(ts, path_in_suite, litConfig, cache):
74 def search1(path_in_suite):
75 # Get the parent config.
79 parent = search(path_in_suite[:-1])
81 # Load the local configuration.
82 source_path = ts.getSourcePath(path_in_suite)
83 cfgpath = os.path.join(source_path, litConfig.local_config_name)
85 litConfig.note('loading local config %r' % cfgpath)
86 return TestingConfig.frompath(cfgpath, parent, litConfig,
88 config = parent.clone(cfgpath))
90 def search(path_in_suite):
91 key = (ts, path_in_suite)
94 cache[key] = res = search1(path_in_suite)
97 return search(path_in_suite)
99 def 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)
103 litConfig.warning('unable to find test suite for %r' % path)
107 litConfig.note('resolved input %r to %r::%r' % (path, ts.name,
110 return ts, getTestsInSuite(ts, path_in_suite, litConfig,
111 testSuiteCache, localConfigCache)
113 def getTestsInSuite(ts, path_in_suite, litConfig,
114 testSuiteCache, localConfigCache):
115 # Check that the source path exists (errors here are reported by the
117 source_path = ts.getSourcePath(path_in_suite)
118 if not os.path.exists(source_path):
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)
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)
132 if lc.test_format is not None:
133 for res in lc.test_format.getTestsInDirectory(ts, path_in_suite,
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:
143 # Ignore non-directories.
144 file_sourcepath = os.path.join(source_path, filename)
145 if not os.path.isdir(file_sourcepath):
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,
155 elif dirContainsTestSuite(file_sourcepath, litConfig):
156 sub_ts, subpath_in_suite = getTestSuite(file_sourcepath, litConfig,
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).
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)
172 subiter = getTestsInSuite(ts, subpath, litConfig, testSuiteCache,
180 litConfig.warning('test suite %r contained no tests' % sub_ts.name)
182 def find_tests_for_inputs(lit_config, inputs):
184 find_tests_for_inputs(lit_config, inputs) -> [Test]
186 Given a configuration object and a list of input specifiers, find all the
190 # Expand '@...' form in inputs.
193 if os.path.exists(input) or not input.startswith('@'):
194 actual_inputs.append(input)
201 actual_inputs.append(ln)
205 # Load the tests from the inputs.
207 test_suite_cache = {}
208 local_config_cache = {}
209 for input in actual_inputs:
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)
216 # If there were any errors during test discovery, exit now.
217 if lit_config.numErrors:
218 print >>sys.stderr, '%d errors, exiting.' % lit_config.numErrors
223 def load_test_suite(inputs):
226 from lit.LitTestCase import LitTestCase
228 # Create the global config object.
229 litConfig = LitConfig.LitConfig(progname = 'lit',
233 valgrindLeakCheck = False,
237 isWindows = (platform.system()=='Windows'),
240 tests = find_tests_for_inputs(litConfig, inputs)
242 # Return a unittest test suite which just runs the tests in order.
243 return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests])