| # Copyright (C) 2011 Google Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| # |
| |
| import fnmatch |
| import json |
| import os |
| import os.path |
| import shutil |
| import sys |
| import tempfile |
| |
| from webkitcorepy import string_utils |
| |
| from webkitpy.common.checkout.scm.detection import detect_scm_system |
| from webkitpy.common.system.executive import ScriptError |
| |
| |
| class BindingsTests: |
| |
| def __init__(self, reset_results, generators, executive, verbose, patterns, json_file_name): |
| self.reset_results = reset_results |
| self.generators = generators |
| self.executive = executive |
| self.verbose = verbose |
| self.patterns = patterns |
| self.json_file_name = json_file_name |
| |
| if self.json_file_name: |
| self.failures = [] |
| |
| def generate_from_idl(self, generator, idl_file, output_directory, supplemental_dependency_file): |
| cmd = ['perl', '-w', |
| '-IWebCore/bindings/scripts', |
| 'WebCore/bindings/scripts/generate-bindings.pl', |
| # idl include directories (path relative to generate-bindings.pl) |
| '--include', '.', |
| '--defines', 'TESTING_%s' % generator, |
| '--generator', generator, |
| '--outputDir', output_directory, |
| '--supplementalDependencyFile', supplemental_dependency_file, |
| '--idlAttributesFile', 'WebCore/bindings/scripts/IDLAttributes.json', |
| idl_file] |
| |
| exit_code = 0 |
| try: |
| output = self.executive.run_command(cmd) |
| if output: |
| print(output) |
| except ScriptError as e: |
| print(e.output) |
| exit_code = e.exit_code |
| return exit_code |
| |
| def generate_supplemental_dependency(self, input_directory, supplemental_dependency_file, supplemental_makefile_dependency_file, window_constructors_file, workerglobalscope_constructors_file, shadowrealmglobalscope_constructors_file, dedicatedworkerglobalscope_constructors_file, serviceworkerglobalscope_constructors_file, sharedworkerglobalscope_constructors_file, workletglobalscope_constructors_file, paintworkletglobalscope_constructors_file, audioworkletglobalscope_constructors_file, testglobalscope_constructors_file): |
| idl_files_list = tempfile.mkstemp() |
| for input_file in os.listdir(input_directory): |
| (name, extension) = os.path.splitext(input_file) |
| if extension != '.idl': |
| continue |
| if name.endswith('Constructors'): |
| continue |
| os.write(idl_files_list[0], string_utils.encode(os.path.join(input_directory, input_file) + "\n")) |
| os.close(idl_files_list[0]) |
| |
| cmd = ['perl', '-w', |
| '-IWebCore/bindings/scripts', |
| 'WebCore/bindings/scripts/preprocess-idls.pl', |
| '--idlFileNamesList', idl_files_list[1], |
| '--testGlobalContextName', 'TestGlobalObject', |
| '--defines', '', |
| '--idlAttributesFile', 'WebCore/bindings/scripts/IDLAttributes.json', |
| '--supplementalDependencyFile', supplemental_dependency_file, |
| '--supplementalMakefileDeps', supplemental_makefile_dependency_file, |
| '--windowConstructorsFile', window_constructors_file, |
| '--workerGlobalScopeConstructorsFile', workerglobalscope_constructors_file, |
| '--shadowRealmGlobalScopeConstructorsFile', shadowrealmglobalscope_constructors_file, |
| '--dedicatedWorkerGlobalScopeConstructorsFile', dedicatedworkerglobalscope_constructors_file, |
| '--serviceWorkerGlobalScopeConstructorsFile', serviceworkerglobalscope_constructors_file, |
| '--sharedWorkerGlobalScopeConstructorsFile', sharedworkerglobalscope_constructors_file, |
| '--workletGlobalScopeConstructorsFile', workletglobalscope_constructors_file, |
| '--paintWorkletGlobalScopeConstructorsFile', paintworkletglobalscope_constructors_file, |
| '--audioWorkletGlobalScopeConstructorsFile', audioworkletglobalscope_constructors_file, |
| '--testGlobalScopeConstructorsFile', testglobalscope_constructors_file, |
| '--validateAgainstParser'] |
| |
| exit_code = 0 |
| try: |
| output = self.executive.run_command(cmd) |
| if output: |
| print(output) |
| except ScriptError as e: |
| print(e.output) |
| exit_code = e.exit_code |
| os.remove(idl_files_list[1]) |
| return exit_code |
| |
| def detect_changes(self, generator, work_directory, reference_directory): |
| changes_found = False |
| for filename in os.listdir(work_directory): |
| if self.detect_file_changes(generator, work_directory, reference_directory, filename): |
| changes_found = True |
| return changes_found |
| |
| def detect_file_changes(self, generator, work_directory, reference_directory, filename): |
| changes_found = False |
| cmd = ['diff', |
| '-u', |
| '-N', |
| os.path.join(reference_directory, filename), |
| os.path.join(work_directory, filename)] |
| |
| exit_code = 0 |
| try: |
| output = self.executive.run_command(cmd) |
| except ScriptError as e: |
| output = e.output |
| exit_code = e.exit_code |
| |
| if exit_code or output: |
| print('FAIL: (%s) %s' % (generator, filename)) |
| print(output) |
| changes_found = True |
| if self.json_file_name: |
| self.failures.append("(%s) %s" % (generator, filename)) |
| elif self.verbose: |
| print('PASS: (%s) %s' % (generator, filename)) |
| sys.stdout.flush() |
| return changes_found |
| |
| def test_matches_patterns(self, test): |
| if not self.patterns: |
| return True |
| for pattern in self.patterns: |
| if fnmatch.fnmatch(test, pattern): |
| return True |
| return False |
| |
| def run_tests(self, generator, input_directory, reference_directory, supplemental_dependency_file): |
| work_directory = reference_directory |
| |
| passed = True |
| for input_file in os.listdir(input_directory): |
| (name, extension) = os.path.splitext(input_file) |
| if extension != '.idl': |
| continue |
| |
| if not self.test_matches_patterns(input_file): |
| continue |
| |
| # Generate output into the work directory (either the given one or a |
| # temp one if not reset_results is performed) |
| if not self.reset_results: |
| work_directory = tempfile.mkdtemp() |
| |
| if self.generate_from_idl(generator, |
| os.path.join(input_directory, input_file), |
| work_directory, |
| supplemental_dependency_file): |
| passed = False |
| |
| if self.reset_results: |
| print("Reset results: (%s) %s" % (generator, input_file)) |
| continue |
| |
| # Detect changes |
| if self.detect_changes(generator, work_directory, reference_directory): |
| passed = False |
| shutil.rmtree(work_directory) |
| |
| return passed |
| |
| def main(self): |
| current_scm = detect_scm_system(os.path.dirname(__file__)) |
| os.chdir(os.path.join(current_scm.checkout_root, 'Source')) |
| |
| all_tests_passed = True |
| |
| supplemental_dependency_filename = 'SupplementalDependencies.txt' |
| supplemental_makefile_dependency_filename = 'SupplementalDependencies.dep' |
| dom_window_constructors_filename = 'DOMWindowConstructors.idl' |
| workerglobalscope_constructors_filename = 'WorkerGlobalScopeConstructors.idl' |
| shadowrealmglobalscope_constructors_filename = 'ShadowRealmGlobalScopeConstructors.idl' |
| dedicatedworkerglobalscope_constructors_filename = 'DedicatedWorkerGlobalScopeConstructors.idl' |
| serviceworkerglobalscope_constructors_filename = 'ServiceWorkerGlobalScopeConstructors.idl' |
| sharedworkerglobalscope_constructors_filename = 'SharedWorkerGlobalScopeConstructors.idl' |
| workletglobalscope_constructors_filename = 'WorkletGlobalScopeConstructors.idl' |
| paintworkletglobalscope_constructors_filename = 'PaintWorkletGlobalScopeConstructors.idl' |
| audioworkletglobalscope_constructors_filename = 'AudioWorkletGlobalScopeConstructors.idl' |
| testglobalscope_constructors_filename = 'BindingTestGlobalConstructors.idl' |
| |
| work_directory = tempfile.mkdtemp() |
| input_directory = os.path.join('WebCore', 'bindings', 'scripts', 'test') |
| supplemental_dependency_file = os.path.join(work_directory, supplemental_dependency_filename) |
| supplemental_makefile_dependency_file = os.path.join(work_directory if not self.reset_results else input_directory, supplemental_makefile_dependency_filename) |
| window_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, dom_window_constructors_filename) |
| workerglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, workerglobalscope_constructors_filename) |
| shadowrealmglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, shadowrealmglobalscope_constructors_filename) |
| dedicatedworkerglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, dedicatedworkerglobalscope_constructors_filename) |
| serviceworkerglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, serviceworkerglobalscope_constructors_filename) |
| sharedworkerglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, sharedworkerglobalscope_constructors_filename) |
| workletglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, workletglobalscope_constructors_filename) |
| paintworkletglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, paintworkletglobalscope_constructors_filename) |
| audioworkletglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, audioworkletglobalscope_constructors_filename) |
| testglobalscope_constructors_file = os.path.join(work_directory if not self.reset_results else input_directory, testglobalscope_constructors_filename) |
| |
| if self.generate_supplemental_dependency(input_directory, supplemental_dependency_file, supplemental_makefile_dependency_file, window_constructors_file, workerglobalscope_constructors_file, shadowrealmglobalscope_constructors_file, dedicatedworkerglobalscope_constructors_file, serviceworkerglobalscope_constructors_file, sharedworkerglobalscope_constructors_file, workletglobalscope_constructors_file, paintworkletglobalscope_constructors_file, audioworkletglobalscope_constructors_file, testglobalscope_constructors_file): |
| print('Failed to generate a supplemental dependency file.') |
| shutil.rmtree(work_directory) |
| return -1 |
| |
| if not self.reset_results: |
| if self.detect_file_changes('dependencies', work_directory, input_directory, supplemental_makefile_dependency_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, dom_window_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, workerglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, shadowrealmglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, dedicatedworkerglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, serviceworkerglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, sharedworkerglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, workletglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, paintworkletglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, audioworkletglobalscope_constructors_filename): |
| all_tests_passed = False |
| if self.detect_file_changes('globalscope', work_directory, input_directory, testglobalscope_constructors_filename): |
| all_tests_passed = False |
| |
| for generator in self.generators: |
| input_directory = os.path.join('WebCore', 'bindings', 'scripts', 'test') |
| reference_directory = os.path.join('WebCore', 'bindings', 'scripts', 'test', generator) |
| if not self.run_tests(generator, input_directory, reference_directory, supplemental_dependency_file): |
| all_tests_passed = False |
| |
| shutil.rmtree(work_directory) |
| |
| if self.json_file_name: |
| json_data = { |
| 'failures': self.failures, |
| } |
| |
| with open(self.json_file_name, 'w') as json_file: |
| json.dump(json_data, json_file) |
| |
| print('') |
| if all_tests_passed: |
| print('All tests PASS!') |
| return 0 |
| else: |
| print('Some tests FAIL! (To update the reference files, execute "run-bindings-tests --reset-results")') |
| return -1 |