Path: blob/main/src/vs/workbench/test/electron-browser/workbenchTestServices.ts
3296 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 { Event } from '../../../base/common/event.js';6import { workbenchInstantiationService as browserWorkbenchInstantiationService, ITestInstantiationService, TestEncodingOracle, TestEnvironmentService, TestFileDialogService, TestFilesConfigurationService, TestFileService, TestLifecycleService, TestTextFileService } from '../browser/workbenchTestServices.js';7import { ISharedProcessService } from '../../../platform/ipc/electron-browser/services.js';8import { INativeHostService, INativeHostOptions, IOSProperties, IOSStatistics } from '../../../platform/native/common/native.js';9import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../base/common/buffer.js';10import { DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';11import { URI } from '../../../base/common/uri.js';12import { IFileDialogService, INativeOpenDialogOptions } from '../../../platform/dialogs/common/dialogs.js';13import { IPartsSplash } from '../../../platform/theme/common/themeService.js';14import { IOpenedMainWindow, IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IColorScheme, IRectangle, IPoint } from '../../../platform/window/common/window.js';15import { TestConfigurationService } from '../../../platform/configuration/test/common/testConfigurationService.js';16import { IContextKeyService } from '../../../platform/contextkey/common/contextkey.js';17import { IEnvironmentService, INativeEnvironmentService } from '../../../platform/environment/common/environment.js';18import { IFileService } from '../../../platform/files/common/files.js';19import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';20import { IEditorService } from '../../services/editor/common/editorService.js';21import { IPathService } from '../../services/path/common/pathService.js';22import { ITextEditorService } from '../../services/textfile/common/textEditorService.js';23import { ITextFileService } from '../../services/textfile/common/textfiles.js';24import { AbstractNativeExtensionTipsService } from '../../../platform/extensionManagement/common/extensionTipsService.js';25import { IExtensionManagementService } from '../../../platform/extensionManagement/common/extensionManagement.js';26import { IExtensionRecommendationNotificationService } from '../../../platform/extensionRecommendations/common/extensionRecommendations.js';27import { IProductService } from '../../../platform/product/common/productService.js';28import { IStorageService } from '../../../platform/storage/common/storage.js';29import { ITelemetryService } from '../../../platform/telemetry/common/telemetry.js';30import { IModelService } from '../../../editor/common/services/model.js';31import { ModelService } from '../../../editor/common/services/modelService.js';32import { IWorkspaceContextService } from '../../../platform/workspace/common/workspace.js';33import { IFilesConfigurationService } from '../../services/filesConfiguration/common/filesConfigurationService.js';34import { ILifecycleService } from '../../services/lifecycle/common/lifecycle.js';35import { IWorkingCopyBackupService } from '../../services/workingCopy/common/workingCopyBackup.js';36import { IWorkingCopyService } from '../../services/workingCopy/common/workingCopyService.js';37import { TestContextService } from '../common/workbenchTestServices.js';38import { NativeTextFileService } from '../../services/textfile/electron-browser/nativeTextFileService.js';39import { insert } from '../../../base/common/arrays.js';40import { Schemas } from '../../../base/common/network.js';41import { FileService } from '../../../platform/files/common/fileService.js';42import { InMemoryFileSystemProvider } from '../../../platform/files/common/inMemoryFilesystemProvider.js';43import { NullLogService } from '../../../platform/log/common/log.js';44import { FileUserDataProvider } from '../../../platform/userData/common/fileUserDataProvider.js';45import { IWorkingCopyIdentifier } from '../../services/workingCopy/common/workingCopy.js';46import { NativeWorkingCopyBackupService } from '../../services/workingCopy/electron-browser/workingCopyBackupService.js';47import { CancellationToken } from '../../../base/common/cancellation.js';48import { UriIdentityService } from '../../../platform/uriIdentity/common/uriIdentityService.js';49import { UserDataProfilesService } from '../../../platform/userDataProfile/common/userDataProfile.js';50import { AuthInfo, Credentials } from '../../../platform/request/common/request.js';5152export class TestSharedProcessService implements ISharedProcessService {5354declare readonly _serviceBrand: undefined;5556createRawConnection(): never { throw new Error('Not Implemented'); }57getChannel(channelName: string): any { return undefined; }58registerChannel(channelName: string, channel: any): void { }59notifyRestored(): void { }60}6162export class TestNativeHostService implements INativeHostService {63declare readonly _serviceBrand: undefined;6465readonly windowId = -1;6667onDidOpenMainWindow: Event<number> = Event.None;68onDidMaximizeWindow: Event<number> = Event.None;69onDidUnmaximizeWindow: Event<number> = Event.None;70onDidFocusMainWindow: Event<number> = Event.None;71onDidBlurMainWindow: Event<number> = Event.None;72onDidFocusMainOrAuxiliaryWindow: Event<number> = Event.None;73onDidBlurMainOrAuxiliaryWindow: Event<number> = Event.None;74onDidResumeOS: Event<unknown> = Event.None;75onDidChangeColorScheme = Event.None;76onDidChangePassword = Event.None;77onDidTriggerWindowSystemContextMenu: Event<{ windowId: number; x: number; y: number }> = Event.None;78onDidChangeWindowFullScreen = Event.None;79onDidChangeWindowAlwaysOnTop = Event.None;80onDidChangeDisplay = Event.None;8182windowCount = Promise.resolve(1);83getWindowCount(): Promise<number> { return this.windowCount; }8485async getWindows(): Promise<IOpenedMainWindow[]> { return []; }86async getActiveWindowId(): Promise<number | undefined> { return undefined; }87async getActiveWindowPosition(): Promise<IRectangle | undefined> { return undefined; }88async getNativeWindowHandle(windowId: number): Promise<VSBuffer | undefined> { return undefined; }8990openWindow(options?: IOpenEmptyWindowOptions): Promise<void>;91openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise<void>;92openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise<void> {93throw new Error('Method not implemented.');94}9596async toggleFullScreen(): Promise<void> { }97async isMaximized(): Promise<boolean> { return true; }98async isFullScreen(): Promise<boolean> { return true; }99async maximizeWindow(): Promise<void> { }100async unmaximizeWindow(): Promise<void> { }101async minimizeWindow(): Promise<void> { }102async moveWindowTop(options?: INativeHostOptions): Promise<void> { }103async isWindowAlwaysOnTop(options?: INativeHostOptions): Promise<boolean> { return false; }104async toggleWindowAlwaysOnTop(options?: INativeHostOptions): Promise<void> { }105async setWindowAlwaysOnTop(alwaysOnTop: boolean, options?: INativeHostOptions): Promise<void> { }106async getCursorScreenPoint(): Promise<{ readonly point: IPoint; readonly display: IRectangle }> { throw new Error('Method not implemented.'); }107async positionWindow(position: IRectangle, options?: INativeHostOptions): Promise<void> { }108async updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string }): Promise<void> { }109async updateWindowAccentColor(color: string): Promise<void> { }110async setMinimumSize(width: number | undefined, height: number | undefined): Promise<void> { }111async saveWindowSplash(value: IPartsSplash): Promise<void> { }112async setBackgroundThrottling(throttling: boolean): Promise<void> { }113async focusWindow(options?: INativeHostOptions): Promise<void> { }114async showMessageBox(options: Electron.MessageBoxOptions): Promise<Electron.MessageBoxReturnValue> { throw new Error('Method not implemented.'); }115async showSaveDialog(options: Electron.SaveDialogOptions): Promise<Electron.SaveDialogReturnValue> { throw new Error('Method not implemented.'); }116async showOpenDialog(options: Electron.OpenDialogOptions): Promise<Electron.OpenDialogReturnValue> { throw new Error('Method not implemented.'); }117async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> { }118async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> { }119async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> { }120async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> { }121async showItemInFolder(path: string): Promise<void> { }122async setRepresentedFilename(path: string): Promise<void> { }123async isAdmin(): Promise<boolean> { return false; }124async writeElevated(source: URI, target: URI): Promise<void> { }125async isRunningUnderARM64Translation(): Promise<boolean> { return false; }126async getOSProperties(): Promise<IOSProperties> { return Object.create(null); }127async getOSStatistics(): Promise<IOSStatistics> { return Object.create(null); }128async getOSVirtualMachineHint(): Promise<number> { return 0; }129async getOSColorScheme(): Promise<IColorScheme> { return { dark: true, highContrast: false }; }130async hasWSLFeatureInstalled(): Promise<boolean> { return false; }131async getProcessId(): Promise<number> { throw new Error('Method not implemented.'); }132async killProcess(): Promise<void> { }133async setDocumentEdited(edited: boolean): Promise<void> { }134async openExternal(url: string, defaultApplication?: string): Promise<boolean> { return false; }135async updateTouchBar(): Promise<void> { }136async moveItemToTrash(): Promise<void> { }137async newWindowTab(): Promise<void> { }138async showPreviousWindowTab(): Promise<void> { }139async showNextWindowTab(): Promise<void> { }140async moveWindowTabToNewWindow(): Promise<void> { }141async mergeAllWindowTabs(): Promise<void> { }142async toggleWindowTabsBar(): Promise<void> { }143async installShellCommand(): Promise<void> { }144async uninstallShellCommand(): Promise<void> { }145async notifyReady(): Promise<void> { }146async relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined } | undefined): Promise<void> { }147async reload(): Promise<void> { }148async closeWindow(): Promise<void> { }149async quit(): Promise<void> { }150async exit(code: number): Promise<void> { }151async openDevTools(options?: Partial<Electron.OpenDevToolsOptions> & INativeHostOptions | undefined): Promise<void> { }152async toggleDevTools(): Promise<void> { }153async stopTracing(): Promise<void> { }154async openDevToolsWindow(url: string): Promise<void> { }155async openGPUInfoWindow(): Promise<void> { }156async resolveProxy(url: string): Promise<string | undefined> { return undefined; }157async lookupAuthorization(authInfo: AuthInfo): Promise<Credentials | undefined> { return undefined; }158async lookupKerberosAuthorization(url: string): Promise<string | undefined> { return undefined; }159async loadCertificates(): Promise<string[]> { return []; }160async isPortFree() { return Promise.resolve(true); }161async findFreePort(startPort: number, giveUpAfter: number, timeout: number, stride?: number): Promise<number> { return -1; }162async readClipboardText(type?: 'selection' | 'clipboard' | undefined): Promise<string> { return ''; }163async writeClipboardText(text: string, type?: 'selection' | 'clipboard' | undefined): Promise<void> { }164async readClipboardFindText(): Promise<string> { return ''; }165async writeClipboardFindText(text: string): Promise<void> { }166async writeClipboardBuffer(format: string, buffer: VSBuffer, type?: 'selection' | 'clipboard' | undefined): Promise<void> { }167async triggerPaste(options?: INativeHostOptions): Promise<void> { }168async readImage(): Promise<Uint8Array> { return Uint8Array.from([]); }169async readClipboardBuffer(format: string): Promise<VSBuffer> { return VSBuffer.wrap(Uint8Array.from([])); }170async hasClipboard(format: string, type?: 'selection' | 'clipboard' | undefined): Promise<boolean> { return false; }171async windowsGetStringRegKey(hive: 'HKEY_CURRENT_USER' | 'HKEY_LOCAL_MACHINE' | 'HKEY_CLASSES_ROOT' | 'HKEY_USERS' | 'HKEY_CURRENT_CONFIG', path: string, name: string): Promise<string | undefined> { return undefined; }172async profileRenderer(): Promise<any> { throw new Error(); }173async getScreenshot(rect?: IRectangle): Promise<VSBuffer | undefined> { return undefined; }174}175176export class TestExtensionTipsService extends AbstractNativeExtensionTipsService {177178constructor(179@INativeEnvironmentService environmentService: INativeEnvironmentService,180@ITelemetryService telemetryService: ITelemetryService,181@IExtensionManagementService extensionManagementService: IExtensionManagementService,182@IStorageService storageService: IStorageService,183@INativeHostService nativeHostService: INativeHostService,184@IExtensionRecommendationNotificationService extensionRecommendationNotificationService: IExtensionRecommendationNotificationService,185@IFileService fileService: IFileService,186@IProductService productService: IProductService,187) {188super(environmentService.userHome, nativeHostService, telemetryService, extensionManagementService, storageService, extensionRecommendationNotificationService, fileService, productService);189}190}191192export function workbenchInstantiationService(overrides?: {193environmentService?: (instantiationService: IInstantiationService) => IEnvironmentService;194fileService?: (instantiationService: IInstantiationService) => IFileService;195configurationService?: (instantiationService: IInstantiationService) => TestConfigurationService;196textFileService?: (instantiationService: IInstantiationService) => ITextFileService;197pathService?: (instantiationService: IInstantiationService) => IPathService;198editorService?: (instantiationService: IInstantiationService) => IEditorService;199contextKeyService?: (instantiationService: IInstantiationService) => IContextKeyService;200textEditorService?: (instantiationService: IInstantiationService) => ITextEditorService;201}, disposables = new DisposableStore()): ITestInstantiationService {202const instantiationService = browserWorkbenchInstantiationService({203workingCopyBackupService: () => disposables.add(new TestNativeWorkingCopyBackupService()),204...overrides205}, disposables);206207instantiationService.stub(INativeHostService, new TestNativeHostService());208209return instantiationService;210}211212export class TestServiceAccessor {213constructor(214@ILifecycleService public lifecycleService: TestLifecycleService,215@ITextFileService public textFileService: TestTextFileService,216@IFilesConfigurationService public filesConfigurationService: TestFilesConfigurationService,217@IWorkspaceContextService public contextService: TestContextService,218@IModelService public modelService: ModelService,219@IFileService public fileService: TestFileService,220@INativeHostService public nativeHostService: TestNativeHostService,221@IFileDialogService public fileDialogService: TestFileDialogService,222@IWorkingCopyBackupService public workingCopyBackupService: TestNativeWorkingCopyBackupService,223@IWorkingCopyService public workingCopyService: IWorkingCopyService,224@IEditorService public editorService: IEditorService225) {226}227}228229export class TestNativeTextFileServiceWithEncodingOverrides extends NativeTextFileService {230231private _testEncoding: TestEncodingOracle | undefined;232override get encoding(): TestEncodingOracle {233if (!this._testEncoding) {234this._testEncoding = this._register(this.instantiationService.createInstance(TestEncodingOracle));235}236237return this._testEncoding;238}239}240241export class TestNativeWorkingCopyBackupService extends NativeWorkingCopyBackupService implements IDisposable {242243private backupResourceJoiners: Function[];244private discardBackupJoiners: Function[];245discardedBackups: IWorkingCopyIdentifier[];246discardedAllBackups: boolean;247private pendingBackupsArr: Promise<void>[];248249constructor() {250const environmentService = TestEnvironmentService;251const logService = new NullLogService();252const fileService = new FileService(logService);253const lifecycleService = new TestLifecycleService();254super(environmentService as any, fileService, logService, lifecycleService);255256const inMemoryFileSystemProvider = this._register(new InMemoryFileSystemProvider());257this._register(fileService.registerProvider(Schemas.inMemory, inMemoryFileSystemProvider));258const uriIdentityService = this._register(new UriIdentityService(fileService));259const userDataProfilesService = this._register(new UserDataProfilesService(environmentService, fileService, uriIdentityService, logService));260this._register(fileService.registerProvider(Schemas.vscodeUserData, this._register(new FileUserDataProvider(Schemas.file, inMemoryFileSystemProvider, Schemas.vscodeUserData, userDataProfilesService, uriIdentityService, logService))));261262this.backupResourceJoiners = [];263this.discardBackupJoiners = [];264this.discardedBackups = [];265this.pendingBackupsArr = [];266this.discardedAllBackups = false;267268this._register(fileService);269this._register(lifecycleService);270}271272testGetFileService(): IFileService {273return this.fileService;274}275276async waitForAllBackups(): Promise<void> {277await Promise.all(this.pendingBackupsArr);278}279280joinBackupResource(): Promise<void> {281return new Promise(resolve => this.backupResourceJoiners.push(resolve));282}283284override async backup(identifier: IWorkingCopyIdentifier, content?: VSBufferReadableStream | VSBufferReadable, versionId?: number, meta?: any, token?: CancellationToken): Promise<void> {285const p = super.backup(identifier, content, versionId, meta, token);286const removeFromPendingBackups = insert(this.pendingBackupsArr, p.then(undefined, undefined));287288try {289await p;290} finally {291removeFromPendingBackups();292}293294while (this.backupResourceJoiners.length) {295this.backupResourceJoiners.pop()!();296}297}298299joinDiscardBackup(): Promise<void> {300return new Promise(resolve => this.discardBackupJoiners.push(resolve));301}302303override async discardBackup(identifier: IWorkingCopyIdentifier): Promise<void> {304await super.discardBackup(identifier);305this.discardedBackups.push(identifier);306307while (this.discardBackupJoiners.length) {308this.discardBackupJoiners.pop()!();309}310}311312override async discardBackups(filter?: { except: IWorkingCopyIdentifier[] }): Promise<void> {313this.discardedAllBackups = true;314315return super.discardBackups(filter);316}317318async getBackupContents(identifier: IWorkingCopyIdentifier): Promise<string> {319const backupResource = this.toBackupResource(identifier);320321const fileContents = await this.fileService.readFile(backupResource);322323return fileContents.value.toString();324}325}326327328