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_dependencies and idl_compiler | |
Nils Barth (inactive)
2014/03/17 02:06:14
Could you update this to: "compute_interfaces_info
terry
2014/03/17 16:36:38
Done.
| |
37 module_path = os.path.dirname(__file__) | |
38 source_path = os.path.normpath(os.path.join(module_path, os.pardir, | |
Nils Barth (inactive)
2014/03/17 02:06:14
Could you wrap the line slightly tighter?
It fits
terry
2014/03/17 16:36:38
Done.
| |
39 os.pardir, os.pardir, os.pardir, | |
40 'Source')) | |
41 sys.path.append(source_path) | |
42 | |
43 from bindings.scripts.compute_interfaces_info import compute_interfaces_info, in terfaces_info | |
44 from bindings.scripts.idl_compiler import IdlCompilerV8 | |
45 | |
46 | |
35 PASS_MESSAGE = 'All tests PASS!' | 47 PASS_MESSAGE = 'All tests PASS!' |
36 FAIL_MESSAGE = """Some tests FAIL! | 48 FAIL_MESSAGE = """Some tests FAIL! |
37 To update the reference files, execute: | 49 To update the reference files, execute: |
38 run-bindings-tests --reset-results | 50 run-bindings-tests --reset-results |
39 | 51 |
40 If the failures are not due to your changes, test results may be out of sync; | 52 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. | 53 please rebaseline them in a separate CL, after checking that tests fail in ToT. |
42 In CL, please set: | 54 In CL, please set: |
43 NOTRY=true | 55 NOTRY=true |
44 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) | 56 TBR=(someone in Source/bindings/OWNERS or WATCHLISTS:bindings) |
45 """ | 57 """ |
46 | 58 |
47 DEPENDENCY_IDL_FILES = set([ | 59 DEPENDENCY_IDL_FILES = set([ |
48 'SupportTestPartialInterface.idl', | 60 'SupportTestPartialInterface.idl', |
49 'TestImplements.idl', | 61 'TestImplements.idl', |
50 'TestImplements2.idl', | 62 'TestImplements2.idl', |
51 'TestImplements3.idl', | 63 'TestImplements3.idl', |
52 'TestPartialInterface.idl', | 64 'TestPartialInterface.idl', |
53 'TestPartialInterfacePython.idl', | 65 'TestPartialInterfacePython.idl', |
54 'TestPartialInterfacePython2.idl', | 66 'TestPartialInterfacePython2.idl', |
55 ]) | 67 ]) |
56 | 68 |
69 | |
70 EXTENDED_ATTRIBUTES_FILE = 'bindings/IDLExtendedAttributes.txt' | |
71 | |
57 all_input_directory = '.' # Relative to Source/ | 72 all_input_directory = '.' # Relative to Source/ |
58 test_input_directory = os.path.join('bindings', 'tests', 'idls') | 73 test_input_directory = os.path.join('bindings', 'tests', 'idls') |
59 reference_directory = os.path.join('bindings', 'tests', 'results') | 74 reference_directory = os.path.join('bindings', 'tests', 'results') |
60 | 75 |
61 | 76 |
62 class ScopedTempFileProvider(object): | 77 class ScopedTempFileProvider(object): |
63 def __init__(self): | 78 def __init__(self): |
64 self.file_handles = [] | 79 self.file_handles = [] |
65 self.file_paths = [] | 80 self.file_paths = [] |
66 self.dir_paths = [] | 81 self.dir_paths = [] |
(...skipping 22 matching lines...) Expand all Loading... | |
89 self.dir_paths.append(dir_path) | 104 self.dir_paths.append(dir_path) |
90 return dir_path | 105 return dir_path |
91 | 106 |
92 | 107 |
93 class BindingsTests(object): | 108 class BindingsTests(object): |
94 def __init__(self, reset_results, verbose, provider): | 109 def __init__(self, reset_results, verbose, provider): |
95 self.reset_results = reset_results | 110 self.reset_results = reset_results |
96 self.verbose = verbose | 111 self.verbose = verbose |
97 self.executive = executive.Executive() | 112 self.executive = executive.Executive() |
98 self.provider = provider | 113 self.provider = provider |
99 _, self.interfaces_info_filename = provider.new_temp_file() | 114 self.idl_compiler = None |
100 # Generate output into the reference directory if resetting results, or | 115 # Generate output into the reference directory if resetting results, or |
101 # a temp directory if not. | 116 # a temp directory if not. |
102 if reset_results: | 117 if reset_results: |
103 self.output_directory = reference_directory | 118 self.output_directory = reference_directory |
104 else: | 119 else: |
105 self.output_directory = provider.new_temp_dir() | 120 self.output_directory = provider.new_temp_dir() |
106 | 121 |
107 def run_command(self, cmd): | 122 def run_command(self, cmd): |
108 output = self.executive.run_command(cmd) | 123 output = self.executive.run_command(cmd) |
109 if output: | 124 if output: |
110 print output | 125 print output |
111 | 126 |
112 def generate_from_idl(self, idl_file): | 127 def generate_from_idl(self, idl_file): |
113 cmd = ['python', | |
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 idl_file_fullpath = os.path.realpath(idl_file) |
Nils Barth (inactive)
2014/03/17 02:06:14
Could you move this before the try statement?
terry
2014/03/17 16:36:38
Done.
| |
130 self.idl_compiler.compile_file(idl_file_fullpath) | |
121 except ScriptError, e: | 131 except ScriptError, e: |
Nils Barth (inactive)
2014/03/17 02:06:14
We need to update this catch clause,
since we're n
terry
2014/03/17 16:36:38
Done.
| |
122 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) | 132 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) |
123 print e.output | 133 print e.output |
Nils Barth (inactive)
2014/03/17 02:06:14
This can then just be:
print err
terry
2014/03/17 16:36:38
Done.
| |
124 return e.exit_code | 134 return e.exit_code |
Nils Barth (inactive)
2014/03/17 02:06:14
...and then:
return 1
terry
2014/03/17 16:36:38
Done.
| |
135 | |
125 return 0 | 136 return 0 |
126 | 137 |
127 def generate_interface_dependencies(self): | 138 def generate_interface_dependencies(self): |
128 def idl_paths(directory): | 139 def idl_paths(directory): |
129 return [os.path.join(directory, input_file) | 140 return [os.path.join(directory, input_file) |
130 for input_file in os.listdir(directory) | 141 for input_file in os.listdir(directory) |
131 if input_file.endswith('.idl')] | 142 if input_file.endswith('.idl')] |
132 | 143 |
133 def idl_paths_recursive(directory): | 144 def idl_paths_recursive(directory): |
134 idl_paths = [] | 145 idl_paths = [] |
135 for dirpath, _, files in os.walk(directory): | 146 for dirpath, _, files in os.walk(directory): |
136 idl_paths.extend(os.path.join(dirpath, filename) | 147 idl_paths.extend(os.path.join(dirpath, filename) |
137 for filename in fnmatch.filter(files, '*.idl')) | 148 for filename in fnmatch.filter(files, '*.idl')) |
138 return idl_paths | 149 return idl_paths |
139 | 150 |
140 def write_list_file(idl_paths): | 151 def write_list_file(idl_paths): |
141 list_file, list_filename = self.provider.new_temp_file() | 152 list_file, list_filename = self.provider.new_temp_file() |
142 list_contents = ''.join(idl_path + '\n' | 153 list_contents = ''.join(idl_path + '\n' |
143 for idl_path in idl_paths) | 154 for idl_path in idl_paths) |
144 os.write(list_file, list_contents) | 155 os.write(list_file, list_contents) |
145 return list_filename | 156 return list_filename |
146 | 157 |
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 | 158 # We compute interfaces info for *all* IDL files, not just test IDL |
156 # files, as code generator output depends on inheritance (both ancestor | 159 # files, as code generator output depends on inheritance (both ancestor |
157 # chain and inherited extended attributes), and some real interfaces | 160 # chain and inherited extended attributes), and some real interfaces |
158 # are special-cased, such as Node. | 161 # are special-cased, such as Node. |
159 # | 162 # |
160 # For example, when testing the behavior of interfaces that inherit | 163 # For example, when testing the behavior of interfaces that inherit |
161 # from Node, we also need to know that these inherit from EventTarget, | 164 # from Node, we also need to know that these inherit from EventTarget, |
162 # since this is also special-cased and Node inherits from EventTarget, | 165 # since this is also special-cased and Node inherits from EventTarget, |
163 # but this inheritance information requires computing dependencies for | 166 # but this inheritance information requires computing dependencies for |
164 # the real Node.idl file. | 167 # the real Node.idl file. |
165 all_idl_files_list_filename = write_list_file(idl_paths_recursive(all_in put_directory)) | |
166 try: | 168 try: |
167 compute_interfaces_info(all_idl_files_list_filename) | 169 compute_interfaces_info(idl_paths_recursive(all_input_directory)) |
170 | |
168 except ScriptError, e: | 171 except ScriptError, e: |
Nils Barth (inactive)
2014/03/17 02:06:14
Could you update this catch clause as described ab
terry
2014/03/17 16:36:38
Done.
| |
169 print 'ERROR: compute_interfaces_info.py' | 172 print 'ERROR: compute_interfaces_info.py' |
170 print e.output | 173 print e.output |
171 return e.exit_code | 174 return e.exit_code |
175 | |
172 return 0 | 176 return 0 |
173 | 177 |
174 def delete_cache_files(self): | 178 def delete_cache_files(self): |
175 # FIXME: Instead of deleting cache files, don't generate them. | 179 # FIXME: Instead of deleting cache files, don't generate them. |
176 cache_files = [os.path.join(self.output_directory, output_file) | 180 cache_files = [os.path.join(self.output_directory, output_file) |
177 for output_file in os.listdir(self.output_directory) | 181 for output_file in os.listdir(self.output_directory) |
178 if (output_file in ('lextab.py', # PLY lex | 182 if (output_file in ('lextab.py', # PLY lex |
179 'lextab.pyc', | 183 'lextab.pyc', |
180 'parsetab.pickle') or # PLY yacc | 184 'parsetab.pickle') or # PLY yacc |
181 output_file.endswith('.cache'))] # Jinja | 185 output_file.endswith('.cache'))] # Jinja |
182 for cache_file in cache_files: | 186 for cache_file in cache_files: |
183 os.remove(cache_file) | 187 os.remove(cache_file) |
184 | 188 |
185 def identical_file(self, reference_filename, output_filename): | 189 def identical_file(self, reference_filename, output_filename): |
186 reference_basename = os.path.basename(reference_filename) | 190 reference_basename = os.path.basename(reference_filename) |
187 cmd = ['diff', | 191 cmd = ['diff', |
188 '-u', | 192 '-u', |
189 '-N', | 193 '-N', |
190 reference_filename, | 194 reference_filename, |
191 output_filename] | 195 output_filename] |
192 try: | 196 try: |
193 self.run_command(cmd) | 197 self.run_command(cmd) |
194 except ScriptError, e: | 198 except ScriptError, e: |
Nils Barth (inactive)
2014/03/17 02:06:14
BTW, could you update this to:
except ScriptError
terry
2014/03/17 16:36:38
Done.
| |
195 # run_command throws an exception on diff (b/c non-zero exit code) | 199 # run_command throws an exception on diff (b/c non-zero exit code) |
196 print 'FAIL: %s' % reference_basename | 200 print 'FAIL: %s' % reference_basename |
197 print e.output | 201 print e.output |
198 return False | 202 return False |
199 | 203 |
200 if self.verbose: | 204 if self.verbose: |
201 print 'PASS: %s' % reference_basename | 205 print 'PASS: %s' % reference_basename |
202 return True | 206 return True |
203 | 207 |
204 def identical_output_files(self): | 208 def identical_output_files(self): |
(...skipping 14 matching lines...) Expand all Loading... | |
219 '(probably cruft from renaming or deleting):\n' + | 223 '(probably cruft from renaming or deleting):\n' + |
220 '\n'.join(excess_files)) | 224 '\n'.join(excess_files)) |
221 return False | 225 return False |
222 return True | 226 return True |
223 | 227 |
224 def run_tests(self): | 228 def run_tests(self): |
225 # Generate output, immediately dying on failure | 229 # Generate output, immediately dying on failure |
226 if self.generate_interface_dependencies(): | 230 if self.generate_interface_dependencies(): |
227 return False | 231 return False |
228 | 232 |
233 self.idl_compiler = IdlCompilerV8(self.output_directory, | |
Nils Barth (inactive)
2014/03/17 02:06:14
Could you move this up into the __init__?
terry
2014/03/17 16:36:38
I don't think so the interfaces_info isn't compute
Nils Barth (inactive)
2014/03/18 09:23:16
Got it, thanks!
(I think we could simplify r-b-t b
| |
234 EXTENDED_ATTRIBUTES_FILE, | |
235 interfaces_info=interfaces_info, | |
236 only_if_changed=True) | |
237 | |
229 for input_filename in os.listdir(test_input_directory): | 238 for input_filename in os.listdir(test_input_directory): |
230 if not input_filename.endswith('.idl'): | 239 if not input_filename.endswith('.idl'): |
231 continue | 240 continue |
232 if input_filename in DEPENDENCY_IDL_FILES: | 241 if input_filename in DEPENDENCY_IDL_FILES: |
233 # Dependencies aren't built (they are used by the dependent) | 242 # Dependencies aren't built (they are used by the dependent) |
234 if self.verbose: | 243 if self.verbose: |
235 print 'DEPENDENCY: %s' % input_filename | 244 print 'DEPENDENCY: %s' % input_filename |
236 continue | 245 continue |
237 | 246 |
238 idl_path = os.path.join(test_input_directory, input_filename) | 247 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')) | 262 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) |
254 | 263 |
255 all_tests_passed = self.run_tests() | 264 all_tests_passed = self.run_tests() |
256 if all_tests_passed: | 265 if all_tests_passed: |
257 if self.verbose: | 266 if self.verbose: |
258 print | 267 print |
259 print PASS_MESSAGE | 268 print PASS_MESSAGE |
260 return 0 | 269 return 0 |
261 print | 270 print |
262 print FAIL_MESSAGE | 271 print FAIL_MESSAGE |
263 return -1 | 272 return -1 |
Nils Barth (inactive)
2014/03/17 02:06:14
Also, could we update this to
return 1
?
(Exit sta
terry
2014/03/17 16:36:38
Done.
| |
264 | 273 |
265 | 274 |
266 def run_bindings_tests(reset_results, verbose): | 275 def run_bindings_tests(reset_results, verbose): |
267 with ScopedTempFileProvider() as provider: | 276 with ScopedTempFileProvider() as provider: |
268 return BindingsTests(reset_results, verbose, provider).main() | 277 return BindingsTests(reset_results, verbose, provider).main() |
OLD | NEW |