Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/codeAction/test/browser/codeActionModel.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 assert from 'assert';
7
import { promiseWithResolvers } from '../../../../../base/common/async.js';
8
import { assertType } from '../../../../../base/common/types.js';
9
import { URI } from '../../../../../base/common/uri.js';
10
import { runWithFakedTimers } from '../../../../../base/test/common/timeTravelScheduler.js';
11
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
12
import { MockContextKeyService } from '../../../../../platform/keybinding/test/common/mockKeybindingService.js';
13
import { MarkerService } from '../../../../../platform/markers/common/markerService.js';
14
import { ICodeEditor } from '../../../../browser/editorBrowser.js';
15
import { LanguageFeatureRegistry } from '../../../../common/languageFeatureRegistry.js';
16
import * as languages from '../../../../common/languages.js';
17
import { TextModel } from '../../../../common/model/textModel.js';
18
import { createTestCodeEditor } from '../../../../test/browser/testCodeEditor.js';
19
import { createTextModel } from '../../../../test/common/testTextModel.js';
20
import { CodeActionModel, CodeActionsState } from '../../browser/codeActionModel.js';
21
22
const testProvider = {
23
provideCodeActions(): languages.CodeActionList {
24
return {
25
actions: [
26
{ title: 'test', command: { id: 'test-command', title: 'test', arguments: [] } }
27
],
28
dispose() { /* noop*/ }
29
};
30
}
31
};
32
33
suite('CodeActionModel', () => {
34
35
const languageId = 'foo-lang';
36
const uri = URI.parse('untitled:path');
37
let model: TextModel;
38
let markerService: MarkerService;
39
let editor: ICodeEditor;
40
let registry: LanguageFeatureRegistry<languages.CodeActionProvider>;
41
42
setup(() => {
43
markerService = new MarkerService();
44
model = createTextModel('foobar foo bar\nfarboo far boo', languageId, undefined, uri);
45
editor = createTestCodeEditor(model);
46
editor.setPosition({ lineNumber: 1, column: 1 });
47
registry = new LanguageFeatureRegistry();
48
});
49
50
const store = ensureNoDisposablesAreLeakedInTestSuite();
51
52
teardown(() => {
53
editor.dispose();
54
model.dispose();
55
markerService.dispose();
56
});
57
58
test('Oracle -> marker added', async () => {
59
const { promise: donePromise, resolve: done } = promiseWithResolvers<void>();
60
61
await runWithFakedTimers({ useFakeTimers: true }, () => {
62
const reg = registry.register(languageId, testProvider);
63
store.add(reg);
64
65
const contextKeys = new MockContextKeyService();
66
const model = store.add(new CodeActionModel(editor, registry, markerService, contextKeys, undefined));
67
store.add(model.onDidChangeState((e: CodeActionsState.State) => {
68
assertType(e.type === CodeActionsState.Type.Triggered);
69
70
assert.strictEqual(e.trigger.type, languages.CodeActionTriggerType.Auto);
71
assert.ok(e.actions);
72
73
e.actions.then(fixes => {
74
model.dispose();
75
assert.strictEqual(fixes.validActions.length, 1);
76
done();
77
}, done);
78
}));
79
80
// start here
81
markerService.changeOne('fake', uri, [{
82
startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6,
83
message: 'error',
84
severity: 1,
85
code: '',
86
source: ''
87
}]);
88
return donePromise;
89
});
90
});
91
92
test('Oracle -> position changed', async () => {
93
await runWithFakedTimers({ useFakeTimers: true }, () => {
94
const reg = registry.register(languageId, testProvider);
95
store.add(reg);
96
97
markerService.changeOne('fake', uri, [{
98
startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6,
99
message: 'error',
100
severity: 1,
101
code: '',
102
source: ''
103
}]);
104
105
editor.setPosition({ lineNumber: 2, column: 1 });
106
107
return new Promise((resolve, reject) => {
108
const contextKeys = new MockContextKeyService();
109
const model = store.add(new CodeActionModel(editor, registry, markerService, contextKeys, undefined));
110
store.add(model.onDidChangeState((e: CodeActionsState.State) => {
111
assertType(e.type === CodeActionsState.Type.Triggered);
112
113
assert.strictEqual(e.trigger.type, languages.CodeActionTriggerType.Auto);
114
assert.ok(e.actions);
115
e.actions.then(fixes => {
116
model.dispose();
117
assert.strictEqual(fixes.validActions.length, 1);
118
resolve(undefined);
119
}, reject);
120
}));
121
// start here
122
editor.setPosition({ lineNumber: 1, column: 1 });
123
});
124
});
125
});
126
127
test('Oracle -> should only auto trigger once for cursor and marker update right after each other', async () => {
128
const { promise: donePromise, resolve: done } = promiseWithResolvers<void>();
129
await runWithFakedTimers({ useFakeTimers: true }, () => {
130
const reg = registry.register(languageId, testProvider);
131
store.add(reg);
132
133
let triggerCount = 0;
134
const contextKeys = new MockContextKeyService();
135
const model = store.add(new CodeActionModel(editor, registry, markerService, contextKeys, undefined));
136
store.add(model.onDidChangeState((e: CodeActionsState.State) => {
137
assertType(e.type === CodeActionsState.Type.Triggered);
138
139
assert.strictEqual(e.trigger.type, languages.CodeActionTriggerType.Auto);
140
++triggerCount;
141
142
// give time for second trigger before completing test
143
setTimeout(() => {
144
model.dispose();
145
assert.strictEqual(triggerCount, 1);
146
done();
147
}, 0);
148
}, 5 /*delay*/));
149
150
markerService.changeOne('fake', uri, [{
151
startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6,
152
message: 'error',
153
severity: 1,
154
code: '',
155
source: ''
156
}]);
157
158
editor.setSelection({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 });
159
160
return donePromise;
161
});
162
});
163
});
164
165