Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/test/common/workbenchTestServices.ts
5239 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 { DeferredPromise, timeout } from '../../../base/common/async.js';
7
import { bufferToStream, readableToBuffer, VSBuffer, VSBufferReadable } from '../../../base/common/buffer.js';
8
import { CancellationToken } from '../../../base/common/cancellation.js';
9
import { Emitter, Event } from '../../../base/common/event.js';
10
import { Iterable } from '../../../base/common/iterator.js';
11
import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
12
import { ResourceMap } from '../../../base/common/map.js';
13
import { Schemas } from '../../../base/common/network.js';
14
import { observableValue } from '../../../base/common/observable.js';
15
import { join } from '../../../base/common/path.js';
16
import { isLinux, isMacintosh } from '../../../base/common/platform.js';
17
import { basename, isEqual, isEqualOrParent } from '../../../base/common/resources.js';
18
import { URI } from '../../../base/common/uri.js';
19
import { ITextResourcePropertiesService } from '../../../editor/common/services/textResourceConfiguration.js';
20
import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
21
import { IResourceEditorInput } from '../../../platform/editor/common/editor.js';
22
import { FileChangesEvent, FileOperationEvent, FileSystemProviderCapabilities, IBaseFileStat, ICreateFileOptions, IFileContent, IFileService, IFileStat, IFileStatResult, IFileStatWithMetadata, IFileStatWithPartialMetadata, IFileStreamContent, IFileSystemProvider, IFileSystemProviderActivationEvent, IFileSystemProviderCapabilitiesChangeEvent, IFileSystemWatcher, IReadFileOptions, IReadFileStreamOptions, IResolveFileOptions, IResolveMetadataFileOptions, IWatchOptions, IWatchOptionsWithCorrelation, IWriteFileOptions } from '../../../platform/files/common/files.js';
23
import { AbstractLoggerService, ILogger, LogLevel, NullLogger } from '../../../platform/log/common/log.js';
24
import { IMarker, IMarkerData, IMarkerService, IResourceMarker, MarkerStatistics } from '../../../platform/markers/common/markers.js';
25
import product from '../../../platform/product/common/product.js';
26
import { IProgress, IProgressStep } from '../../../platform/progress/common/progress.js';
27
import { InMemoryStorageService, WillSaveStateReason } from '../../../platform/storage/common/storage.js';
28
import { toUserDataProfile } from '../../../platform/userDataProfile/common/userDataProfile.js';
29
import { ISingleFolderWorkspaceIdentifier, IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, IWorkspaceFoldersWillChangeEvent, IWorkspaceIdentifier, WorkbenchState, Workspace } from '../../../platform/workspace/common/workspace.js';
30
import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, IWorkspaceTrustTransitionParticipant, IWorkspaceTrustUriInfo, ResourceTrustRequestOptions, WorkspaceTrustRequestOptions, WorkspaceTrustUriResponse } from '../../../platform/workspace/common/workspaceTrust.js';
31
import { TestWorkspace } from '../../../platform/workspace/test/common/testWorkspace.js';
32
import { GroupIdentifier, IRevertOptions, ISaveOptions, SaveReason } from '../../common/editor.js';
33
import { EditorInput } from '../../common/editor/editorInput.js';
34
import { IActivity, IActivityService } from '../../services/activity/common/activity.js';
35
import { ChatEntitlement, IChatEntitlementService } from '../../services/chat/common/chatEntitlementService.js';
36
import { NullExtensionService } from '../../services/extensions/common/extensions.js';
37
import { IAutoSaveConfiguration, IAutoSaveMode, IFilesConfigurationService } from '../../services/filesConfiguration/common/filesConfigurationService.js';
38
import { IHistoryService } from '../../services/history/common/history.js';
39
import { BeforeShutdownErrorEvent, ILifecycleService, InternalBeforeShutdownEvent, LifecyclePhase, ShutdownReason, StartupKind, WillShutdownEvent } from '../../services/lifecycle/common/lifecycle.js';
40
import { IResourceEncoding } from '../../services/textfile/common/textfiles.js';
41
import { IUserDataProfileService } from '../../services/userDataProfile/common/userDataProfile.js';
42
import { IStoredFileWorkingCopySaveEvent } from '../../services/workingCopy/common/storedFileWorkingCopy.js';
43
import { IWorkingCopy, IWorkingCopyBackup, WorkingCopyCapabilities } from '../../services/workingCopy/common/workingCopy.js';
44
import { ICopyOperation, ICreateFileOperation, ICreateOperation, IDeleteOperation, IFileOperationUndoRedoInfo, IMoveOperation, IStoredFileWorkingCopySaveParticipant, IStoredFileWorkingCopySaveParticipantContext, IWorkingCopyFileOperationParticipant, IWorkingCopyFileService, WorkingCopyFileEvent } from '../../services/workingCopy/common/workingCopyFileService.js';
45
46
export class TestLoggerService extends AbstractLoggerService {
47
constructor(logsHome?: URI) {
48
super(LogLevel.Info, logsHome ?? URI.file('tests').with({ scheme: 'vscode-tests' }));
49
}
50
protected doCreateLogger(): ILogger { return new NullLogger(); }
51
}
52
53
export class TestTextResourcePropertiesService implements ITextResourcePropertiesService {
54
55
declare readonly _serviceBrand: undefined;
56
57
constructor(
58
@IConfigurationService private readonly configurationService: IConfigurationService,
59
) {
60
}
61
62
getEOL(resource: URI, language?: string): string {
63
const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource });
64
if (eol && typeof eol === 'string' && eol !== 'auto') {
65
return eol;
66
}
67
return (isLinux || isMacintosh) ? '\n' : '\r\n';
68
}
69
}
70
71
export class TestUserDataProfileService implements IUserDataProfileService {
72
73
readonly _serviceBrand: undefined;
74
readonly onDidChangeCurrentProfile = Event.None;
75
readonly currentProfile = toUserDataProfile('test', 'test', URI.file('tests').with({ scheme: 'vscode-tests' }), URI.file('tests').with({ scheme: 'vscode-tests' }));
76
async updateCurrentProfile(): Promise<void> { }
77
}
78
79
export class TestContextService implements IWorkspaceContextService {
80
81
declare readonly _serviceBrand: undefined;
82
83
private workspace: Workspace;
84
private options: object;
85
86
private readonly _onDidChangeWorkspaceName: Emitter<void>;
87
get onDidChangeWorkspaceName(): Event<void> { return this._onDidChangeWorkspaceName.event; }
88
89
private readonly _onWillChangeWorkspaceFolders: Emitter<IWorkspaceFoldersWillChangeEvent>;
90
get onWillChangeWorkspaceFolders(): Event<IWorkspaceFoldersWillChangeEvent> { return this._onWillChangeWorkspaceFolders.event; }
91
92
private readonly _onDidChangeWorkspaceFolders: Emitter<IWorkspaceFoldersChangeEvent>;
93
get onDidChangeWorkspaceFolders(): Event<IWorkspaceFoldersChangeEvent> { return this._onDidChangeWorkspaceFolders.event; }
94
95
private readonly _onDidChangeWorkbenchState: Emitter<WorkbenchState>;
96
get onDidChangeWorkbenchState(): Event<WorkbenchState> { return this._onDidChangeWorkbenchState.event; }
97
98
constructor(workspace = TestWorkspace, options = null) {
99
this.workspace = workspace;
100
this.options = options || Object.create(null);
101
this._onDidChangeWorkspaceName = new Emitter<void>();
102
this._onWillChangeWorkspaceFolders = new Emitter<IWorkspaceFoldersWillChangeEvent>();
103
this._onDidChangeWorkspaceFolders = new Emitter<IWorkspaceFoldersChangeEvent>();
104
this._onDidChangeWorkbenchState = new Emitter<WorkbenchState>();
105
}
106
107
getFolders(): IWorkspaceFolder[] {
108
return this.workspace ? this.workspace.folders : [];
109
}
110
111
getWorkbenchState(): WorkbenchState {
112
if (this.workspace.configuration) {
113
return WorkbenchState.WORKSPACE;
114
}
115
116
if (this.workspace.folders.length) {
117
return WorkbenchState.FOLDER;
118
}
119
120
return WorkbenchState.EMPTY;
121
}
122
123
getCompleteWorkspace(): Promise<IWorkspace> {
124
return Promise.resolve(this.getWorkspace());
125
}
126
127
getWorkspace(): IWorkspace {
128
return this.workspace;
129
}
130
131
getWorkspaceFolder(resource: URI): IWorkspaceFolder | null {
132
return this.workspace.getFolder(resource);
133
}
134
135
setWorkspace(workspace: any): void {
136
this.workspace = workspace;
137
}
138
139
getOptions() {
140
return this.options;
141
}
142
143
updateOptions() { }
144
145
isInsideWorkspace(resource: URI): boolean {
146
if (resource && this.workspace) {
147
return isEqualOrParent(resource, this.workspace.folders[0].uri);
148
}
149
150
return false;
151
}
152
153
toResource(workspaceRelativePath: string): URI {
154
return URI.file(join('C:\\', workspaceRelativePath));
155
}
156
157
isCurrentWorkspace(workspaceIdOrFolder: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI): boolean {
158
return URI.isUri(workspaceIdOrFolder) && isEqual(this.workspace.folders[0].uri, workspaceIdOrFolder);
159
}
160
}
161
162
export class TestStorageService extends InMemoryStorageService {
163
164
testEmitWillSaveState(reason: WillSaveStateReason): void {
165
super.emitWillSaveState(reason);
166
}
167
}
168
169
export class TestHistoryService implements IHistoryService {
170
171
declare readonly _serviceBrand: undefined;
172
173
constructor(private root?: URI) { }
174
175
async reopenLastClosedEditor(): Promise<void> { }
176
async goForward(): Promise<void> { }
177
async goBack(): Promise<void> { }
178
async goPrevious(): Promise<void> { }
179
async goLast(): Promise<void> { }
180
removeFromHistory(_input: EditorInput | IResourceEditorInput): void { }
181
clear(): void { }
182
clearRecentlyOpened(): void { }
183
getHistory(): readonly (EditorInput | IResourceEditorInput)[] { return []; }
184
async openNextRecentlyUsedEditor(group?: GroupIdentifier): Promise<void> { }
185
async openPreviouslyUsedEditor(group?: GroupIdentifier): Promise<void> { }
186
getLastActiveWorkspaceRoot(_schemeFilter: string): URI | undefined { return this.root; }
187
getLastActiveFile(_schemeFilter: string): URI | undefined { return undefined; }
188
}
189
190
export class TestWorkingCopy extends Disposable implements IWorkingCopy {
191
192
private readonly _onDidChangeDirty = this._register(new Emitter<void>());
193
readonly onDidChangeDirty = this._onDidChangeDirty.event;
194
195
private readonly _onDidChangeContent = this._register(new Emitter<void>());
196
readonly onDidChangeContent = this._onDidChangeContent.event;
197
198
private readonly _onDidSave = this._register(new Emitter<IStoredFileWorkingCopySaveEvent>());
199
readonly onDidSave = this._onDidSave.event;
200
201
readonly capabilities = WorkingCopyCapabilities.None;
202
203
readonly name;
204
205
private dirty = false;
206
207
constructor(readonly resource: URI, isDirty = false, readonly typeId = 'testWorkingCopyType') {
208
super();
209
210
this.name = basename(this.resource);
211
this.dirty = isDirty;
212
}
213
214
setDirty(dirty: boolean): void {
215
if (this.dirty !== dirty) {
216
this.dirty = dirty;
217
this._onDidChangeDirty.fire();
218
}
219
}
220
221
setContent(content: string): void {
222
this._onDidChangeContent.fire();
223
}
224
225
isDirty(): boolean {
226
return this.dirty;
227
}
228
229
isModified(): boolean {
230
return this.isDirty();
231
}
232
233
async save(options?: ISaveOptions, stat?: IFileStatWithMetadata): Promise<boolean> {
234
this._onDidSave.fire({ reason: options?.reason ?? SaveReason.EXPLICIT, stat: stat ?? createFileStat(this.resource), source: options?.source });
235
236
return true;
237
}
238
239
async revert(options?: IRevertOptions): Promise<void> {
240
this.setDirty(false);
241
}
242
243
async backup(token: CancellationToken): Promise<IWorkingCopyBackup> {
244
return {};
245
}
246
}
247
248
export function createFileStat(resource: URI, readonly = false, isFile?: boolean, isDirectory?: boolean, isSymbolicLink?: boolean, children?: { resource: URI; isFile?: boolean; isDirectory?: boolean; isSymbolicLink?: boolean; executable?: boolean }[] | undefined, executable?: boolean): IFileStatWithMetadata {
249
return {
250
resource,
251
etag: Date.now().toString(),
252
mtime: Date.now(),
253
ctime: Date.now(),
254
size: 42,
255
isFile: isFile ?? true,
256
isDirectory: isDirectory ?? false,
257
isSymbolicLink: isSymbolicLink ?? false,
258
readonly,
259
locked: false,
260
executable: executable ?? false,
261
name: basename(resource),
262
children: children?.map(c => createFileStat(c.resource, false, c.isFile, c.isDirectory, c.isSymbolicLink, undefined, c.executable)),
263
};
264
}
265
266
export class TestWorkingCopyFileService implements IWorkingCopyFileService {
267
268
declare readonly _serviceBrand: undefined;
269
270
readonly onWillRunWorkingCopyFileOperation: Event<WorkingCopyFileEvent> = Event.None;
271
readonly onDidFailWorkingCopyFileOperation: Event<WorkingCopyFileEvent> = Event.None;
272
readonly onDidRunWorkingCopyFileOperation: Event<WorkingCopyFileEvent> = Event.None;
273
274
addFileOperationParticipant(participant: IWorkingCopyFileOperationParticipant): IDisposable { return Disposable.None; }
275
276
readonly hasSaveParticipants = false;
277
addSaveParticipant(participant: IStoredFileWorkingCopySaveParticipant): IDisposable { return Disposable.None; }
278
async runSaveParticipants(workingCopy: IWorkingCopy, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> { }
279
280
async delete(operations: IDeleteOperation[], token: CancellationToken, undoInfo?: IFileOperationUndoRedoInfo): Promise<void> { }
281
282
registerWorkingCopyProvider(provider: (resourceOrFolder: URI) => IWorkingCopy[]): IDisposable { return Disposable.None; }
283
284
getDirty(resource: URI): IWorkingCopy[] { return []; }
285
286
create(operations: ICreateFileOperation[], token: CancellationToken, undoInfo?: IFileOperationUndoRedoInfo): Promise<IFileStatWithMetadata[]> { throw new Error('Method not implemented.'); }
287
createFolder(operations: ICreateOperation[], token: CancellationToken, undoInfo?: IFileOperationUndoRedoInfo): Promise<IFileStatWithMetadata[]> { throw new Error('Method not implemented.'); }
288
289
move(operations: IMoveOperation[], token: CancellationToken, undoInfo?: IFileOperationUndoRedoInfo): Promise<IFileStatWithMetadata[]> { throw new Error('Method not implemented.'); }
290
291
copy(operations: ICopyOperation[], token: CancellationToken, undoInfo?: IFileOperationUndoRedoInfo): Promise<IFileStatWithMetadata[]> { throw new Error('Method not implemented.'); }
292
}
293
294
export function mock<T>(): Ctor<T> {
295
// eslint-disable-next-line local/code-no-any-casts
296
return function () { } as any;
297
}
298
299
export interface Ctor<T> {
300
new(): T;
301
}
302
303
export class TestExtensionService extends NullExtensionService { }
304
305
export const TestProductService = { _serviceBrand: undefined, ...product };
306
307
export class TestActivityService implements IActivityService {
308
_serviceBrand: undefined;
309
onDidChangeActivity = Event.None;
310
getViewContainerActivities(viewContainerId: string): IActivity[] {
311
return [];
312
}
313
getActivity(id: string): IActivity[] {
314
return [];
315
}
316
showViewContainerActivity(viewContainerId: string, badge: IActivity): IDisposable {
317
return this;
318
}
319
showViewActivity(viewId: string, badge: IActivity): IDisposable {
320
return this;
321
}
322
showAccountsActivity(activity: IActivity): IDisposable {
323
return this;
324
}
325
showGlobalActivity(activity: IActivity): IDisposable {
326
return this;
327
}
328
329
dispose() { }
330
}
331
332
export const NullFilesConfigurationService = new class implements IFilesConfigurationService {
333
334
_serviceBrand: undefined;
335
336
readonly onDidChangeAutoSaveConfiguration = Event.None;
337
readonly onDidChangeAutoSaveDisabled = Event.None;
338
readonly onDidChangeReadonly = Event.None;
339
readonly onDidChangeFilesAssociation = Event.None;
340
341
readonly isHotExitEnabled = false;
342
readonly hotExitConfiguration = undefined;
343
344
getAutoSaveConfiguration(): IAutoSaveConfiguration { throw new Error('Method not implemented.'); }
345
getAutoSaveMode(): IAutoSaveMode { throw new Error('Method not implemented.'); }
346
hasShortAutoSaveDelay(): boolean { throw new Error('Method not implemented.'); }
347
toggleAutoSave(): Promise<void> { throw new Error('Method not implemented.'); }
348
enableAutoSaveAfterShortDelay(resourceOrEditor: URI | EditorInput): IDisposable { throw new Error('Method not implemented.'); }
349
disableAutoSave(resourceOrEditor: URI | EditorInput): IDisposable { throw new Error('Method not implemented.'); }
350
isReadonly(resource: URI, stat?: IBaseFileStat | undefined): boolean { return false; }
351
async updateReadonly(resource: URI, readonly: boolean | 'toggle' | 'reset'): Promise<void> { }
352
preventSaveConflicts(resource: URI, language?: string | undefined): boolean { throw new Error('Method not implemented.'); }
353
};
354
355
export class TestWorkspaceTrustEnablementService implements IWorkspaceTrustEnablementService {
356
_serviceBrand: undefined;
357
358
constructor(private isEnabled: boolean = true) { }
359
360
isWorkspaceTrustEnabled(): boolean {
361
return this.isEnabled;
362
}
363
}
364
365
export class TestWorkspaceTrustManagementService extends Disposable implements IWorkspaceTrustManagementService {
366
_serviceBrand: undefined;
367
368
private _onDidChangeTrust = this._register(new Emitter<boolean>());
369
onDidChangeTrust = this._onDidChangeTrust.event;
370
371
private _onDidChangeTrustedFolders = this._register(new Emitter<void>());
372
onDidChangeTrustedFolders = this._onDidChangeTrustedFolders.event;
373
374
private _onDidInitiateWorkspaceTrustRequestOnStartup = this._register(new Emitter<void>());
375
onDidInitiateWorkspaceTrustRequestOnStartup = this._onDidInitiateWorkspaceTrustRequestOnStartup.event;
376
377
378
constructor(
379
private trusted: boolean = true
380
) {
381
super();
382
}
383
384
get acceptsOutOfWorkspaceFiles(): boolean {
385
throw new Error('Method not implemented.');
386
}
387
388
set acceptsOutOfWorkspaceFiles(value: boolean) {
389
throw new Error('Method not implemented.');
390
}
391
392
addWorkspaceTrustTransitionParticipant(participant: IWorkspaceTrustTransitionParticipant): IDisposable {
393
throw new Error('Method not implemented.');
394
}
395
396
getTrustedUris(): URI[] {
397
throw new Error('Method not implemented.');
398
}
399
400
setParentFolderTrust(trusted: boolean): Promise<void> {
401
throw new Error('Method not implemented.');
402
}
403
404
getUriTrustInfo(uri: URI): Promise<IWorkspaceTrustUriInfo> {
405
throw new Error('Method not implemented.');
406
}
407
408
async setTrustedUris(folders: URI[]): Promise<void> {
409
throw new Error('Method not implemented.');
410
}
411
412
async setUrisTrust(uris: URI[], trusted: boolean): Promise<void> {
413
throw new Error('Method not implemented.');
414
}
415
416
canSetParentFolderTrust(): boolean {
417
throw new Error('Method not implemented.');
418
}
419
420
canSetWorkspaceTrust(): boolean {
421
throw new Error('Method not implemented.');
422
}
423
424
isWorkspaceTrusted(): boolean {
425
return this.trusted;
426
}
427
428
isWorkspaceTrustForced(): boolean {
429
return false;
430
}
431
432
get workspaceTrustInitialized(): Promise<void> {
433
return Promise.resolve();
434
}
435
436
get workspaceResolved(): Promise<void> {
437
return Promise.resolve();
438
}
439
440
async setWorkspaceTrust(trusted: boolean): Promise<void> {
441
if (this.trusted !== trusted) {
442
this.trusted = trusted;
443
this._onDidChangeTrust.fire(this.trusted);
444
}
445
}
446
}
447
448
export class TestWorkspaceTrustRequestService extends Disposable implements IWorkspaceTrustRequestService {
449
_serviceBrand: any;
450
451
private readonly _onDidInitiateOpenFilesTrustRequest = this._register(new Emitter<void>());
452
readonly onDidInitiateOpenFilesTrustRequest = this._onDidInitiateOpenFilesTrustRequest.event;
453
454
private readonly _onDidInitiateResourcesTrustRequest = this._register(new Emitter<ResourceTrustRequestOptions>());
455
readonly onDidInitiateResourcesTrustRequest = this._onDidInitiateResourcesTrustRequest.event;
456
457
private readonly _onDidInitiateWorkspaceTrustRequest = this._register(new Emitter<WorkspaceTrustRequestOptions>());
458
readonly onDidInitiateWorkspaceTrustRequest = this._onDidInitiateWorkspaceTrustRequest.event;
459
460
private readonly _onDidInitiateWorkspaceTrustRequestOnStartup = this._register(new Emitter<void>());
461
readonly onDidInitiateWorkspaceTrustRequestOnStartup = this._onDidInitiateWorkspaceTrustRequestOnStartup.event;
462
463
constructor(private readonly _trusted: boolean) {
464
super();
465
}
466
467
requestOpenUrisHandler = async (uris: URI[]) => {
468
return WorkspaceTrustUriResponse.Open;
469
};
470
471
requestOpenFilesTrust(uris: URI[]): Promise<WorkspaceTrustUriResponse> {
472
return this.requestOpenUrisHandler(uris);
473
}
474
475
async completeOpenFilesTrustRequest(result: WorkspaceTrustUriResponse, saveResponse: boolean): Promise<void> {
476
throw new Error('Method not implemented.');
477
}
478
479
async completeResourcesTrustRequest(uri: URI, result: WorkspaceTrustUriResponse): Promise<void> {
480
throw new Error('Method not implemented.');
481
}
482
483
async requestResourcesTrust(options: ResourceTrustRequestOptions): Promise<boolean | undefined> {
484
return this._trusted;
485
}
486
487
cancelWorkspaceTrustRequest(): void {
488
throw new Error('Method not implemented.');
489
}
490
491
async completeWorkspaceTrustRequest(trusted?: boolean): Promise<void> {
492
throw new Error('Method not implemented.');
493
}
494
495
async requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise<boolean> {
496
return this._trusted;
497
}
498
499
requestWorkspaceTrustOnStartup(): void {
500
throw new Error('Method not implemented.');
501
}
502
}
503
504
export class TestMarkerService implements IMarkerService {
505
506
_serviceBrand: undefined;
507
508
onMarkerChanged = Event.None;
509
510
getStatistics(): MarkerStatistics { throw new Error('Method not implemented.'); }
511
changeOne(owner: string, resource: URI, markers: IMarkerData[]): void { }
512
changeAll(owner: string, data: IResourceMarker[]): void { }
513
remove(owner: string, resources: URI[]): void { }
514
read(filter?: { owner?: string | undefined; resource?: URI | undefined; severities?: number | undefined; take?: number | undefined } | undefined): IMarker[] { return []; }
515
installResourceFilter(resource: URI, reason: string): IDisposable {
516
return { dispose: () => { /* TODO: Implement cleanup logic */ } };
517
}
518
}
519
520
export class TestFileService implements IFileService {
521
522
declare readonly _serviceBrand: undefined;
523
524
private readonly _onDidFilesChange = new Emitter<FileChangesEvent>();
525
get onDidFilesChange(): Event<FileChangesEvent> { return this._onDidFilesChange.event; }
526
fireFileChanges(event: FileChangesEvent): void { this._onDidFilesChange.fire(event); }
527
528
private readonly _onDidRunOperation = new Emitter<FileOperationEvent>();
529
get onDidRunOperation(): Event<FileOperationEvent> { return this._onDidRunOperation.event; }
530
fireAfterOperation(event: FileOperationEvent): void { this._onDidRunOperation.fire(event); }
531
532
private readonly _onDidChangeFileSystemProviderCapabilities = new Emitter<IFileSystemProviderCapabilitiesChangeEvent>();
533
get onDidChangeFileSystemProviderCapabilities(): Event<IFileSystemProviderCapabilitiesChangeEvent> { return this._onDidChangeFileSystemProviderCapabilities.event; }
534
fireFileSystemProviderCapabilitiesChangeEvent(event: IFileSystemProviderCapabilitiesChangeEvent): void { this._onDidChangeFileSystemProviderCapabilities.fire(event); }
535
536
private _onWillActivateFileSystemProvider = new Emitter<IFileSystemProviderActivationEvent>();
537
readonly onWillActivateFileSystemProvider = this._onWillActivateFileSystemProvider.event;
538
readonly onDidWatchError = Event.None;
539
540
protected content = 'Hello Html';
541
protected lastReadFileUri!: URI;
542
543
readonly = false;
544
545
// Tracking functionality for tests
546
readonly writeOperations: Array<{ resource: URI; content: string }> = [];
547
readonly readOperations: Array<{ resource: URI }> = [];
548
549
setContent(content: string): void { this.content = content; }
550
getContent(): string { return this.content; }
551
getLastReadFileUri(): URI { return this.lastReadFileUri; }
552
553
// Clear tracking data for tests
554
clearTracking(): void {
555
this.writeOperations.length = 0;
556
this.readOperations.length = 0;
557
}
558
559
resolve(resource: URI, _options: IResolveMetadataFileOptions): Promise<IFileStatWithMetadata>;
560
resolve(resource: URI, _options?: IResolveFileOptions): Promise<IFileStat>;
561
async resolve(resource: URI, _options?: IResolveFileOptions): Promise<IFileStat> {
562
return createFileStat(resource, this.readonly);
563
}
564
565
stat(resource: URI): Promise<IFileStatWithPartialMetadata> {
566
return this.resolve(resource, { resolveMetadata: true });
567
}
568
569
async realpath(resource: URI): Promise<URI> {
570
return resource;
571
}
572
573
async resolveAll(toResolve: { resource: URI; options?: IResolveFileOptions }[]): Promise<IFileStatResult[]> {
574
const stats = await Promise.all(toResolve.map(resourceAndOption => this.resolve(resourceAndOption.resource, resourceAndOption.options)));
575
576
return stats.map(stat => ({ stat, success: true }));
577
}
578
579
readonly notExistsSet = new ResourceMap<boolean>();
580
581
async exists(_resource: URI): Promise<boolean> { return !this.notExistsSet.has(_resource); }
582
583
readShouldThrowError: Error | undefined = undefined;
584
585
async readFile(resource: URI, options?: IReadFileOptions | undefined): Promise<IFileContent> {
586
if (this.readShouldThrowError) {
587
throw this.readShouldThrowError;
588
}
589
590
this.lastReadFileUri = resource;
591
this.readOperations.push({ resource });
592
593
return {
594
...createFileStat(resource, this.readonly),
595
value: VSBuffer.fromString(this.content)
596
};
597
}
598
599
async readFileStream(resource: URI, options?: IReadFileStreamOptions | undefined): Promise<IFileStreamContent> {
600
if (this.readShouldThrowError) {
601
throw this.readShouldThrowError;
602
}
603
604
this.lastReadFileUri = resource;
605
606
return {
607
...createFileStat(resource, this.readonly),
608
value: bufferToStream(VSBuffer.fromString(this.content))
609
};
610
}
611
612
writeShouldThrowError: Error | undefined = undefined;
613
614
async writeFile(resource: URI, bufferOrReadable: VSBuffer | VSBufferReadable, options?: IWriteFileOptions): Promise<IFileStatWithMetadata> {
615
await timeout(0);
616
617
if (this.writeShouldThrowError) {
618
throw this.writeShouldThrowError;
619
}
620
621
let content: VSBuffer | undefined;
622
if (bufferOrReadable instanceof VSBuffer) {
623
content = bufferOrReadable;
624
} else {
625
try {
626
content = readableToBuffer(bufferOrReadable);
627
} catch {
628
// Some preexisting tests are writing with invalid objects
629
}
630
}
631
632
if (content) {
633
this.writeOperations.push({ resource, content: content.toString() });
634
}
635
636
return createFileStat(resource, this.readonly);
637
}
638
639
move(_source: URI, _target: URI, _overwrite?: boolean): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); }
640
copy(_source: URI, _target: URI, _overwrite?: boolean): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); }
641
async cloneFile(_source: URI, _target: URI): Promise<void> { }
642
createFile(_resource: URI, _content?: VSBuffer | VSBufferReadable, _options?: ICreateFileOptions): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); }
643
createFolder(_resource: URI): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); }
644
645
onDidChangeFileSystemProviderRegistrations = Event.None;
646
647
private providers = new Map<string, IFileSystemProvider>();
648
649
registerProvider(scheme: string, provider: IFileSystemProvider) {
650
this.providers.set(scheme, provider);
651
652
return toDisposable(() => this.providers.delete(scheme));
653
}
654
655
getProvider(scheme: string) {
656
return this.providers.get(scheme);
657
}
658
659
async activateProvider(_scheme: string): Promise<void> {
660
this._onWillActivateFileSystemProvider.fire({ scheme: _scheme, join: () => { } });
661
}
662
async canHandleResource(resource: URI): Promise<boolean> { return this.hasProvider(resource); }
663
hasProvider(resource: URI): boolean { return resource.scheme === Schemas.file || this.providers.has(resource.scheme); }
664
listCapabilities() {
665
return [
666
{ scheme: Schemas.file, capabilities: FileSystemProviderCapabilities.FileOpenReadWriteClose },
667
...Iterable.map(this.providers, ([scheme, p]) => { return { scheme, capabilities: p.capabilities }; })
668
];
669
}
670
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean {
671
if (capability === FileSystemProviderCapabilities.PathCaseSensitive && isLinux) {
672
return true;
673
}
674
675
const provider = this.getProvider(resource.scheme);
676
677
return !!(provider && (provider.capabilities & capability));
678
}
679
680
async del(_resource: URI, _options?: { useTrash?: boolean; recursive?: boolean }): Promise<void> { }
681
682
createWatcher(resource: URI, options: IWatchOptions): IFileSystemWatcher {
683
return {
684
onDidChange: Event.None,
685
dispose: () => { }
686
};
687
}
688
689
690
readonly watches: URI[] = [];
691
watch(_resource: URI, options: IWatchOptionsWithCorrelation): IFileSystemWatcher;
692
watch(_resource: URI): IDisposable;
693
watch(_resource: URI): IDisposable {
694
this.watches.push(_resource);
695
696
return toDisposable(() => this.watches.splice(this.watches.indexOf(_resource), 1));
697
}
698
699
getWriteEncoding(_resource: URI): IResourceEncoding { return { encoding: 'utf8', hasBOM: false }; }
700
dispose(): void { }
701
702
async canCreateFile(source: URI, options?: ICreateFileOptions): Promise<Error | true> { return true; }
703
async canMove(source: URI, target: URI, overwrite?: boolean | undefined): Promise<Error | true> { return true; }
704
async canCopy(source: URI, target: URI, overwrite?: boolean | undefined): Promise<Error | true> { return true; }
705
async canDelete(resource: URI, options?: { useTrash?: boolean | undefined; recursive?: boolean | undefined } | undefined): Promise<Error | true> { return true; }
706
}
707
708
/**
709
* TestFileService with in-memory file storage.
710
* Use this when your test needs to write files and read them back.
711
*/
712
export class InMemoryTestFileService extends TestFileService {
713
714
private files = new ResourceMap<VSBuffer>();
715
716
override clearTracking(): void {
717
super.clearTracking();
718
this.files.clear();
719
}
720
721
override async readFile(resource: URI, options?: IReadFileOptions | undefined): Promise<IFileContent> {
722
if (this.readShouldThrowError) {
723
throw this.readShouldThrowError;
724
}
725
726
this.lastReadFileUri = resource;
727
this.readOperations.push({ resource });
728
729
// Check if we have content in our in-memory store
730
const content = this.files.get(resource);
731
if (content) {
732
return {
733
...createFileStat(resource, this.readonly),
734
value: content
735
};
736
}
737
738
return {
739
...createFileStat(resource, this.readonly),
740
value: VSBuffer.fromString(this.content)
741
};
742
}
743
744
override async writeFile(resource: URI, bufferOrReadable: VSBuffer | VSBufferReadable, options?: IWriteFileOptions): Promise<IFileStatWithMetadata> {
745
await timeout(0);
746
747
if (this.writeShouldThrowError) {
748
throw this.writeShouldThrowError;
749
}
750
751
let content: VSBuffer;
752
if (bufferOrReadable instanceof VSBuffer) {
753
content = bufferOrReadable;
754
} else {
755
content = readableToBuffer(bufferOrReadable);
756
}
757
758
// Store in memory and track
759
this.files.set(resource, content);
760
this.writeOperations.push({ resource, content: content.toString() });
761
762
return createFileStat(resource, this.readonly);
763
}
764
765
override async del(resource: URI, _options?: { useTrash?: boolean; recursive?: boolean }): Promise<void> {
766
this.files.delete(resource);
767
this.notExistsSet.set(resource, true);
768
}
769
770
override async exists(resource: URI): Promise<boolean> {
771
const inMemory = this.files.has(resource);
772
if (inMemory) {
773
return true;
774
}
775
776
return super.exists(resource);
777
}
778
}
779
780
export class TestChatEntitlementService implements IChatEntitlementService {
781
782
_serviceBrand: undefined;
783
784
readonly organisations: undefined;
785
readonly isInternal = false;
786
readonly sku = undefined;
787
readonly copilotTrackingId = undefined;
788
789
readonly onDidChangeQuotaExceeded = Event.None;
790
readonly onDidChangeQuotaRemaining = Event.None;
791
readonly quotas = {};
792
793
update(token: CancellationToken): Promise<void> {
794
throw new Error('Method not implemented.');
795
}
796
797
readonly onDidChangeSentiment = Event.None;
798
readonly sentimentObs = observableValue({}, {});
799
readonly sentiment = {};
800
801
readonly onDidChangeEntitlement = Event.None;
802
entitlement: ChatEntitlement = ChatEntitlement.Unknown;
803
readonly entitlementObs = observableValue({}, ChatEntitlement.Unknown);
804
805
readonly anonymous = false;
806
onDidChangeAnonymous = Event.None;
807
readonly anonymousObs = observableValue({}, false);
808
809
readonly previewFeaturesDisabled = false;
810
}
811
812
export class TestLifecycleService extends Disposable implements ILifecycleService {
813
814
declare readonly _serviceBrand: undefined;
815
816
usePhases = false;
817
_phase!: LifecyclePhase;
818
get phase(): LifecyclePhase { return this._phase; }
819
set phase(value: LifecyclePhase) {
820
this._phase = value;
821
if (value === LifecyclePhase.Starting) {
822
this.whenStarted.complete();
823
} else if (value === LifecyclePhase.Ready) {
824
this.whenReady.complete();
825
} else if (value === LifecyclePhase.Restored) {
826
this.whenRestored.complete();
827
} else if (value === LifecyclePhase.Eventually) {
828
this.whenEventually.complete();
829
}
830
}
831
832
private readonly whenStarted = new DeferredPromise<void>();
833
private readonly whenReady = new DeferredPromise<void>();
834
private readonly whenRestored = new DeferredPromise<void>();
835
private readonly whenEventually = new DeferredPromise<void>();
836
async when(phase: LifecyclePhase): Promise<void> {
837
if (!this.usePhases) {
838
return;
839
}
840
if (phase === LifecyclePhase.Starting) {
841
await this.whenStarted.p;
842
} else if (phase === LifecyclePhase.Ready) {
843
await this.whenReady.p;
844
} else if (phase === LifecyclePhase.Restored) {
845
await this.whenRestored.p;
846
} else if (phase === LifecyclePhase.Eventually) {
847
await this.whenEventually.p;
848
}
849
}
850
851
startupKind!: StartupKind;
852
willShutdown = false;
853
854
private readonly _onBeforeShutdown = this._register(new Emitter<InternalBeforeShutdownEvent>());
855
get onBeforeShutdown(): Event<InternalBeforeShutdownEvent> { return this._onBeforeShutdown.event; }
856
857
private readonly _onBeforeShutdownError = this._register(new Emitter<BeforeShutdownErrorEvent>());
858
get onBeforeShutdownError(): Event<BeforeShutdownErrorEvent> { return this._onBeforeShutdownError.event; }
859
860
private readonly _onShutdownVeto = this._register(new Emitter<void>());
861
get onShutdownVeto(): Event<void> { return this._onShutdownVeto.event; }
862
863
private readonly _onWillShutdown = this._register(new Emitter<WillShutdownEvent>());
864
get onWillShutdown(): Event<WillShutdownEvent> { return this._onWillShutdown.event; }
865
866
private readonly _onDidShutdown = this._register(new Emitter<void>());
867
get onDidShutdown(): Event<void> { return this._onDidShutdown.event; }
868
869
shutdownJoiners: Promise<void>[] = [];
870
871
fireShutdown(reason = ShutdownReason.QUIT): void {
872
this.shutdownJoiners = [];
873
874
this._onWillShutdown.fire({
875
join: p => {
876
this.shutdownJoiners.push(typeof p === 'function' ? p() : p);
877
},
878
joiners: () => [],
879
force: () => { /* No-Op in tests */ },
880
token: CancellationToken.None,
881
reason
882
});
883
}
884
885
fireBeforeShutdown(event: InternalBeforeShutdownEvent): void { this._onBeforeShutdown.fire(event); }
886
887
fireWillShutdown(event: WillShutdownEvent): void { this._onWillShutdown.fire(event); }
888
889
async shutdown(): Promise<void> {
890
this.fireShutdown();
891
}
892
}
893
894