Alex Rickabaugh c9879deded test(language-service): introduce new, more configurable testing env (#40679)
The Ivy Language Service codebase testing suite contains a few testing
utilities which allow for assertions of Language Service operations against
an in-memory project. However, this existing utility lacks the flexibility
to test more complex scenarios, such as those involving multiple TS projects
with dependencies between them.

This commit introduces a new 'testing' package for the Ivy LS which attempts
to more faithfully represent the possible states of an IDE, and allows for
testing of more advanced scenarios. The new utility borrows from the prior
version and is geared towards more ergonomic testing. Only basic
functionality is present in this initial implementation, but this will grow
over time.

PR Close #40679
2021-02-22 08:40:41 -08:00

119 lines
3.2 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
import {MockFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
import * as ts from 'typescript/lib/tsserverlibrary';
const NOOP_FILE_WATCHER: ts.FileWatcher = {
close() {}
};
export class MockServerHost implements ts.server.ServerHost {
constructor(private fs: MockFileSystem) {}
get newLine(): string {
return '\n';
}
get useCaseSensitiveFileNames(): boolean {
return this.fs.isCaseSensitive();
}
readFile(path: string, encoding?: string): string|undefined {
return this.fs.readFile(absoluteFrom(path));
}
resolvePath(path: string): string {
return this.fs.resolve(path);
}
fileExists(path: string): boolean {
const absPath = absoluteFrom(path);
return this.fs.exists(absPath) && this.fs.lstat(absPath).isFile();
}
directoryExists(path: string): boolean {
const absPath = absoluteFrom(path);
return this.fs.exists(absPath) && this.fs.lstat(absPath).isDirectory();
}
createDirectory(path: string): void {
this.fs.ensureDir(absoluteFrom(path));
}
getExecutingFilePath(): string {
// This is load-bearing, as TypeScript uses the result of this call to locate the directory in
// which it expects to find .d.ts files for the "standard libraries" - DOM, ES2015, etc.
return '/node_modules/typescript/lib/tsserver.js';
}
getCurrentDirectory(): string {
return '/';
}
createHash(data: string): string {
return ts.sys.createHash!(data);
}
get args(): string[] {
throw new Error('Property not implemented.');
}
watchFile(
path: string, callback: ts.FileWatcherCallback, pollingInterval?: number,
options?: ts.WatchOptions): ts.FileWatcher {
return NOOP_FILE_WATCHER;
}
watchDirectory(
path: string, callback: ts.DirectoryWatcherCallback, recursive?: boolean,
options?: ts.WatchOptions): ts.FileWatcher {
return NOOP_FILE_WATCHER;
}
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]) {
throw new Error('Method not implemented.');
}
clearTimeout(timeoutId: any): void {
throw new Error('Method not implemented.');
}
setImmediate(callback: (...args: any[]) => void, ...args: any[]) {
throw new Error('Method not implemented.');
}
clearImmediate(timeoutId: any): void {
throw new Error('Method not implemented.');
}
write(s: string): void {
throw new Error('Method not implemented.');
}
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void {
throw new Error('Method not implemented.');
}
getDirectories(path: string): string[] {
throw new Error('Method not implemented.');
}
readDirectory(
path: string, extensions?: readonly string[], exclude?: readonly string[],
include?: readonly string[], depth?: number): string[] {
throw new Error('Method not implemented.');
}
exit(exitCode?: number): void {
throw new Error('Method not implemented.');
}
}