Skip to content

Commit 7173da2

Browse files
committed
Adding test for #16329 to verify the caching of file system when opening file
1 parent 3908325 commit 7173da2

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3996,4 +3996,130 @@ namespace ts.projectSystem {
39963996
}
39973997
});
39983998
});
3999+
4000+
describe("CachingFileSystemInformation", () => {
4001+
function getFunctionWithCalledMapForSingleArgumentCb<T>(cb: (f: string) => T) {
4002+
const calledMap = createMultiMap<true>();
4003+
return {
4004+
cb: (f: string) => {
4005+
calledMap.add(f, /*value*/ true);
4006+
return cb(f);
4007+
},
4008+
calledMap
4009+
};
4010+
}
4011+
4012+
function getFunctionWithCalledMapForFiveArgumentCb<T, U, V, W, X>(cb: (f: string, arg1?: U, arg2?: V, arg3?: W, arg4?: X) => T) {
4013+
const calledMap = createMultiMap<[U, V, W, X]>();
4014+
return {
4015+
cb: (f: string, arg1?: U, arg2?: V, arg3?: W, arg4?: X) => {
4016+
calledMap.add(f, [arg1, arg2, arg3, arg4]);
4017+
return cb(f, arg1, arg2, arg3, arg4);
4018+
},
4019+
calledMap
4020+
};
4021+
}
4022+
4023+
function checkMultiMapKeysForSingleEntry<T>(caption: string, multiMap: MultiMap<T>, expectedKeys: string[]) {
4024+
assert.equal(multiMap.size, expectedKeys.length, `${caption}: incorrect size of map: Actual keys: ${arrayFrom(multiMap.keys())} Expected: ${expectedKeys}`);
4025+
for (const name of expectedKeys) {
4026+
assert.isTrue(multiMap.has(name), `${caption} is expected to contain ${name}, actual keys: ${arrayFrom(multiMap.keys())}`);
4027+
assert.equal(multiMap.get(name).length, 1, `${caption} is expected to have just one entry for key ${name}, actual entry: ${multiMap.get(name)}`);
4028+
}
4029+
}
4030+
4031+
it("when calling goto definition of module", () => {
4032+
const clientFile: FileOrFolder = {
4033+
path: "/a/b/controllers/vessels/client.ts",
4034+
content: `
4035+
import { Vessel } from '~/models/vessel';
4036+
const v = new Vessel();
4037+
`
4038+
};
4039+
const anotherModuleFile: FileOrFolder = {
4040+
path: "/a/b/utils/db.ts",
4041+
content: "export class Bookshelf { }"
4042+
};
4043+
const moduleFile: FileOrFolder = {
4044+
path: "/a/b/models/vessel.ts",
4045+
content: `
4046+
import { Bookshelf } from '~/utils/db';
4047+
export class Vessel extends Bookshelf {}
4048+
`
4049+
};
4050+
const tsconfigFile: FileOrFolder = {
4051+
path: "/a/b/tsconfig.json",
4052+
content: JSON.stringify({
4053+
compilerOptions: {
4054+
target: "es6",
4055+
module: "es6",
4056+
baseUrl: "./", // all paths are relative to the baseUrl
4057+
paths: {
4058+
"~/*": ["*"] // resolve any `~/foo/bar` to `<baseUrl>/foo/bar`
4059+
}
4060+
},
4061+
exclude: [
4062+
"api",
4063+
"build",
4064+
"node_modules",
4065+
"public",
4066+
"seeds",
4067+
"sql_updates",
4068+
"tests.build"
4069+
]
4070+
})
4071+
};
4072+
4073+
const projectFiles = [clientFile, anotherModuleFile, moduleFile, tsconfigFile];
4074+
const host = createServerHost(projectFiles);
4075+
const session = createSession(host);
4076+
const projectService = session.getProjectService();
4077+
const { configFileName } = projectService.openClientFile(clientFile.path);
4078+
4079+
assert.isDefined(configFileName, `should find config`);
4080+
checkNumberOfConfiguredProjects(projectService, 1);
4081+
4082+
const project = projectService.configuredProjects.get(tsconfigFile.path);
4083+
checkProjectActualFiles(project, map(projectFiles, f => f.path));
4084+
4085+
const fileExistsCalledOn = getFunctionWithCalledMapForSingleArgumentCb<boolean>(host.fileExists.bind(host));
4086+
host.fileExists = fileExistsCalledOn.cb;
4087+
const directoryExistsCalledOn = getFunctionWithCalledMapForSingleArgumentCb<boolean>(host.directoryExists.bind(host));
4088+
host.directoryExists = directoryExistsCalledOn.cb;
4089+
const getDirectoriesCalledOn = getFunctionWithCalledMapForSingleArgumentCb<string[]>(host.getDirectories.bind(host));
4090+
host.getDirectories = getDirectoriesCalledOn.cb;
4091+
const readFileCalledOn = getFunctionWithCalledMapForSingleArgumentCb<string>(host.readFile.bind(host));
4092+
host.readFile = readFileCalledOn.cb;
4093+
const readDirectoryCalledOn = getFunctionWithCalledMapForFiveArgumentCb<string[], ReadonlyArray<string>, ReadonlyArray<string>, ReadonlyArray<string>, number>(host.readDirectory.bind(host));
4094+
host.readDirectory = readDirectoryCalledOn.cb;
4095+
4096+
4097+
// Get definitions shouldnt make host requests
4098+
const getDefinitionRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(protocol.CommandTypes.Definition, {
4099+
file: clientFile.path,
4100+
position: clientFile.content.indexOf("/vessel") + 1,
4101+
line: undefined,
4102+
offset: undefined
4103+
});
4104+
const { response } = session.executeCommand(getDefinitionRequest);
4105+
assert.equal(response[0].file, moduleFile.path, "Should go to definition of vessel: response: " + JSON.stringify(response));
4106+
assert.equal(fileExistsCalledOn.calledMap.size, 0, `fileExists shouldnt be called`);
4107+
assert.equal(directoryExistsCalledOn.calledMap.size, 0, `directoryExists shouldnt be called`);
4108+
assert.equal(getDirectoriesCalledOn.calledMap.size, 0, `getDirectories shouldnt be called`);
4109+
assert.equal(readFileCalledOn.calledMap.size, 0, `readFile shouldnt be called`);
4110+
assert.equal(readDirectoryCalledOn.calledMap.size, 0, `readDirectory shouldnt be called`);
4111+
4112+
// Open the file should call only file exists on module directory and use cached value for parental directory
4113+
const { configFileName: config2 } = projectService.openClientFile(moduleFile.path);
4114+
assert.equal(config2, configFileName);
4115+
checkMultiMapKeysForSingleEntry("fileExists", fileExistsCalledOn.calledMap, ["/a/b/models/tsconfig.json", "/a/b/models/jsconfig.json"]);
4116+
assert.equal(directoryExistsCalledOn.calledMap.size, 0, `directoryExists shouldnt be called`);
4117+
assert.equal(getDirectoriesCalledOn.calledMap.size, 0, `getDirectories shouldnt be called`);
4118+
assert.equal(readFileCalledOn.calledMap.size, 0, `readFile shouldnt be called`);
4119+
assert.equal(readDirectoryCalledOn.calledMap.size, 0, `readDirectory shouldnt be called`);
4120+
4121+
checkNumberOfConfiguredProjects(projectService, 1);
4122+
assert.strictEqual(projectService.configuredProjects.get(tsconfigFile.path), project);
4123+
});
4124+
});
39994125
}

0 commit comments

Comments
 (0)