Roll src/third_party/WebKit d10c917:a1123a1 (svn 198729:198730)
[chromium-blink-merge.git] / tools / clang / blink_gc_plugin / tests / test.py
blob91ae684bc1776e482904ca78c9b95d6506429558
1 #!/usr/bin/env python
2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
7 import argparse
8 import glob
9 import os
10 import subprocess
11 import sys
14 def run_test(test_base_name, cmd, reset_results):
15 """Run a test case.
17 Args:
18 test_base_name: The name for the test C++ source file without the extension.
19 cmd: The actual command to run for the test.
20 reset_results: True if the results should be overwritten in place.
22 Returns:
23 None on pass, or a str with the description of the failure.
24 """
25 try:
26 actual = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
27 except subprocess.CalledProcessError as e:
28 # Some of the Blink GC plugin tests intentionally trigger compile errors, so
29 # just ignore an exit code that indicates failure.
30 actual = e.output
31 except Exception as e:
32 return 'could not execute %s (%s)' % (cmd, e)
34 # Some Blink GC plugins dump a JSON representation of the object graph, and
35 # use the processed results as the actual results of the test.
36 if os.path.exists('%s.graph.json' % test_base_name):
37 try:
38 actual = subprocess.check_output(
39 ['python', '../process-graph.py', '-c',
40 '%s.graph.json' % test_base_name],
41 stderr=subprocess.STDOUT)
42 except subprocess.CalledProcessError, e:
43 # The graph processing script returns a failure exit code if the graph is
44 # 'bad' (e.g. it has a cycle). The output still needs to be captured in
45 # that case, since the expected results capture the errors.
46 actual = e.output
47 finally:
48 # Clean up the .graph.json file to prevent false passes from stale results
49 # from a previous run.
50 os.remove('%s.graph.json' % test_base_name)
52 # On Windows, clang emits CRLF as the end of line marker. Normalize it to LF
53 # to match posix systems.
54 actual = actual.replace('\r\n', '\n')
56 result_file = '%s.txt%s' % (
57 test_base_name, '' if reset_results else '.actual')
58 try:
59 expected = open('%s.txt' % test_base_name).read()
60 except IOError:
61 open(result_file, 'w').write(actual)
62 return 'no expected file found'
64 if expected != actual:
65 open(result_file, 'w').write(actual)
66 error = 'expected and actual differed\n'
67 error += 'Actual:\n' + actual
68 error += 'Expected:\n' + expected
69 return error
72 def run_tests(clang_path, plugin_path, reset_results):
73 """Runs the tests.
75 Args:
76 clang_path: The path to the clang binary to be tested.
77 plugin_path: An optional path to the plugin to test. This may be None, if
78 plugin is built directly into clang, like on Windows.
79 reset_results: True if the results should be overwritten in place.
81 Returns:
82 (passing, failing): Two lists containing the base names of the passing and
83 failing tests respectively.
84 """
85 passing = []
86 failing = []
88 # The plugin option to dump the object graph is incompatible with
89 # -fsyntax-only. It generates the .graph.json file based on the name of the
90 # output file, but there is no output filename with -fsyntax-only.
91 base_cmd = [clang_path, '-c', '-std=c++11']
92 base_cmd.extend(['-Wno-inaccessible-base'])
93 if plugin_path:
94 base_cmd.extend(['-Xclang', '-load', '-Xclang', plugin_path])
95 base_cmd.extend(['-Xclang', '-add-plugin', '-Xclang', 'blink-gc-plugin'])
97 tests = glob.glob('*.cpp')
98 for test in tests:
99 sys.stdout.write('Testing %s... ' % test)
100 test_base_name, _ = os.path.splitext(test)
102 cmd = base_cmd[:]
103 try:
104 cmd.extend(file('%s.flags' % test_base_name).read().split())
105 except IOError:
106 pass
107 cmd.append(test)
109 failure_message = run_test(test_base_name, cmd, reset_results)
110 if failure_message:
111 print 'failed: %s' % failure_message
112 failing.append(test_base_name)
113 else:
114 print 'passed!'
115 passing.append(test_base_name)
117 return passing, failing
120 def main():
121 parser = argparse.ArgumentParser()
122 parser.add_argument(
123 '--reset-results', action='store_true',
124 help='If specified, overwrites the expected results in place.')
125 parser.add_argument('clang_path', help='The path to the clang binary.')
126 parser.add_argument('plugin_path', nargs='?',
127 help='The path to the plugin library, if any.')
128 args = parser.parse_args()
130 os.chdir(os.path.dirname(os.path.realpath(__file__)))
132 print 'Using clang %s...' % args.clang_path
133 print 'Using plugin %s...' % args.plugin_path
135 passing, failing = run_tests(args.clang_path,
136 args.plugin_path,
137 args.reset_results)
138 print 'Ran %d tests: %d succeeded, %d failed' % (
139 len(passing) + len(failing), len(passing), len(failing))
140 for test in failing:
141 print ' %s' % test
142 return len(failing)
145 if __name__ == '__main__':
146 sys.exit(main())