* Copyright (c) 2025 Huawei Technologies Co., Ltd.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { AbsolutePath, DescriptiveError, Dirent, FS } from '../core';
import { CliExecutor, CliOptions } from './CliExecutor';
import { IFs, memfs, NestedDirectoryJSON } from 'memfs';
import RawMemDirent from 'memfs/lib/Dirent';
import { Logger } from './Logger';
import chalk from 'chalk';
export class FakeCliExecutor extends CliExecutor {
private commands: string[] = [];
constructor(private onRun: (command: string) => Promise<string>) {
super();
}
run(command: string, options: CliOptions): Promise<string> {
let commandWithArgs = command;
if (options.args) {
commandWithArgs += options.args.join(' ');
}
this.commands.push(commandWithArgs);
return this.onRun(commandWithArgs);
}
getCommands() {
return this.commands;
}
}
class MemFSDirent extends Dirent {
constructor(private rawDirent: RawMemDirent) {
super();
}
isDirectory(): boolean {
return this.rawDirent.isDirectory();
}
isSymbolicLink(): boolean {
return false;
}
get name(): string {
return this.rawDirent.name.toString();
}
get path(): AbsolutePath {
return new AbsolutePath(this.rawDirent.path).copyWithNewSegment(
this.rawDirent.name.toString()
);
}
}
export class MemFS extends FS {
private fs: IFs;
constructor(initialFileStructure: NestedDirectoryJSON) {
super();
this.fs = memfs(initialFileStructure, './').fs;
}
existsSync(path: AbsolutePath): boolean {
return this.fs.existsSync(path.toString());
}
readTextSync(path: AbsolutePath): string {
return this.fs.readFileSync(path.toString()).toString();
}
async readText(path: AbsolutePath): Promise<string> {
return new Promise((resolve, reject) => {
this.fs.readFile(path.toString(), {}, (err, data) => {
if (err) {
reject(err);
return;
}
resolve(data?.toString() ?? '');
});
});
}
writeTextSync(path: AbsolutePath, data: string): void {
return this.fs.writeFileSync(path.toString(), data);
}
readDirentsSync(
path: AbsolutePath,
options?: { recursive?: boolean | undefined } | undefined
): Dirent[] {
return this.fs
.readdirSync(path.toString(), {
withFileTypes: true,
recursive: options?.recursive,
})
.flatMap((dataOutOrDirent) => {
if (!(dataOutOrDirent instanceof RawMemDirent)) {
return [];
}
return [new MemFSDirent(dataOutOrDirent)];
});
}
}
export class MockedLogger extends Logger {
private logs: { type: 'debug' | 'info' | 'warn' | 'error'; msg: string }[] =
[];
debug(prepareMsg: (styles: typeof import('chalk')) => string): void {
chalk.level = 0;
this.logs.push({ type: 'debug', msg: prepareMsg(chalk) });
}
info(
prepareMsg: (styles: typeof import('chalk')) => string,
options?: { prefix?: boolean }
): void {
chalk.level = 0;
this.logs.push({ type: 'info', msg: prepareMsg(chalk) });
}
warn(prepareMsg: (styles: typeof chalk) => string): void {
chalk.level = 0;
this.logs.push({ type: 'warn', msg: prepareMsg(chalk) });
}
descriptiveError(error: DescriptiveError): void {
chalk.level = 0;
this.logs.push({ type: 'error', msg: error.getMessage() });
}
getLogs() {
return this.logs;
}
}