Skip to content

Commit ccb4f74

Browse files
authored
Merge pull request microsoft#128390 from microsoft/hediet/fix-inline-completion-tests
Implements custom time travel scheduler that provides more debug information.
2 parents d9b1bd4 + 6769b6b commit ccb4f74

File tree

3 files changed

+457
-86
lines changed

3 files changed

+457
-86
lines changed

src/vs/editor/contrib/inlineCompletions/test/inlineCompletionsProvider.test.ts

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { InlineCompletionsModel, inlineCompletionToGhostText } from 'vs/editor/c
1313
import { GhostTextContext, MockInlineCompletionsProvider } from 'vs/editor/contrib/inlineCompletions/test/utils';
1414
import { ITestCodeEditor, TestCodeEditorCreationOptions, withAsyncTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
1515
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
16-
import sinon = require('sinon');
1716
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
17+
import { runWithFakedTimers } from 'vs/editor/contrib/inlineCompletions/test/timeTravelScheduler';
1818

1919
suite('Inline Completions', () => {
2020
ensureNoDisposablesAreLeakedInTestSuite();
@@ -488,41 +488,38 @@ suite('Inline Completions', () => {
488488
});
489489
});
490490

491-
async function withAsyncTestCodeEditorAndInlineCompletionsModel(
491+
async function withAsyncTestCodeEditorAndInlineCompletionsModel<T>(
492492
text: string,
493493
options: TestCodeEditorCreationOptions & { provider?: InlineCompletionsProvider, fakeClock?: boolean },
494-
callback: (args: { editor: ITestCodeEditor, editorViewModel: ViewModel, model: InlineCompletionsModel, context: GhostTextContext }) => Promise<void>
495-
): Promise<void> {
496-
const disposableStore = new DisposableStore();
497-
498-
if (options.provider) {
499-
const d = InlineCompletionsProviderRegistry.register({ pattern: '**' }, options.provider);
500-
disposableStore.add(d);
501-
}
502-
503-
let clock: sinon.SinonFakeTimers | undefined;
504-
if (options.fakeClock) {
505-
clock = sinon.useFakeTimers();
506-
}
507-
try {
508-
const p = withAsyncTestCodeEditor(text, options, async (editor, editorViewModel, instantiationService) => {
509-
const model = instantiationService.createInstance(InlineCompletionsModel, editor);
510-
const context = new GhostTextContext(model, editor);
511-
await callback({ editor, editorViewModel, model, context });
512-
context.dispose();
513-
model.dispose();
514-
});
494+
callback: (args: { editor: ITestCodeEditor, editorViewModel: ViewModel, model: InlineCompletionsModel, context: GhostTextContext }) => Promise<T>
495+
): Promise<T> {
496+
return await runWithFakedTimers({
497+
useFakeTimers: options.fakeClock,
498+
}, async () => {
499+
const disposableStore = new DisposableStore();
500+
501+
try {
502+
if (options.provider) {
503+
const d = InlineCompletionsProviderRegistry.register({ pattern: '**' }, options.provider);
504+
disposableStore.add(d);
505+
}
515506

516-
const p2 = clock?.runAllAsync();
507+
let result: T;
508+
await withAsyncTestCodeEditor(text, options, async (editor, editorViewModel, instantiationService) => {
509+
const model = instantiationService.createInstance(InlineCompletionsModel, editor);
510+
const context = new GhostTextContext(model, editor);
511+
result = await callback({ editor, editorViewModel, model, context });
512+
context.dispose();
513+
model.dispose();
514+
});
517515

518-
await p;
519-
await p2;
516+
if (options.provider instanceof MockInlineCompletionsProvider) {
517+
options.provider.assertNotCalledTwiceWithin50ms();
518+
}
520519

521-
if (options.provider instanceof MockInlineCompletionsProvider) {
522-
options.provider.assertNotCalledTwiceWithin50ms();
520+
return result!;
521+
} finally {
522+
disposableStore.dispose();
523523
}
524-
} finally {
525-
clock?.restore();
526-
disposableStore.dispose();
527-
}
524+
});
528525
}

src/vs/editor/contrib/inlineCompletions/test/suggestWidgetModel.test.ts

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { ISuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory';
1717
import { IMenuService, IMenu } from 'vs/platform/actions/common/actions';
1818
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
1919
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
20-
import sinon = require('sinon');
2120
import { timeout } from 'vs/base/common/async';
2221
import { DisposableStore } from 'vs/base/common/lifecycle';
2322
import { CompletionItemKind, CompletionItemProvider, CompletionProviderRegistry } from 'vs/editor/common/modes';
@@ -27,9 +26,9 @@ import { Event } from 'vs/base/common/event';
2726
import assert = require('assert');
2827
import { GhostTextContext } from 'vs/editor/contrib/inlineCompletions/test/utils';
2928
import { Range } from 'vs/editor/common/core/range';
29+
import { runWithFakedTimers } from 'vs/editor/contrib/inlineCompletions/test/timeTravelScheduler';
3030

3131
suite('Suggest Widget Model', () => {
32-
3332
test('Active', async () => {
3433
await withAsyncTestCodeEditorAndInlineCompletionsModel('',
3534
{ fakeClock: true, provider, },
@@ -110,57 +109,49 @@ async function withAsyncTestCodeEditorAndInlineCompletionsModel(
110109
options: TestCodeEditorCreationOptions & { provider?: CompletionItemProvider, fakeClock?: boolean, serviceCollection?: never },
111110
callback: (args: { editor: ITestCodeEditor, editorViewModel: ViewModel, model: SuggestWidgetAdapterModel, context: GhostTextContext }) => Promise<void>
112111
): Promise<void> {
113-
const serviceCollection = new ServiceCollection(
114-
[ITelemetryService, NullTelemetryService],
115-
[ILogService, new NullLogService()],
116-
[IStorageService, new InMemoryStorageService()],
117-
[IKeybindingService, new MockKeybindingService()],
118-
[IEditorWorkerService, new class extends mock<IEditorWorkerService>() {
119-
override computeWordRanges() {
120-
return Promise.resolve({});
121-
}
122-
}],
123-
[ISuggestMemoryService, new class extends mock<ISuggestMemoryService>() {
124-
override memorize(): void { }
125-
override select(): number { return 0; }
126-
}],
127-
[IMenuService, new class extends mock<IMenuService>() {
128-
override createMenu() {
129-
return new class extends mock<IMenu>() {
130-
override onDidChange = Event.None;
131-
override dispose() { }
132-
};
112+
await runWithFakedTimers({ useFakeTimers: options.fakeClock }, async () => {
113+
const disposableStore = new DisposableStore();
114+
115+
try {
116+
const serviceCollection = new ServiceCollection(
117+
[ITelemetryService, NullTelemetryService],
118+
[ILogService, new NullLogService()],
119+
[IStorageService, new InMemoryStorageService()],
120+
[IKeybindingService, new MockKeybindingService()],
121+
[IEditorWorkerService, new class extends mock<IEditorWorkerService>() {
122+
override computeWordRanges() {
123+
return Promise.resolve({});
124+
}
125+
}],
126+
[ISuggestMemoryService, new class extends mock<ISuggestMemoryService>() {
127+
override memorize(): void { }
128+
override select(): number { return 0; }
129+
}],
130+
[IMenuService, new class extends mock<IMenuService>() {
131+
override createMenu() {
132+
return new class extends mock<IMenu>() {
133+
override onDidChange = Event.None;
134+
override dispose() { }
135+
};
136+
}
137+
}]
138+
);
139+
140+
if (options.provider) {
141+
const d = CompletionProviderRegistry.register({ pattern: '**' }, options.provider);
142+
disposableStore.add(d);
133143
}
134-
}]
135-
);
136-
137-
const disposableStore = new DisposableStore();
138-
139-
if (options.provider) {
140-
const d = CompletionProviderRegistry.register({ pattern: '**' }, options.provider);
141-
disposableStore.add(d);
142-
}
143-
144-
let clock: sinon.SinonFakeTimers | undefined;
145-
if (options.fakeClock) {
146-
clock = sinon.useFakeTimers();
147-
}
148-
try {
149-
const p = withAsyncTestCodeEditor(text, { ...options, serviceCollection }, async (editor, editorViewModel, instantiationService) => {
150-
editor.registerAndInstantiateContribution(SnippetController2.ID, SnippetController2);
151-
editor.registerAndInstantiateContribution(SuggestController.ID, SuggestController);
152-
const model = instantiationService.createInstance(SuggestWidgetAdapterModel, editor);
153-
const context = new GhostTextContext(model, editor);
154-
await callback({ editor, editorViewModel, model, context });
155-
model.dispose();
156-
});
157-
158-
const p2 = clock?.runAllAsync();
159-
160-
await p;
161-
await p2;
162-
} finally {
163-
clock?.restore();
164-
disposableStore.dispose();
165-
}
144+
145+
await withAsyncTestCodeEditor(text, { ...options, serviceCollection }, async (editor, editorViewModel, instantiationService) => {
146+
editor.registerAndInstantiateContribution(SnippetController2.ID, SnippetController2);
147+
editor.registerAndInstantiateContribution(SuggestController.ID, SuggestController);
148+
const model = instantiationService.createInstance(SuggestWidgetAdapterModel, editor);
149+
const context = new GhostTextContext(model, editor);
150+
await callback({ editor, editorViewModel, model, context });
151+
model.dispose();
152+
});
153+
} finally {
154+
disposableStore.dispose();
155+
}
156+
});
166157
}

0 commit comments

Comments
 (0)