Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions src/harness/unittests/compileOnSave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />

namespace ts.projectSystem {
function createTestTypingsInstaller(host: server.ServerHost) {
return new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
}

describe("CompileOnSave affected list", () => {
function sendAffectedFileRequestAndCheckResult(session: server.Session, request: server.protocol.Request, expectedFileList: { projectFileName: string, files: FileOrFolder[] }[]) {
const response: server.protocol.CompileOnSaveAffectedFileListSingleProject[] = session.executeCommand(request).response;
Expand Down Expand Up @@ -105,7 +109,7 @@ namespace ts.projectSystem {

it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => {
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1, file1Consumer1], session);
Expand All @@ -130,7 +134,7 @@ namespace ts.projectSystem {

it("should be up-to-date with the reference map changes", () => {
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1, file1Consumer1], session);
Expand Down Expand Up @@ -177,7 +181,7 @@ namespace ts.projectSystem {

it("should be up-to-date with changes made in non-open files", () => {
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1], session);
Expand All @@ -195,7 +199,7 @@ namespace ts.projectSystem {

it("should be up-to-date with deleted files", () => {
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1], session);
Expand All @@ -210,7 +214,7 @@ namespace ts.projectSystem {

it("should be up-to-date with newly created files", () => {
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1], session);
Expand Down Expand Up @@ -247,7 +251,7 @@ namespace ts.projectSystem {
};

const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1, file1Consumer1], session);
Expand All @@ -264,7 +268,7 @@ namespace ts.projectSystem {

it("should return all files if a global file changed shape", () => {
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([globalFile3], session);
Expand All @@ -290,7 +294,7 @@ namespace ts.projectSystem {
};

const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
openFilesForSession([moduleFile1], session);
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, []);
Expand All @@ -308,7 +312,7 @@ namespace ts.projectSystem {
};

const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
openFilesForSession([moduleFile1], session);

Expand Down Expand Up @@ -337,7 +341,7 @@ namespace ts.projectSystem {
};

const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
openFilesForSession([moduleFile1], session);

Expand All @@ -359,7 +363,7 @@ namespace ts.projectSystem {
content: `import {y} from "./file1Consumer1";`
};
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer1Consumer1, globalFile3, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([moduleFile1, file1Consumer1], session);
Expand Down Expand Up @@ -392,7 +396,7 @@ namespace ts.projectSystem {
export var t2 = 10;`
};
const host = createServerHost([file1, file2, configFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([file1, file2], session);
Expand Down Expand Up @@ -475,7 +479,7 @@ namespace ts.projectSystem {
content: `{}`
};
const host = createServerHost([file1, file2, configFile, libFile]);
const typingsInstaller = new TestTypingsInstaller("/a/data/", host);
const typingsInstaller = createTestTypingsInstaller(host);
const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);

openFilesForSession([file1, file2], session);
Expand Down
73 changes: 55 additions & 18 deletions src/harness/unittests/tsserverProjectSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />

namespace ts.projectSystem {
import TI = server.typingsInstaller;

const safeList = {
path: <Path>"/safeList.json",
content: JSON.stringify({
Expand All @@ -13,6 +15,14 @@ namespace ts.projectSystem {
})
};

export interface PostExecAction {
readonly requestKind: TI.RequestKind;
readonly error: Error;
readonly stdout: string;
readonly stderr: string;
readonly callback: (err: Error, stdout: string, stderr: string) => void;
}

export function notImplemented(): any {
throw new Error("Not yet implemented");
}
Expand All @@ -39,21 +49,27 @@ namespace ts.projectSystem {
content: libFileContent
};

export class TestTypingsInstaller extends server.typingsInstaller.TypingsInstaller implements server.ITypingsInstaller {
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
protected projectService: server.ProjectService;
constructor(readonly globalTypingsCacheLocation: string, readonly installTypingHost: server.ServerHost) {
super(globalTypingsCacheLocation, safeList.path);
constructor(readonly globalTypingsCacheLocation: string, throttleLimit: number, readonly installTypingHost: server.ServerHost) {
super(globalTypingsCacheLocation, "npm", safeList.path, throttleLimit);
this.init();
}

safeFileList = safeList.path;
postInstallActions: ((map: (t: string[]) => string[]) => void)[] = [];
protected postExecActions: PostExecAction[] = [];

runPostInstallActions(map: (t: string[]) => string[]) {
for (const f of this.postInstallActions) {
f(map);
executePendingCommands() {
const actionsToRun = this.postExecActions;
this.postExecActions = [];
for (const action of actionsToRun) {
action.callback(action.error, action.stdout, action.stderr);
}
this.postInstallActions = [];
}

checkPendingCommands(expected: TI.RequestKind[]) {
assert.equal(this.postExecActions.length, expected.length, `Expected ${expected.length} post install actions`);
this.postExecActions.forEach((act, i) => assert.equal(act.requestKind, expected[i], "Unexpected post install action"));
}

onProjectClosed(p: server.Project) {
Expand All @@ -67,14 +83,15 @@ namespace ts.projectSystem {
return this.installTypingHost;
}

isPackageInstalled(packageName: string) {
return true;
}

runInstall(cachePath: string, typingsToInstall: string[], postInstallAction: (installedTypings: string[]) => void) {
this.postInstallActions.push(map => {
postInstallAction(map(typingsToInstall));
});
runCommand(requestKind: TI.RequestKind, requestId: number, command: string, cwd: string, cb: (err: Error, stdout: string, stderr: string) => void): void {
switch (requestKind) {
case TI.NpmViewRequest:
case TI.NpmInstallRequest:
break;
default:
assert.isTrue(false, `request ${requestKind} is not supported`);
}
this.addPostExecAction(requestKind, "success", cb);
}

sendResponse(response: server.SetTypings | server.InvalidateCachedTypings) {
Expand All @@ -85,6 +102,26 @@ namespace ts.projectSystem {
const request = server.createInstallTypingsRequest(project, typingOptions, this.globalTypingsCacheLocation);
this.install(request);
}

addPostExecAction(requestKind: TI.RequestKind, stdout: string | string[], cb: TI.RequestCompletedAction) {
const out = typeof stdout === "string" ? stdout : createNpmPackageJsonString(stdout);
const action: PostExecAction = {
error: undefined,
stdout: out,
stderr: "",
callback: cb,
requestKind
};
this.postExecActions.push(action);
}
}

function createNpmPackageJsonString(installedTypings: string[]): string {
const dependencies: MapLike<any> = {};
for (const typing of installedTypings) {
dependencies[typing] = "1.0.0";
}
return JSON.stringify({ dependencies: dependencies });
}

export function getExecutingFilePathFromLibFile(libFilePath: string): string {
Expand Down Expand Up @@ -124,7 +161,7 @@ namespace ts.projectSystem {

export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller) {
if (typingsInstaller === undefined) {
typingsInstaller = new TestTypingsInstaller("/a/data/", host);
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
}
return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
}
Expand Down Expand Up @@ -1615,7 +1652,7 @@ namespace ts.projectSystem {
const host: TestServerHost & ModuleResolutionHost = createServerHost([file1, lib]);
const resolutionTrace: string[] = [];
host.trace = resolutionTrace.push.bind(resolutionTrace);
const projectService = createProjectService(host, { typingsInstaller: new TestTypingsInstaller("/a/cache", host) });
const projectService = createProjectService(host, { typingsInstaller: new TestTypingsInstaller("/a/cache", /*throttleLimit*/5, host) });

projectService.setCompilerOptionsForInferredProjects({ traceResolution: true, allowJs: true });
projectService.openClientFile(file1.path);
Expand Down
Loading