Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: Tools/Scripts/webkitpy/bindings/main.py

Issue 216663004: Simplify run-bindings-test (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Comments Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.
(...skipping 11 matching lines...) Expand all
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 filecmp 25 import filecmp
26 import fnmatch 26 import fnmatch
27 import os 27 import os
28 import shutil 28 import shutil
29 import sys 29 import sys
30 import tempfile 30 import tempfile
31 31
32 from webkitpy.common.checkout.scm.detection import detect_scm_system 32 from webkitpy.common.system.executive import Executive
33 from webkitpy.common.system import executive
34 33
35 # Add Source path to PYTHONPATH to support function calls to bindings/scripts 34 # Add Source path to PYTHONPATH to support function calls to bindings/scripts
36 # for compute_interfaces_info and idl_compiler 35 # for compute_interfaces_info and idl_compiler
37 module_path = os.path.dirname(__file__) 36 module_path = os.path.dirname(__file__)
38 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir, 37 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir,
39 os.pardir, os.pardir, 'Source')) 38 os.pardir, os.pardir, 'Source'))
40 sys.path.append(source_path) 39 sys.path.append(source_path)
41 40
42 from bindings.scripts.compute_interfaces_info import compute_interfaces_info, in terfaces_info 41 from bindings.scripts.compute_interfaces_info import compute_interfaces_info, in terfaces_info
43 from bindings.scripts.idl_compiler import IdlCompilerV8 42 from bindings.scripts.idl_compiler import IdlCompilerV8
(...skipping 13 matching lines...) Expand all
57 56
58 DEPENDENCY_IDL_FILES = frozenset([ 57 DEPENDENCY_IDL_FILES = frozenset([
59 'TestImplements.idl', 58 'TestImplements.idl',
60 'TestImplements2.idl', 59 'TestImplements2.idl',
61 'TestImplements3.idl', 60 'TestImplements3.idl',
62 'TestPartialInterface.idl', 61 'TestPartialInterface.idl',
63 'TestPartialInterface2.idl', 62 'TestPartialInterface2.idl',
64 ]) 63 ])
65 64
66 65
67 EXTENDED_ATTRIBUTES_FILE = 'bindings/IDLExtendedAttributes.txt' 66 EXTENDED_ATTRIBUTES_FILE = os.path.join(source_path,
67 'bindings/IDLExtendedAttributes.txt')
68 68
69 all_input_directory = '.' # Relative to Source/ 69 test_input_directory = os.path.join(source_path, 'bindings', 'tests', 'idls')
70 test_input_directory = os.path.join('bindings', 'tests', 'idls') 70 reference_directory = os.path.join(source_path, 'bindings', 'tests', 'results')
71 reference_directory = os.path.join('bindings', 'tests', 'results')
72 71
73 72
74 class ScopedTempDir(object): 73 class ScopedTempDir(object):
75 """Wrapper for tempfile.mkdtemp() so it's usable with 'with' statement.""" 74 """Wrapper for tempfile.mkdtemp() so it's usable with 'with' statement."""
76 def __init__(self): 75 def __init__(self):
77 self.dir_path = tempfile.mkdtemp() 76 self.dir_path = tempfile.mkdtemp()
78 77
79 def __enter__(self): 78 def __enter__(self):
80 return self.dir_path 79 return self.dir_path
81 80
82 def __exit__(self, exc_type, exc_value, traceback): 81 def __exit__(self, exc_type, exc_value, traceback):
83 # The temporary directory is used as an output directory, so it 82 # The temporary directory is used as an output directory, so it
84 # contains unknown files (it isn't empty), hence use rmtree 83 # contains unknown files (it isn't empty), hence use rmtree
85 shutil.rmtree(self.dir_path) 84 shutil.rmtree(self.dir_path)
86 85
87 86
87 def generate_interface_dependencies():
88 def idl_paths_recursive(directory):
89 # This is slow, especially on Windows, due to os.walk making
90 # excess stat() calls. Faster versions may appear in future
91 # versions of Python:
92 # https://github.com/benhoyt/scandir
93 # http://bugs.python.org/issue11406
94 idl_paths = []
95 for dirpath, _, files in os.walk(directory):
96 idl_paths.extend(os.path.join(dirpath, filename)
97 for filename in fnmatch.filter(files, '*.idl'))
98 return idl_paths
88 99
89 class BindingsTests(object): 100 # We compute interfaces info for *all* IDL files, not just test IDL
90 def __init__(self, output_directory, verbose): 101 # files, as code generator output depends on inheritance (both ancestor
91 self.verbose = verbose 102 # chain and inherited extended attributes), and some real interfaces
92 self.executive = executive.Executive() 103 # are special-cased, such as Node.
93 self.idl_compiler = None 104 #
94 self.output_directory = output_directory 105 # For example, when testing the behavior of interfaces that inherit
106 # from Node, we also need to know that these inherit from EventTarget,
107 # since this is also special-cased and Node inherits from EventTarget,
108 # but this inheritance information requires computing dependencies for
109 # the real Node.idl file.
110 compute_interfaces_info(idl_paths_recursive(source_path))
95 111
96 def diff(self, filename1, filename2): 112
113 def bindings_tests(output_directory, verbose):
114 executive = Executive()
115
116 def diff(filename1, filename2):
97 # Python's difflib module is too slow, especially on long output, so 117 # Python's difflib module is too slow, especially on long output, so
98 # run external diff(1) command 118 # run external diff(1) command
99 cmd = ['diff', 119 cmd = ['diff',
100 '-u', 120 '-u', # unified format
101 '-N', 121 '-N', # treat absent files as empty
102 filename1, 122 filename1,
103 filename2] 123 filename2]
104 # Return output and don't raise exception, even though diff(1) has 124 # Return output and don't raise exception, even though diff(1) has
105 # non-zero exit if files differ. 125 # non-zero exit if files differ.
106 return self.executive.run_command(cmd, error_handler=lambda x: None) 126 return executive.run_command(cmd, error_handler=lambda x: None)
107 127
108 def generate_from_idl(self, idl_file): 128 def delete_cache_files():
109 idl_file_fullpath = os.path.realpath(idl_file)
110 self.idl_compiler.compile_file(idl_file_fullpath)
111
112 def generate_interface_dependencies(self):
113 def idl_paths_recursive(directory):
114 idl_paths = []
115 for dirpath, _, files in os.walk(directory):
116 idl_paths.extend(os.path.join(dirpath, filename)
117 for filename in fnmatch.filter(files, '*.idl'))
118 return idl_paths
119
120 # We compute interfaces info for *all* IDL files, not just test IDL
121 # files, as code generator output depends on inheritance (both ancestor
122 # chain and inherited extended attributes), and some real interfaces
123 # are special-cased, such as Node.
124 #
125 # For example, when testing the behavior of interfaces that inherit
126 # from Node, we also need to know that these inherit from EventTarget,
127 # since this is also special-cased and Node inherits from EventTarget,
128 # but this inheritance information requires computing dependencies for
129 # the real Node.idl file.
130 compute_interfaces_info(idl_paths_recursive(all_input_directory))
131
132 def delete_cache_files(self):
133 # FIXME: Instead of deleting cache files, don't generate them. 129 # FIXME: Instead of deleting cache files, don't generate them.
134 cache_files = [os.path.join(self.output_directory, output_file) 130 cache_files = [os.path.join(output_directory, output_file)
135 for output_file in os.listdir(self.output_directory) 131 for output_file in os.listdir(output_directory)
136 if (output_file in ('lextab.py', # PLY lex 132 if (output_file in ('lextab.py', # PLY lex
137 'lextab.pyc', 133 'lextab.pyc',
138 'parsetab.pickle') or # PLY yacc 134 'parsetab.pickle') or # PLY yacc
139 output_file.endswith('.cache'))] # Jinja 135 output_file.endswith('.cache'))] # Jinja
140 for cache_file in cache_files: 136 for cache_file in cache_files:
141 os.remove(cache_file) 137 os.remove(cache_file)
142 138
143 def identical_file(self, reference_filename, output_filename): 139 def identical_file(reference_filename, output_filename):
144 reference_basename = os.path.basename(reference_filename) 140 reference_basename = os.path.basename(reference_filename)
145 141
146 if not filecmp.cmp(reference_filename, output_filename): 142 if not filecmp.cmp(reference_filename, output_filename):
147 print 'FAIL: %s' % reference_basename 143 print 'FAIL: %s' % reference_basename
148 print self.diff(reference_filename, output_filename) 144 print diff(reference_filename, output_filename)
149 return False 145 return False
150 146
151 if self.verbose: 147 if verbose:
152 print 'PASS: %s' % reference_basename 148 print 'PASS: %s' % reference_basename
153 return True 149 return True
154 150
155 def identical_output_files(self): 151 def identical_output_files():
156 file_pairs = [(os.path.join(reference_directory, output_file), 152 file_pairs = [(os.path.join(reference_directory, output_file),
157 os.path.join(self.output_directory, output_file)) 153 os.path.join(output_directory, output_file))
158 for output_file in os.listdir(self.output_directory)] 154 for output_file in os.listdir(output_directory)]
159 return all([self.identical_file(reference_filename, output_filename) 155 return all([identical_file(reference_filename, output_filename)
160 for (reference_filename, output_filename) in file_pairs]) 156 for (reference_filename, output_filename) in file_pairs])
161 157
162 def no_excess_files(self): 158 def no_excess_files():
163 generated_files = set(os.listdir(self.output_directory)) 159 generated_files = set(os.listdir(output_directory))
164 generated_files.add('.svn') # Subversion working copy directory 160 generated_files.add('.svn') # Subversion working copy directory
165 excess_files = [output_file 161 excess_files = [output_file
166 for output_file in os.listdir(reference_directory) 162 for output_file in os.listdir(reference_directory)
167 if output_file not in generated_files] 163 if output_file not in generated_files]
168 if excess_files: 164 if excess_files:
169 print ('Excess reference files! ' 165 print ('Excess reference files! '
170 '(probably cruft from renaming or deleting):\n' + 166 '(probably cruft from renaming or deleting):\n' +
171 '\n'.join(excess_files)) 167 '\n'.join(excess_files))
172 return False 168 return False
173 return True 169 return True
174 170
175 def run_tests(self): 171 generate_interface_dependencies()
176 self.generate_interface_dependencies() 172 idl_compiler = IdlCompilerV8(output_directory,
177 self.idl_compiler = IdlCompilerV8(self.output_directory, 173 EXTENDED_ATTRIBUTES_FILE,
178 EXTENDED_ATTRIBUTES_FILE, 174 interfaces_info=interfaces_info,
179 interfaces_info=interfaces_info, 175 only_if_changed=True)
180 only_if_changed=True)
181 176
182 for input_filename in os.listdir(test_input_directory): 177 idl_basenames = [filename
183 if not input_filename.endswith('.idl'): 178 for filename in os.listdir(test_input_directory)
184 continue 179 if (filename.endswith('.idl') and
185 if input_filename in DEPENDENCY_IDL_FILES: 180 # Dependencies aren't built
186 # Dependencies aren't built (they are used by the dependent) 181 # (they are used by the dependent)
187 if self.verbose: 182 filename not in DEPENDENCY_IDL_FILES)]
188 print 'DEPENDENCY: %s' % input_filename 183 for idl_basename in idl_basenames:
189 continue 184 idl_path = os.path.realpath(
185 os.path.join(test_input_directory, idl_basename))
186 idl_compiler.compile_file(idl_path)
187 if verbose:
188 print 'Compiled: %s' % filename
190 189
191 idl_path = os.path.join(test_input_directory, input_filename) 190 delete_cache_files()
192 self.generate_from_idl(idl_path)
193 if self.verbose:
194 print 'Compiled: %s' % input_filename
195 191
196 self.delete_cache_files() 192 # Detect all changes
193 passed = identical_output_files()
194 passed &= no_excess_files()
197 195
198 # Detect all changes 196 if passed:
199 passed = self.identical_output_files() 197 if verbose:
200 passed &= self.no_excess_files() 198 print
201 return passed 199 print PASS_MESSAGE
202 200 return 0
203 def main(self): 201 print
204 current_scm = detect_scm_system(os.curdir) 202 print FAIL_MESSAGE
205 os.chdir(os.path.join(current_scm.checkout_root, 'Source')) 203 return 1
206
207 all_tests_passed = self.run_tests()
208 if all_tests_passed:
209 if self.verbose:
210 print
211 print PASS_MESSAGE
212 return 0
213 print
214 print FAIL_MESSAGE
215 return 1
216 204
217 205
218 def run_bindings_tests(reset_results, verbose): 206 def run_bindings_tests(reset_results, verbose):
219 # Generate output into the reference directory if resetting results, or 207 # Generate output into the reference directory if resetting results, or
220 # a temp directory if not. 208 # a temp directory if not.
221 if reset_results: 209 if reset_results:
222 print 'Resetting results' 210 print 'Resetting results'
223 return BindingsTests(reference_directory, verbose).main() 211 return bindings_tests(reference_directory, verbose)
224 with ScopedTempDir() as temp_dir: 212 with ScopedTempDir() as temp_dir:
225 return BindingsTests(temp_dir, verbose).main() 213 return bindings_tests(temp_dir, verbose)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698