Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
7
import { IFileService } from '../../../../../platform/files/common/files.js';
8
import { FileService } from '../../../../../platform/files/common/fileService.js';
9
import { Schemas } from '../../../../../base/common/network.js';
10
import { InMemoryFileSystemProvider } from '../../../../../platform/files/common/inMemoryFilesystemProvider.js';
11
import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';
12
import { NullLogService } from '../../../../../platform/log/common/log.js';
13
import { EditSessionsContribution } from '../../browser/editSessions.contribution.js';
14
import { ProgressService } from '../../../../services/progress/browser/progressService.js';
15
import { IProgressService } from '../../../../../platform/progress/common/progress.js';
16
import { ISCMService } from '../../../scm/common/scm.js';
17
import { SCMService } from '../../../scm/common/scmService.js';
18
import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';
19
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
20
import { IWorkspaceContextService, WorkbenchState } from '../../../../../platform/workspace/common/workspace.js';
21
import { mock } from '../../../../../base/test/common/mock.js';
22
import * as sinon from 'sinon';
23
import assert from 'assert';
24
import { ChangeType, FileType, IEditSessionsLogService, IEditSessionsStorageService } from '../../common/editSessions.js';
25
import { URI } from '../../../../../base/common/uri.js';
26
import { joinPath } from '../../../../../base/common/resources.js';
27
import { INotificationService } from '../../../../../platform/notification/common/notification.js';
28
import { TestNotificationService } from '../../../../../platform/notification/test/common/testNotificationService.js';
29
import { TestEnvironmentService } from '../../../../test/browser/workbenchTestServices.js';
30
import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';
31
import { MockContextKeyService } from '../../../../../platform/keybinding/test/common/mockKeybindingService.js';
32
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
33
import { IThemeService } from '../../../../../platform/theme/common/themeService.js';
34
import { Event } from '../../../../../base/common/event.js';
35
import { IViewDescriptorService } from '../../../../common/views.js';
36
import { ITextModelService } from '../../../../../editor/common/services/resolverService.js';
37
import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js';
38
import { IDialogService, IPrompt } from '../../../../../platform/dialogs/common/dialogs.js';
39
import { IEditorService, ISaveAllEditorsOptions } from '../../../../services/editor/common/editorService.js';
40
import { CancellationToken } from '../../../../../base/common/cancellation.js';
41
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
42
import { NullTelemetryService } from '../../../../../platform/telemetry/common/telemetryUtils.js';
43
import { IRemoteAgentService } from '../../../../services/remote/common/remoteAgentService.js';
44
import { IExtensionService } from '../../../../services/extensions/common/extensions.js';
45
import { IEditSessionIdentityService } from '../../../../../platform/workspace/common/editSessions.js';
46
import { IUserDataProfilesService } from '../../../../../platform/userDataProfile/common/userDataProfile.js';
47
import { IProductService } from '../../../../../platform/product/common/productService.js';
48
import { IStorageService } from '../../../../../platform/storage/common/storage.js';
49
import { TestStorageService } from '../../../../test/common/workbenchTestServices.js';
50
import { IUriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentity.js';
51
import { UriIdentityService } from '../../../../../platform/uriIdentity/common/uriIdentityService.js';
52
import { IWorkspaceIdentityService, WorkspaceIdentityService } from '../../../../services/workspaces/common/workspaceIdentityService.js';
53
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
54
55
const folderName = 'test-folder';
56
const folderUri = URI.file(`/${folderName}`);
57
58
suite('Edit session sync', () => {
59
60
let instantiationService: TestInstantiationService;
61
let editSessionsContribution: EditSessionsContribution;
62
let fileService: FileService;
63
let sandbox: sinon.SinonSandbox;
64
65
const disposables = new DisposableStore();
66
67
suiteSetup(() => {
68
69
sandbox = sinon.createSandbox();
70
71
instantiationService = new TestInstantiationService();
72
73
// Set up filesystem
74
const logService = new NullLogService();
75
fileService = disposables.add(new FileService(logService));
76
const fileSystemProvider = disposables.add(new InMemoryFileSystemProvider());
77
fileService.registerProvider(Schemas.file, fileSystemProvider);
78
79
// Stub out all services
80
instantiationService.stub(IEditSessionsLogService, logService);
81
instantiationService.stub(IFileService, fileService);
82
instantiationService.stub(ILifecycleService, new class extends mock<ILifecycleService>() {
83
override onWillShutdown = Event.None;
84
});
85
instantiationService.stub(INotificationService, new TestNotificationService());
86
instantiationService.stub(IProductService, { 'editSessions.store': { url: 'https://test.com', canSwitch: true, authenticationProviders: {} } });
87
instantiationService.stub(IStorageService, new TestStorageService());
88
instantiationService.stub(IUriIdentityService, new UriIdentityService(fileService));
89
instantiationService.stub(IEditSessionsStorageService, new class extends mock<IEditSessionsStorageService>() {
90
override onDidSignIn = Event.None;
91
override onDidSignOut = Event.None;
92
});
93
instantiationService.stub(IExtensionService, new class extends mock<IExtensionService>() {
94
override onDidChangeExtensions = Event.None;
95
});
96
instantiationService.stub(IProgressService, ProgressService);
97
instantiationService.stub(ISCMService, SCMService);
98
instantiationService.stub(IEnvironmentService, TestEnvironmentService);
99
instantiationService.stub(ITelemetryService, NullTelemetryService);
100
instantiationService.stub(IDialogService, new class extends mock<IDialogService>() {
101
override async prompt(prompt: IPrompt<any>) {
102
const result = prompt.buttons?.[0].run({ checkboxChecked: false });
103
return { result };
104
}
105
override async confirm() {
106
return { confirmed: false };
107
}
108
});
109
instantiationService.stub(IRemoteAgentService, new class extends mock<IRemoteAgentService>() {
110
override async getEnvironment() {
111
return null;
112
}
113
});
114
instantiationService.stub(IConfigurationService, new TestConfigurationService({ workbench: { experimental: { editSessions: { enabled: true } } } }));
115
instantiationService.stub(IWorkspaceContextService, new class extends mock<IWorkspaceContextService>() {
116
override getWorkspace() {
117
return {
118
id: 'workspace-id',
119
folders: [{
120
uri: folderUri,
121
name: folderName,
122
index: 0,
123
toResource: (relativePath: string) => joinPath(folderUri, relativePath)
124
}]
125
};
126
}
127
override getWorkbenchState() {
128
return WorkbenchState.FOLDER;
129
}
130
});
131
132
// Stub repositories
133
instantiationService.stub(ISCMService, '_repositories', new Map());
134
instantiationService.stub(IContextKeyService, new MockContextKeyService());
135
instantiationService.stub(IThemeService, new class extends mock<IThemeService>() {
136
override onDidColorThemeChange = Event.None;
137
override onDidFileIconThemeChange = Event.None;
138
});
139
instantiationService.stub(IViewDescriptorService, {
140
onDidChangeLocation: Event.None
141
});
142
instantiationService.stub(ITextModelService, new class extends mock<ITextModelService>() {
143
override registerTextModelContentProvider = () => ({ dispose: () => { } });
144
});
145
instantiationService.stub(IEditorService, new class extends mock<IEditorService>() {
146
override saveAll = async (_options: ISaveAllEditorsOptions) => { return { success: true, editors: [] }; };
147
});
148
instantiationService.stub(IEditSessionIdentityService, new class extends mock<IEditSessionIdentityService>() {
149
override async getEditSessionIdentifier() {
150
return 'test-identity';
151
}
152
});
153
instantiationService.set(IWorkspaceIdentityService, instantiationService.createInstance(WorkspaceIdentityService));
154
instantiationService.stub(IUserDataProfilesService, new class extends mock<IUserDataProfilesService>() {
155
override defaultProfile = {
156
id: 'default',
157
name: 'Default',
158
isDefault: true,
159
location: URI.file('location'),
160
globalStorageHome: URI.file('globalStorageHome'),
161
settingsResource: URI.file('settingsResource'),
162
keybindingsResource: URI.file('keybindingsResource'),
163
tasksResource: URI.file('tasksResource'),
164
mcpResource: URI.file('mcp.json'),
165
snippetsHome: URI.file('snippetsHome'),
166
promptsHome: URI.file('promptsHome'),
167
extensionsResource: URI.file('extensionsResource'),
168
cacheHome: URI.file('cacheHome'),
169
};
170
});
171
172
editSessionsContribution = instantiationService.createInstance(EditSessionsContribution);
173
});
174
175
teardown(() => {
176
sinon.restore();
177
disposables.clear();
178
});
179
180
suiteTeardown(() => {
181
disposables.dispose();
182
});
183
184
test('Can apply edit session', async function () {
185
const fileUri = joinPath(folderUri, 'dir1', 'README.md');
186
const fileContents = '# readme';
187
const editSession = {
188
version: 1,
189
folders: [
190
{
191
name: folderName,
192
workingChanges: [
193
{
194
relativeFilePath: 'dir1/README.md',
195
fileType: FileType.File,
196
contents: fileContents,
197
type: ChangeType.Addition
198
}
199
]
200
}
201
]
202
};
203
204
// Stub sync service to return edit session data
205
const readStub = sandbox.stub().returns({ content: JSON.stringify(editSession), ref: '0' });
206
instantiationService.stub(IEditSessionsStorageService, 'read', readStub);
207
208
// Create root folder
209
await fileService.createFolder(folderUri);
210
211
// Resume edit session
212
await editSessionsContribution.resumeEditSession();
213
214
// Verify edit session was correctly applied
215
assert.equal((await fileService.readFile(fileUri)).value.toString(), fileContents);
216
});
217
218
test('Edit session not stored if there are no edits', async function () {
219
const writeStub = sandbox.stub();
220
instantiationService.stub(IEditSessionsStorageService, 'write', writeStub);
221
222
// Create root folder
223
await fileService.createFolder(folderUri);
224
225
await editSessionsContribution.storeEditSession(true, CancellationToken.None);
226
227
// Verify that we did not attempt to write the edit session
228
assert.equal(writeStub.called, false);
229
});
230
231
ensureNoDisposablesAreLeakedInTestSuite();
232
});
233
234