OSDN Git Service

am 1a961143: (-s ours) Reconcile with jb-mr2-release - do not merge
[android-x86/external-llvm.git] / utils / lit / lit / discovery.py
1 """
2 Test discovery functions.
3 """
4
5 import os
6 import sys
7
8 from lit.TestingConfig import TestingConfig
9 from lit import LitConfig, Test
10
11 def 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
19 def 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
73 def 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
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)
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
113 def 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
182 def 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         print >>sys.stderr, '%d errors, exiting.' % lit_config.numErrors
219         sys.exit(2)
220
221     return tests
222
223 def 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                                     ignoreStdErr = False,
237                                     debug = False,
238                                     isWindows = (platform.system()=='Windows'),
239                                     params = {})
240
241     tests = find_tests_for_inputs(litConfig, inputs)
242
243     # Return a unittest test suite which just runs the tests in order.
244     return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests])
245