| #!/usr/bin/env vpython3 |
| # Copyright 2020 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import base64 |
| import json |
| import os |
| import shutil |
| import tempfile |
| import unittest |
| |
| import merge_js_lib as merger |
| from parameterized import parameterized |
| |
| |
| class MergeJSLibTest(unittest.TestCase): |
| |
| def test_write_parsed_scripts(self): |
| test_files = [{ |
| 'url': '//a/b/c/1.js', |
| 'location': ['a', 'b', 'c', '1.js'], |
| 'exists': True |
| }, { |
| 'url': '//d/e/f/5.js', |
| 'location': ['d', 'e', 'f', '5.js'], |
| 'exists': True |
| }, { |
| 'url': '//a/b/d/7.js', |
| 'location': ['a', 'b', 'd', '7.js'], |
| 'exists': True |
| }, { |
| 'url': 'chrome://test_webui/file.js', |
| 'exists': False |
| }, { |
| 'url': 'file://testing/file.js', |
| 'exists': False |
| }] |
| |
| test_script_file = """{ |
| "text": "test\\ncontents\\n%d", |
| "url": "%s", |
| "sourceMapURL":"%s" |
| }""" |
| |
| scripts_dir = None |
| expected_files = [] |
| |
| try: |
| scripts_dir = tempfile.mkdtemp() |
| for i, test_script in enumerate(test_files): |
| file_path = os.path.join(scripts_dir, '%d.js.json' % i) |
| |
| source_map = '' |
| if test_script['exists']: |
| # Create an inline sourcemap with just the required keys. |
| source_map_data_url = base64.b64encode( |
| json.dumps({ |
| 'sources': [os.path.join(*test_script['location'])], |
| 'sourceRoot': '' |
| }).encode('utf-8')) |
| |
| source_map = 'data:application/json;base64,' + \ |
| source_map_data_url.decode('utf-8') |
| |
| with open(file_path, 'w') as f: |
| f.write(test_script_file % (i, test_script['url'], source_map)) |
| |
| expected_files.append(file_path) |
| if test_script['exists']: |
| expected_files.append( |
| os.path.join(scripts_dir, 'parsed_scripts', |
| *test_script['location'])) |
| |
| if len(expected_files) > 0: |
| expected_files.append( |
| os.path.join(scripts_dir, 'parsed_scripts', 'parsed_scripts.json')) |
| |
| merger.write_parsed_scripts(scripts_dir, source_dir='') |
| actual_files = [] |
| |
| for root, _, files in os.walk(scripts_dir): |
| for file_name in files: |
| actual_files.append(os.path.join(root, file_name)) |
| |
| self.assertCountEqual(expected_files, actual_files) |
| finally: |
| shutil.rmtree(scripts_dir) |
| |
| def test_write_parsed_scripts_negative_cases(self): |
| test_files = [{ |
| 'url': '//a/b/c/1.js', |
| 'contents': """{ |
| "url": "%s" |
| }""" |
| }, { |
| 'url': '//d/e/f/1.js', |
| 'contents': """{ |
| "text": "test\\ncontents\\n%s" |
| }""" |
| }] |
| |
| scripts_dir = None |
| expected_files = [] |
| try: |
| scripts_dir = tempfile.mkdtemp() |
| for i, test_script in enumerate(test_files): |
| file_path = os.path.join(scripts_dir, '%d.js.json' % i) |
| expected_files.append(file_path) |
| with open(file_path, 'w') as f: |
| f.write(test_script['contents'] % test_script['url']) |
| |
| merger.write_parsed_scripts(scripts_dir) |
| |
| actual_files = [] |
| for root, _, files in os.walk(scripts_dir): |
| for file_name in files: |
| actual_files.append(os.path.join(root, file_name)) |
| |
| self.assertCountEqual(expected_files, actual_files) |
| finally: |
| shutil.rmtree(scripts_dir) |
| |
| def test_trailing_curly_brace_stripped(self): |
| test_script_file = """{ |
| "text":"test\\ncontents\\n0", |
| "url":"//a/b/c/1.js", |
| "sourceMapURL":"data:application/json;base64,eyJzb3VyY2VzIjogWyJhL2IvYy8xLmpzIl0sICJzb3VyY2VSb290IjogIiJ9" |
| }}""" |
| |
| scripts_dir = None |
| |
| try: |
| scripts_dir = tempfile.mkdtemp() |
| file_path = os.path.join(scripts_dir, '0.js.json') |
| with open(file_path, 'w') as f: |
| f.write(test_script_file) |
| expected_files = [ |
| file_path, |
| os.path.join(scripts_dir, 'parsed_scripts', 'a', 'b', 'c', '1.js'), |
| os.path.join(scripts_dir, 'parsed_scripts', 'parsed_scripts.json') |
| ] |
| |
| merger.write_parsed_scripts(scripts_dir, source_dir='') |
| actual_files = [] |
| |
| for root, _, files in os.walk(scripts_dir): |
| for file_name in files: |
| actual_files.append(os.path.join(root, file_name)) |
| |
| self.assertCountEqual(expected_files, actual_files) |
| finally: |
| shutil.rmtree(scripts_dir) |
| |
| def test_non_data_urls_are_ignored(self): |
| test_script_file = """{ |
| "text": "test\\ncontents", |
| "url": "http://test_url", |
| "sourceMapURL":"%s" |
| }""" |
| |
| scripts_dir = None |
| expected_files = [] |
| |
| try: |
| scripts_dir = tempfile.mkdtemp() |
| file_path = os.path.join(scripts_dir, 'external_map.js.json') |
| expected_files = [file_path] |
| |
| # Write a script with an external URL as the sourcemap, this should |
| # exclude it from being written to disk. |
| with open(file_path, 'w') as f: |
| f.write(test_script_file % 'external.map') |
| |
| merger.write_parsed_scripts(scripts_dir, source_dir='') |
| actual_files = [] |
| |
| for root, _, files in os.walk(scripts_dir): |
| for file_name in files: |
| actual_files.append(os.path.join(root, file_name)) |
| |
| self.assertCountEqual(expected_files, actual_files) |
| finally: |
| shutil.rmtree(scripts_dir) |
| |
| def test_uninteresting_lines_are_excluded(self): |
| """This contrived istanbul coverage file represents the coverage from |
| the following example file: |
| """ |
| example_test_file = """// Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import './iframe.js'; |
| |
| /* |
| * function comment should be excluded. |
| */ |
| export const add = (a, b) => a + b; // should not be excluded |
| |
| /* should be excluded */ |
| |
| """ |
| |
| test_istanbul_file = """{ |
| "%s":{ |
| "path":"%s", |
| "all":false, |
| "statementMap":{ |
| "1":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}}, |
| "2":{"start":{"line":2,"column":0},"end":{"line":2,"column":73}}, |
| "3":{"start":{"line":3,"column":0},"end":{"line":3,"column":29}}, |
| "4":{"start":{"line":4,"column":0},"end":{"line":4,"column":0}}, |
| "5":{"start":{"line":5,"column":0},"end":{"line":5,"column":21}}, |
| "6":{"start":{"line":6,"column":0},"end":{"line":6,"column":0}}, |
| "7":{"start":{"line":7,"column":0},"end":{"line":7,"column":2}}, |
| "8":{"start":{"line":8,"column":0},"end":{"line":8,"column":39}}, |
| "9":{"start":{"line":9,"column":0},"end":{"line":9,"column":3}}, |
| "10":{"start":{"line":10,"column":0},"end":{"line":10,"column":61}}, |
| "11":{"start":{"line":11,"column":0},"end":{"line":11,"column":0}}, |
| "12":{"start":{"line":12,"column":0},"end":{"line":12,"column":24}}, |
| "13":{"start":{"line":13,"column":0},"end":{"line":13,"column":0}} |
| }, |
| "s":{ |
| "1": 1, |
| "2": 1, |
| "3": 1, |
| "4": 1, |
| "5": 1, |
| "6": 1, |
| "7": 1, |
| "8": 1, |
| "9": 1, |
| "10": 1, |
| "11": 1, |
| "12": 1, |
| "13": 1 |
| } |
| } |
| }""" |
| |
| expected_output_file = """{ |
| "%s": { |
| "path": "%s", |
| "all": false, |
| "statementMap": { |
| "10": { |
| "start": { |
| "line": 10, |
| "column": 0 |
| }, |
| "end": { |
| "line": 10, |
| "column": 61 |
| } |
| } |
| }, |
| "s": { |
| "10": 1 |
| } |
| } |
| }""" |
| |
| try: |
| test_dir = tempfile.mkdtemp() |
| file_path = os.path.join(test_dir, 'coverage.json').replace('\\', '/') |
| example_test_file_path = os.path.join(test_dir, |
| 'fileA.js').replace('\\', '/') |
| expected_output = json.loads( |
| expected_output_file % |
| (example_test_file_path, example_test_file_path)) |
| |
| # Set up the tests files so that exclusions can be performed. |
| with open(file_path, 'w') as f: |
| f.write(test_istanbul_file % |
| (example_test_file_path, example_test_file_path)) |
| with open(example_test_file_path, 'w') as f: |
| f.write(example_test_file) |
| |
| # Perform the exclusion. |
| merger.exclude_uninteresting_lines(file_path) |
| |
| # Assert the final `coverage.json` file matches the expected output. |
| with open(file_path, 'rb') as f: |
| coverage_json = json.load(f) |
| self.assertEqual(coverage_json, expected_output) |
| |
| finally: |
| shutil.rmtree(test_dir) |
| |
| def test_paths_are_remapped_and_removed(self): |
| test_file_data = """{ |
| "/path/to/checkout/chrome/browser/fileA.js": { |
| "path": "/path/to/checkout/chrome/browser/fileA.js" |
| }, |
| "/path/to/checkout/out/dir/chrome/browser/fileB.js": { |
| "path": "/path/to/checkout/out/dir/chrome/browser/fileB.js" |
| }, |
| "/some/random/path/fileC.js": { |
| "path": "/some/random/path/fileC.js" |
| } |
| }""" |
| |
| expected_after_remap = { |
| 'chrome/browser/fileA.js': { |
| 'path': 'chrome/browser/fileA.js' |
| } |
| } |
| |
| try: |
| test_dir = tempfile.mkdtemp() |
| coverage_file_path = os.path.join(test_dir, |
| 'coverage.json').replace('\\', '/') |
| |
| with open(coverage_file_path, 'w', encoding='utf-8', newline='') as f: |
| f.write(test_file_data) |
| |
| merger.remap_paths_to_relative(coverage_file_path, '/path/to/checkout', |
| '/path/to/checkout/out/dir') |
| |
| with open(coverage_file_path, 'rb') as f: |
| coverage_json = json.load(f) |
| self.assertEqual(coverage_json, expected_after_remap) |
| |
| finally: |
| shutil.rmtree(test_dir) |
| |
| @parameterized.expand([ |
| ('// test', True), |
| ('/* test', True), |
| ('*/ test', True), |
| (' * test', True), |
| ('import test', True), |
| (' x = 5 /* comment */', False), |
| ('x = 5', False), |
| ]) |
| def test_should_exclude(self, line, exclude): |
| self.assertEqual(merger.should_exclude(line), exclude) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |