diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 50c90575eee..3fd78e0af7b 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -14,7 +14,7 @@ import util from "util"; import { localizationDirectories } from "./scripts/build/localization.mjs"; import cmdLineOptions from "./scripts/build/options.mjs"; import { buildProject, cleanProject, watchProject } from "./scripts/build/projects.mjs"; -import { localBaseline, localRwcBaseline, refBaseline, refRwcBaseline, runConsoleTests } from "./scripts/build/tests.mjs"; +import { localBaseline, refBaseline, runConsoleTests } from "./scripts/build/tests.mjs"; import { Debouncer, Deferred, exec, getDiffTool, memoize, needsUpdate, readJson } from "./scripts/build/utils.mjs"; const glob = util.promisify(_glob); @@ -740,12 +740,6 @@ export const diff = task({ run: () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true, waitForExit: false }), }); -export const diffRwc = task({ - name: "diff-rwc", - description: "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable", - run: () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true, waitForExit: false }), -}); - /** * @param {string} localBaseline Path to the local copy of the baselines * @param {string} refBaseline Path to the reference copy of the baselines @@ -780,12 +774,6 @@ export const baselineAccept = task({ run: baselineAcceptTask(localBaseline, refBaseline), }); -export const baselineAcceptRwc = task({ - name: "baseline-accept-rwc", - description: "Makes the most recent rwc test results the new baseline, overwriting the old baseline", - run: baselineAcceptTask(localRwcBaseline, refRwcBaseline), -}); - // TODO(rbuckton): Determine if we still need this task. Depending on a relative // path here seems like a bad idea. export const updateSublime = task({ @@ -799,13 +787,6 @@ export const updateSublime = task({ } }); -// TODO(rbuckton): Should the path to DefinitelyTyped be configurable via an environment variable? -export const importDefinitelyTypedTests = task({ - name: "importDefinitelyTypedTests", - description: "Runs the importDefinitelyTypedTests script to copy DT's tests to the TS-internal RWC tests", - run: () => exec(process.execPath, ["scripts/importDefinitelyTypedTests.mjs", "./", "../DefinitelyTyped"]), -}); - export const produceLKG = task({ name: "LKG", diff --git a/scripts/build/tests.mjs b/scripts/build/tests.mjs index a7b8ed20e59..205076f51dd 100644 --- a/scripts/build/tests.mjs +++ b/scripts/build/tests.mjs @@ -12,8 +12,6 @@ import { exec, ExecError } from "./utils.mjs"; const mochaJs = path.resolve(findUpRoot(), "node_modules", "mocha", "bin", "_mocha"); export const localBaseline = "tests/baselines/local/"; export const refBaseline = "tests/baselines/reference/"; -export const localRwcBaseline = "internal/baselines/rwc/local"; -export const refRwcBaseline = "internal/baselines/rwc/reference"; export const coverageDir = "coverage"; /** @@ -25,7 +23,7 @@ export const coverageDir = "coverage"; * @param {boolean} [options.watching] */ export async function runConsoleTests(runJs, defaultReporter, runInParallel, options = {}) { - let testTimeout = cmdLineOptions.timeout; + const testTimeout = cmdLineOptions.timeout; const tests = cmdLineOptions.tests; const inspect = cmdLineOptions.break || cmdLineOptions.inspect; const runners = cmdLineOptions.runners; @@ -67,10 +65,6 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt workerCount = cmdLineOptions.workers; } - if (tests && tests.toLocaleLowerCase() === "rwc") { - testTimeout = 400000; - } - if (options.watching) { console.log(chalk.yellowBright(`[watch] running tests...`)); } @@ -174,8 +168,7 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt } export async function cleanTestDirs() { - await del([localBaseline, localRwcBaseline]); - await fs.promises.mkdir(localRwcBaseline, { recursive: true }); + await del([localBaseline]); await fs.promises.mkdir(localBaseline, { recursive: true }); } diff --git a/scripts/importDefinitelyTypedTests.mjs b/scripts/importDefinitelyTypedTests.mjs deleted file mode 100644 index 4687be1fe6b..00000000000 --- a/scripts/importDefinitelyTypedTests.mjs +++ /dev/null @@ -1,178 +0,0 @@ -import * as childProcess from "child_process"; -import * as fs from "fs"; -import * as os from "os"; -import * as path from "path"; -import url from "url"; - -const __filename = url.fileURLToPath(new URL(import.meta.url)); -const __dirname = path.dirname(__filename); - -main(); -function main() { - const [, progName, tscRoot, definitelyTypedRoot] = process.argv; - if (process.argv.length !== 4) { - if (process.argv.length < 2) { - throw new Error("Expected at least 2 argv elements."); - } - console.log("Usage:"); - console.log(` node ${path.relative(__dirname, progName)} [TypeScript Repo Root] [DefinitelyTyped Repo Root]`); - return; - } - - const tscPath = path.resolve(tscRoot, "built", "local", "tsc.js"); - const rwcTestPath = path.resolve(tscRoot, "internal", "cases", "rwc"); - const resolvedDefinitelyTypedRoot = path.resolve(definitelyTypedRoot); - - console.log(`Resolved TypeScript Compiler Path: '${tscPath}'.`); - console.log(`Resolved TypeScript RWC Path: '${rwcTestPath}'.`); - console.log(`Resolved DefinitelyTyped Repo Root: '${resolvedDefinitelyTypedRoot}'.`); - importDefinitelyTypedTests(tscPath, rwcTestPath, resolvedDefinitelyTypedRoot); -} - -/** - * @param {string} path - * @param {string} endingString - * @returns {boolean} - */ -function filePathEndsWith(path, endingString) { - const pathLen = path.length; - const extLen = endingString.length; - return pathLen > extLen && path.substr(pathLen - extLen, extLen).toLocaleLowerCase() === endingString.toLocaleLowerCase(); -} - -/** - * @param {string} source - * @param {string} destination - */ -function copyFileSync(source, destination) { - const text = fs.readFileSync(source); - fs.writeFileSync(destination, text); -} - -/** - * @param {string} tscPath - * @param {string} rwcTestPath - * @param {string} testCaseName - * @param {string[]} testFiles - * @param {string | undefined} responseFile - */ -function importDefinitelyTypedTest(tscPath, rwcTestPath, testCaseName, testFiles, responseFile) { - let cmd = "node " + tscPath + " --module commonjs " + testFiles.join(" "); - if (responseFile) { - cmd += " @" + responseFile; - } - - const testDirectoryName = testCaseName + "_" + Math.floor((Math.random() * 10000) + 1); - const testDirectoryPath = path.join(os.tmpdir(), testDirectoryName); - if (fs.existsSync(testDirectoryPath)) { - throw new Error("Could not create test directory"); - } - fs.mkdirSync(testDirectoryPath); - - childProcess.exec(cmd, { - maxBuffer: 1 * 1024 * 1024, - cwd: testDirectoryPath - }, (error, stdout, stderr) => { - console.log("importing " + testCaseName + " ..."); - console.log(cmd); - - if (error) { - console.log("importing " + testCaseName + " ..."); - console.log(cmd); - console.log("==> error " + JSON.stringify(error)); - console.log("==> stdout " + String(stdout)); - console.log("==> stderr " + String(stderr)); - console.log("\r\n"); - return; - } - - // copy generated file to output location - const outputFilePath = path.join(testDirectoryPath, "iocapture0.json"); - const testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json"); - copyFileSync(outputFilePath, testCasePath); - - //console.log("output generated at: " + outputFilePath); - - if (!fs.existsSync(testCasePath)) { - throw new Error("could not find test case at: " + testCasePath); - } - else { - fs.unlinkSync(outputFilePath); - fs.rmdirSync(testDirectoryPath); - //console.log("testcase generated at: " + testCasePath); - //console.log("Done."); - } - //console.log("\r\n"); - - }).on("error", (error) => { - console.log("==> error " + JSON.stringify(error)); - console.log("\r\n"); - }); -} - -/** - * @param {string} tscPath - * @param {string} rwcTestPath - * @param {string} definitelyTypedRoot - */ -function importDefinitelyTypedTests(tscPath, rwcTestPath, definitelyTypedRoot) { - fs.readdir(definitelyTypedRoot, (err, subDirectories) => { - if (err) { - throw err; - } - - // When you just want to test the script out on one or two files, - // just add a line like the following: - // - // .filter(d => d.indexOf("sipml") >= 0 ) - subDirectories - .filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) < 0) - .filter(i => fs.statSync(path.join(definitelyTypedRoot, i)).isDirectory()) - .forEach(d => { - const directoryPath = path.join(definitelyTypedRoot, d); - fs.readdir(directoryPath, (err, files) => { - if (err) { - throw err; - } - - /** @type {string[]} */ - const tsFiles = []; - /** @type {string[]} */ - const testFiles = []; - /** @type {string | undefined} */ - let paramFile; - - for (const filePath of files.map(f => path.join(directoryPath, f))) { - if (filePathEndsWith(filePath, ".ts")) { - tsFiles.push(filePath); - - if (filePathEndsWith(filePath, "-tests.ts")) { - testFiles.push(filePath); - } - } - else if (filePathEndsWith(filePath, ".tscparams")) { - paramFile = filePath; - } - } - - if (testFiles.length === 0) { - // no test files but multiple d.ts's, e.g. winjs - const regexp = new RegExp(d + "(([-][0-9])|(\\.d\\.ts))"); - if (tsFiles.length > 1 && tsFiles.every(t => filePathEndsWith(t, ".d.ts") && regexp.test(t))) { - for (const fileName of tsFiles) { - importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, ".d.ts"), [fileName], paramFile); - } - } - else { - importDefinitelyTypedTest(tscPath, rwcTestPath, d, tsFiles, paramFile); - } - } - else { - for (const fileName of tsFiles) { - importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, "-tests.ts"), [fileName], paramFile); - } - } - }); - }); - }); -} diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts index f195920ecec..41f4ca2469f 100644 --- a/src/harness/runnerbase.ts +++ b/src/harness/runnerbase.ts @@ -5,7 +5,7 @@ import { } from "./_namespaces/Harness"; import * as ts from "./_namespaces/ts"; -export type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc"; +export type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project"; export type CompilerTestKind = "conformance" | "compiler"; export type FourslashTestKind = "fourslash" | "fourslash-shims" | "fourslash-shims-pp" | "fourslash-server"; diff --git a/src/loggedIO/_namespaces/Harness.ts b/src/loggedIO/_namespaces/Harness.ts deleted file mode 100644 index bcd2ed640dd..00000000000 --- a/src/loggedIO/_namespaces/Harness.ts +++ /dev/null @@ -1,4 +0,0 @@ -/* Generated file to emulate the Harness namespace. */ - -export * from "../../harness/_namespaces/Harness"; -export * from "../loggedIO"; diff --git a/src/loggedIO/_namespaces/Playback.ts b/src/loggedIO/_namespaces/Playback.ts deleted file mode 100644 index a2e238e856a..00000000000 --- a/src/loggedIO/_namespaces/Playback.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* Generated file to emulate the Playback namespace. */ - -export * from "../loggedIO"; diff --git a/src/loggedIO/_namespaces/ts.server.ts b/src/loggedIO/_namespaces/ts.server.ts deleted file mode 100644 index b4a44f9d78c..00000000000 --- a/src/loggedIO/_namespaces/ts.server.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* Generated file to emulate the ts.server namespace. */ - -export * from "../../jsTyping/_namespaces/ts.server"; -export * from "../../server/_namespaces/ts.server"; -export * from "../../typingsInstallerCore/_namespaces/ts.server"; -export * from "../../harness/_namespaces/ts.server"; -export * from "../loggedIO"; diff --git a/src/loggedIO/_namespaces/ts.ts b/src/loggedIO/_namespaces/ts.ts deleted file mode 100644 index 2f90a4b4fb3..00000000000 --- a/src/loggedIO/_namespaces/ts.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* Generated file to emulate the ts namespace. */ - -export * from "../../compiler/_namespaces/ts"; -export * from "../../services/_namespaces/ts"; -export * from "../../jsTyping/_namespaces/ts"; -export * from "../../server/_namespaces/ts"; -export * from "../../typingsInstallerCore/_namespaces/ts"; -export * from "../../harness/_namespaces/ts"; -import * as server from "./ts.server"; -export { server }; diff --git a/src/loggedIO/loggedIO.ts b/src/loggedIO/loggedIO.ts deleted file mode 100644 index 93c596b7f5e..00000000000 --- a/src/loggedIO/loggedIO.ts +++ /dev/null @@ -1,450 +0,0 @@ -import * as Harness from "./_namespaces/Harness"; -import * as ts from "./_namespaces/ts"; - -interface FileInformation { - contents?: string; - contentsPath?: string; - codepage: number; - bom?: string; -} - -interface FindFileResult { -} - -interface IoLogFile { - path: string; - codepage: number; - result?: FileInformation; -} - -export interface IoLog { - timestamp: string; - arguments: string[]; - executingPath: string; - currentDirectory: string; - useCustomLibraryFile?: boolean; - filesRead: IoLogFile[]; - filesWritten: { - path: string; - contents?: string; - contentsPath?: string; - bom: boolean; - }[]; - filesDeleted: string[]; - filesAppended: { - path: string; - contents?: string; - contentsPath?: string; - }[]; - fileExists: { - path: string; - result?: boolean; - }[]; - filesFound: { - path: string; - pattern: string; - result?: FindFileResult; - }[]; - dirs: { - path: string; - re: string; - re_m: boolean; - re_g: boolean; - re_i: boolean; - opts: { recursive?: boolean; }; - result?: string[]; - }[]; - dirExists: { - path: string; - result?: boolean; - }[]; - dirsCreated: string[]; - pathsResolved: { - path: string; - result?: string; - }[]; - directoriesRead: { - path: string, - extensions: readonly string[] | undefined, - exclude: readonly string[] | undefined, - include: readonly string[] | undefined, - depth: number | undefined, - result: readonly string[], - }[]; - useCaseSensitiveFileNames?: boolean; -} - -interface PlaybackControl { - startReplayFromFile(logFileName: string): void; - startReplayFromString(logContents: string): void; - startReplayFromData(log: IoLog): void; - endReplay(): void; - startRecord(logFileName: string): void; - endRecord(): void; -} - -let recordLog: IoLog | undefined; -let replayLog: IoLog | undefined; -let replayFilesRead: Map | undefined; -let recordLogFileNameBase = ""; - -interface Memoized { - (s: string): T; - reset(): void; -} - -function memoize(func: (s: string) => T): Memoized { - let lookup: { [s: string]: T } = {}; - const run: Memoized = ((s: string) => { - if (ts.hasProperty(lookup, s)) return lookup[s]; - return lookup[s] = func(s); - }) as Memoized; - run.reset = () => { - lookup = undefined!; // TODO: GH#18217 - }; - - return run; -} - -export interface PlaybackIO extends Harness.IO, PlaybackControl { } - -export interface PlaybackSystem extends ts.System, PlaybackControl { } - -function createEmptyLog(): IoLog { - return { - timestamp: (new Date()).toString(), - arguments: [], - currentDirectory: "", - filesRead: [], - directoriesRead: [], - filesWritten: [], - filesDeleted: [], - filesAppended: [], - fileExists: [], - filesFound: [], - dirs: [], - dirExists: [], - dirsCreated: [], - pathsResolved: [], - executingPath: "" - }; -} - -export function newStyleLogIntoOldStyleLog(log: IoLog, host: ts.System | Harness.IO, baseName: string) { - for (const file of log.filesAppended) { - if (file.contentsPath) { - file.contents = host.readFile(ts.combinePaths(baseName, file.contentsPath)); - delete file.contentsPath; - } - } - for (const file of log.filesWritten) { - if (file.contentsPath) { - file.contents = host.readFile(ts.combinePaths(baseName, file.contentsPath)); - delete file.contentsPath; - } - } - for (const file of log.filesRead) { - const result = file.result!; // TODO: GH#18217 - if (result.contentsPath) { - // `readFile` strips away a BOM (and actually reinerprets the file contents according to the correct encoding) - // - but this has the unfortunate sideeffect of removing the BOM from any outputs based on the file, so we readd it here. - result.contents = (result.bom || "") + host.readFile(ts.combinePaths(baseName, result.contentsPath)); - delete result.contentsPath; - } - } - return log; -} - -const canonicalizeForHarness = ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false); // This is done so tests work on windows _and_ linux -function sanitizeTestFilePath(name: string) { - const path = ts.toPath(ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), "", canonicalizeForHarness); - if (ts.startsWith(path, "/")) { - return path.substring(1); - } - return path; -} - -export function oldStyleLogIntoNewStyleLog(log: IoLog, writeFile: typeof Harness.IO.writeFile, baseTestName: string) { - if (log.filesAppended) { - for (const file of log.filesAppended) { - if (file.contents !== undefined) { - file.contentsPath = ts.combinePaths("appended", sanitizeTestFilePath(file.path)); - writeFile(ts.combinePaths(baseTestName, file.contentsPath), file.contents); - delete file.contents; - } - } - } - if (log.filesWritten) { - for (const file of log.filesWritten) { - if (file.contents !== undefined) { - file.contentsPath = ts.combinePaths("written", sanitizeTestFilePath(file.path)); - writeFile(ts.combinePaths(baseTestName, file.contentsPath), file.contents); - delete file.contents; - } - } - } - if (log.filesRead) { - for (const file of log.filesRead) { - const result = file.result!; // TODO: GH#18217 - const { contents } = result; - if (contents !== undefined) { - result.contentsPath = ts.combinePaths("read", sanitizeTestFilePath(file.path)); - writeFile(ts.combinePaths(baseTestName, result.contentsPath), contents); - const len = contents.length; - if (len >= 2 && contents.charCodeAt(0) === 0xfeff) { - result.bom = "\ufeff"; - } - if (len >= 2 && contents.charCodeAt(0) === 0xfffe) { - result.bom = "\ufffe"; - } - if (len >= 3 && contents.charCodeAt(0) === 0xefbb && contents.charCodeAt(1) === 0xbf) { - result.bom = "\uefbb\xbf"; - } - delete result.contents; - } - } - } - return log; -} - -export function initWrapper(...[wrapper, underlying]: [PlaybackSystem, ts.System] | [PlaybackIO, Harness.IO]): void { - ts.forEach(Object.keys(underlying), prop => { - (wrapper as any)[prop] = (underlying as any)[prop]; - }); - - wrapper.startReplayFromString = logString => { - wrapper.startReplayFromData(JSON.parse(logString)); - }; - wrapper.startReplayFromData = log => { - replayLog = log; - // Remove non-found files from the log (shouldn't really need them, but we still record them for diagnostic purposes) - replayLog.filesRead = replayLog.filesRead.filter(f => f.result!.contents !== undefined); - replayFilesRead = new Map(); - for (const file of replayLog.filesRead) { - replayFilesRead.set(ts.normalizeSlashes(file.path).toLowerCase(), file); - } - }; - - wrapper.endReplay = () => { - replayLog = undefined; - replayFilesRead = undefined; - }; - - wrapper.startRecord = (fileNameBase) => { - recordLogFileNameBase = fileNameBase; - recordLog = createEmptyLog(); - recordLog.useCaseSensitiveFileNames = typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames; - if (typeof underlying.args !== "function") { - recordLog.arguments = underlying.args; - } - }; - - wrapper.startReplayFromFile = logFn => { - wrapper.startReplayFromString(underlying.readFile(logFn)!); - }; - wrapper.endRecord = () => { - if (recordLog !== undefined) { - let i = 0; - const getBase = () => recordLogFileNameBase + i; - while (underlying.fileExists(ts.combinePaths(getBase(), "test.json"))) i++; - const newLog = oldStyleLogIntoNewStyleLog(recordLog, (path, str) => underlying.writeFile(path, str), getBase()); - underlying.writeFile(ts.combinePaths(getBase(), "test.json"), JSON.stringify(newLog, null, 4)); // eslint-disable-line no-null/no-null - const syntheticTsconfig = generateTsconfig(newLog); - if (syntheticTsconfig) { - underlying.writeFile(ts.combinePaths(getBase(), "tsconfig.json"), JSON.stringify(syntheticTsconfig, null, 4)); // eslint-disable-line no-null/no-null - } - recordLog = undefined; - } - }; - - function generateTsconfig(newLog: IoLog): undefined | { compilerOptions: ts.CompilerOptions, files: string[] } { - if (newLog.filesRead.some(file => /tsconfig.+json$/.test(file.path))) { - return; - } - const files = []; - for (const file of newLog.filesRead) { - const result = file.result!; - if (result.contentsPath && - Harness.isDefaultLibraryFile(result.contentsPath) && - /\.[tj]s$/.test(result.contentsPath)) { - files.push(result.contentsPath); - } - } - return { compilerOptions: ts.parseCommandLine(newLog.arguments).options, files }; - } - - wrapper.fileExists = recordReplay(wrapper.fileExists, underlying)( - path => callAndRecord(underlying.fileExists(path), recordLog!.fileExists, { path }), - memoize(path => { - // If we read from the file, it must exist - if (findFileByPath(path, /*throwFileNotFoundError*/ false)) { - return true; - } - else { - return findResultByFields(replayLog!.fileExists, { path }, /*defaultValue*/ false)!; - } - }) - ); - - wrapper.getExecutingFilePath = () => { - if (replayLog !== undefined) { - return replayLog.executingPath; - } - else if (recordLog !== undefined) { - return recordLog.executingPath = underlying.getExecutingFilePath(); - } - else { - return underlying.getExecutingFilePath(); - } - }; - - wrapper.getCurrentDirectory = () => { - if (replayLog !== undefined) { - return replayLog.currentDirectory || ""; - } - else if (recordLog !== undefined) { - return recordLog.currentDirectory = underlying.getCurrentDirectory(); - } - else { - return underlying.getCurrentDirectory(); - } - }; - - wrapper.resolvePath = recordReplay(wrapper.resolvePath, underlying)( - path => callAndRecord(underlying.resolvePath(path), recordLog!.pathsResolved, { path }), - memoize(path => findResultByFields(replayLog!.pathsResolved, { path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog!.currentDirectory ? replayLog!.currentDirectory + "/" + path : ts.normalizeSlashes(path)))); - - wrapper.readFile = recordReplay(wrapper.readFile, underlying)( - (path: string) => { - const result = underlying.readFile(path); - const logEntry = { path, codepage: 0, result: { contents: result, codepage: 0 } }; - recordLog!.filesRead.push(logEntry); - return result; - }, - memoize(path => findFileByPath(path, /*throwFileNotFoundError*/ true)!.contents)); - - wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)( - (path, extensions, exclude, include, depth) => { - const result = (underlying as ts.System).readDirectory(path, extensions, exclude, include, depth); - recordLog!.directoriesRead.push({ path, extensions, exclude, include, depth, result }); - return result; - }, - path => { - // Because extensions is an array of all allowed extension, we will want to merge each of the replayLog.directoriesRead into one - // if each of the directoriesRead has matched path with the given path (directory with same path but different extension will considered - // different entry). - // TODO (yuisu): We can certainly remove these once we recapture the RWC using new API - const normalizedPath = ts.normalizePath(path).toLowerCase(); - return ts.flatMap(replayLog!.directoriesRead, directory => { - if (ts.normalizeSlashes(directory.path).toLowerCase() === normalizedPath) { - return directory.result; - } - }); - }); - - wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)( - (path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog!.filesWritten, { path, contents, bom: false }), - () => noOpReplay("writeFile")); - - wrapper.exit = (exitCode) => { - if (recordLog !== undefined) { - wrapper.endRecord(); - } - underlying.exit(exitCode); - }; - - wrapper.useCaseSensitiveFileNames = () => { - if (replayLog !== undefined) { - return !!replayLog.useCaseSensitiveFileNames; - } - return typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames; - }; -} - -function recordReplay(original: T, underlying: any) { - function createWrapper(record: T, replay: T): T { - // eslint-disable-next-line local/only-arrow-functions - return (function () { - if (replayLog !== undefined) { - return replay.apply(undefined, arguments); - } - else if (recordLog !== undefined) { - return record.apply(undefined, arguments); - } - else { - return original.apply(underlying, arguments); - } - } as any); - } - return createWrapper; -} - -function callAndRecord(underlyingResult: T, logArray: U[], logEntry: U): T { - if (underlyingResult !== undefined) { - (logEntry as any).result = underlyingResult; - } - logArray.push(logEntry); - return underlyingResult; -} - -function findResultByFields(logArray: { result?: T }[], expectedFields: {}, defaultValue?: T): T | undefined { - const predicate = (entry: { result?: T }) => { - return Object.getOwnPropertyNames(expectedFields).every((name) => (entry as any)[name] === (expectedFields as any)[name]); - }; - const results = logArray.filter(entry => predicate(entry)); - if (results.length === 0) { - if (defaultValue !== undefined) { - return defaultValue; - } - else { - throw new Error("No matching result in log array for: " + JSON.stringify(expectedFields)); - } - } - return results[0].result; -} - -function findFileByPath(expectedPath: string, throwFileNotFoundError: boolean): FileInformation | undefined { - const normalizedName = ts.normalizePath(expectedPath).toLowerCase(); - // Try to find the result through normal fileName - const result = replayFilesRead!.get(normalizedName); - if (result) { - return result.result; - } - - // If we got here, we didn't find a match - if (throwFileNotFoundError) { - throw new Error("No matching result in log array for path: " + expectedPath); - } - else { - return undefined; - } -} - -function noOpReplay(_name: string) { - // console.log("Swallowed write operation during replay: " + name); -} - -export function wrapIO(underlying: Harness.IO): PlaybackIO { - const wrapper: PlaybackIO = {} as any; - initWrapper(wrapper, underlying); - - wrapper.directoryName = notSupported; - wrapper.createDirectory = notSupported; - wrapper.directoryExists = notSupported; - wrapper.deleteFile = notSupported; - wrapper.listFiles = notSupported; - - return wrapper; - - function notSupported(): never { - throw new Error("NotSupported"); - } -} - -export function wrapSystem(underlying: ts.System): PlaybackSystem { - const wrapper: PlaybackSystem = {} as any; - initWrapper(wrapper, underlying); - return wrapper; -} - -// empty modules for the module migration script diff --git a/src/loggedIO/tsconfig.json b/src/loggedIO/tsconfig.json deleted file mode 100644 index 9d5e45ea88e..00000000000 --- a/src/loggedIO/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../tsconfig-base", - "compilerOptions": { - "types": [ - ] - }, - "references": [ - { "path": "../compiler" }, - { "path": "../services" }, - { "path": "../jsTyping" }, - { "path": "../server" }, - { "path": "../typingsInstallerCore" }, - { "path": "../harness" }, - ], - - "include": ["**/*"] -} diff --git a/src/testRunner/_namespaces/Harness.ts b/src/testRunner/_namespaces/Harness.ts index 8ce2b8b1710..e9b235a19d6 100644 --- a/src/testRunner/_namespaces/Harness.ts +++ b/src/testRunner/_namespaces/Harness.ts @@ -1,7 +1,6 @@ /* Generated file to emulate the Harness namespace. */ export * from "../../harness/_namespaces/Harness"; -export * from "../../loggedIO/_namespaces/Harness"; import * as Parallel from "./Harness.Parallel"; export { Parallel }; diff --git a/src/testRunner/_namespaces/Playback.ts b/src/testRunner/_namespaces/Playback.ts deleted file mode 100644 index 90e7eae5f16..00000000000 --- a/src/testRunner/_namespaces/Playback.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* Generated file to emulate the Playback namespace. */ - -export * from "../../loggedIO/_namespaces/Playback"; diff --git a/src/testRunner/_namespaces/RWC.ts b/src/testRunner/_namespaces/RWC.ts deleted file mode 100644 index a2d6ebf4fa8..00000000000 --- a/src/testRunner/_namespaces/RWC.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* Generated file to emulate the RWC namespace. */ - -export * from "../rwcRunner"; diff --git a/src/testRunner/_namespaces/ts.server.ts b/src/testRunner/_namespaces/ts.server.ts index 3af988500c0..b0a090fcfed 100644 --- a/src/testRunner/_namespaces/ts.server.ts +++ b/src/testRunner/_namespaces/ts.server.ts @@ -4,4 +4,3 @@ export * from "../../jsTyping/_namespaces/ts.server"; export * from "../../server/_namespaces/ts.server"; export * from "../../typingsInstallerCore/_namespaces/ts.server"; export * from "../../harness/_namespaces/ts.server"; -export * from "../../loggedIO/_namespaces/ts.server"; diff --git a/src/testRunner/_namespaces/ts.ts b/src/testRunner/_namespaces/ts.ts index d9f1d2e9eef..18d1bb33fc9 100644 --- a/src/testRunner/_namespaces/ts.ts +++ b/src/testRunner/_namespaces/ts.ts @@ -8,6 +8,5 @@ export * from "../../server/_namespaces/ts"; export * from "../../typingsInstallerCore/_namespaces/ts"; export * from "../../deprecatedCompat/_namespaces/ts"; export * from "../../harness/_namespaces/ts"; -export * from "../../loggedIO/_namespaces/ts"; import * as server from "./ts.server"; export { server }; diff --git a/src/testRunner/runner.ts b/src/testRunner/runner.ts index 24c9fca26ac..3331be003e7 100644 --- a/src/testRunner/runner.ts +++ b/src/testRunner/runner.ts @@ -13,7 +13,6 @@ import { TestRunnerKind, } from "./_namespaces/Harness"; import * as project from "./_namespaces/project"; -import * as RWC from "./_namespaces/RWC"; import * as ts from "./_namespaces/ts"; import * as vpath from "./_namespaces/vpath"; @@ -72,8 +71,6 @@ export function createRunner(kind: TestRunnerKind): RunnerBase { return new FourSlashRunner(FourSlash.FourSlashTestType.Server); case "project": return new project.ProjectRunner(); - case "rwc": - return new RWC.RWCRunner(); } return ts.Debug.fail(`Unknown runner kind ${kind}`); } @@ -205,8 +202,6 @@ function handleTestConfig() { case "fourslash-generated": runners.push(new GeneratedFourslashRunner(FourSlash.FourSlashTestType.Native)); break; - case "rwc": - runners.push(new RWC.RWCRunner()); break; } } diff --git a/src/testRunner/rwcRunner.ts b/src/testRunner/rwcRunner.ts deleted file mode 100644 index b68e58cc686..00000000000 --- a/src/testRunner/rwcRunner.ts +++ /dev/null @@ -1,239 +0,0 @@ -import * as compiler from "./_namespaces/compiler"; -import * as Harness from "./_namespaces/Harness"; -import * as Playback from "./_namespaces/Playback"; -import * as ts from "./_namespaces/ts"; -import * as vpath from "./_namespaces/vpath"; - -// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`. -function runWithIOLog(ioLog: Playback.IoLog, fn: (oldIO: Harness.IO) => void) { - const oldIO = Harness.IO; - - const wrappedIO = Playback.wrapIO(oldIO); - wrappedIO.startReplayFromData(ioLog); - Harness.setHarnessIO(wrappedIO); - - try { - fn(oldIO); - } - finally { - wrappedIO.endReplay(); - Harness.setHarnessIO(oldIO); - } -} - -export function runRWCTest(jsonPath: string) { - describe("Testing a rwc project: " + jsonPath, () => { - let inputFiles: Harness.Compiler.TestFile[] = []; - let otherFiles: Harness.Compiler.TestFile[] = []; - let tsconfigFiles: Harness.Compiler.TestFile[] = []; - let compilerResult: compiler.CompilationResult; - let compilerOptions: ts.CompilerOptions; - const baselineOpts: Harness.Baseline.BaselineOptions = { - Subfolder: "rwc", - Baselinefolder: "internal/baselines" - }; - const baseName = ts.getBaseFileName(jsonPath); - let currentDirectory: string; - let useCustomLibraryFile: boolean; - let caseSensitive: boolean; - after(() => { - // Mocha holds onto the closure environment of the describe callback even after the test is done. - // Therefore we have to clean out large objects after the test is done. - inputFiles = []; - otherFiles = []; - tsconfigFiles = []; - compilerResult = undefined!; - compilerOptions = undefined!; - currentDirectory = undefined!; - // useCustomLibraryFile is a flag specified in the json object to indicate whether to use built/local/lib.d.ts - // or to use lib.d.ts inside the json object. If the flag is true, use the lib.d.ts inside json file - // otherwise use the lib.d.ts from built/local - useCustomLibraryFile = false; - caseSensitive = false; - }); - - it("can compile", function (this: Mocha.Context) { - this.timeout(800_000); // Allow long timeouts for RWC compilations - let opts!: ts.ParsedCommandLine; - - const ioLog: Playback.IoLog = Playback.newStyleLogIntoOldStyleLog(JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)!), Harness.IO, `internal/cases/rwc/${baseName}`); - currentDirectory = ioLog.currentDirectory; - useCustomLibraryFile = !!ioLog.useCustomLibraryFile; - runWithIOLog(ioLog, () => { - opts = ts.parseCommandLine(ioLog.arguments, fileName => Harness.IO.readFile(fileName)); - assert.equal(opts.errors.length, 0); - - // To provide test coverage of output javascript file, - // we will set noEmitOnError flag to be false. - opts.options.noEmitOnError = false; - }); - let fileNames = opts.fileNames; - - runWithIOLog(ioLog, () => { - const tsconfigFile = ts.forEach(ioLog.filesRead, f => vpath.isTsConfigFile(f.path) ? f : undefined); - if (tsconfigFile) { - const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path); - tsconfigFiles.push({ unitName: tsconfigFile.path, content: tsconfigFileContents.content }); - const parsedTsconfigFileContents = ts.parseJsonText(tsconfigFile.path, tsconfigFileContents.content); - const configParseHost: ts.ParseConfigHost = { - useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(), - fileExists: Harness.IO.fileExists, - readDirectory: Harness.IO.readDirectory, - readFile: Harness.IO.readFile - }; - const configParseResult = ts.parseJsonSourceFileConfigFileContent(parsedTsconfigFileContents, configParseHost, ts.getDirectoryPath(tsconfigFile.path)); - fileNames = configParseResult.fileNames; - opts.options = ts.extend(opts.options, configParseResult.options); - ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile); - } - - // Deduplicate files so they are only printed once in baselines (they are deduplicated within the compiler already) - const uniqueNames = new Map(); - for (const fileName of fileNames) { - // Must maintain order, build result list while checking map - const normalized = ts.normalizeSlashes(Harness.IO.resolvePath(fileName)!); - if (!uniqueNames.has(normalized)) { - uniqueNames.set(normalized, true); - // Load the file - inputFiles.push(getHarnessCompilerInputUnit(fileName)); - } - } - - // Add files to compilation - for (const fileRead of ioLog.filesRead) { - const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileRead.path)!); - if (!uniqueNames.has(unitName) && !Harness.isDefaultLibraryFile(fileRead.path)) { - uniqueNames.set(unitName, true); - otherFiles.push(getHarnessCompilerInputUnit(fileRead.path)); - } - else if (!opts.options.noLib && Harness.isDefaultLibraryFile(fileRead.path) && !uniqueNames.has(unitName) && useCustomLibraryFile) { - // If useCustomLibraryFile is true, we will use lib.d.ts from json object - // otherwise use the lib.d.ts from built/local - // Majority of RWC code will be using built/local/lib.d.ts instead of - // lib.d.ts inside json file. However, some RWC cases will still use - // their own version of lib.d.ts because they have customized lib.d.ts - uniqueNames.set(unitName, true); - inputFiles.push(getHarnessCompilerInputUnit(fileRead.path)); - } - } - }); - - if (useCustomLibraryFile) { - // do not use lib since we already read it in above - opts.options.lib = undefined; - opts.options.noLib = true; - } - - caseSensitive = ioLog.useCaseSensitiveFileNames || false; - // Emit the results - compilerResult = Harness.Compiler.compileFiles( - inputFiles, - otherFiles, - { useCaseSensitiveFileNames: "" + caseSensitive }, - opts.options, - // Since each RWC json file specifies its current directory in its json file, we need - // to pass this information in explicitly instead of acquiring it from the process. - currentDirectory); - compilerOptions = compilerResult.options; - - function getHarnessCompilerInputUnit(fileName: string): Harness.Compiler.TestFile { - const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName)!); - let content: string; - try { - content = Harness.IO.readFile(unitName)!; - } - catch (e) { - content = Harness.IO.readFile(fileName)!; - } - return { unitName, content }; - } - }); - - - it("has the expected emitted code", function (this: Mocha.Context) { - this.timeout(100_000); // Allow longer timeouts for RWC js verification - Harness.Baseline.runMultifileBaseline(baseName, "", () => { - return Harness.Compiler.iterateOutputs(compilerResult.js.values()); - }, baselineOpts, [".js", ".jsx"]); - }); - - it("has the expected declaration file content", () => { - Harness.Baseline.runMultifileBaseline(baseName, "", () => { - if (!compilerResult.dts.size) { - return null; // eslint-disable-line no-null/no-null - } - - return Harness.Compiler.iterateOutputs(compilerResult.dts.values()); - }, baselineOpts, [".d.ts"]); - }); - - it("has the expected source maps", () => { - Harness.Baseline.runMultifileBaseline(baseName, "", () => { - if (!compilerResult.maps.size) { - return null; // eslint-disable-line no-null/no-null - } - - return Harness.Compiler.iterateOutputs(compilerResult.maps.values()); - }, baselineOpts, [".map"]); - }); - - it("has the expected errors", () => { - Harness.Baseline.runMultifileBaseline(baseName, ".errors.txt", () => { - if (compilerResult.diagnostics.length === 0) { - return null; // eslint-disable-line no-null/no-null - } - // Do not include the library in the baselines to avoid noise - const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName)); - const errors = compilerResult.diagnostics.filter(e => !e.file || !Harness.isDefaultLibraryFile(e.file.fileName)); - return Harness.Compiler.iterateErrorBaseline(baselineFiles, errors, { caseSensitive, currentDirectory }); - }, baselineOpts); - }); - - // Ideally, a generated declaration file will have no errors. But we allow generated - // declaration file errors as part of the baseline. - it("has the expected errors in generated declaration files", () => { - if (compilerOptions.declaration && !compilerResult.diagnostics.length) { - Harness.Baseline.runMultifileBaseline(baseName, ".dts.errors.txt", () => { - if (compilerResult.diagnostics.length === 0) { - return null; // eslint-disable-line no-null/no-null - } - - const declContext = Harness.Compiler.prepareDeclarationCompilationContext( - inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined!, compilerOptions, currentDirectory // TODO: GH#18217 - ); - // Reset compilerResult before calling into `compileDeclarationFiles` so the memory from the original compilation can be freed - const links = compilerResult.symlinks; - compilerResult = undefined!; - const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext, links)!; - - return Harness.Compiler.iterateErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics, { caseSensitive, currentDirectory }); - }, baselineOpts); - } - }); - }); -} - -export class RWCRunner extends Harness.RunnerBase { - public enumerateTestFiles() { - // see also: `enumerateTestFiles` in tests/webTestServer.ts - return Harness.IO.getDirectories("internal/cases/rwc/"); - } - - public kind(): Harness.TestRunnerKind { - return "rwc"; - } - - /** Setup the runner's tests so that they are ready to be executed by the harness - * The first test should be a describe/it block that sets up the harness's compiler instance appropriately - */ - public initializeTests(): void { - // Read in and evaluate the test list - for (const test of this.tests && this.tests.length ? this.tests : this.getTestFiles()) { - this.runTest(typeof test === "string" ? test : test.file); - } - } - - private runTest(jsonFileName: string) { - runRWCTest(jsonFileName); - } -} diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index d1c9eb3671e..89bcb24c0d5 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -14,7 +14,6 @@ { "path": "../typingsInstallerCore" }, { "path": "../deprecatedCompat" }, { "path": "../harness" }, - { "path": "../loggedIO" } ], "include": ["**/*"] } diff --git a/src/tsconfig.json b/src/tsconfig.json index 8603eaa5bab..41c4a2026a7 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -8,7 +8,6 @@ { "path": "./executeCommandLine" }, { "path": "./harness" }, { "path": "./jsTyping" }, - { "path": "./loggedIO" }, { "path": "./server" }, { "path": "./services" }, { "path": "./testRunner" },