| OLD | NEW |
| 1 # Copyright (C) 2011 Google Inc. All rights reserved. | 1 # Copyright (C) 2011 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions | 4 # modification, are permitted provided that the following conditions |
| 5 # are met: | 5 # are met: |
| 6 # 1. Redistributions of source code must retain the above copyright | 6 # 1. Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. | 7 # notice, this list of conditions and the following disclaimer. |
| 8 # 2. Redistributions in binary form must reproduce the above copyright | 8 # 2. Redistributions in binary form must reproduce the above copyright |
| 9 # notice, this list of conditions and the following disclaimer in the | 9 # notice, this list of conditions and the following disclaimer in the |
| 10 # documentation and/or other materials provided with the distribution. | 10 # documentation and/or other materials provided with the distribution. |
| 11 # | 11 # |
| 12 # THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 12 # THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| 13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| 16 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 16 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 17 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 17 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 18 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 18 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 19 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 19 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 20 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 20 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 21 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 # | 23 # |
| 24 | 24 |
| 25 import fnmatch | 25 import fnmatch |
| 26 import os | 26 import os |
| 27 import cPickle as pickle | |
| 28 import shutil | 27 import shutil |
| 28 import sys |
| 29 import tempfile | 29 import tempfile |
| 30 | 30 |
| 31 from webkitpy.common.checkout.scm.detection import detect_scm_system | 31 from webkitpy.common.checkout.scm.detection import detect_scm_system |
| 32 from webkitpy.common.system import executive | 32 from webkitpy.common.system import executive |
| 33 from webkitpy.common.system.executive import ScriptError | 33 from webkitpy.common.system.executive import ScriptError |
| 34 | 34 |
| 35 # Add Source path to PYTHONPATH to support function calls to bindings/scripts |
| 36 # for compute_interfaces_info and idl_compiler |
| 37 module_path = os.path.dirname(__file__) |
| 38 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir, |
| 39 os.pardir, os.pardir, 'Source')) |
| 40 sys.path.append(source_path) |
| 41 |
| 42 from bindings.scripts.compute_interfaces_info import compute_interfaces_info, in
terfaces_info |
| 43 from bindings.scripts.idl_compiler import IdlCompilerV8 |
| 44 |
| 45 |
| 35 PASS_MESSAGE = 'All tests PASS!' | 46 PASS_MESSAGE = 'All tests PASS!' |
| 36 FAIL_MESSAGE = """Some tests FAIL! | 47 FAIL_MESSAGE = """Some tests FAIL! |
| 37 To update the reference files, execute: | 48 To update the reference files, execute: |
| 38 run-bindings-tests --reset-results | 49 run-bindings-tests --reset-results |
| 39 | 50 |
| 40 If the failures are not due to your changes, test results may be out of sync; | 51 If the failures are not due to your changes, test results may be out of sync; |
| 41 please rebaseline them in a separate CL, after checking that tests fail in ToT. | 52 please rebaseline them in a separate CL, after checking that tests fail in ToT. |
| 42 In CL, please set: | 53 In CL, please set: |
| 43 NOTRY=true | 54 NOTRY=true |
| 44 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) | 55 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) |
| 45 """ | 56 """ |
| 46 | 57 |
| 47 DEPENDENCY_IDL_FILES = set([ | 58 DEPENDENCY_IDL_FILES = set([ |
| 48 'SupportTestPartialInterface.idl', | 59 'SupportTestPartialInterface.idl', |
| 49 'TestImplements.idl', | 60 'TestImplements.idl', |
| 50 'TestImplements2.idl', | 61 'TestImplements2.idl', |
| 51 'TestImplements3.idl', | 62 'TestImplements3.idl', |
| 52 'TestPartialInterface.idl', | 63 'TestPartialInterface.idl', |
| 53 'TestPartialInterfacePython.idl', | 64 'TestPartialInterfacePython.idl', |
| 54 'TestPartialInterfacePython2.idl', | 65 'TestPartialInterfacePython2.idl', |
| 55 ]) | 66 ]) |
| 56 | 67 |
| 68 |
| 69 EXTENDED_ATTRIBUTES_FILE = 'bindings/IDLExtendedAttributes.txt' |
| 70 |
| 57 all_input_directory = '.' # Relative to Source/ | 71 all_input_directory = '.' # Relative to Source/ |
| 58 test_input_directory = os.path.join('bindings', 'tests', 'idls') | 72 test_input_directory = os.path.join('bindings', 'tests', 'idls') |
| 59 reference_directory = os.path.join('bindings', 'tests', 'results') | 73 reference_directory = os.path.join('bindings', 'tests', 'results') |
| 60 | 74 |
| 61 | 75 |
| 62 class ScopedTempFileProvider(object): | 76 class ScopedTempFileProvider(object): |
| 63 def __init__(self): | 77 def __init__(self): |
| 64 self.file_handles = [] | 78 self.file_handles = [] |
| 65 self.file_paths = [] | 79 self.file_paths = [] |
| 66 self.dir_paths = [] | 80 self.dir_paths = [] |
| (...skipping 22 matching lines...) Expand all Loading... |
| 89 self.dir_paths.append(dir_path) | 103 self.dir_paths.append(dir_path) |
| 90 return dir_path | 104 return dir_path |
| 91 | 105 |
| 92 | 106 |
| 93 class BindingsTests(object): | 107 class BindingsTests(object): |
| 94 def __init__(self, reset_results, verbose, provider): | 108 def __init__(self, reset_results, verbose, provider): |
| 95 self.reset_results = reset_results | 109 self.reset_results = reset_results |
| 96 self.verbose = verbose | 110 self.verbose = verbose |
| 97 self.executive = executive.Executive() | 111 self.executive = executive.Executive() |
| 98 self.provider = provider | 112 self.provider = provider |
| 99 _, self.interfaces_info_filename = provider.new_temp_file() | 113 self.idl_compiler = None |
| 100 # Generate output into the reference directory if resetting results, or | 114 # Generate output into the reference directory if resetting results, or |
| 101 # a temp directory if not. | 115 # a temp directory if not. |
| 102 if reset_results: | 116 if reset_results: |
| 103 self.output_directory = reference_directory | 117 self.output_directory = reference_directory |
| 104 else: | 118 else: |
| 105 self.output_directory = provider.new_temp_dir() | 119 self.output_directory = provider.new_temp_dir() |
| 106 | 120 |
| 107 def run_command(self, cmd): | 121 def run_command(self, cmd): |
| 108 output = self.executive.run_command(cmd) | 122 output = self.executive.run_command(cmd) |
| 109 if output: | 123 if output: |
| 110 print output | 124 print output |
| 111 | 125 |
| 112 def generate_from_idl(self, idl_file): | 126 def generate_from_idl(self, idl_file): |
| 113 cmd = ['python', | 127 idl_file_fullpath = os.path.realpath(idl_file) |
| 114 'bindings/scripts/idl_compiler.py', | |
| 115 '--output-dir', self.output_directory, | |
| 116 '--idl-attributes-file', 'bindings/IDLExtendedAttributes.txt', | |
| 117 '--interfaces-info-file', self.interfaces_info_filename, | |
| 118 idl_file] | |
| 119 try: | 128 try: |
| 120 self.run_command(cmd) | 129 self.idl_compiler.compile_file(idl_file_fullpath) |
| 121 except ScriptError, e: | 130 except Exception as err: |
| 122 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) | 131 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) |
| 123 print e.output | 132 print err |
| 124 return e.exit_code | 133 return 1 |
| 134 |
| 125 return 0 | 135 return 0 |
| 126 | 136 |
| 127 def generate_interface_dependencies(self): | 137 def generate_interface_dependencies(self): |
| 128 def idl_paths(directory): | 138 def idl_paths(directory): |
| 129 return [os.path.join(directory, input_file) | 139 return [os.path.join(directory, input_file) |
| 130 for input_file in os.listdir(directory) | 140 for input_file in os.listdir(directory) |
| 131 if input_file.endswith('.idl')] | 141 if input_file.endswith('.idl')] |
| 132 | 142 |
| 133 def idl_paths_recursive(directory): | 143 def idl_paths_recursive(directory): |
| 134 idl_paths = [] | 144 idl_paths = [] |
| 135 for dirpath, _, files in os.walk(directory): | 145 for dirpath, _, files in os.walk(directory): |
| 136 idl_paths.extend(os.path.join(dirpath, filename) | 146 idl_paths.extend(os.path.join(dirpath, filename) |
| 137 for filename in fnmatch.filter(files, '*.idl')) | 147 for filename in fnmatch.filter(files, '*.idl')) |
| 138 return idl_paths | 148 return idl_paths |
| 139 | 149 |
| 140 def write_list_file(idl_paths): | 150 def write_list_file(idl_paths): |
| 141 list_file, list_filename = self.provider.new_temp_file() | 151 list_file, list_filename = self.provider.new_temp_file() |
| 142 list_contents = ''.join(idl_path + '\n' | 152 list_contents = ''.join(idl_path + '\n' |
| 143 for idl_path in idl_paths) | 153 for idl_path in idl_paths) |
| 144 os.write(list_file, list_contents) | 154 os.write(list_file, list_contents) |
| 145 return list_filename | 155 return list_filename |
| 146 | 156 |
| 147 def compute_interfaces_info(idl_files_list_filename): | |
| 148 cmd = ['python', | |
| 149 'bindings/scripts/compute_interfaces_info.py', | |
| 150 '--idl-files-list', idl_files_list_filename, | |
| 151 '--interfaces-info-file', self.interfaces_info_filename, | |
| 152 '--write-file-only-if-changed', '0'] | |
| 153 self.run_command(cmd) | |
| 154 | |
| 155 # We compute interfaces info for *all* IDL files, not just test IDL | 157 # We compute interfaces info for *all* IDL files, not just test IDL |
| 156 # files, as code generator output depends on inheritance (both ancestor | 158 # files, as code generator output depends on inheritance (both ancestor |
| 157 # chain and inherited extended attributes), and some real interfaces | 159 # chain and inherited extended attributes), and some real interfaces |
| 158 # are special-cased, such as Node. | 160 # are special-cased, such as Node. |
| 159 # | 161 # |
| 160 # For example, when testing the behavior of interfaces that inherit | 162 # For example, when testing the behavior of interfaces that inherit |
| 161 # from Node, we also need to know that these inherit from EventTarget, | 163 # from Node, we also need to know that these inherit from EventTarget, |
| 162 # since this is also special-cased and Node inherits from EventTarget, | 164 # since this is also special-cased and Node inherits from EventTarget, |
| 163 # but this inheritance information requires computing dependencies for | 165 # but this inheritance information requires computing dependencies for |
| 164 # the real Node.idl file. | 166 # the real Node.idl file. |
| 165 all_idl_files_list_filename = write_list_file(idl_paths_recursive(all_in
put_directory)) | |
| 166 try: | 167 try: |
| 167 compute_interfaces_info(all_idl_files_list_filename) | 168 compute_interfaces_info(idl_paths_recursive(all_input_directory)) |
| 168 except ScriptError, e: | 169 except Exception as err: |
| 169 print 'ERROR: compute_interfaces_info.py' | 170 print 'ERROR: compute_interfaces_info.py' |
| 170 print e.output | 171 print err |
| 171 return e.exit_code | 172 return 1 |
| 173 |
| 172 return 0 | 174 return 0 |
| 173 | 175 |
| 174 def delete_cache_files(self): | 176 def delete_cache_files(self): |
| 175 # FIXME: Instead of deleting cache files, don't generate them. | 177 # FIXME: Instead of deleting cache files, don't generate them. |
| 176 cache_files = [os.path.join(self.output_directory, output_file) | 178 cache_files = [os.path.join(self.output_directory, output_file) |
| 177 for output_file in os.listdir(self.output_directory) | 179 for output_file in os.listdir(self.output_directory) |
| 178 if (output_file in ('lextab.py', # PLY lex | 180 if (output_file in ('lextab.py', # PLY lex |
| 179 'lextab.pyc', | 181 'lextab.pyc', |
| 180 'parsetab.pickle') or # PLY yacc | 182 'parsetab.pickle') or # PLY yacc |
| 181 output_file.endswith('.cache'))] # Jinja | 183 output_file.endswith('.cache'))] # Jinja |
| 182 for cache_file in cache_files: | 184 for cache_file in cache_files: |
| 183 os.remove(cache_file) | 185 os.remove(cache_file) |
| 184 | 186 |
| 185 def identical_file(self, reference_filename, output_filename): | 187 def identical_file(self, reference_filename, output_filename): |
| 186 reference_basename = os.path.basename(reference_filename) | 188 reference_basename = os.path.basename(reference_filename) |
| 187 cmd = ['diff', | 189 cmd = ['diff', |
| 188 '-u', | 190 '-u', |
| 189 '-N', | 191 '-N', |
| 190 reference_filename, | 192 reference_filename, |
| 191 output_filename] | 193 output_filename] |
| 192 try: | 194 try: |
| 193 self.run_command(cmd) | 195 self.run_command(cmd) |
| 194 except ScriptError, e: | 196 except ScriptError as err: |
| 195 # run_command throws an exception on diff (b/c non-zero exit code) | 197 # run_command throws an exception on diff (b/c non-zero exit code) |
| 196 print 'FAIL: %s' % reference_basename | 198 print 'FAIL: %s' % reference_basename |
| 197 print e.output | 199 print err.output |
| 198 return False | 200 return False |
| 199 | 201 |
| 200 if self.verbose: | 202 if self.verbose: |
| 201 print 'PASS: %s' % reference_basename | 203 print 'PASS: %s' % reference_basename |
| 202 return True | 204 return True |
| 203 | 205 |
| 204 def identical_output_files(self): | 206 def identical_output_files(self): |
| 205 file_pairs = [(os.path.join(reference_directory, output_file), | 207 file_pairs = [(os.path.join(reference_directory, output_file), |
| 206 os.path.join(self.output_directory, output_file)) | 208 os.path.join(self.output_directory, output_file)) |
| 207 for output_file in os.listdir(self.output_directory)] | 209 for output_file in os.listdir(self.output_directory)] |
| (...skipping 11 matching lines...) Expand all Loading... |
| 219 '(probably cruft from renaming or deleting):\n' + | 221 '(probably cruft from renaming or deleting):\n' + |
| 220 '\n'.join(excess_files)) | 222 '\n'.join(excess_files)) |
| 221 return False | 223 return False |
| 222 return True | 224 return True |
| 223 | 225 |
| 224 def run_tests(self): | 226 def run_tests(self): |
| 225 # Generate output, immediately dying on failure | 227 # Generate output, immediately dying on failure |
| 226 if self.generate_interface_dependencies(): | 228 if self.generate_interface_dependencies(): |
| 227 return False | 229 return False |
| 228 | 230 |
| 231 self.idl_compiler = IdlCompilerV8(self.output_directory, |
| 232 EXTENDED_ATTRIBUTES_FILE, |
| 233 interfaces_info=interfaces_info, |
| 234 only_if_changed=True) |
| 235 |
| 229 for input_filename in os.listdir(test_input_directory): | 236 for input_filename in os.listdir(test_input_directory): |
| 230 if not input_filename.endswith('.idl'): | 237 if not input_filename.endswith('.idl'): |
| 231 continue | 238 continue |
| 232 if input_filename in DEPENDENCY_IDL_FILES: | 239 if input_filename in DEPENDENCY_IDL_FILES: |
| 233 # Dependencies aren't built (they are used by the dependent) | 240 # Dependencies aren't built (they are used by the dependent) |
| 234 if self.verbose: | 241 if self.verbose: |
| 235 print 'DEPENDENCY: %s' % input_filename | 242 print 'DEPENDENCY: %s' % input_filename |
| 236 continue | 243 continue |
| 237 | 244 |
| 238 idl_path = os.path.join(test_input_directory, input_filename) | 245 idl_path = os.path.join(test_input_directory, input_filename) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 253 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) | 260 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) |
| 254 | 261 |
| 255 all_tests_passed = self.run_tests() | 262 all_tests_passed = self.run_tests() |
| 256 if all_tests_passed: | 263 if all_tests_passed: |
| 257 if self.verbose: | 264 if self.verbose: |
| 258 print | 265 print |
| 259 print PASS_MESSAGE | 266 print PASS_MESSAGE |
| 260 return 0 | 267 return 0 |
| 261 print | 268 print |
| 262 print FAIL_MESSAGE | 269 print FAIL_MESSAGE |
| 263 return -1 | 270 return 1 |
| 264 | 271 |
| 265 | 272 |
| 266 def run_bindings_tests(reset_results, verbose): | 273 def run_bindings_tests(reset_results, verbose): |
| 267 with ScopedTempFileProvider() as provider: | 274 with ScopedTempFileProvider() as provider: |
| 268 return BindingsTests(reset_results, verbose, provider).main() | 275 return BindingsTests(reset_results, verbose, provider).main() |
| OLD | NEW |