OLD | NEW |
(Empty) | |
| 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. |
| 5 |
| 6 |
| 7 import argparse |
| 8 import glob |
| 9 import os |
| 10 import subprocess |
| 11 import sys |
| 12 |
| 13 |
| 14 def run_test(test_base_name, cmd, reset_results): |
| 15 """Run a test case. |
| 16 |
| 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. |
| 21 |
| 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) |
| 33 |
| 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) |
| 51 |
| 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') |
| 55 |
| 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' |
| 63 |
| 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 |
| 70 |
| 71 |
| 72 def run_tests(clang_path, plugin_path, reset_results): |
| 73 """Runs the tests. |
| 74 |
| 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. |
| 80 |
| 81 Returns: |
| 82 (passing, failing): Two lists containing the base names of the passing and |
| 83 failing tests respectively. |
| 84 """ |
| 85 passing = [] |
| 86 failing = [] |
| 87 |
| 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']) |
| 96 |
| 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) |
| 101 |
| 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) |
| 108 |
| 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) |
| 116 |
| 117 return passing, failing |
| 118 |
| 119 |
| 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() |
| 129 |
| 130 os.chdir(os.path.dirname(os.path.realpath(__file__))) |
| 131 |
| 132 print 'Using clang %s...' % args.clang_path |
| 133 print 'Using plugin %s...' % args.plugin_path |
| 134 |
| 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) |
| 143 |
| 144 |
| 145 if __name__ == '__main__': |
| 146 sys.exit(main()) |
OLD | NEW |