aa454397467d8cd57a7827cadebbc84f5ae0d93e
[platform/framework/web/crosswalk.git] / src / third_party / libc++ / trunk / test / lit.cfg
1 # -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
2
3 # Configuration file for the 'lit' test runner.
4
5 import errno
6 import os
7 import platform
8 import re
9 import shlex
10 import signal
11 import subprocess
12 import sys
13 import tempfile
14 import time
15
16 import lit.Test
17 import lit.formats
18 import lit.util
19
20 class LibcxxTestFormat(lit.formats.FileBasedTest):
21     """
22     Custom test format handler for use with the test format use by libc++.
23
24     Tests fall into two categories:
25       FOO.pass.cpp - Executable test which should compile, run, and exit with
26                      code 0.
27       FOO.fail.cpp - Negative test case which is expected to fail compilation.
28     """
29
30     def __init__(self, cxx_under_test, cpp_flags, ld_flags, exec_env):
31         self.cxx_under_test = cxx_under_test
32         self.cpp_flags = list(cpp_flags)
33         self.ld_flags = list(ld_flags)
34         self.exec_env = dict(exec_env)
35
36     def execute_command(self, command, in_dir=None):
37         kwargs = {
38             'stdin' :subprocess.PIPE,
39             'stdout':subprocess.PIPE,
40             'stderr':subprocess.PIPE,
41         }
42         if in_dir:
43             kwargs['cwd'] = in_dir
44         p = subprocess.Popen(command, **kwargs)
45         out,err = p.communicate()
46         exitCode = p.wait()
47
48         # Detect Ctrl-C in subprocess.
49         if exitCode == -signal.SIGINT:
50             raise KeyboardInterrupt
51
52         return out, err, exitCode
53
54     def execute(self, test, lit_config):
55         while True:
56             try:
57                 return self._execute(test, lit_config)
58             except OSError, oe:
59                 if oe.errno != errno.ETXTBSY:
60                     raise
61                 time.sleep(0.1)
62
63     def _execute(self, test, lit_config):
64         # Extract test metadata from the test file.
65         requires = []
66         with open(test.getSourcePath()) as f:
67             for ln in f:
68                 if 'XFAIL:' in ln:
69                     items = ln[ln.index('XFAIL:') + 6:].split(',')
70                     test.xfails.extend([s.strip() for s in items])
71                 elif 'REQUIRES:' in ln:
72                     items = ln[ln.index('REQUIRES:') + 9:].split(',')
73                     requires.extend([s.strip() for s in items])
74                 elif not ln.startswith("//") and ln.strip():
75                     # Stop at the first non-empty line that is not a C++
76                     # comment.
77                     break
78
79         # Check that we have the required features.
80         #
81         # FIXME: For now, this is cribbed from lit.TestRunner, to avoid
82         # introducing a dependency there. What we more ideally would like to do
83         # is lift the "requires" handling to be a core lit framework feature.
84         missing_required_features = [f for f in requires
85                                      if f not in test.config.available_features]
86         if missing_required_features:
87             return (lit.Test.UNSUPPORTED,
88                     "Test requires the following features: %s" % (
89                       ', '.join(missing_required_features),))
90
91         # Evaluate the test.
92         return self._evaluate_test(test, lit_config)
93
94     def _evaluate_test(self, test, lit_config):
95         name = test.path_in_suite[-1]
96         source_path = test.getSourcePath()
97         source_dir = os.path.dirname(source_path)
98
99         # Check what kind of test this is.
100         assert name.endswith('.pass.cpp') or name.endswith('.fail.cpp')
101         expected_compile_fail = name.endswith('.fail.cpp')
102
103         # If this is a compile (failure) test, build it and check for failure.
104         if expected_compile_fail:
105             cmd = [self.cxx_under_test, '-c',
106                    '-o', '/dev/null', source_path] + self.cpp_flags
107             out, err, exitCode = self.execute_command(cmd)
108             if exitCode == 1:
109                 return lit.Test.PASS, ""
110             else:
111                 report = """Command: %s\n""" % ' '.join(["'%s'" % a
112                                                          for a in cmd])
113                 report += """Exit Code: %d\n""" % exitCode
114                 if out:
115                     report += """Standard Output:\n--\n%s--""" % out
116                 if err:
117                     report += """Standard Error:\n--\n%s--""" % err
118                 report += "\n\nExpected compilation to fail!"
119                 return lit.Test.FAIL, report
120         else:
121             exec_file = tempfile.NamedTemporaryFile(suffix="exe", delete=False)
122             exec_path = exec_file.name
123             exec_file.close()
124
125             try:
126                 compile_cmd = [self.cxx_under_test, '-o', exec_path,
127                        source_path] + self.cpp_flags + self.ld_flags
128                 cmd = compile_cmd
129                 out, err, exitCode = self.execute_command(cmd)
130                 if exitCode != 0:
131                     report = """Command: %s\n""" % ' '.join(["'%s'" % a
132                                                              for a in cmd])
133                     report += """Exit Code: %d\n""" % exitCode
134                     if out:
135                         report += """Standard Output:\n--\n%s--""" % out
136                     if err:
137                         report += """Standard Error:\n--\n%s--""" % err
138                     report += "\n\nCompilation failed unexpectedly!"
139                     return lit.Test.FAIL, report
140
141                 cmd = []
142                 if self.exec_env:
143                     cmd.append('env')
144                     cmd.extend('%s=%s' % (name, value)
145                                for name,value in self.exec_env.items())
146                 cmd.append(exec_path)
147                 if lit_config.useValgrind:
148                     cmd = lit_config.valgrindArgs + cmd
149                 out, err, exitCode = self.execute_command(cmd, source_dir)
150                 if exitCode != 0:
151                     report = """Compiled With: %s\n""" % \
152                         ' '.join(["'%s'" % a for a in compile_cmd])
153                     report += """Command: %s\n""" % \
154                         ' '.join(["'%s'" % a for a in cmd])
155                     report += """Exit Code: %d\n""" % exitCode
156                     if out:
157                         report += """Standard Output:\n--\n%s--""" % out
158                     if err:
159                         report += """Standard Error:\n--\n%s--""" % err
160                     report += "\n\nCompiled test failed unexpectedly!"
161                     return lit.Test.FAIL, report
162             finally:
163                 try:
164                     os.remove(exec_path)
165                 except:
166                     pass
167         return lit.Test.PASS, ""
168
169 # name: The name of this test suite.
170 config.name = 'libc++'
171
172 # suffixes: A list of file extensions to treat as test files.
173 config.suffixes = ['.cpp']
174
175 # test_source_root: The root path where tests are located.
176 config.test_source_root = os.path.dirname(__file__)
177
178 # Gather various compiler parameters.
179 cxx_under_test = lit_config.params.get('cxx_under_test', None)
180 if cxx_under_test is None:
181     cxx_under_test = getattr(config, 'cxx_under_test', None)
182
183     # If no specific cxx_under_test was given, attempt to infer it as clang++.
184     clangxx = lit.util.which('clang++', config.environment['PATH'])
185     if clangxx is not None:
186         cxx_under_test = clangxx
187         lit_config.note("inferred cxx_under_test as: %r" % (cxx_under_test,))
188 if cxx_under_test is None:
189     lit_config.fatal('must specify user parameter cxx_under_test '
190                      '(e.g., --param=cxx_under_test=clang++)')
191
192 libcxx_src_root = lit_config.params.get('libcxx_src_root', None)
193 if libcxx_src_root is None:
194     libcxx_src_root = getattr(config, 'libcxx_src_root', None)
195     if libcxx_src_root is None:
196         libcxx_src_root = os.path.dirname(config.test_source_root)
197
198 libcxx_obj_root = lit_config.params.get('libcxx_obj_root', None)
199 if libcxx_obj_root is None:
200     libcxx_obj_root = getattr(config, 'libcxx_obj_root', None)
201     if libcxx_obj_root is None:
202         libcxx_obj_root = libcxx_src_root
203
204 cxx_has_stdcxx0x_flag_str = lit_config.params.get('cxx_has_stdcxx0x_flag', None)
205 if cxx_has_stdcxx0x_flag_str is not None:
206     if cxx_has_stdcxx0x_flag_str.lower() in ('1', 'true'):
207         cxx_has_stdcxx0x_flag = True
208     elif cxx_has_stdcxx0x_flag_str.lower() in ('', '0', 'false'):
209         cxx_has_stdcxx0x_flag = False
210     else:
211         lit_config.fatal(
212             'user parameter cxx_has_stdcxx0x_flag_str should be 0 or 1')
213 else:
214     cxx_has_stdcxx0x_flag = getattr(config, 'cxx_has_stdcxx0x_flag', True)
215
216 # This test suite supports testing against either the system library or the
217 # locally built one; the former mode is useful for testing ABI compatibility
218 # between the current headers and a shipping dynamic library.
219 use_system_lib_str = lit_config.params.get('use_system_lib', None)
220 if use_system_lib_str is not None:
221     if use_system_lib_str.lower() in ('1', 'true'):
222         use_system_lib = True
223     elif use_system_lib_str.lower() in ('', '0', 'false'):
224         use_system_lib = False
225     else:
226         lit_config.fatal('user parameter use_system_lib should be 0 or 1')
227 else:
228     # Default to testing against the locally built libc++ library.
229     use_system_lib = False
230     lit_config.note("inferred use_system_lib as: %r" % (use_system_lib,))
231
232 link_flags = []
233 link_flags_str = lit_config.params.get('link_flags', None)
234 if link_flags_str is None:
235     link_flags_str = getattr(config, 'link_flags', None)
236     if link_flags_str is None:
237       cxx_abi = getattr(config, 'cxx_abi', 'libcxxabi')
238       if cxx_abi == 'libstdc++':
239         link_flags += ['-lstdc++']
240       elif cxx_abi == 'libsupc++':
241         link_flags += ['-lsupc++']
242       elif cxx_abi == 'libcxxabi':
243         link_flags += ['-lc++abi']
244       elif cxx_abi == 'none':
245         pass
246       else:
247         lit_config.fatal('C++ ABI setting %s unsupported for tests' % cxx_abi)
248
249       if sys.platform == 'darwin':
250         link_flags += ['-lSystem']
251       elif sys.platform == 'linux2':
252         link_flags += [ '-lgcc_eh', '-lc', '-lm', '-lpthread',
253               '-lrt', '-lgcc_s']
254       else:
255         lit_config.fatal("unrecognized system")
256
257       lit_config.note("inferred link_flags as: %r" % (link_flags,))
258 if not link_flags_str is None:
259     link_flags += shlex.split(link_flags_str)
260
261 # Configure extra compiler flags.
262 include_paths = ['-I' + libcxx_src_root + '/include',
263     '-I' + libcxx_src_root + '/test/support']
264 library_paths = ['-L' + libcxx_obj_root + '/lib']
265 compile_flags = []
266 if cxx_has_stdcxx0x_flag:
267     compile_flags += ['-std=c++0x']
268
269 # Configure extra linker parameters.
270 exec_env = {}
271 if sys.platform == 'darwin':
272     if not use_system_lib:
273         exec_env['DYLD_LIBRARY_PATH'] = os.path.join(libcxx_obj_root, 'lib')
274 elif sys.platform == 'linux2':
275     if not use_system_lib:
276         link_flags += ['-Wl,-R', libcxx_obj_root + '/lib']
277     compile_flags += ['-D__STDC_FORMAT_MACROS', '-D__STDC_LIMIT_MACROS',
278         '-D__STDC_CONSTANT_MACROS']
279 else:
280     lit_config.fatal("unrecognized system")
281
282 config.test_format = LibcxxTestFormat(
283     cxx_under_test,
284     cpp_flags = ['-nostdinc++'] + compile_flags + include_paths,
285     ld_flags = ['-nodefaultlibs'] + library_paths + ['-lc++'] + link_flags,
286     exec_env = exec_env)
287
288 # Get or infer the target triple.
289 config.target_triple = lit_config.params.get('target_triple', None)
290 # If no target triple was given, try to infer it from the compiler under test.
291 if config.target_triple is None:
292     config.target_triple = lit.util.capture(
293         [cxx_under_test, '-dumpmachine']).strip()
294     lit_config.note("inferred target_triple as: %r" % (config.target_triple,))
295
296 # Write an "available feature" that combines the triple when use_system_lib is
297 # enabled. This is so that we can easily write XFAIL markers for tests that are
298 # known to fail with versions of libc++ as were shipped with a particular
299 # triple.
300 if use_system_lib:
301     # Drop sub-major version components from the triple, because the current
302     # XFAIL handling expects exact matches for feature checks.
303     sanitized_triple = re.sub(r"([^-]+)-([^-]+)-([^-.]+).*", r"\1-\2-\3",
304                               config.target_triple)
305     config.available_features.add('with_system_lib=%s' % (sanitized_triple,))