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 | |
37 module_path = os.path.dirname(__file__) | |
38 source_path = os.path.normpath(os.path.join(module_path, os.pardir, | |
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 | |
44 from bindings.scripts.idl_compiler import compile_idl | |
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 reference_event_names_filename = os.path.join(reference_directory, 'EventInterfa ces.in') | 75 reference_event_names_filename = os.path.join(reference_directory, 'EventInterfa ces.in') |
61 | 76 |
62 | 77 |
63 class ScopedTempFileProvider(object): | 78 class ScopedTempFileProvider(object): |
64 def __init__(self): | 79 def __init__(self): |
65 self.file_handles = [] | 80 self.file_handles = [] |
66 self.file_paths = [] | 81 self.file_paths = [] |
(...skipping 23 matching lines...) Expand all Loading... | |
90 self.dir_paths.append(dir_path) | 105 self.dir_paths.append(dir_path) |
91 return dir_path | 106 return dir_path |
92 | 107 |
93 | 108 |
94 class BindingsTests(object): | 109 class BindingsTests(object): |
95 def __init__(self, reset_results, verbose, provider): | 110 def __init__(self, reset_results, verbose, provider): |
96 self.reset_results = reset_results | 111 self.reset_results = reset_results |
97 self.verbose = verbose | 112 self.verbose = verbose |
98 self.executive = executive.Executive() | 113 self.executive = executive.Executive() |
99 self.provider = provider | 114 self.provider = provider |
115 self.reader = None | |
Nils Barth (inactive)
2014/03/03 01:32:48
If we make the compiler an object, this becomes se
| |
100 _, self.interface_dependencies_filename = provider.new_temp_file() | 116 _, self.interface_dependencies_filename = provider.new_temp_file() |
101 _, self.interfaces_info_filename = provider.new_temp_file() | 117 _, self.interfaces_info_filename = provider.new_temp_file() |
102 # Generate output into the reference directory if resetting results, or | 118 # Generate output into the reference directory if resetting results, or |
103 # a temp directory if not. | 119 # a temp directory if not. |
104 if reset_results: | 120 if reset_results: |
105 self.output_directory = reference_directory | 121 self.output_directory = reference_directory |
106 else: | 122 else: |
107 self.output_directory = provider.new_temp_dir() | 123 self.output_directory = provider.new_temp_dir() |
108 self.event_names_filename = os.path.join(self.output_directory, 'EventIn terfaces.in') | 124 self.event_names_filename = os.path.join(self.output_directory, 'EventIn terfaces.in') |
109 | 125 |
110 def run_command(self, cmd): | 126 def run_command(self, cmd): |
111 output = self.executive.run_command(cmd) | 127 output = self.executive.run_command(cmd) |
112 if output: | 128 if output: |
113 print output | 129 print output |
114 | 130 |
115 def generate_from_idl(self, idl_file): | 131 def generate_from_idl(self, idl_file): |
116 cmd = ['python', | |
117 'bindings/scripts/idl_compiler.py', | |
118 '--output-dir', self.output_directory, | |
119 '--idl-attributes-file', 'bindings/IDLExtendedAttributes.txt', | |
120 '--interfaces-info-file', self.interfaces_info_filename, | |
121 idl_file] | |
122 try: | 132 try: |
123 self.run_command(cmd) | 133 idl_file_fullpath = os.path.realpath(idl_file) |
134 self.reader = compile_idl(idl_file_fullpath, | |
135 self.output_directory, | |
136 EXTENDED_ATTRIBUTES_FILE, | |
137 self.interfaces_info_filename, | |
138 True, self.reader) | |
124 except ScriptError, e: | 139 except ScriptError, e: |
125 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) | 140 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file) |
126 print e.output | 141 print e.output |
127 return e.exit_code | 142 return e.exit_code |
143 | |
128 return 0 | 144 return 0 |
129 | 145 |
130 def generate_interface_dependencies(self): | 146 def generate_interface_dependencies(self): |
131 def idl_paths(directory): | 147 def idl_paths(directory): |
132 return [os.path.join(directory, input_file) | 148 return [os.path.join(directory, input_file) |
133 for input_file in os.listdir(directory) | 149 for input_file in os.listdir(directory) |
134 if input_file.endswith('.idl')] | 150 if input_file.endswith('.idl')] |
135 | 151 |
136 def idl_paths_recursive(directory): | 152 def idl_paths_recursive(directory): |
137 idl_paths = [] | 153 idl_paths = [] |
138 for dirpath, _, files in os.walk(directory): | 154 for dirpath, _, files in os.walk(directory): |
139 idl_paths.extend(os.path.join(dirpath, filename) | 155 idl_paths.extend(os.path.join(dirpath, filename) |
140 for filename in fnmatch.filter(files, '*.idl')) | 156 for filename in fnmatch.filter(files, '*.idl')) |
141 return idl_paths | 157 return idl_paths |
142 | 158 |
143 def write_list_file(idl_paths): | 159 def write_list_file(idl_paths): |
144 list_file, list_filename = self.provider.new_temp_file() | 160 list_file, list_filename = self.provider.new_temp_file() |
145 list_contents = ''.join(idl_path + '\n' | 161 list_contents = ''.join(idl_path + '\n' |
146 for idl_path in idl_paths) | 162 for idl_path in idl_paths) |
147 os.write(list_file, list_contents) | 163 os.write(list_file, list_contents) |
148 return list_filename | 164 return list_filename |
149 | 165 |
166 # Faster in-memory file list. | |
167 def list_idl_file(idl_paths): | |
Nils Barth (inactive)
2014/03/03 01:32:48
This is unnecessary, right?
(It's just copying a l
| |
168 idls = [] | |
169 for idl_path in idl_paths: | |
170 idls.append(idl_path) | |
171 return idls | |
172 | |
150 def compute_interfaces_info(idl_files_list_filename, | 173 def compute_interfaces_info(idl_files_list_filename, |
Nils Barth (inactive)
2014/03/03 06:45:49
I'm simplifying this (remove EventInterfaces.in),
| |
151 event_names_filename): | 174 event_names_filename): |
152 cmd = ['python', | 175 compute(idl_files_list_filename, self.interfaces_info_filename, |
153 'bindings/scripts/compute_interfaces_info.py', | 176 self.interface_dependencies_filename, |
154 '--idl-files-list', idl_files_list_filename, | 177 event_names_filename, False) |
155 '--interface-dependencies-file', self.interface_dependencies_ filename, | |
156 '--interfaces-info-file', self.interfaces_info_filename, | |
157 '--event-names-file', event_names_filename, | |
158 '--write-file-only-if-changed', '0'] | |
159 self.run_command(cmd) | |
160 | 178 |
161 test_idl_files_list_filename = write_list_file(idl_paths(test_input_dire ctory)) | 179 test_idl_files_list = list_idl_file(idl_paths(test_input_directory)) |
162 all_idl_files_list_filename = write_list_file(idl_paths_recursive(all_in put_directory)) | 180 all_idl_files_list = list_idl_file(idl_paths_recursive(all_input_directo ry)) |
163 | 181 |
164 if self.reset_results and self.verbose: | 182 if self.reset_results and self.verbose: |
165 print 'Reset results: EventInterfaces.in' | 183 print 'Reset results: EventInterfaces.in' |
166 try: | 184 try: |
167 # We first compute interfaces info for testing files only, | 185 # We first compute interfaces info for testing files only, |
168 # so we can compare EventInterfaces.in. | 186 # so we can compare EventInterfaces.in. |
169 compute_interfaces_info(test_idl_files_list_filename, | 187 compute_interfaces_info(test_idl_files_list, self.event_names_filena me) |
170 self.event_names_filename) | |
171 | 188 |
172 # We then compute interfaces info for all IDL files, as code | 189 # We then compute interfaces info for all IDL files, as code |
173 # generator output depends on inheritance (both ancestor chain and | 190 # generator output depends on inheritance (both ancestor chain and |
174 # inherited extended attributes), and some real interfaces are | 191 # inherited extended attributes), and some real interfaces are |
175 # special-cased, such as Node. | 192 # special-cased, such as Node. |
176 # For example, when testing the behavior of interfaces that inherit | 193 # For example, when testing the behavior of interfaces that inherit |
177 # from Node, we also need to know that these inherit from | 194 # from Node, we also need to know that these inherit from |
178 # EventTarget, since this is also special-cased and Node inherits | 195 # EventTarget, since this is also special-cased and Node inherits |
179 # from EventTarget, but this inheritance information requires | 196 # from EventTarget, but this inheritance information requires |
180 # computing dependencies for the real Node.idl file. | 197 # computing dependencies for the real Node.idl file. |
181 # | 198 # |
182 # Don't overwrite the event names file generated for testing IDLs | 199 # Don't overwrite the event names file generated for testing IDLs |
183 _, dummy_event_names_filename = self.provider.new_temp_file() | 200 _, dummy_event_names_filename = self.provider.new_temp_file() |
184 compute_interfaces_info(all_idl_files_list_filename, | 201 compute_interfaces_info(all_idl_files_list, dummy_event_names_filena me) |
185 dummy_event_names_filename) | |
186 except ScriptError, e: | 202 except ScriptError, e: |
187 print 'ERROR: compute_interfaces_info.py' | 203 print 'ERROR: compute_interfaces_info.py' |
188 print e.output | 204 print e.output |
189 return e.exit_code | 205 return e.exit_code |
206 | |
190 return 0 | 207 return 0 |
191 | 208 |
192 def identical_file(self, reference_filename, output_filename): | 209 def identical_file(self, reference_filename, output_filename): |
193 reference_basename = os.path.basename(reference_filename) | 210 reference_basename = os.path.basename(reference_filename) |
194 cmd = ['diff', | 211 cmd = ['diff', |
195 '-u', | 212 '-u', |
196 '-N', | 213 '-N', |
197 reference_filename, | 214 reference_filename, |
198 output_filename] | 215 output_filename] |
199 try: | 216 try: |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 print 'DEPENDENCY: %s' % input_filename | 263 print 'DEPENDENCY: %s' % input_filename |
247 continue | 264 continue |
248 | 265 |
249 idl_path = os.path.join(test_input_directory, input_filename) | 266 idl_path = os.path.join(test_input_directory, input_filename) |
250 if self.generate_from_idl(idl_path): | 267 if self.generate_from_idl(idl_path): |
251 return False | 268 return False |
252 if self.reset_results and self.verbose: | 269 if self.reset_results and self.verbose: |
253 print 'Reset results: %s' % input_filename | 270 print 'Reset results: %s' % input_filename |
254 | 271 |
255 # Detect all changes | 272 # Detect all changes |
256 passed = self.identical_file(reference_event_names_filename, | 273 passed = self.identical_file(reference_event_names_filename, self.event_ names_filename) |
257 self.event_names_filename) | |
258 passed &= self.identical_output_files() | 274 passed &= self.identical_output_files() |
259 passed &= self.no_excess_files() | 275 passed &= self.no_excess_files() |
260 return passed | 276 return passed |
261 | 277 |
262 def main(self): | 278 def main(self): |
263 current_scm = detect_scm_system(os.curdir) | 279 current_scm = detect_scm_system(os.curdir) |
264 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) | 280 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) |
265 | 281 |
266 all_tests_passed = self.run_tests() | 282 all_tests_passed = self.run_tests() |
267 if all_tests_passed: | 283 if all_tests_passed: |
268 if self.verbose: | 284 if self.verbose: |
269 print | 285 print |
270 print PASS_MESSAGE | 286 print PASS_MESSAGE |
271 return 0 | 287 return 0 |
272 print | 288 print |
273 print FAIL_MESSAGE | 289 print FAIL_MESSAGE |
274 return -1 | 290 return -1 |
275 | 291 |
276 | 292 |
277 def run_bindings_tests(reset_results, verbose): | 293 def run_bindings_tests(reset_results, verbose): |
278 with ScopedTempFileProvider() as provider: | 294 with ScopedTempFileProvider() as provider: |
279 return BindingsTests(reset_results, verbose, provider).main() | 295 return BindingsTests(reset_results, verbose, provider).main() |
OLD | NEW |