From e719419d3f95c488d86126739df9197a89d1caff Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Wed, 11 Nov 2020 15:29:43 +0000 Subject: [PATCH] test(compiler-cli): create initial "linked compile" compliance tests (#39617) This commit adds bazel rules to test whether linking the golden partial files for test cases produces the same output as a full compile of the test case would. PR Close #39617 --- .../test/compliance/linked/BUILD.bazel | 29 +++++++ .../compliance/linked/linked_compile_spec.ts | 79 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 packages/compiler-cli/test/compliance/linked/BUILD.bazel create mode 100644 packages/compiler-cli/test/compliance/linked/linked_compile_spec.ts diff --git a/packages/compiler-cli/test/compliance/linked/BUILD.bazel b/packages/compiler-cli/test/compliance/linked/BUILD.bazel new file mode 100644 index 0000000000..e98f95b35d --- /dev/null +++ b/packages/compiler-cli/test/compliance/linked/BUILD.bazel @@ -0,0 +1,29 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "test_lib", + testonly = True, + srcs = ["linked_compile_spec.ts"], + deps = [ + "//packages/compiler-cli/linker/babel", + "//packages/compiler-cli/src/ngtsc/file_system", + "//packages/compiler-cli/test/compliance/test_helpers", + "@npm//@types/babel__core", + ], +) + +jasmine_node_test( + name = "linked", + bootstrap = ["//tools/testing:node_no_angular_es5"], + data = [ + "//packages/compiler-cli/test/compliance/test_cases", + "//packages/compiler-cli/test/ngtsc/fake_core:npm_package", + ], + shard_count = 2, + tags = [ + "ivy-only", + ], + deps = [ + ":test_lib", + ], +) diff --git a/packages/compiler-cli/test/compliance/linked/linked_compile_spec.ts b/packages/compiler-cli/test/compliance/linked/linked_compile_spec.ts new file mode 100644 index 0000000000..af99c45cd8 --- /dev/null +++ b/packages/compiler-cli/test/compliance/linked/linked_compile_spec.ts @@ -0,0 +1,79 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {PluginObj, transformSync} from '@babel/core'; + +import {createEs2015LinkerPlugin} from '../../../linker/babel'; +import {AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system'; +import {getBuildOutputDirectory} from '../test_helpers/compile_test'; +import {ComplianceTest} from '../test_helpers/get_compliance_tests'; +import {parseGoldenPartial} from '../test_helpers/golden_partials'; +import {runTests} from '../test_helpers/test_runner'; + +runTests('partial compile + link', linkPartials); + +/** + * Link all the partials specified in the given `test`. + * + * @param fs The mock file-system to use for linking the partials. + * @param test The compliance test whose partials will be linked. + */ +function linkPartials(fs: FileSystem, test: ComplianceTest): void { + const builtDirectory = getBuildOutputDirectory(fs); + const linkerPlugin = createEs2015LinkerPlugin(test.angularCompilerOptions); + const goldenPartialPath = fs.resolve('/GOLDEN_PARTIAL.js'); + if (!fs.exists(goldenPartialPath)) { + throw new Error( + 'Golden partial does not exist for this test\n' + + 'Try generating it by running:\n' + + `bazel run //packages/compiler-cli/test/compliance/test_cases:${ + test.relativePath}.golden.update`); + } + const partialFile = fs.readFile(goldenPartialPath); + const partials = parseGoldenPartial(partialFile).filter(f => f.path.endsWith('.js')); + for (const partial of partials) { + const linkedSource = + applyLinker({fileName: partial.path, source: partial.content}, linkerPlugin); + safeWrite(fs, fs.resolve(builtDirectory, partial.path), linkedSource); + } +} + +/** + * Run the file through the Babel linker plugin. + * + * It will ignore files that do not have a `.js` extension. + * + * @param file The file name and its source to be transformed using the linker. + * @param linkerPlugin The linker plugin to apply. + * @returns The file's source content, which has been transformed using the linker if necessary. + */ +function applyLinker(file: {fileName: string; source: string}, linkerPlugin: PluginObj): string { + if (!file.fileName.endsWith('.js')) { + return file.source; + } + const result = transformSync(file.source, { + filename: file.fileName, + plugins: [linkerPlugin], + parserOpts: {sourceType: 'unambiguous'}, + }); + if (result === null) { + throw fail('Babel transform did not have output'); + } + if (result.code == null) { + throw fail('Babel transform result does not have any code'); + } + return result.code; +} + +/** + * Write the `content` to the `path` on the `fs` file-system, first ensuring that the containing + * directory exists. + */ +function safeWrite(fs: FileSystem, path: AbsoluteFsPath, content: string): void { + fs.ensureDir(fs.dirname(path)); + fs.writeFile(path, content); +}