test(ivy): support chdir() on the compiler's filesystem abstraction (#33828)
This commit adds the ability to change directories using the compiler's internal filesystem abstraction. This is a prerequisite for writing tests which are sensitive to the current working directory. In addition to supporting the `chdir()` operation, this commit also fixes `getDefaultLibLocation()` for mock filesystems to not assume `node_modules` is in the current directory, but to resolve it similarly to how Node does by progressively looking higher in the directory tree. PR Close #33828
This commit is contained in:
parent
6bf2531b19
commit
51720745dd
|
@ -99,6 +99,7 @@ export class CachedFileSystem implements FileSystem {
|
|||
// The following methods simply call through to the delegate.
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] { return this.delegate.readdir(path); }
|
||||
pwd(): AbsoluteFsPath { return this.delegate.pwd(); }
|
||||
chdir(path: AbsoluteFsPath): void { this.delegate.chdir(path); }
|
||||
extname(path: AbsoluteFsPath|PathSegment): string { return this.delegate.extname(path); }
|
||||
isCaseSensitive(): boolean { return this.delegate.isCaseSensitive(); }
|
||||
isRoot(path: AbsoluteFsPath): boolean { return this.delegate.isRoot(path); }
|
||||
|
|
|
@ -24,6 +24,7 @@ export class InvalidFileSystem implements FileSystem {
|
|||
lstat(path: AbsoluteFsPath): FileStats { throw makeError(); }
|
||||
stat(path: AbsoluteFsPath): FileStats { throw makeError(); }
|
||||
pwd(): AbsoluteFsPath { throw makeError(); }
|
||||
chdir(path: AbsoluteFsPath): void { throw makeError(); }
|
||||
extname(path: AbsoluteFsPath|PathSegment): string { throw makeError(); }
|
||||
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); }
|
||||
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); }
|
||||
|
|
|
@ -26,6 +26,7 @@ export class NodeJSFileSystem implements FileSystem {
|
|||
lstat(path: AbsoluteFsPath): FileStats { return fs.lstatSync(path); }
|
||||
stat(path: AbsoluteFsPath): FileStats { return fs.statSync(path); }
|
||||
pwd(): AbsoluteFsPath { return this.normalize(process.cwd()) as AbsoluteFsPath; }
|
||||
chdir(dir: AbsoluteFsPath): void { process.chdir(dir); }
|
||||
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { fs.copyFileSync(from, to); }
|
||||
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { fs.renameSync(from, to); }
|
||||
ensureDir(path: AbsoluteFsPath): void {
|
||||
|
|
|
@ -43,6 +43,7 @@ export interface FileSystem {
|
|||
lstat(path: AbsoluteFsPath): FileStats;
|
||||
stat(path: AbsoluteFsPath): FileStats;
|
||||
pwd(): AbsoluteFsPath;
|
||||
chdir(path: AbsoluteFsPath): void;
|
||||
extname(path: AbsoluteFsPath|PathSegment): string;
|
||||
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
|
||||
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
|
||||
|
|
|
@ -132,7 +132,36 @@ export abstract class MockFileSystem implements FileSystem {
|
|||
|
||||
pwd(): AbsoluteFsPath { return this._cwd; }
|
||||
|
||||
getDefaultLibLocation(): AbsoluteFsPath { return this.resolve('node_modules/typescript/lib'); }
|
||||
chdir(path: AbsoluteFsPath): void { this._cwd = this.normalize(path); }
|
||||
|
||||
getDefaultLibLocation(): AbsoluteFsPath {
|
||||
// Mimic the node module resolution algorithm and start in the current directory, then look
|
||||
// progressively further up the tree until reaching the FS root.
|
||||
// E.g. if the current directory is /foo/bar, look in /foo/bar/node_modules, then
|
||||
// /foo/node_modules, then /node_modules.
|
||||
|
||||
let path = 'node_modules/typescript/lib';
|
||||
let resolvedPath = this.resolve(path);
|
||||
|
||||
// Construct a path for the top-level node_modules to identify the stopping point.
|
||||
const topLevelNodeModules = this.resolve('/' + path);
|
||||
|
||||
while (resolvedPath !== topLevelNodeModules) {
|
||||
if (this.exists(resolvedPath)) {
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
// Not here, look one level higher.
|
||||
path = '../' + path;
|
||||
resolvedPath = this.resolve(path);
|
||||
}
|
||||
|
||||
// The loop exits before checking the existence of /node_modules/typescript at the top level.
|
||||
// This is intentional - if no /node_modules/typescript exists anywhere in the tree, there's
|
||||
// nothing this function can do about it, and TS may error later if it looks for a lib.d.ts file
|
||||
// within this directory. It might be okay, though, if TS never checks for one.
|
||||
return topLevelNodeModules;
|
||||
}
|
||||
|
||||
abstract resolve(...paths: string[]): AbsoluteFsPath;
|
||||
abstract dirname<T extends string>(file: T): T;
|
||||
|
|
|
@ -35,7 +35,8 @@ export class NgtscTestEnvironment {
|
|||
/**
|
||||
* Set up a new testing environment.
|
||||
*/
|
||||
static setup(files?: Folder): NgtscTestEnvironment {
|
||||
static setup(files?: Folder, workingDir: AbsoluteFsPath = absoluteFrom('/')):
|
||||
NgtscTestEnvironment {
|
||||
const fs = getFileSystem();
|
||||
if (files !== undefined && fs instanceof MockFileSystem) {
|
||||
fs.init(files);
|
||||
|
@ -44,7 +45,8 @@ export class NgtscTestEnvironment {
|
|||
const host = new AugmentedCompilerHost(fs);
|
||||
setWrapHostForTest(makeWrapHost(host));
|
||||
|
||||
const env = new NgtscTestEnvironment(fs, fs.resolve('/built'), absoluteFrom('/'));
|
||||
const env = new NgtscTestEnvironment(fs, fs.resolve('/built'), workingDir);
|
||||
fs.chdir(workingDir);
|
||||
|
||||
env.write(absoluteFrom('/tsconfig-base.json'), `{
|
||||
"compilerOptions": {
|
||||
|
@ -54,7 +56,6 @@ export class NgtscTestEnvironment {
|
|||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"outDir": "built",
|
||||
"rootDir": ".",
|
||||
"baseUrl": ".",
|
||||
"declaration": true,
|
||||
"target": "es5",
|
||||
|
|
Loading…
Reference in New Issue