mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
More PR comments
1. Move VirtualServerHost code to correct vfs/harness location. 2. Serialise watch and timeout information. 3. Improve test by modifying an unopened file. 4. Test can run arbitrary actions in addition to commands.
This commit is contained in:
@@ -113,6 +113,12 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
delete this.map[key];
|
||||
}
|
||||
}
|
||||
|
||||
serialize(baseline: string[]) {
|
||||
for (const id in this.map) {
|
||||
baseline.push(`${id} at time ${this.map[id].time} in ${this.map[id].ms} ms: ${this.map[id].args[1]}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TimeOutCallback = (...args: any[]) => void;
|
||||
@@ -243,7 +249,7 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
if (this.inodes) this.inodes.set(path, this.nextInode++);
|
||||
}
|
||||
override getInode(path: Path): number | undefined {
|
||||
if (this.inodes) return this.inodes.get(path)
|
||||
if (this.inodes) return this.inodes.get(path);
|
||||
}
|
||||
protected override deleteInode(path: Path) {
|
||||
if (this.inodes) this.inodes.delete(path);
|
||||
@@ -414,6 +420,10 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
this.timeoutCallbacks.unregister(timeoutId);
|
||||
}
|
||||
|
||||
serializeTimeout(baseline: string[]) {
|
||||
this.timeoutCallbacks.serialize(baseline)
|
||||
}
|
||||
|
||||
clearScreen(): void {
|
||||
this.screenClears.push(this.output.length);
|
||||
}
|
||||
@@ -490,14 +500,11 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
this.clearOutput();
|
||||
}
|
||||
|
||||
serializeWatches(baseline: string[] = []) {
|
||||
serializeMultiMap(baseline, "WatchedFiles", this.watchedFiles, ({ fileName, pollingInterval }) => ({ fileName, pollingInterval }));
|
||||
baseline.push("");
|
||||
serializeMultiMap(baseline, "FsWatches", this.fsWatches, serializeTestFsWatcher);
|
||||
baseline.push("");
|
||||
serializeMultiMap(baseline, "FsWatchesRecursive", this.fsWatchesRecursive, serializeTestFsWatcher);
|
||||
baseline.push("");
|
||||
return baseline;
|
||||
readonly exitMessage = "System Exit";
|
||||
exitCode: number | undefined;
|
||||
exit(exitCode?: number) {
|
||||
this.exitCode = exitCode;
|
||||
throw new Error(this.exitMessage);
|
||||
}
|
||||
|
||||
override getEnvironmentVariable(name: string) {
|
||||
@@ -505,7 +512,7 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
}
|
||||
}
|
||||
|
||||
export function snap(fshost: VirtualFS.VirtualServerHost): ESMap<Path, FSEntry> {
|
||||
export function snap(fshost: VirtualServerHost): ESMap<Path, FSEntry> {
|
||||
const result = new Map<Path, FSEntry>();
|
||||
fshost.fs.forEach((value, key) => {
|
||||
const cloneValue = clone(value);
|
||||
@@ -518,7 +525,7 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
return result;
|
||||
}
|
||||
|
||||
export function diff(fshost: VirtualFS.VirtualServerHost, baseline: string[], base: ESMap<Path, FSEntry> = new Map()) {
|
||||
export function diff(fshost: VirtualServerHost, baseline: string[], base: ESMap<Path, FSEntry> = new Map()) {
|
||||
fshost.fs.forEach((newFsEntry, path) => {
|
||||
diffFsEntry(baseline, base.get(path), newFsEntry, fshost.getInode(path), fshost.writtenFiles);
|
||||
});
|
||||
@@ -598,23 +605,6 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
}
|
||||
}
|
||||
|
||||
function serializeTestFsWatcher({ directoryName, inode }: VirtualFsWatcher) {
|
||||
return {
|
||||
directoryName,
|
||||
inode,
|
||||
};
|
||||
}
|
||||
|
||||
function serializeMultiMap<T, U>(baseline: string[], caption: string, multiMap: MultiMap<string, T>, valueMapper: (value: T) => U) {
|
||||
baseline.push(`${caption}::`);
|
||||
multiMap.forEach((values, key) => {
|
||||
baseline.push(`${key}:`);
|
||||
for (const value of values) {
|
||||
baseline.push(` ${JSON.stringify(valueMapper(value))}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function baselineOutputs(baseline: string[], output: readonly string[], start: number, end = output.length) {
|
||||
let baselinedOutput: string[] | undefined;
|
||||
for (let i = start; i < end; i++) {
|
||||
|
||||
@@ -416,7 +416,7 @@ namespace ts.server {
|
||||
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
|
||||
// VirtualFS
|
||||
ensureFileOrFolder: fshost.ensureFileOrFolder.bind(fshost),
|
||||
} as any;
|
||||
} as ServerHost;
|
||||
}
|
||||
|
||||
const noopConfigFileWatcher: FileWatcher = { close: noop };
|
||||
@@ -3757,13 +3757,13 @@ namespace ts.server {
|
||||
updateFileSystem(updatedFiles: protocol.FileSystemRequestArgs[] | undefined, deletedFiles?: string[]) {
|
||||
const fshost = this.host as unknown as FileServerHost;
|
||||
if (updatedFiles) {
|
||||
Debug.assert(fshost.ensureFileOrFolder)
|
||||
Debug.assert(fshost.ensureFileOrFolder);
|
||||
for (const { file, fileContent } of updatedFiles) {
|
||||
fshost.ensureFileOrFolder({ path: file, content: fileContent });
|
||||
}
|
||||
}
|
||||
if (deletedFiles) {
|
||||
Debug.assert(fshost.deleteFile)
|
||||
Debug.assert(fshost.deleteFile);
|
||||
for (const file of deletedFiles) {
|
||||
fshost.deleteFile(file, /*deleteEmptyParentFolders*/ true);
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ interface Symbol {
|
||||
originalReadCall?: System["readFile"],
|
||||
) {
|
||||
const buildInfoPath = getTsBuildInfoEmitOutputFilePath(options);
|
||||
if (!buildInfoPath || !sys.writtenFiles!.has(toPathWithSystem(sys, buildInfoPath))) return;
|
||||
if (!buildInfoPath || !sys.writtenFiles.has(toPathWithSystem(sys, buildInfoPath))) return;
|
||||
if (!sys.fileExists(buildInfoPath)) return;
|
||||
|
||||
const buildInfo = getBuildInfo((originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!);
|
||||
|
||||
@@ -22,42 +22,46 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const lib: protocol.FileSystemRequestArgs = {
|
||||
file: "/fshost/lib/lib.d.ts",
|
||||
fileContent: `/// <reference no-default-lib="true"/>
|
||||
interface Boolean {}
|
||||
interface Function {}
|
||||
interface CallableFunction {}
|
||||
interface NewableFunction {}
|
||||
interface IArguments {}
|
||||
interface Number { toExponential: any; }
|
||||
interface Object {}
|
||||
interface RegExp {}
|
||||
interface String { charAt: any; }
|
||||
interface Array<T> { length: number; [n: number]: T; }`
|
||||
};
|
||||
fileContent: libFile.content
|
||||
};
|
||||
|
||||
function fileContentWithComment(file: protocol.FileSystemRequestArgs) {
|
||||
return `// some copy right notice
|
||||
${file.fileContent}`;
|
||||
}
|
||||
function baselineFileSystem(scenario: string, subScenario: string, requests: [string, Partial<protocol.Request>][], host: VirtualFS.VirtualServerHost, session: TestSession) {
|
||||
function baselineFileSystem(scenario: string, subScenario: string, requests: [string, (() => void) | Partial<protocol.Request>][], host: TestServerHost, fshost: VirtualFS.VirtualServerHost, session: TestSession) {
|
||||
const history: string[] = [];
|
||||
let prev = VirtualFS.snap(host);
|
||||
|
||||
let prev = VirtualFS.snap(fshost);
|
||||
let prev2 = VirtualFS.snap(host);
|
||||
for (const [name, request] of requests) {
|
||||
session.executeCommandSeq(request);
|
||||
if (typeof request === "function") {
|
||||
request();
|
||||
}
|
||||
else {
|
||||
session.executeCommandSeq(request);
|
||||
}
|
||||
history.push("");
|
||||
history.push("#### " + name);
|
||||
VirtualFS.diff(host, history, prev);
|
||||
prev = VirtualFS.snap(host);
|
||||
VirtualFS.diff(fshost, history, prev);
|
||||
prev = VirtualFS.snap(fshost);
|
||||
VirtualFS.diff(host, history, prev2);
|
||||
prev2 = VirtualFS.snap(host);
|
||||
host.serializeTimeout(history)
|
||||
}
|
||||
history.push("### fshost watches")
|
||||
fshost.serializeWatches(history)
|
||||
history.push("### host watches")
|
||||
host.serializeWatches(history)
|
||||
Harness.Baseline.runBaseline(`tsserver/${scenario}/${subScenario.split(" ").join("-")}.txt`, history.join("\r\n"));
|
||||
baselineTsserverLogs(scenario, subScenario, session);
|
||||
}
|
||||
|
||||
it("with updateFileSystem request", () => {
|
||||
const host = VirtualFS.createVirtualServerHost({ executingFilePath: "/host/tsc.js" });
|
||||
const host = VirtualFS.createServerHost({ executingFilePath: "/host/tsc.js" });
|
||||
const fshost = VirtualFS.createVirtualServerHost({ executingFilePath: "/fshost/tsc.js" });
|
||||
const session = createSession(host, { fshost, logger: createLoggerWithInMemoryLogs(), canUseEvents: true });
|
||||
const requests: [string, Partial<protocol.Request>][] = [
|
||||
const requests: [string, (() => void) | Partial<protocol.Request>][] = [
|
||||
["Initial updateFileSystem", {
|
||||
command: protocol.CommandTypes.UpdateFileSystem,
|
||||
arguments:{
|
||||
@@ -96,6 +100,22 @@ ${file.fileContent}`;
|
||||
deleted: [],
|
||||
},
|
||||
}],
|
||||
["ensure /host/app.ts exists", () => host.ensureFileOrFolder({
|
||||
path: "/host/b/app.ts",
|
||||
content: 'console.log("hello")'
|
||||
})],
|
||||
["modify /host/app.ts", () => host.modifyFile(
|
||||
"/host/b/app.ts",
|
||||
"console.log('goodbye')"
|
||||
)],
|
||||
["ensure /fshost/file4.ts exists", () => fshost.ensureFileOrFolder({
|
||||
path:"/fshost/b/file4.ts",
|
||||
content: "console.log('file4 exists')",
|
||||
})],
|
||||
["modify /fshost/file4", () => fshost.modifyFile(
|
||||
"/fshost/b/file4.ts",
|
||||
"console.log('file4 modified')"
|
||||
)],
|
||||
["delete", {
|
||||
command: protocol.CommandTypes.UpdateFileSystem,
|
||||
arguments:{
|
||||
@@ -119,17 +139,7 @@ ${file.fileContent}`;
|
||||
|
||||
const scenario = "updateFileSystem";
|
||||
const subScenario = "open and close files";
|
||||
baselineFileSystem(scenario, subScenario, requests, fshost, session);
|
||||
|
||||
host.ensureFileOrFolder({
|
||||
path: "/host/b/app.ts",
|
||||
content: 'console.log("hello")'
|
||||
});
|
||||
host.modifyFile("/host/b/app.ts", "console.log('goodbye')");
|
||||
assert.isFalse(host.fileExists("/fshost/b/app.ts"), "host fileExists /fshost/b/app.ts");
|
||||
assert.isTrue(fshost.fileExists("/fshost/b/app.ts"), "fshost fileExists /fshost/b/app.ts");
|
||||
assert.isTrue(host.fileExists("/host/b/app.ts"), "host fileExists /host/b/app.ts");
|
||||
assert.isFalse(fshost.fileExists("/host/b/app.ts"), "fshost fileExists /host/b/app.ts");
|
||||
baselineFileSystem(scenario, subScenario, requests, host, fshost, session);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace ts.projectSystem {
|
||||
if (isVfs) {
|
||||
serverMode = LanguageServiceMode.Semantic;
|
||||
fshost = VirtualFS.createVirtualServerHost({ executingFilePath: "/a/lib/tsc.js" });
|
||||
(fshost as VirtualFS.VirtualServerHost).ensureFileOrFolder(libFile);
|
||||
(fshost).ensureFileOrFolder(libFile);
|
||||
}
|
||||
const logger = logLevel !== undefined ? new server.MainProcessLogger(logLevel, webHost) : nullLogger();
|
||||
const session = new TestWorkerSession(webSys, fshost, webHost, { serverMode }, logger);
|
||||
|
||||
@@ -636,18 +636,39 @@ namespace ts.VirtualFS {
|
||||
return fsEntry?.fullPath || realFullPath;
|
||||
}
|
||||
|
||||
readonly exitMessage = "System Exit";
|
||||
exitCode: number | undefined;
|
||||
readonly resolvePath = (s: string) => s;
|
||||
readonly getExecutingFilePath = () => this.executingFilePath;
|
||||
readonly getCurrentDirectory = () => this.currentDirectory;
|
||||
exit(exitCode?: number) {
|
||||
this.exitCode = exitCode;
|
||||
throw new Error(this.exitMessage);
|
||||
|
||||
serializeWatches(baseline: string[] = []) {
|
||||
serializeMultiMap(baseline, "WatchedFiles", this.watchedFiles, ({ fileName, pollingInterval }) => ({ fileName, pollingInterval }));
|
||||
baseline.push("");
|
||||
serializeMultiMap(baseline, "FsWatches", this.fsWatches, serializeTestFsWatcher);
|
||||
baseline.push("");
|
||||
serializeMultiMap(baseline, "FsWatchesRecursive", this.fsWatchesRecursive, serializeTestFsWatcher);
|
||||
baseline.push("");
|
||||
return baseline;
|
||||
}
|
||||
|
||||
getEnvironmentVariable(_name: string) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function serializeTestFsWatcher({ directoryName, inode }: VirtualFsWatcher) {
|
||||
return {
|
||||
directoryName,
|
||||
inode,
|
||||
};
|
||||
}
|
||||
|
||||
function serializeMultiMap<T, U>(baseline: string[], caption: string, multiMap: MultiMap<string, T>, valueMapper: (value: T) => U) {
|
||||
baseline.push(`${caption}::`);
|
||||
multiMap.forEach((values, key) => {
|
||||
baseline.push(`${key}:`);
|
||||
for (const value of values) {
|
||||
baseline.push(` ${JSON.stringify(valueMapper(value))}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ Project '/fshost/b/tsconfig.json' (Configured)
|
||||
-----------------------------------------------
|
||||
event:
|
||||
{"seq":0,"type":"event","event":"projectLoadingFinish","body":{"projectName":"/fshost/b/tsconfig.json"}}
|
||||
event:
|
||||
{"seq":0,"type":"event","event":"telemetry","body":{"telemetryEventName":"projectInfo","payload":{"projectId":"bea14cc795bf8fe7209e389c09ff1c7f1d8288597401b8616cd5edcd3f073d77","fileStats":{"js":0,"jsSize":0,"jsx":0,"jsxSize":0,"ts":4,"tsSize":79,"tsx":0,"tsxSize":0,"dts":0,"dtsSize":0,"deferred":0,"deferredSize":0},"compilerOptions":{},"typeAcquisition":{"enable":false,"include":false,"exclude":false},"extends":false,"files":false,"include":false,"exclude":false,"compileOnSave":false,"configFileName":"tsconfig.json","projectType":"configured","languageServiceEnabled":true,"version":"FakeVersion"}}}
|
||||
event:
|
||||
{"seq":0,"type":"event","event":"configFileDiag","body":{"triggerFile":"/fshost/b/app.ts","configFile":"/fshost/b/tsconfig.json","diagnostics":[{"text":"File '/fshost/lib.d.ts' not found.\n The file is in the program because:\n Default library for target 'es3'","code":6053,"category":"error"},{"text":"Cannot find global type 'Array'.","code":2318,"category":"error"},{"text":"Cannot find global type 'Boolean'.","code":2318,"category":"error"},{"text":"Cannot find global type 'Function'.","code":2318,"category":"error"},{"text":"Cannot find global type 'IArguments'.","code":2318,"category":"error"},{"text":"Cannot find global type 'Number'.","code":2318,"category":"error"},{"text":"Cannot find global type 'Object'.","code":2318,"category":"error"},{"text":"Cannot find global type 'RegExp'.","code":2318,"category":"error"},{"text":"Cannot find global type 'String'.","code":2318,"category":"error"}]}}
|
||||
Project '/fshost/b/tsconfig.json' (Configured)
|
||||
@@ -82,15 +84,19 @@ request:{"command":"updateFileSystem","arguments":{"fileSystem":"memfs","files":
|
||||
response:{"response":true,"responseRequired":true}
|
||||
request:{"command":"updateFileSystem","arguments":{"fileSystem":"memfs","files":[{"file":"/fshost/b/app.ts","fileContent":"import { xyz } from './file3'; let y = xyz"}],"deleted":[]},"seq":5,"type":"request"}
|
||||
response:{"response":true,"responseRequired":true}
|
||||
DirectoryWatcher:: Triggered with /fshost/b/file4.ts :: WatchInfo: /fshost/b 1 undefined Config: /fshost/b/tsconfig.json WatchType: Wild card directory
|
||||
Scheduled: /fshost/b/tsconfig.json
|
||||
Scheduled: *ensureProjectForOpenFiles*
|
||||
Elapsed:: *ms DirectoryWatcher:: Triggered with /fshost/b/file4.ts :: WatchInfo: /fshost/b 1 undefined Config: /fshost/b/tsconfig.json WatchType: Wild card directory
|
||||
request:{"command":"updateFileSystem","arguments":{"fileSystem":"memfs","files":[],"deleted":["/fshost/b/commonFile1.ts"]},"seq":6,"type":"request"}
|
||||
FileWatcher:: Triggered with /fshost/b/commonFile1.ts 2:: WatchInfo: /fshost/b/commonFile1.ts 500 undefined WatchType: Closed Script info
|
||||
FileWatcher:: Close:: WatchInfo: /fshost/b/commonFile1.ts 500 undefined WatchType: Closed Script info
|
||||
Scheduled: /fshost/b/tsconfig.json
|
||||
Scheduled: *ensureProjectForOpenFiles*
|
||||
Scheduled: /fshost/b/tsconfig.json, Cancelled earlier one
|
||||
Scheduled: *ensureProjectForOpenFiles*, Cancelled earlier one
|
||||
Elapsed:: *ms FileWatcher:: Triggered with /fshost/b/commonFile1.ts 2:: WatchInfo: /fshost/b/commonFile1.ts 500 undefined WatchType: Closed Script info
|
||||
DirectoryWatcher:: Triggered with /fshost/b/commonFile1.ts :: WatchInfo: /fshost/b 1 undefined Config: /fshost/b/tsconfig.json WatchType: Wild card directory
|
||||
Scheduled: /fshost/b/tsconfig.json
|
||||
Scheduled: *ensureProjectForOpenFiles*
|
||||
Scheduled: /fshost/b/tsconfig.json, Cancelled earlier one
|
||||
Scheduled: *ensureProjectForOpenFiles*, Cancelled earlier one
|
||||
Elapsed:: *ms DirectoryWatcher:: Triggered with /fshost/b/commonFile1.ts :: WatchInfo: /fshost/b 1 undefined Config: /fshost/b/tsconfig.json WatchType: Wild card directory
|
||||
response:{"response":true,"responseRequired":true}
|
||||
request:{"command":"close","arguments":{"file":"/fshost/b/app.ts"},"seq":7,"type":"request"}
|
||||
|
||||
@@ -30,23 +30,96 @@ interface Array<T> { length: number; [n: number]: T; }
|
||||
|
||||
|
||||
|
||||
|
||||
#### Opening app.ts
|
||||
|
||||
|
||||
|
||||
#### Opening file3.ts
|
||||
|
||||
|
||||
|
||||
#### non-delete
|
||||
|
||||
|
||||
|
||||
#### change app.ts content
|
||||
//// [/fshost/b/app.ts]
|
||||
import { xyz } from './file3'; let y = xyz
|
||||
|
||||
|
||||
|
||||
|
||||
#### ensure /host/app.ts exists
|
||||
|
||||
//// [/host/b/app.ts]
|
||||
console.log("hello")
|
||||
|
||||
|
||||
|
||||
#### modify /host/app.ts
|
||||
|
||||
//// [/host/b/app.ts]
|
||||
console.log('goodbye')
|
||||
|
||||
|
||||
|
||||
#### ensure /fshost/file4.ts exists
|
||||
//// [/fshost/b/file4.ts]
|
||||
console.log('file4 exists')
|
||||
|
||||
|
||||
|
||||
1 at time 12000 in 250 ms: /fshost/b/tsconfig.json
|
||||
2 at time 12000 in 2500 ms: *ensureProjectForOpenFiles*
|
||||
|
||||
#### modify /fshost/file4
|
||||
//// [/fshost/b/file4.ts]
|
||||
console.log('file4 modified')
|
||||
|
||||
|
||||
|
||||
1 at time 12000 in 250 ms: /fshost/b/tsconfig.json
|
||||
2 at time 12000 in 2500 ms: *ensureProjectForOpenFiles*
|
||||
|
||||
#### delete
|
||||
//// [/fshost/b/commonFile1.ts] deleted
|
||||
|
||||
|
||||
5 at time 12000 in 250 ms: /fshost/b/tsconfig.json
|
||||
6 at time 12000 in 2500 ms: *ensureProjectForOpenFiles*
|
||||
|
||||
#### close
|
||||
|
||||
|
||||
5 at time 12000 in 250 ms: /fshost/b/tsconfig.json
|
||||
6 at time 12000 in 2500 ms: *ensureProjectForOpenFiles*
|
||||
### fshost watches
|
||||
WatchedFiles::
|
||||
/fshost/b/tsconfig.json:
|
||||
{"fileName":"/fshost/b/tsconfig.json","pollingInterval":250}
|
||||
/fshost/b:
|
||||
{"fileName":"/fshost/b","pollingInterval":500}
|
||||
/fshost/b/commonfile2.ts:
|
||||
{"fileName":"/fshost/b/commonFile2.ts","pollingInterval":250}
|
||||
/fshost/lib.d.ts:
|
||||
{"fileName":"/fshost/lib.d.ts","pollingInterval":250}
|
||||
/fshost/b/node_modules/@types:
|
||||
{"fileName":"/fshost/b/node_modules/@types","pollingInterval":500}
|
||||
/fshost/b/app.ts:
|
||||
{"fileName":"/fshost/b/app.ts","pollingInterval":250}
|
||||
|
||||
FsWatches::
|
||||
/host/b/app.ts:
|
||||
{"directoryName":"/host/b"}
|
||||
|
||||
FsWatchesRecursive::
|
||||
/fshost/b:
|
||||
{"directoryName":"/fshost/b"}
|
||||
|
||||
### host watches
|
||||
WatchedFiles::
|
||||
|
||||
FsWatches::
|
||||
|
||||
FsWatchesRecursive::
|
||||
|
||||
Reference in New Issue
Block a user