Path: blob/main/extensions/copilot/src/platform/filesystem/node/test/mockFileSystemService.ts
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { FileStat, FileSystemWatcher } from 'vscode';6import { basename, dirname } from '../../../../util/vs/base/common/resources';7import { URI } from '../../../../util/vs/base/common/uri';8import { IFileSystemService } from '../../common/fileSystemService';9import { FileType } from '../../common/fileTypes';1011export class MockFileSystemService implements IFileSystemService {12_serviceBrand: undefined;1314private mockDirs = new Map<string, [string, FileType][]>();15private mockFiles = new Map<string, string>();16private mockErrors = new Map<string, Error>();17private mockMtimes = new Map<string, number>();18private statCalls = 0;1920mockDirectory(uri: URI | string, entries: [string, FileType][]) {21const uriString = typeof uri === 'string' ? uri : uri.toString();22this.mockDirs.set(uriString, entries);23}2425mockFile(uri: URI | string, contents: string, mtime?: number) {26const uriString = typeof uri === 'string' ? uri : uri.toString();27this.mockFiles.set(uriString, contents);28if (mtime !== undefined) {29this.mockMtimes.set(uriString, mtime);30}31}3233mockError(uri: URI | string, error: Error) {34const uriString = typeof uri === 'string' ? uri : uri.toString();35this.mockErrors.set(uriString, error);36}3738getStatCallCount(): number {39return this.statCalls;40}4142resetStatCallCount(): void {43this.statCalls = 0;44}4546async readDirectory(uri: URI): Promise<[string, FileType][]> {47const uriString = uri.toString();48if (this.mockErrors.has(uriString)) {49throw this.mockErrors.get(uriString);50}51return this.mockDirs.get(uriString) || [];52}5354async readFile(uri: URI, disableLimit?: boolean): Promise<Uint8Array> {55const uriString = uri.toString();56if (this.mockErrors.has(uriString)) {57throw this.mockErrors.get(uriString);58}59const contents = this.mockFiles.get(uriString);60if (contents === undefined) {61throw new Error('ENOENT');62}63return new TextEncoder().encode(contents);64}6566async stat(uri: URI): Promise<FileStat> {67this.statCalls++; // Track stat calls to verify caching68const uriString = uri.toString();69if (this.mockErrors.has(uriString)) {70throw this.mockErrors.get(uriString);71}72if (this.mockFiles.has(uriString)) {73const contents = this.mockFiles.get(uriString)!;74const mtime = this.mockMtimes.get(uriString) ?? Date.now();75return { type: FileType.File as unknown as FileType, ctime: Date.now() - 1000, mtime, size: contents.length };76}77if (this.mockDirs.has(uriString)) {78const mtime = this.mockMtimes.get(uriString) ?? Date.now();79return { type: FileType.Directory as unknown as FileType, ctime: Date.now() - 1000, mtime, size: 0 };80}81throw new Error('ENOENT');82}8384// Required interface methods85isWritableFileSystem(): boolean | undefined { return true; }86createFileSystemWatcher(): FileSystemWatcher { throw new Error('not implemented'); }8788async createDirectory(uri: URI): Promise<void> {89const uriString = uri.toString();9091// Recursively ensure parent directories exist first92const parentUri = dirname(uri);93if (parentUri && parentUri.toString() !== uriString) {94if (!this.mockDirs.has(parentUri.toString())) {95await this.createDirectory(parentUri);96}9798const entries = this.mockDirs.get(parentUri.toString())!;99const bname = basename(uri);100if (!entries.find(e => e[0] === bname)) {101entries.push([bname, FileType.Directory]);102}103}104105// Mark as directory by adding empty entry list106if (!this.mockDirs.has(uriString)) {107this.mockDirs.set(uriString, []);108// Store creation time for stat() calls109this.mockMtimes.set(uriString, Date.now());110}111}112113async writeFile(uri: URI, content: Uint8Array): Promise<void> {114const uriString = uri.toString();115const text = new TextDecoder().decode(content);116this.mockFiles.set(uriString, text);117// Store write time for stat() calls118this.mockMtimes.set(uriString, Date.now());119120// add the file to the mock directory listing of its parent directory121const parentUri = uriString.substring(0, uriString.lastIndexOf('/'));122if (this.mockDirs.has(parentUri)) {123const entries = this.mockDirs.get(parentUri)!;124const fileName = uriString.substring(uriString.lastIndexOf('/') + 1);125if (!entries.find(e => e[0] === fileName)) {126entries.push([fileName, FileType.File]);127}128} else {129this.mockDirs.set(parentUri, [[uriString.substring(uriString.lastIndexOf('/') + 1), FileType.File]]);130}131}132133async delete(uri: URI, options?: { recursive?: boolean; useTrash?: boolean }): Promise<void> {134const uriString = uri.toString();135this.mockFiles.delete(uriString);136this.mockDirs.delete(uriString);137this.mockErrors.delete(uriString);138this.mockMtimes.delete(uriString);139140const parentUri = dirname(uri);141if (parentUri && this.mockDirs.has(parentUri.toString())) {142const entries = this.mockDirs.get(parentUri.toString())!;143const bname = basename(uri);144this.mockDirs.set(parentUri.toString(), entries.filter(e => e[0] !== bname));145}146}147148async rename(oldURI: URI, newURI: URI, options?: { overwrite?: boolean }): Promise<void> {149const oldUriString = oldURI.toString();150const newUriString = newURI.toString();151152// Check if target exists and overwrite is not allowed153if (!options?.overwrite && (this.mockFiles.has(newUriString) || this.mockDirs.has(newUriString))) {154throw new Error('EEXIST: File exists');155}156157// Move file or directory158if (this.mockFiles.has(oldUriString)) {159const content = this.mockFiles.get(oldUriString)!;160this.mockFiles.set(newUriString, content);161this.mockFiles.delete(oldUriString);162163if (this.mockMtimes.has(oldUriString)) {164const mtime = this.mockMtimes.get(oldUriString)!;165this.mockMtimes.set(newUriString, mtime);166this.mockMtimes.delete(oldUriString);167}168} else if (this.mockDirs.has(oldUriString)) {169const entries = this.mockDirs.get(oldUriString)!;170this.mockDirs.set(newUriString, entries);171this.mockDirs.delete(oldUriString);172} else {173throw new Error('ENOENT: File not found');174}175}176copy(source: URI, destination: URI, options?: { overwrite?: boolean }): Promise<void> {177throw new Error('Method not implemented.');178}179}180181182