Index: third_party/lit/lit/discovery.py |
diff --git a/third_party/lit/lit/discovery.py b/third_party/lit/lit/discovery.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4befe582d454c37dfb33c1f302793695bafa0fe0 |
--- /dev/null |
+++ b/third_party/lit/lit/discovery.py |
@@ -0,0 +1,255 @@ |
+""" |
+Test discovery functions. |
+""" |
+ |
+import copy |
+import os |
+import sys |
+ |
+import lit.run |
+from lit.TestingConfig import TestingConfig |
+from lit import LitConfig, Test |
+ |
+def dirContainsTestSuite(path, lit_config): |
+ cfgpath = os.path.join(path, lit_config.site_config_name) |
+ if os.path.exists(cfgpath): |
+ return cfgpath |
+ cfgpath = os.path.join(path, lit_config.config_name) |
+ if os.path.exists(cfgpath): |
+ return cfgpath |
+ |
+def getTestSuite(item, litConfig, cache): |
+ """getTestSuite(item, litConfig, cache) -> (suite, relative_path) |
+ |
+ Find the test suite containing @arg item. |
+ |
+ @retval (None, ...) - Indicates no test suite contains @arg item. |
+ @retval (suite, relative_path) - The suite that @arg item is in, and its |
+ relative path inside that suite. |
+ """ |
+ def search1(path): |
+ # Check for a site config or a lit config. |
+ cfgpath = dirContainsTestSuite(path, litConfig) |
+ |
+ # If we didn't find a config file, keep looking. |
+ if not cfgpath: |
+ parent,base = os.path.split(path) |
+ if parent == path: |
+ return (None, ()) |
+ |
+ ts, relative = search(parent) |
+ return (ts, relative + (base,)) |
+ |
+ # We found a test suite, create a new config for it and load it. |
+ if litConfig.debug: |
+ litConfig.note('loading suite config %r' % cfgpath) |
+ |
+ cfg = TestingConfig.fromdefaults(litConfig) |
+ cfg.load_from_path(cfgpath, litConfig) |
+ source_root = os.path.realpath(cfg.test_source_root or path) |
+ exec_root = os.path.realpath(cfg.test_exec_root or path) |
+ return Test.TestSuite(cfg.name, source_root, exec_root, cfg), () |
+ |
+ def search(path): |
+ # Check for an already instantiated test suite. |
+ res = cache.get(path) |
+ if res is None: |
+ cache[path] = res = search1(path) |
+ return res |
+ |
+ # Canonicalize the path. |
+ item = os.path.realpath(item) |
+ |
+ # Skip files and virtual components. |
+ components = [] |
+ while not os.path.isdir(item): |
+ parent,base = os.path.split(item) |
+ if parent == item: |
+ return (None, ()) |
+ components.append(base) |
+ item = parent |
+ components.reverse() |
+ |
+ ts, relative = search(item) |
+ return ts, tuple(relative + tuple(components)) |
+ |
+def getLocalConfig(ts, path_in_suite, litConfig, cache): |
+ def search1(path_in_suite): |
+ # Get the parent config. |
+ if not path_in_suite: |
+ parent = ts.config |
+ else: |
+ parent = search(path_in_suite[:-1]) |
+ |
+ # Check if there is a local configuration file. |
+ source_path = ts.getSourcePath(path_in_suite) |
+ cfgpath = os.path.join(source_path, litConfig.local_config_name) |
+ |
+ # If not, just reuse the parent config. |
+ if not os.path.exists(cfgpath): |
+ return parent |
+ |
+ # Otherwise, copy the current config and load the local configuration |
+ # file into it. |
+ config = copy.deepcopy(parent) |
+ if litConfig.debug: |
+ litConfig.note('loading local config %r' % cfgpath) |
+ config.load_from_path(cfgpath, litConfig) |
+ return config |
+ |
+ def search(path_in_suite): |
+ key = (ts, path_in_suite) |
+ res = cache.get(key) |
+ if res is None: |
+ cache[key] = res = search1(path_in_suite) |
+ return res |
+ |
+ return search(path_in_suite) |
+ |
+def getTests(path, litConfig, testSuiteCache, localConfigCache): |
+ # Find the test suite for this input and its relative path. |
+ ts,path_in_suite = getTestSuite(path, litConfig, testSuiteCache) |
+ if ts is None: |
+ litConfig.warning('unable to find test suite for %r' % path) |
+ return (),() |
+ |
+ if litConfig.debug: |
+ litConfig.note('resolved input %r to %r::%r' % (path, ts.name, |
+ path_in_suite)) |
+ |
+ return ts, getTestsInSuite(ts, path_in_suite, litConfig, |
+ testSuiteCache, localConfigCache) |
+ |
+def getTestsInSuite(ts, path_in_suite, litConfig, |
+ testSuiteCache, localConfigCache): |
+ # Check that the source path exists (errors here are reported by the |
+ # caller). |
+ source_path = ts.getSourcePath(path_in_suite) |
+ if not os.path.exists(source_path): |
+ return |
+ |
+ # Check if the user named a test directly. |
+ if not os.path.isdir(source_path): |
+ lc = getLocalConfig(ts, path_in_suite[:-1], litConfig, localConfigCache) |
+ yield Test.Test(ts, path_in_suite, lc) |
+ return |
+ |
+ # Otherwise we have a directory to search for tests, start by getting the |
+ # local configuration. |
+ lc = getLocalConfig(ts, path_in_suite, litConfig, localConfigCache) |
+ |
+ # Search for tests. |
+ if lc.test_format is not None: |
+ for res in lc.test_format.getTestsInDirectory(ts, path_in_suite, |
+ litConfig, lc): |
+ yield res |
+ |
+ # Search subdirectories. |
+ for filename in os.listdir(source_path): |
+ # FIXME: This doesn't belong here? |
+ if filename in ('Output', '.svn', '.git') or filename in lc.excludes: |
+ continue |
+ |
+ # Ignore non-directories. |
+ file_sourcepath = os.path.join(source_path, filename) |
+ if not os.path.isdir(file_sourcepath): |
+ continue |
+ |
+ # Check for nested test suites, first in the execpath in case there is a |
+ # site configuration and then in the source path. |
+ subpath = path_in_suite + (filename,) |
+ file_execpath = ts.getExecPath(subpath) |
+ if dirContainsTestSuite(file_execpath, litConfig): |
+ sub_ts, subpath_in_suite = getTestSuite(file_execpath, litConfig, |
+ testSuiteCache) |
+ elif dirContainsTestSuite(file_sourcepath, litConfig): |
+ sub_ts, subpath_in_suite = getTestSuite(file_sourcepath, litConfig, |
+ testSuiteCache) |
+ else: |
+ sub_ts = None |
+ |
+ # If the this directory recursively maps back to the current test suite, |
+ # disregard it (this can happen if the exec root is located inside the |
+ # current test suite, for example). |
+ if sub_ts is ts: |
+ continue |
+ |
+ # Otherwise, load from the nested test suite, if present. |
+ if sub_ts is not None: |
+ subiter = getTestsInSuite(sub_ts, subpath_in_suite, litConfig, |
+ testSuiteCache, localConfigCache) |
+ else: |
+ subiter = getTestsInSuite(ts, subpath, litConfig, testSuiteCache, |
+ localConfigCache) |
+ |
+ N = 0 |
+ for res in subiter: |
+ N += 1 |
+ yield res |
+ if sub_ts and not N: |
+ litConfig.warning('test suite %r contained no tests' % sub_ts.name) |
+ |
+def find_tests_for_inputs(lit_config, inputs): |
+ """ |
+ find_tests_for_inputs(lit_config, inputs) -> [Test] |
+ |
+ Given a configuration object and a list of input specifiers, find all the |
+ tests to execute. |
+ """ |
+ |
+ # Expand '@...' form in inputs. |
+ actual_inputs = [] |
+ for input in inputs: |
+ if input.startswith('@'): |
+ f = open(input[1:]) |
+ try: |
+ for ln in f: |
+ ln = ln.strip() |
+ if ln: |
+ actual_inputs.append(ln) |
+ finally: |
+ f.close() |
+ else: |
+ actual_inputs.append(input) |
+ |
+ # Load the tests from the inputs. |
+ tests = [] |
+ test_suite_cache = {} |
+ local_config_cache = {} |
+ for input in actual_inputs: |
+ prev = len(tests) |
+ tests.extend(getTests(input, lit_config, |
+ test_suite_cache, local_config_cache)[1]) |
+ if prev == len(tests): |
+ lit_config.warning('input %r contained no tests' % input) |
+ |
+ # If there were any errors during test discovery, exit now. |
+ if lit_config.numErrors: |
+ sys.stderr.write('%d errors, exiting.\n' % lit_config.numErrors) |
+ sys.exit(2) |
+ |
+ return tests |
+ |
+def load_test_suite(inputs): |
+ import platform |
+ import unittest |
+ from lit.LitTestCase import LitTestCase |
+ |
+ # Create the global config object. |
+ litConfig = LitConfig.LitConfig(progname = 'lit', |
+ path = [], |
+ quiet = False, |
+ useValgrind = False, |
+ valgrindLeakCheck = False, |
+ valgrindArgs = [], |
+ noExecute = False, |
+ debug = False, |
+ isWindows = (platform.system()=='Windows'), |
+ params = {}) |
+ |
+ # Perform test discovery. |
+ run = lit.run.Run(litConfig, find_tests_for_inputs(litConfig, inputs)) |
+ |
+ # Return a unittest test suite which just runs the tests in order. |
+ return unittest.TestSuite([LitTestCase(test, run) |
+ for test in run.tests]) |