Write first test with --build and --watch

This commit is contained in:
Sheetal Nandi 2018-08-17 14:05:05 -07:00
parent 13bd4788d9
commit 17ee9231b7
8 changed files with 123 additions and 46 deletions

View File

@ -66,20 +66,20 @@ namespace ts {
mtime: Date;
}
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
const existingDirectories = createMap<boolean>();
function getCanonicalFileName(fileName: string): string {
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
// otherwise use toLowerCase as a canonical form.
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
let text: string | undefined;
try {
performance.mark("beforeIORead");
text = sys.readFile(fileName, options.charset);
text = system.readFile(fileName, options.charset);
performance.mark("afterIORead");
performance.measure("I/O Read", "beforeIORead", "afterIORead");
}
@ -97,7 +97,7 @@ namespace ts {
if (existingDirectories.has(directoryPath)) {
return true;
}
if (sys.directoryExists(directoryPath)) {
if (system.directoryExists(directoryPath)) {
existingDirectories.set(directoryPath, true);
return true;
}
@ -108,7 +108,7 @@ namespace ts {
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
const parentDirectory = getDirectoryPath(directoryPath);
ensureDirectoriesExist(parentDirectory);
sys.createDirectory(directoryPath);
system.createDirectory(directoryPath);
}
}
@ -119,8 +119,8 @@ namespace ts {
outputFingerprints = createMap<OutputFingerprint>();
}
const hash = sys.createHash!(data); // TODO: GH#18217
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
const hash = system.createHash!(data); // TODO: GH#18217
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
if (mtimeBefore) {
const fingerprint = outputFingerprints.get(fileName);
@ -133,9 +133,9 @@ namespace ts {
}
}
sys.writeFile(fileName, data, writeByteOrderMark);
system.writeFile(fileName, data, writeByteOrderMark);
const mtimeAfter = sys.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
outputFingerprints.set(fileName, {
hash,
@ -149,11 +149,11 @@ namespace ts {
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
writeFileIfUpdated(fileName, data, writeByteOrderMark);
}
else {
sys.writeFile(fileName, data, writeByteOrderMark);
system.writeFile(fileName, data, writeByteOrderMark);
}
performance.mark("afterIOWrite");
@ -167,32 +167,32 @@ namespace ts {
}
function getDefaultLibLocation(): string {
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
}
const newLine = getNewLineCharacter(options);
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
const realpath = system.realpath && ((path: string) => system.realpath!(path));
return {
getSourceFile,
getDefaultLibLocation,
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
writeFile,
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
getCanonicalFileName,
getNewLine: () => newLine,
fileExists: fileName => sys.fileExists(fileName),
readFile: fileName => sys.readFile(fileName),
trace: (s: string) => sys.write(s + newLine),
directoryExists: directoryName => sys.directoryExists(directoryName),
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
getDirectories: (path: string) => sys.getDirectories(path),
fileExists: fileName => system.fileExists(fileName),
readFile: fileName => system.readFile(fileName),
trace: (s: string) => system.write(s + newLine),
directoryExists: directoryName => system.directoryExists(directoryName),
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
getDirectories: (path: string) => system.getDirectories(path),
realpath,
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
getModifiedTime: system.getModifiedTime && (path => system.getModifiedTime!(path)),
setModifiedTime: system.setModifiedTime && ((path, date) => system.setModifiedTime!(path, date)),
deleteFile: system.deleteFile && (path => system.deleteFile!(path))
};
}

View File

@ -620,14 +620,14 @@ interface Array<T> {}`
}
}
removeFile(filePath: string) {
deleteFile(filePath: string) {
const path = this.toFullPath(filePath);
const currentEntry = this.fs.get(path) as FsFile;
Debug.assert(isFsFile(currentEntry));
this.removeFileOrFolder(currentEntry, returnFalse);
}
removeFolder(folderPath: string, recursive?: boolean) {
deleteFolder(folderPath: string, recursive?: boolean) {
const path = this.toFullPath(folderPath);
const currentEntry = this.fs.get(path) as FsFolder;
Debug.assert(isFsFolder(currentEntry));
@ -635,7 +635,7 @@ interface Array<T> {}`
const subEntries = currentEntry.entries.slice();
subEntries.forEach(fsEntry => {
if (isFsFolder(fsEntry)) {
this.removeFolder(fsEntry.fullPath, recursive);
this.deleteFolder(fsEntry.fullPath, recursive);
}
else {
this.removeFileOrFolder(fsEntry, returnFalse);
@ -766,6 +766,14 @@ interface Array<T> {}`
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
}
setModifiedTime(s: string, date: Date) {
const path = this.toFullPath(s);
const fsEntry = this.fs.get(path);
if (fsEntry) {
fsEntry.modifiedTime = date;
}
}
readFile(s: string): string | undefined {
const fsEntry = this.getRealFile(this.toFullPath(s));
return fsEntry ? fsEntry.content : undefined;

View File

@ -80,6 +80,7 @@
"unittests/transform.ts",
"unittests/transpile.ts",
"unittests/tsbuild.ts",
"unittests/tsbuildWatchMode.ts",
"unittests/tsconfigParsing.ts",
"unittests/tscWatchMode.ts",
"unittests/versionCache.ts",

View File

@ -0,0 +1,69 @@
namespace ts.tscWatch {
export import libFile = TestFSWithWatch.libFile;
function createSolutionBuilder(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
const compilerHost = createCompilerHost({}, /*setParentNodes*/ undefined, host);
const reportDiag = createDiagnosticReporter(host);
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
const buildHost: BuildHost = {
error: report,
verbose: report,
message: report,
errorDiagnostic: d => reportDiag(d)
};
return ts.createSolutionBuilder(compilerHost, buildHost, rootNames, defaultOptions || { dry: false, force: false, verbose: false }, host);
}
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions);
solutionBuilder.buildAllProjects();
solutionBuilder.startWatching();
return solutionBuilder;
}
describe("tsbuild-watch program updates", () => {
const projectsLocation = "/user/username/projects";
const project = "sample1";
const enum SubProject {
core = "core",
logic = "logic",
tests = "tests",
ui = "ui"
}
type ReadonlyFile = Readonly<File>;
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
const root = Harness.IO.getWorkspaceRoot();
function projectFile(subProject: SubProject, baseFileName: string): File {
return {
path: `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`,
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${subProject}/${baseFileName}`)!
};
}
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
const tsconfig = projectFile(subProject, "tsconfig.json");
const index = projectFile(subProject, "index.ts");
if (!anotherModuleAndSomeDecl) {
return [tsconfig, index];
}
const anotherModule = projectFile(SubProject.core, "anotherModule.ts");
const someDecl = projectFile(SubProject.core, "some_decl.ts");
return [tsconfig, index, anotherModule, someDecl];
}
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
const logic = subProjectFiles(SubProject.logic);
const tests = subProjectFiles(SubProject.tests);
const ui = subProjectFiles(SubProject.ui);
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
it("creates solution in watch mode", () => {
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
const originalWrite = host.write;
host.write = s => { console.log(s); originalWrite.call(host, s); };
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
});
});
}

View File

@ -1,17 +1,16 @@
namespace ts.tscWatch {
import WatchedSystem = TestFSWithWatch.TestServerHost;
type File = TestFSWithWatch.File;
type SymLink = TestFSWithWatch.SymLink;
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
import checkArray = TestFSWithWatch.checkArray;
import libFile = TestFSWithWatch.libFile;
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
import checkOutputContains = TestFSWithWatch.checkOutputContains;
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
export import WatchedSystem = TestFSWithWatch.TestServerHost;
export type File = TestFSWithWatch.File;
export type SymLink = TestFSWithWatch.SymLink;
export import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
export import checkArray = TestFSWithWatch.checkArray;
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
export import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
export import checkOutputContains = TestFSWithWatch.checkOutputContains;
export import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
export import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);

View File

@ -8257,7 +8257,7 @@ new C();`
verifyProjectWithResolvedModule(session);
host.removeFolder(recognizersTextDist, /*recursive*/ true);
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
host.runQueuedTimeoutCallbacks();
verifyProjectWithUnresolvedModule(session);
@ -9173,7 +9173,7 @@ describe("Test Suite 1", () => {
checkProjectActualFiles(project, expectedFilesWithUnitTest1);
const navBarResultUnitTest1 = navBarFull(session, unitTest1);
host.removeFile(unitTest1.path);
host.deleteFile(unitTest1.path);
host.checkTimeoutQueueLengthAndRun(2);
checkProjectActualFiles(project, expectedFilesWithoutUnitTest1);
@ -9297,7 +9297,7 @@ export function Test2() {
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
// Testing what happens if we delete the original sources.
host.removeFile(bTs.path);
host.deleteFile(bTs.path);
openFilesForSession([userTs], session);
const service = session.getProjectService();

View File

@ -4125,7 +4125,7 @@ declare namespace ts {
declare namespace ts {
function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName?: string): string | undefined;
function resolveTripleslashReference(moduleName: string, containingFile: string): string;
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost;
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean, system?: System): CompilerHost;
function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
interface FormatDiagnosticsHost {
getCurrentDirectory(): string;

View File

@ -4125,7 +4125,7 @@ declare namespace ts {
declare namespace ts {
function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName?: string): string | undefined;
function resolveTripleslashReference(moduleName: string, containingFile: string): string;
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost;
function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean, system?: System): CompilerHost;
function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
interface FormatDiagnosticsHost {
getCurrentDirectory(): string;