Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/documentSymbols/test/browser/outlineModel.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 { CancellationToken, CancellationTokenSource } from '../../../../../base/common/cancellation.js';
8
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
9
import { URI } from '../../../../../base/common/uri.js';
10
import { Range } from '../../../../common/core/range.js';
11
import { DocumentSymbol, SymbolKind } from '../../../../common/languages.js';
12
import { LanguageFeatureDebounceService } from '../../../../common/services/languageFeatureDebounce.js';
13
import { LanguageFeaturesService } from '../../../../common/services/languageFeaturesService.js';
14
import { IModelService } from '../../../../common/services/model.js';
15
import { createModelServices, createTextModel } from '../../../../test/common/testTextModel.js';
16
import { NullLogService } from '../../../../../platform/log/common/log.js';
17
import { IMarker, MarkerSeverity } from '../../../../../platform/markers/common/markers.js';
18
import { OutlineElement, OutlineGroup, OutlineModel, OutlineModelService } from '../../browser/outlineModel.js';
19
import { mock } from '../../../../../base/test/common/mock.js';
20
import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';
21
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
22
23
suite('OutlineModel', function () {
24
25
const disposables = new DisposableStore();
26
const languageFeaturesService = new LanguageFeaturesService();
27
28
teardown(function () {
29
disposables.clear();
30
});
31
32
ensureNoDisposablesAreLeakedInTestSuite();
33
34
test('OutlineModel#create, cached', async function () {
35
36
const insta = createModelServices(disposables);
37
const modelService = insta.get(IModelService);
38
const envService = new class extends mock<IEnvironmentService>() {
39
override isBuilt: boolean = true;
40
override isExtensionDevelopment: boolean = false;
41
};
42
const service = new OutlineModelService(languageFeaturesService, new LanguageFeatureDebounceService(new NullLogService(), envService), modelService);
43
44
const model = createTextModel('foo', undefined, undefined, URI.file('/fome/path.foo'));
45
let count = 0;
46
const reg = languageFeaturesService.documentSymbolProvider.register({ pattern: '**/path.foo' }, {
47
provideDocumentSymbols() {
48
count += 1;
49
return [];
50
}
51
});
52
53
await service.getOrCreate(model, CancellationToken.None);
54
assert.strictEqual(count, 1);
55
56
// cached
57
await service.getOrCreate(model, CancellationToken.None);
58
assert.strictEqual(count, 1);
59
60
// new version
61
model.applyEdits([{ text: 'XXX', range: new Range(1, 1, 1, 1) }]);
62
await service.getOrCreate(model, CancellationToken.None);
63
assert.strictEqual(count, 2);
64
65
reg.dispose();
66
model.dispose();
67
service.dispose();
68
});
69
70
test('OutlineModel#create, cached/cancel', async function () {
71
72
const insta = createModelServices(disposables);
73
const modelService = insta.get(IModelService);
74
const envService = new class extends mock<IEnvironmentService>() {
75
override isBuilt: boolean = true;
76
override isExtensionDevelopment: boolean = false;
77
};
78
const service = new OutlineModelService(languageFeaturesService, new LanguageFeatureDebounceService(new NullLogService(), envService), modelService);
79
const model = createTextModel('foo', undefined, undefined, URI.file('/fome/path.foo'));
80
let isCancelled = false;
81
82
const reg = languageFeaturesService.documentSymbolProvider.register({ pattern: '**/path.foo' }, {
83
provideDocumentSymbols(d, token) {
84
return new Promise(resolve => {
85
const l = token.onCancellationRequested(_ => {
86
isCancelled = true;
87
resolve(null);
88
l.dispose();
89
});
90
});
91
}
92
});
93
94
assert.strictEqual(isCancelled, false);
95
const s1 = new CancellationTokenSource();
96
service.getOrCreate(model, s1.token);
97
const s2 = new CancellationTokenSource();
98
service.getOrCreate(model, s2.token);
99
100
s1.cancel();
101
assert.strictEqual(isCancelled, false);
102
103
s2.cancel();
104
assert.strictEqual(isCancelled, true);
105
106
reg.dispose();
107
model.dispose();
108
service.dispose();
109
110
});
111
112
function fakeSymbolInformation(range: Range, name: string = 'foo'): DocumentSymbol {
113
return {
114
name,
115
detail: 'fake',
116
kind: SymbolKind.Boolean,
117
tags: [],
118
selectionRange: range,
119
range: range
120
};
121
}
122
123
function fakeMarker(range: Range): IMarker {
124
return { ...range, owner: 'ffff', message: 'test', severity: MarkerSeverity.Error, resource: null! };
125
}
126
127
test('OutlineElement - updateMarker', function () {
128
129
const e0 = new OutlineElement('foo1', null!, fakeSymbolInformation(new Range(1, 1, 1, 10)));
130
const e1 = new OutlineElement('foo2', null!, fakeSymbolInformation(new Range(2, 1, 5, 1)));
131
const e2 = new OutlineElement('foo3', null!, fakeSymbolInformation(new Range(6, 1, 10, 10)));
132
133
const group = new OutlineGroup('group', null!, null!, 1);
134
group.children.set(e0.id, e0);
135
group.children.set(e1.id, e1);
136
group.children.set(e2.id, e2);
137
138
const data = [fakeMarker(new Range(6, 1, 6, 7)), fakeMarker(new Range(1, 1, 1, 4)), fakeMarker(new Range(10, 2, 14, 1))];
139
data.sort(Range.compareRangesUsingStarts); // model does this
140
141
group.updateMarker(data);
142
assert.strictEqual(data.length, 0); // all 'stolen'
143
assert.strictEqual(e0.marker!.count, 1);
144
assert.strictEqual(e1.marker, undefined);
145
assert.strictEqual(e2.marker!.count, 2);
146
147
group.updateMarker([]);
148
assert.strictEqual(e0.marker, undefined);
149
assert.strictEqual(e1.marker, undefined);
150
assert.strictEqual(e2.marker, undefined);
151
});
152
153
test('OutlineElement - updateMarker, 2', function () {
154
155
const p = new OutlineElement('A', null!, fakeSymbolInformation(new Range(1, 1, 11, 1)));
156
const c1 = new OutlineElement('A/B', null!, fakeSymbolInformation(new Range(2, 4, 5, 4)));
157
const c2 = new OutlineElement('A/C', null!, fakeSymbolInformation(new Range(6, 4, 9, 4)));
158
159
const group = new OutlineGroup('group', null!, null!, 1);
160
group.children.set(p.id, p);
161
p.children.set(c1.id, c1);
162
p.children.set(c2.id, c2);
163
164
let data = [
165
fakeMarker(new Range(2, 4, 5, 4))
166
];
167
168
group.updateMarker(data);
169
assert.strictEqual(p.marker!.count, 0);
170
assert.strictEqual(c1.marker!.count, 1);
171
assert.strictEqual(c2.marker, undefined);
172
173
data = [
174
fakeMarker(new Range(2, 4, 5, 4)),
175
fakeMarker(new Range(2, 6, 2, 8)),
176
fakeMarker(new Range(7, 6, 7, 8)),
177
];
178
group.updateMarker(data);
179
assert.strictEqual(p.marker!.count, 0);
180
assert.strictEqual(c1.marker!.count, 2);
181
assert.strictEqual(c2.marker!.count, 1);
182
183
data = [
184
fakeMarker(new Range(1, 4, 1, 11)),
185
fakeMarker(new Range(7, 6, 7, 8)),
186
];
187
group.updateMarker(data);
188
assert.strictEqual(p.marker!.count, 1);
189
assert.strictEqual(c1.marker, undefined);
190
assert.strictEqual(c2.marker!.count, 1);
191
});
192
193
test('OutlineElement - updateMarker/multiple groups', function () {
194
195
const model = new class extends OutlineModel {
196
constructor() {
197
super(null!);
198
}
199
readyForTesting() {
200
this._groups = this.children as any;
201
}
202
};
203
model.children.set('g1', new OutlineGroup('g1', model, null!, 1));
204
model.children.get('g1')!.children.set('c1', new OutlineElement('c1', model.children.get('g1')!, fakeSymbolInformation(new Range(1, 1, 11, 1))));
205
206
model.children.set('g2', new OutlineGroup('g2', model, null!, 1));
207
model.children.get('g2')!.children.set('c2', new OutlineElement('c2', model.children.get('g2')!, fakeSymbolInformation(new Range(1, 1, 7, 1))));
208
model.children.get('g2')!.children.get('c2')!.children.set('c2.1', new OutlineElement('c2.1', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(1, 3, 2, 19))));
209
model.children.get('g2')!.children.get('c2')!.children.set('c2.2', new OutlineElement('c2.2', model.children.get('g2')!.children.get('c2')!, fakeSymbolInformation(new Range(4, 1, 6, 10))));
210
211
model.readyForTesting();
212
213
const data = [
214
fakeMarker(new Range(1, 1, 2, 8)),
215
fakeMarker(new Range(6, 1, 6, 98)),
216
];
217
218
model.updateMarker(data);
219
220
assert.strictEqual(model.children.get('g1')!.children.get('c1')!.marker!.count, 2);
221
assert.strictEqual(model.children.get('g2')!.children.get('c2')!.children.get('c2.1')!.marker!.count, 1);
222
assert.strictEqual(model.children.get('g2')!.children.get('c2')!.children.get('c2.2')!.marker!.count, 1);
223
});
224
225
});
226
227