diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts index f2e269763ab..dee4d749487 100644 --- a/src/harness/unittests/reuseProgramStructure.ts +++ b/src/harness/unittests/reuseProgramStructure.ts @@ -869,4 +869,172 @@ namespace ts { createProgram([], {}); }); }); + + import TestSystem = ts.TestFSWithWatch.TestServerHost; + type FileOrFolder = ts.TestFSWithWatch.FileOrFolder; + import createTestSystem = ts.TestFSWithWatch.createWatchedSystem; + import libFile = ts.TestFSWithWatch.libFile; + + describe("isProgramUptoDate should return true when there is no change in compiler options and", () => { + function verifyProgramIsUptoDate( + program: Program, + newRootFileNames: string[], + newOptions: CompilerOptions + ) { + const actual = isProgramUptoDate( + program, newRootFileNames, newOptions, + path => program.getSourceFileByPath(path).version, /*fileExists*/ returnFalse, + /*hasInvalidatedResolution*/ returnFalse, + /*hasChangedAutomaticTypeDirectiveNames*/ returnFalse + ); + assert.isTrue(actual); + } + + function duplicate(options: CompilerOptions): CompilerOptions; + function duplicate(fileNames: string[]): string[]; + function duplicate(filesOrOptions: CompilerOptions | string[]) { + return JSON.parse(JSON.stringify(filesOrOptions)); + } + + function createWatchingSystemHost(host: TestSystem) { + return ts.createWatchingSystemHost(/*pretty*/ undefined, host); + } + + function verifyProgramWithoutConfigFile(watchingSystemHost: WatchingSystemHost, rootFiles: string[], options: CompilerOptions) { + const program = createWatchModeWithoutConfigFile(rootFiles, options, watchingSystemHost)(); + verifyProgramIsUptoDate(program, duplicate(rootFiles), duplicate(options)); + } + + function getConfigParseResult(watchingSystemHost: WatchingSystemHost, configFileName: string) { + return parseConfigFile(configFileName, {}, watchingSystemHost.system, watchingSystemHost.reportDiagnostic, watchingSystemHost.reportWatchDiagnostic); + } + + function verifyProgramWithConfigFile(watchingSystemHost: WatchingSystemHost, configFile: string) { + const result = getConfigParseResult(watchingSystemHost, configFile); + const program = createWatchModeWithConfigFile(result, {}, watchingSystemHost)(); + const { fileNames, options } = getConfigParseResult(watchingSystemHost, configFile); + verifyProgramIsUptoDate(program, fileNames, options); + } + + function verifyProgram(files: FileOrFolder[], rootFiles: string[], options: CompilerOptions, configFile: string) { + const watchingSystemHost = createWatchingSystemHost(createTestSystem(files)); + verifyProgramWithoutConfigFile(watchingSystemHost, rootFiles, options); + verifyProgramWithConfigFile(watchingSystemHost, configFile); + } + + it("has empty options", () => { + const file1: FileOrFolder = { + path: "/a/b/file1.ts", + content: "let x = 1" + }; + const file2: FileOrFolder = { + path: "/a/b/file2.ts", + content: "let y = 1" + }; + const configFile: FileOrFolder = { + path: "/a/b/tsconfig.json", + content: "{}" + }; + verifyProgram([file1, file2, libFile, configFile], [file1.path, file2.path], {}, configFile.path); + }); + + it("has lib specified in the options", () => { + const compilerOptions: CompilerOptions = { lib: ["es5", "es2015.promise"] }; + const app: FileOrFolder = { + path: "/src/app.ts", + content: "var x: Promise;" + }; + const configFile: FileOrFolder = { + path: "/src/tsconfig.json", + content: JSON.stringify({ compilerOptions }) + }; + const es5Lib: FileOrFolder = { + path: "/compiler/lib.es5.d.ts", + content: "declare const eval: any" + }; + const es2015Promise: FileOrFolder = { + path: "/compiler/lib.es2015.promise.d.ts", + content: "declare class Promise {}" + }; + + verifyProgram([app, configFile, es5Lib, es2015Promise], [app.path], compilerOptions, configFile.path); + }); + + it("has paths specified in the options", () => { + const compilerOptions: CompilerOptions = { + baseUrl: ".", + paths: { + "*": [ + "packages/mail/data/*", + "packages/styles/*", + "*" + ] + } + }; + const app: FileOrFolder = { + path: "/src/packages/framework/app.ts", + content: 'import classc from "module1/lib/file1";\ + import classD from "module3/file3";\ + let x = new classc();\ + let y = new classD();' + }; + const module1: FileOrFolder = { + path: "/src/packages/mail/data/module1/lib/file1.ts", + content: 'import classc from "module2/file2";export default classc;', + }; + const module2: FileOrFolder = { + path: "/src/packages/mail/data/module1/lib/module2/file2.ts", + content: 'class classc { method2() { return "hello"; } }\nexport default classc', + }; + const module3: FileOrFolder = { + path: "/src/packages/styles/module3/file3.ts", + content: "class classD { method() { return 10; } }\nexport default classD;" + }; + const configFile: FileOrFolder = { + path: "/src/tsconfig.json", + content: JSON.stringify({ compilerOptions }) + }; + + verifyProgram([app, module1, module2, module3, libFile, configFile], [app.path], compilerOptions, configFile.path); + }); + + it("has include paths specified in tsconfig file", () => { + const compilerOptions: CompilerOptions = { + baseUrl: ".", + paths: { + "*": [ + "packages/mail/data/*", + "packages/styles/*", + "*" + ] + } + }; + const app: FileOrFolder = { + path: "/src/packages/framework/app.ts", + content: 'import classc from "module1/lib/file1";\ + import classD from "module3/file3";\ + let x = new classc();\ + let y = new classD();' + }; + const module1: FileOrFolder = { + path: "/src/packages/mail/data/module1/lib/file1.ts", + content: 'import classc from "module2/file2";export default classc;', + }; + const module2: FileOrFolder = { + path: "/src/packages/mail/data/module1/lib/module2/file2.ts", + content: 'class classc { method2() { return "hello"; } }\nexport default classc', + }; + const module3: FileOrFolder = { + path: "/src/packages/styles/module3/file3.ts", + content: "class classD { method() { return 10; } }\nexport default classD;" + }; + const configFile: FileOrFolder = { + path: "/src/tsconfig.json", + content: JSON.stringify({ compilerOptions, include: ["packages/**/ *.ts"] }) + }; + + const watchingSystemHost = createWatchingSystemHost(createTestSystem([app, module1, module2, module3, libFile, configFile])); + verifyProgramWithConfigFile(watchingSystemHost, configFile.path); + }); + }); }