Path: blob/main/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.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 { DisposableStore } from '../../../../../base/common/lifecycle.js';6import { IFileService } from '../../../../../platform/files/common/files.js';7import { FileService } from '../../../../../platform/files/common/fileService.js';8import { Schemas } from '../../../../../base/common/network.js';9import { InMemoryFileSystemProvider } from '../../../../../platform/files/common/inMemoryFilesystemProvider.js';10import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';11import { NullLogService } from '../../../../../platform/log/common/log.js';12import { EditSessionsContribution } from '../../browser/editSessions.contribution.js';13import { ProgressService } from '../../../../services/progress/browser/progressService.js';14import { IProgressService } from '../../../../../platform/progress/common/progress.js';15import { ISCMService } from '../../../scm/common/scm.js';16import { SCMService } from '../../../scm/common/scmService.js';17import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';18import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';19import { IWorkspaceContextService, WorkbenchState } from '../../../../../platform/workspace/common/workspace.js';20import { mock } from '../../../../../base/test/common/mock.js';21import * as sinon from 'sinon';22import assert from 'assert';23import { ChangeType, FileType, IEditSessionsLogService, IEditSessionsStorageService } from '../../common/editSessions.js';24import { URI } from '../../../../../base/common/uri.js';25import { joinPath } from '../../../../../base/common/resources.js';26import { INotificationService } from '../../../../../platform/notification/common/notification.js';27import { TestNotificationService } from '../../../../../platform/notification/test/common/testNotificationService.js';28import { TestEnvironmentService } from '../../../../test/browser/workbenchTestServices.js';29import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';30import { MockContextKeyService } from '../../../../../platform/keybinding/test/common/mockKeybindingService.js';31import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';32import { IThemeService } from '../../../../../platform/theme/common/themeService.js';33import { Event } from '../../../../../base/common/event.js';34import { IViewDescriptorService } from '../../../../common/views.js';35import { ITextModelService } from '../../../../../editor/common/services/resolverService.js';36import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js';37import { IDialogService, IPrompt } from '../../../../../platform/dialogs/common/dialogs.js';38import { IEditorService, ISaveAllEditorsOptions } from '../../../../services/editor/common/editorService.js';39import { CancellationToken } from '../../../../../base/common/cancellation.js';40import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';41import { NullTelemetryService } from '../../../../../platform/telemetry/common/telemetryUtils.js';42import { IRemoteAgentService } from '../../../../services/remote/common/remoteAgentService.js';43import { IExtensionService } from '../../../../services/extensions/common/extensions.js';44import { IEditSessionIdentityService } from '../../../../../platform/workspace/common/editSessions.js';45import { IUserDataProfilesService } from '../../../../../platform/userDataProfile/common/userDataProfile.js';46import { IProductService } from '../../../../../platform/product/common/productService.js';47import { IStorageService } from '../../../../../platform/storage/common/storage.js';48import { TestStorageService } from '../../../../test/common/workbenchTestServices.js';49import { IUriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentity.js';50import { UriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentityService.js';51import { IWorkspaceIdentityService, WorkspaceIdentityService } from '../../../../services/workspaces/common/workspaceIdentityService.js';52import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';5354const folderName = 'test-folder';55const folderUri = URI.file(`/${folderName}`);5657suite('Edit session sync', () => {5859let instantiationService: TestInstantiationService;60let editSessionsContribution: EditSessionsContribution;61let fileService: FileService;62let sandbox: sinon.SinonSandbox;6364const disposables = new DisposableStore();6566suiteSetup(() => {6768sandbox = sinon.createSandbox();6970instantiationService = new TestInstantiationService();7172// Set up filesystem73const logService = new NullLogService();74fileService = disposables.add(new FileService(logService));75const fileSystemProvider = disposables.add(new InMemoryFileSystemProvider());76fileService.registerProvider(Schemas.file, fileSystemProvider);7778// Stub out all services79instantiationService.stub(IEditSessionsLogService, logService);80instantiationService.stub(IFileService, fileService);81instantiationService.stub(ILifecycleService, new class extends mock<ILifecycleService>() {82override onWillShutdown = Event.None;83});84instantiationService.stub(INotificationService, new TestNotificationService());85instantiationService.stub(IProductService, { 'editSessions.store': { url: 'https://test.com', canSwitch: true, authenticationProviders: {} } });86instantiationService.stub(IStorageService, new TestStorageService());87instantiationService.stub(IUriIdentityService, new UriIdentityService(fileService));88instantiationService.stub(IEditSessionsStorageService, new class extends mock<IEditSessionsStorageService>() {89override onDidSignIn = Event.None;90override onDidSignOut = Event.None;91});92instantiationService.stub(IExtensionService, new class extends mock<IExtensionService>() {93override onDidChangeExtensions = Event.None;94});95instantiationService.stub(IProgressService, ProgressService);96instantiationService.stub(ISCMService, SCMService);97instantiationService.stub(IEnvironmentService, TestEnvironmentService);98instantiationService.stub(ITelemetryService, NullTelemetryService);99instantiationService.stub(IDialogService, new class extends mock<IDialogService>() {100override async prompt(prompt: IPrompt<any>) {101const result = prompt.buttons?.[0].run({ checkboxChecked: false });102return { result };103}104override async confirm() {105return { confirmed: false };106}107});108instantiationService.stub(IRemoteAgentService, new class extends mock<IRemoteAgentService>() {109override async getEnvironment() {110return null;111}112});113instantiationService.stub(IConfigurationService, new TestConfigurationService({ workbench: { experimental: { editSessions: { enabled: true } } } }));114instantiationService.stub(IWorkspaceContextService, new class extends mock<IWorkspaceContextService>() {115override getWorkspace() {116return {117id: 'workspace-id',118folders: [{119uri: folderUri,120name: folderName,121index: 0,122toResource: (relativePath: string) => joinPath(folderUri, relativePath)123}]124};125}126override getWorkbenchState() {127return WorkbenchState.FOLDER;128}129});130131// Stub repositories132instantiationService.stub(ISCMService, '_repositories', new Map());133instantiationService.stub(IContextKeyService, new MockContextKeyService());134instantiationService.stub(IThemeService, new class extends mock<IThemeService>() {135override onDidColorThemeChange = Event.None;136override onDidFileIconThemeChange = Event.None;137});138instantiationService.stub(IViewDescriptorService, {139onDidChangeLocation: Event.None140});141instantiationService.stub(ITextModelService, new class extends mock<ITextModelService>() {142override registerTextModelContentProvider = () => ({ dispose: () => { } });143});144instantiationService.stub(IEditorService, new class extends mock<IEditorService>() {145override saveAll = async (_options: ISaveAllEditorsOptions) => { return { success: true, editors: [] }; };146});147instantiationService.stub(IEditSessionIdentityService, new class extends mock<IEditSessionIdentityService>() {148override async getEditSessionIdentifier() {149return 'test-identity';150}151});152instantiationService.set(IWorkspaceIdentityService, instantiationService.createInstance(WorkspaceIdentityService));153instantiationService.stub(IUserDataProfilesService, new class extends mock<IUserDataProfilesService>() {154override defaultProfile = {155id: 'default',156name: 'Default',157isDefault: true,158location: URI.file('location'),159globalStorageHome: URI.file('globalStorageHome'),160settingsResource: URI.file('settingsResource'),161keybindingsResource: URI.file('keybindingsResource'),162tasksResource: URI.file('tasksResource'),163mcpResource: URI.file('mcp.json'),164snippetsHome: URI.file('snippetsHome'),165promptsHome: URI.file('promptsHome'),166extensionsResource: URI.file('extensionsResource'),167cacheHome: URI.file('cacheHome'),168};169});170171editSessionsContribution = instantiationService.createInstance(EditSessionsContribution);172});173174teardown(() => {175sinon.restore();176disposables.clear();177});178179suiteTeardown(() => {180disposables.dispose();181});182183test('Can apply edit session', async function () {184const fileUri = joinPath(folderUri, 'dir1', 'README.md');185const fileContents = '# readme';186const editSession = {187version: 1,188folders: [189{190name: folderName,191workingChanges: [192{193relativeFilePath: 'dir1/README.md',194fileType: FileType.File,195contents: fileContents,196type: ChangeType.Addition197}198]199}200]201};202203// Stub sync service to return edit session data204const readStub = sandbox.stub().returns({ content: JSON.stringify(editSession), ref: '0' });205instantiationService.stub(IEditSessionsStorageService, 'read', readStub);206207// Create root folder208await fileService.createFolder(folderUri);209210// Resume edit session211await editSessionsContribution.resumeEditSession();212213// Verify edit session was correctly applied214assert.equal((await fileService.readFile(fileUri)).value.toString(), fileContents);215});216217test('Edit session not stored if there are no edits', async function () {218const writeStub = sandbox.stub();219instantiationService.stub(IEditSessionsStorageService, 'write', writeStub);220221// Create root folder222await fileService.createFolder(folderUri);223224await editSessionsContribution.storeEditSession(true, CancellationToken.None);225226// Verify that we did not attempt to write the edit session227assert.equal(writeStub.called, false);228});229230ensureNoDisposablesAreLeakedInTestSuite();231});232233234