| 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 from shutil import rmtree | 27 from shutil import rmtree |
| 28 import sys |
| 29 import tempfile | 29 import tempfile |
| 30 from webkitpy.common.checkout.scm.detection import detect_scm_system | 30 from webkitpy.common.checkout.scm.detection import detect_scm_system |
| 31 from webkitpy.common.system.executive import ScriptError | 31 from webkitpy.common.system.executive import ScriptError |
| 32 | 32 |
| 33 # Add Source path to PYTHONPATH to support function calls to bindings/scripts |
| 34 # for compute_dependencies and idl_compiler |
| 35 module_path = os.path.dirname(__file__) |
| 36 source_path = os.path.normpath(os.path.join(module_path, os.pardir, |
| 37 os.pardir, os.pardir, os.pardir, |
| 38 'Source')) |
| 39 sys.path.append(source_path) |
| 40 |
| 41 from bindings.scripts.compute_dependencies import compute |
| 42 from bindings.scripts.unstable.idl_compiler import compile_idl |
| 43 |
| 44 |
| 33 PASS_MESSAGE = 'All tests PASS!' | 45 PASS_MESSAGE = 'All tests PASS!' |
| 34 FAIL_MESSAGE = """Some tests FAIL! | 46 FAIL_MESSAGE = """Some tests FAIL! |
| 35 To update the reference files, execute: | 47 To update the reference files, execute: |
| 36 run-bindings-tests --reset-results | 48 run-bindings-tests --reset-results |
| 37 | 49 |
| 38 If the failures are not due to your changes, test results may be out of sync; | 50 If the failures are not due to your changes, test results may be out of sync; |
| 39 please rebaseline them in a separate CL, after checking that tests fail in ToT. | 51 please rebaseline them in a separate CL, after checking that tests fail in ToT. |
| 40 In CL, please set: | 52 In CL, please set: |
| 41 NOTRY=true | 53 NOTRY=true |
| 42 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) | 54 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) |
| 43 """ | 55 """ |
| 44 | 56 |
| 45 DEPENDENCY_IDL_FILES = set([ | 57 DEPENDENCY_IDL_FILES = set([ |
| 46 'SupportTestPartialInterface.idl', | 58 'SupportTestPartialInterface.idl', |
| 47 'TestImplements.idl', | 59 'TestImplements.idl', |
| 48 'TestImplements2.idl', | 60 'TestImplements2.idl', |
| 49 'TestImplements3.idl', | 61 'TestImplements3.idl', |
| 50 'TestPartialInterface.idl', | 62 'TestPartialInterface.idl', |
| 51 'TestPartialInterfacePython.idl', | 63 'TestPartialInterfacePython.idl', |
| 52 'TestPartialInterfacePython2.idl', | 64 'TestPartialInterfacePython2.idl', |
| 53 ]) | 65 ]) |
| 54 | 66 |
| 55 SKIP_PYTHON = 'TestSVG.idl' # Not implementing SVG-specific hacks in Python | 67 SKIP_PYTHON = 'TestSVG.idl' # Not implementing SVG-specific hacks in Python |
| 56 | 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 reference_event_names_filename = os.path.join(reference_directory, 'EventInterfa
ces.in') | 74 reference_event_names_filename = os.path.join(reference_directory, 'EventInterfa
ces.in') |
| 61 | 75 |
| 62 | 76 |
| 63 class ScopedTempFileProvider(object): | 77 class ScopedTempFileProvider(object): |
| 64 def __init__(self): | 78 def __init__(self): |
| 65 self.files = [] | 79 self.files = [] |
| 66 self.directories = [] | 80 self.directories = [] |
| (...skipping 12 matching lines...) Expand all Loading... |
| 79 def newtempdir(self): | 93 def newtempdir(self): |
| 80 path = tempfile.mkdtemp() | 94 path = tempfile.mkdtemp() |
| 81 self.directories.append(path) | 95 self.directories.append(path) |
| 82 return path | 96 return path |
| 83 | 97 |
| 84 provider = ScopedTempFileProvider() | 98 provider = ScopedTempFileProvider() |
| 85 | 99 |
| 86 | 100 |
| 87 class BindingsTests(object): | 101 class BindingsTests(object): |
| 88 def __init__(self, reset_results, test_python, verbose, executive): | 102 def __init__(self, reset_results, test_python, verbose, executive): |
| 103 self.interfaces_info = {} # in-memory interfaces |
| 89 self.reset_results = reset_results | 104 self.reset_results = reset_results |
| 90 self.test_python = test_python | 105 self.test_python = test_python |
| 91 self.verbose = verbose | 106 self.verbose = verbose |
| 92 self.executive = executive | 107 self.executive = executive |
| 108 self.reader = None |
| 93 _, self.interface_dependencies_filename = provider.newtempfile() | 109 _, self.interface_dependencies_filename = provider.newtempfile() |
| 94 _, self.interfaces_info_filename = provider.newtempfile() | 110 _, self.interfaces_info_filename = provider.newtempfile() |
| 95 # Generate output into the reference directory if resetting results, or | 111 # Generate output into the reference directory if resetting results, or |
| 96 # a temp directory if not. | 112 # a temp directory if not. |
| 97 if reset_results: | 113 if reset_results: |
| 98 self.output_directory = reference_directory | 114 self.output_directory = reference_directory |
| 99 else: | 115 else: |
| 100 self.output_directory = provider.newtempdir() | 116 self.output_directory = provider.newtempdir() |
| 101 self.output_directory_py = provider.newtempdir() | 117 self.output_directory_py = provider.newtempdir() |
| 102 self.event_names_filename = os.path.join(self.output_directory, 'EventIn
terfaces.in') | 118 self.event_names_filename = os.path.join(self.output_directory, 'EventIn
terfaces.in') |
| 103 | 119 |
| 104 def run_command(self, cmd): | 120 def run_command(self, cmd): |
| 105 output = self.executive.run_command(cmd) | 121 output = self.executive.run_command(cmd) |
| 106 if output: | 122 if output: |
| 107 print output | 123 print output |
| 108 | 124 |
| 109 def generate_from_idl_pl(self, idl_file): | 125 def generate_from_idl_pl(self, idl_file): |
| 110 cmd = ['perl', '-w', | 126 cmd = ['perl', '-w', |
| 111 '-Ibindings/scripts', | 127 '-Ibindings/scripts', |
| 112 '-Ibuild/scripts', | 128 '-Ibuild/scripts', |
| 113 '-Icore/scripts', | 129 '-Icore/scripts', |
| 114 '-I../../JSON/out/lib/perl5', | 130 '-I../../JSON/out/lib/perl5', |
| 115 'bindings/scripts/generate_bindings.pl', | 131 'bindings/scripts/generate_bindings.pl', |
| 116 # idl include directories (path relative to generate-bindings.pl) | 132 # idl include directories (path relative to generate-bindings.pl) |
| 117 '--include', '.', | 133 '--include', '.', |
| 118 '--outputDir', self.output_directory, | 134 '--outputDir', self.output_directory, |
| 119 '--interfaceDependenciesFile', self.interface_dependencies_filena
me, | 135 '--interfaceDependenciesFile', self.interface_dependencies_filena
me, |
| 120 '--idlAttributesFile', 'bindings/IDLExtendedAttributes.txt', | 136 '--idlAttributesFile', EXTENDED_ATTRIBUTES_FILE, |
| 121 idl_file] | 137 idl_file] |
| 122 try: | 138 try: |
| 123 self.run_command(cmd) | 139 self.run_command(cmd) |
| 124 except ScriptError, e: | 140 except ScriptError, e: |
| 125 print 'ERROR: generate_bindings.pl: ' + os.path.basename(idl_file) | 141 print 'ERROR: generate_bindings.pl: ' + os.path.basename(idl_file) |
| 126 print e.output | 142 print e.output |
| 127 return e.exit_code | 143 return e.exit_code |
| 128 return 0 | 144 return 0 |
| 129 | 145 |
| 130 def generate_from_idl_py(self, idl_file): | 146 def generate_from_idl_py(self, idl_file): |
| 131 cmd = ['python', | |
| 132 'bindings/scripts/unstable/idl_compiler.py', | |
| 133 '--output-dir', self.output_directory_py, | |
| 134 '--idl-attributes-file', 'bindings/IDLExtendedAttributes.txt', | |
| 135 '--interfaces-info-file', self.interfaces_info_filename, | |
| 136 idl_file] | |
| 137 try: | 147 try: |
| 138 self.run_command(cmd) | 148 idl_file_fullpath = os.path.realpath(idl_file) |
| 149 self.reader = compile_idl(idl_file_fullpath, |
| 150 self.output_directory_py, |
| 151 EXTENDED_ATTRIBUTES_FILE, |
| 152 self.interfaces_info, self.reader) |
| 139 except ScriptError, e: | 153 except ScriptError, e: |
| 140 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) | 154 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) |
| 141 print e.output | 155 print e.output |
| 142 return e.exit_code | 156 return e.exit_code |
| 157 |
| 143 return 0 | 158 return 0 |
| 144 | 159 |
| 145 def generate_interface_dependencies(self): | 160 def generate_interface_dependencies(self): |
| 146 def idl_paths(directory): | 161 def idl_paths(directory): |
| 147 return [os.path.join(directory, input_file) | 162 return [os.path.join(directory, input_file) |
| 148 for input_file in os.listdir(directory) | 163 for input_file in os.listdir(directory) |
| 149 if input_file.endswith('.idl')] | 164 if input_file.endswith('.idl')] |
| 150 | 165 |
| 151 def idl_paths_recursive(directory): | 166 def idl_paths_recursive(directory): |
| 152 idl_paths = [] | 167 idl_paths = [] |
| 153 for dirpath, _, files in os.walk(directory): | 168 for dirpath, _, files in os.walk(directory): |
| 154 idl_paths.extend(os.path.join(dirpath, filename) | 169 idl_paths.extend(os.path.join(dirpath, filename) |
| 155 for filename in fnmatch.filter(files, '*.idl')) | 170 for filename in fnmatch.filter(files, '*.idl')) |
| 156 return idl_paths | 171 return idl_paths |
| 157 | 172 |
| 158 def write_list_file(idl_paths): | 173 def write_list_file(idl_paths): |
| 159 list_file, list_filename = provider.newtempfile() | 174 list_file, list_filename = provider.newtempfile() |
| 160 list_contents = ''.join(idl_path + '\n' | 175 list_contents = ''.join(idl_path + '\n' |
| 161 for idl_path in idl_paths) | 176 for idl_path in idl_paths) |
| 162 os.write(list_file, list_contents) | 177 os.write(list_file, list_contents) |
| 163 return list_filename | 178 return list_filename |
| 164 | 179 |
| 165 def compute_dependencies(idl_files_list_filename, | 180 # Faster in-memory file list. |
| 166 event_names_filename): | 181 def list_idl_file(idl_paths): |
| 182 idls = [] |
| 183 for idl_path in idl_paths: |
| 184 idls.append(idl_path) |
| 185 return idls |
| 186 |
| 187 def compute_dependencies(idl_files_list, event_names_filename, pickle_na
me): |
| 167 # Dummy files, required by compute_dependencies but not checked | 188 # Dummy files, required by compute_dependencies but not checked |
| 168 _, window_constructors_file = provider.newtempfile() | 189 _, window_constructors_file = provider.newtempfile() |
| 169 _, workerglobalscope_constructors_file = provider.newtempfile() | 190 _, workerglobalscope_constructors_file = provider.newtempfile() |
| 170 _, sharedworkerglobalscope_constructors_file = provider.newtempfile(
) | 191 _, sharedworkerglobalscope_constructors_file = provider.newtempfile(
) |
| 171 _, dedicatedworkerglobalscope_constructors_file = provider.newtempfi
le() | 192 _, dedicatedworkerglobalscope_constructors_file = provider.newtempfi
le() |
| 172 _, serviceworkersglobalscope_constructors_file = provider.newtempfil
e() | 193 _, serviceworkersglobalscope_constructors_file = provider.newtempfil
e() |
| 173 cmd = ['python', | |
| 174 'bindings/scripts/compute_dependencies.py', | |
| 175 '--idl-files-list', idl_files_list_filename, | |
| 176 '--interface-dependencies-file', self.interface_dependencies_
filename, | |
| 177 '--interfaces-info-file', self.interfaces_info_filename, | |
| 178 '--window-constructors-file', window_constructors_file, | |
| 179 '--workerglobalscope-constructors-file', workerglobalscope_co
nstructors_file, | |
| 180 '--sharedworkerglobalscope-constructors-file', sharedworkergl
obalscope_constructors_file, | |
| 181 '--dedicatedworkerglobalscope-constructors-file', dedicatedwo
rkerglobalscope_constructors_file, | |
| 182 '--serviceworkerglobalscope-constructors-file', serviceworker
sglobalscope_constructors_file, | |
| 183 '--event-names-file', event_names_filename, | |
| 184 '--write-file-only-if-changed', '0'] | |
| 185 self.run_command(cmd) | |
| 186 | 194 |
| 187 test_idl_files_list_filename = write_list_file(idl_paths(test_input_dire
ctory)) | 195 return compute(idl_files_list, |
| 188 all_idl_files_list_filename = write_list_file(idl_paths_recursive(all_in
put_directory)) | 196 self.interface_dependencies_filename, |
| 197 window_constructors_file, |
| 198 workerglobalscope_constructors_file, |
| 199 sharedworkerglobalscope_constructors_file, |
| 200 dedicatedworkerglobalscope_constructors_file, |
| 201 serviceworkersglobalscope_constructors_file, |
| 202 event_names_filename, False) |
| 203 |
| 204 test_idl_files_list = list_idl_file(idl_paths(test_input_directory)) |
| 205 all_idl_files_list = list_idl_file(idl_paths_recursive(all_input_directo
ry)) |
| 189 | 206 |
| 190 if self.reset_results and self.verbose: | 207 if self.reset_results and self.verbose: |
| 191 print 'Reset results: EventInterfaces.in' | 208 print 'Reset results: EventInterfaces.in' |
| 192 try: | 209 try: |
| 193 # We first compute dependencies for testing files only, | 210 # We first compute dependencies for testing files only, |
| 194 # so we can compare EventInterfaces.in. | 211 # so we can compare EventInterfaces.in. |
| 195 compute_dependencies(test_idl_files_list_filename, | 212 compute_dependencies(test_idl_files_list, self.event_names_filename, |
| 196 self.event_names_filename) | 213 self.interfaces_info_filename) |
| 197 | 214 |
| 198 # We then compute dependencies for all IDL files, as code generator | 215 # We then compute dependencies for all IDL files, as code generator |
| 199 # output depends on inheritance (both ancestor chain and inherited | 216 # output depends on inheritance (both ancestor chain and inherited |
| 200 # extended attributes), and some real interfaces are special-cased, | 217 # extended attributes), and some real interfaces are special-cased, |
| 201 # such as Node. | 218 # such as Node. |
| 202 # For example, when testing the behavior of interfaces that inherit | 219 # For example, when testing the behavior of interfaces that inherit |
| 203 # from Node, we also need to know that these inherit from | 220 # from Node, we also need to know that these inherit from |
| 204 # EventTarget, since this is also special-cased and Node inherits | 221 # EventTarget, since this is also special-cased and Node inherits |
| 205 # from EventTarget, but this inheritance information requires | 222 # from EventTarget, but this inheritance information requires |
| 206 # computing dependencies for the real Node.idl file. | 223 # computing dependencies for the real Node.idl file. |
| 207 # | 224 # |
| 208 # Don't overwrite the event names file generated for testing IDLs | 225 # Don't overwrite the event names file generated for testing IDLs |
| 209 _, dummy_event_names_filename = provider.newtempfile() | 226 _, dummy_event_names_filename = provider.newtempfile() |
| 210 compute_dependencies(all_idl_files_list_filename, | 227 self.interfaces_info = compute_dependencies(all_idl_files_list, |
| 211 dummy_event_names_filename) | 228 dummy_event_names_filena
me, |
| 229 self.interfaces_info_fil
ename) |
| 212 except ScriptError, e: | 230 except ScriptError, e: |
| 213 print 'ERROR: compute_dependencies.py' | 231 print 'ERROR: compute_dependencies.py' |
| 214 print e.output | 232 print e.output |
| 215 return e.exit_code | 233 return e.exit_code |
| 216 return 0 | 234 return 0 |
| 217 | 235 |
| 218 def identical_file(self, reference_filename, output_filename): | 236 def identical_file(self, reference_filename, output_filename): |
| 219 reference_basename = os.path.basename(reference_filename) | 237 reference_basename = os.path.basename(reference_filename) |
| 220 cmd = ['diff', | 238 cmd = ['diff', |
| 221 '-u', | 239 '-u', |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 | 321 |
| 304 all_tests_passed = self.run_tests() | 322 all_tests_passed = self.run_tests() |
| 305 if all_tests_passed: | 323 if all_tests_passed: |
| 306 if self.verbose: | 324 if self.verbose: |
| 307 print | 325 print |
| 308 print PASS_MESSAGE | 326 print PASS_MESSAGE |
| 309 return 0 | 327 return 0 |
| 310 print | 328 print |
| 311 print FAIL_MESSAGE | 329 print FAIL_MESSAGE |
| 312 return -1 | 330 return -1 |
| OLD | NEW |