| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 | 6 |
| 7 import argparse | |
| 8 import glob | 7 import glob |
| 9 import os | 8 import os |
| 10 import subprocess | 9 import subprocess |
| 11 import sys | 10 import sys |
| 12 | 11 |
| 13 | 12 |
| 14 def run_test(test_base_name, cmd, reset_results): | 13 def run_test(test_base_name, cmd): |
| 15 """Run a test case. | 14 """Run a test case. |
| 16 | 15 |
| 17 Args: | 16 Args: |
| 18 test_base_name: The name for the test C++ source file without the extension. | 17 test_base_name: The name for the test C++ source file without the extension. |
| 19 cmd: The actual command to run for the test. | 18 cmd: The actual command to run for the test. |
| 20 reset_results: True if the results should be overwritten in place. | |
| 21 | 19 |
| 22 Returns: | 20 Returns: |
| 23 None on pass, or a str with the description of the failure. | 21 None on pass, or a str with the description of the failure. |
| 24 """ | 22 """ |
| 25 try: | 23 try: |
| 26 actual = subprocess.check_output(cmd, stderr=subprocess.STDOUT) | 24 actual = subprocess.check_output(cmd, stderr=subprocess.STDOUT) |
| 27 except subprocess.CalledProcessError as e: | 25 except subprocess.CalledProcessError as e: |
| 28 # Some of the Blink GC plugin tests intentionally trigger compile errors, so | 26 # Some of the Blink GC plugin tests intentionally trigger compile errors, so |
| 29 # just ignore an exit code that indicates failure. | 27 # just ignore an exit code that indicates failure. |
| 30 actual = e.output | 28 actual = e.output |
| (...skipping 11 matching lines...) Expand all Loading... |
| 42 except subprocess.CalledProcessError, e: | 40 except subprocess.CalledProcessError, e: |
| 43 # The graph processing script returns a failure exit code if the graph is | 41 # 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 | 42 # '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. | 43 # that case, since the expected results capture the errors. |
| 46 actual = e.output | 44 actual = e.output |
| 47 finally: | 45 finally: |
| 48 # Clean up the .graph.json file to prevent false passes from stale results | 46 # Clean up the .graph.json file to prevent false passes from stale results |
| 49 # from a previous run. | 47 # from a previous run. |
| 50 os.remove('%s.graph.json' % test_base_name) | 48 os.remove('%s.graph.json' % test_base_name) |
| 51 | 49 |
| 50 # TODO(dcheng): Remove the rstrip() and just rebaseline the tests to match. |
| 51 actual = actual.rstrip() |
| 52 |
| 52 # On Windows, clang emits CRLF as the end of line marker. Normalize it to LF | 53 # On Windows, clang emits CRLF as the end of line marker. Normalize it to LF |
| 53 # to match posix systems. | 54 # to match posix systems. |
| 54 actual = actual.replace('\r\n', '\n') | 55 actual = actual.replace('\r\n', '\n') |
| 55 | 56 |
| 56 result_file = '%s.txt%s' % ( | |
| 57 test_base_name, '' if reset_results else '.actual') | |
| 58 try: | 57 try: |
| 59 expected = open('%s.txt' % test_base_name).read() | 58 expected = open('%s.txt' % test_base_name).read().rstrip() |
| 60 except IOError: | 59 except IOError: |
| 61 open(result_file, 'w').write(actual) | 60 open('%s.txt.actual' % test_base_name, 'w').write(actual) |
| 62 return 'no expected file found' | 61 return 'no expected file found' |
| 63 | 62 |
| 64 if expected != actual: | 63 if expected != actual: |
| 65 open(result_file, 'w').write(actual) | 64 open('%s.txt.actual' % test_base_name, 'w').write(actual) |
| 66 return 'expected and actual differed' | 65 return 'expected and actual differed' |
| 67 | 66 |
| 68 | 67 |
| 69 def run_tests(clang_path, plugin_path, reset_results): | 68 def run_tests(clang_path, plugin_path): |
| 70 """Runs the tests. | 69 """Runs the tests. |
| 71 | 70 |
| 72 Args: | 71 Args: |
| 73 clang_path: The path to the clang binary to be tested. | 72 clang_path: The path to the clang binary to be tested. |
| 74 plugin_path: An optional path to the plugin to test. This may be None, if | 73 plugin_path: An optional path to the plugin to test. This may be None, if |
| 75 plugin is built directly into clang, like on Windows. | 74 plugin is built directly into clang, like on Windows. |
| 76 reset_results: True if the results should be overwritten in place. | |
| 77 | 75 |
| 78 Returns: | 76 Returns: |
| 79 (passing, failing): Two lists containing the base names of the passing and | 77 (passing, failing): Two lists containing the base names of the passing and |
| 80 failing tests respectively. | 78 failing tests respectively. |
| 81 """ | 79 """ |
| 82 passing = [] | 80 passing = [] |
| 83 failing = [] | 81 failing = [] |
| 84 | 82 |
| 85 # The plugin option to dump the object graph is incompatible with | 83 # The plugin option to dump the object graph is incompatible with |
| 86 # -fsyntax-only. It generates the .graph.json file based on the name of the | 84 # -fsyntax-only. It generates the .graph.json file based on the name of the |
| 87 # output file, but there is no output filename with -fsyntax-only. | 85 # output file, but there is no output filename with -fsyntax-only. |
| 88 base_cmd = [clang_path, '-c', '-std=c++11'] | 86 base_cmd = [clang_path, '-c', '-std=c++11'] |
| 89 base_cmd.extend(['-Wno-inaccessible-base']) | 87 base_cmd.extend(['-Wno-inaccessible-base']) |
| 90 if plugin_path: | 88 if plugin_path: |
| 91 base_cmd.extend(['-Xclang', '-load', '-Xclang', plugin_path]) | 89 base_cmd.extend(['-Xclang', '-load', '-Xclang', plugin_path]) |
| 92 base_cmd.extend(['-Xclang', '-add-plugin', '-Xclang', 'blink-gc-plugin']) | 90 base_cmd.extend(['-Xclang', '-add-plugin', '-Xclang', 'blink-gc-plugin']) |
| 93 | 91 |
| 94 tests = glob.glob('*.cpp') | 92 tests = glob.glob('*.cpp') |
| 95 for test in tests: | 93 for test in tests: |
| 96 sys.stdout.write('Testing %s... ' % test) | 94 sys.stdout.write('Testing %s... ' % test) |
| 97 test_base_name, _ = os.path.splitext(test) | 95 test_base_name, _ = os.path.splitext(test) |
| 98 | 96 |
| 99 cmd = base_cmd[:] | 97 cmd = base_cmd[:] |
| 100 try: | 98 try: |
| 101 cmd.extend(file('%s.flags' % test_base_name).read().split()) | 99 cmd.extend(file('%s.flags' % test_base_name).read().split()) |
| 102 except IOError: | 100 except IOError: |
| 103 pass | 101 pass |
| 104 cmd.append(test) | 102 cmd.append(test) |
| 105 | 103 |
| 106 failure_message = run_test(test_base_name, cmd, reset_results) | 104 failure_message = run_test(test_base_name, cmd) |
| 107 if failure_message: | 105 if failure_message: |
| 108 print 'failed: %s' % failure_message | 106 print 'failed: %s' % failure_message |
| 109 failing.append(test_base_name) | 107 failing.append(test_base_name) |
| 110 else: | 108 else: |
| 111 print 'passed!' | 109 print 'passed!' |
| 112 passing.append(test_base_name) | 110 passing.append(test_base_name) |
| 113 | 111 |
| 114 return passing, failing | 112 return passing, failing |
| 115 | 113 |
| 116 | 114 |
| 117 def main(): | 115 def main(): |
| 118 parser = argparse.ArgumentParser() | 116 if len(sys.argv) < 2: |
| 119 parser.add_argument( | 117 print 'Usage: <path to clang>[ <path to plugin>]' |
| 120 '--reset-results', action='store_true', | 118 return -1 |
| 121 help='If specified, overwrites the expected results in place.') | |
| 122 parser.add_argument('clang_path', help='The path to the clang binary.') | |
| 123 parser.add_argument('plugin_path', nargs='?', | |
| 124 help='The path to the plugin library, if any.') | |
| 125 args = parser.parse_args() | |
| 126 | 119 |
| 127 os.chdir(os.path.dirname(os.path.realpath(__file__))) | 120 os.chdir(os.path.dirname(os.path.realpath(__file__))) |
| 128 | 121 |
| 129 print 'Using clang %s...' % args.clang_path | 122 clang_path = sys.argv[1] |
| 130 print 'Using plugin %s...' % args.plugin_path | 123 plugin_path = sys.argv[2] if len(sys.argv) > 2 else None |
| 124 print 'Using clang %s...' % clang_path |
| 125 print 'Using plugin %s...' % plugin_path |
| 131 | 126 |
| 132 passing, failing = run_tests(args.clang_path, | 127 passing, failing = run_tests(clang_path, plugin_path) |
| 133 args.plugin_path, | |
| 134 args.reset_results) | |
| 135 print 'Ran %d tests: %d succeeded, %d failed' % ( | 128 print 'Ran %d tests: %d succeeded, %d failed' % ( |
| 136 len(passing) + len(failing), len(passing), len(failing)) | 129 len(passing) + len(failing), len(passing), len(failing)) |
| 137 for test in failing: | 130 for test in failing: |
| 138 print ' %s' % test | 131 print ' %s' % test |
| 139 return len(failing) | 132 return len(failing) |
| 140 | 133 |
| 141 | 134 |
| 142 if __name__ == '__main__': | 135 if __name__ == '__main__': |
| 143 sys.exit(main()) | 136 sys.exit(main()) |
| OLD | NEW |