Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/inlineEdits/test/vscode-node/diagnosticsCollection.spec.ts
13405 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 * as assert from 'assert';
7
import { suite, test } from 'vitest';
8
import { DiagnosticData } from '../../../../platform/inlineEdits/common/dataTypes/diagnosticData';
9
import { URI } from '../../../../util/vs/base/common/uri';
10
import { StringEdit } from '../../../../util/vs/editor/common/core/edits/stringEdit';
11
import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';
12
import { StringText } from '../../../../util/vs/editor/common/core/text/abstractText';
13
import { Diagnostic } from '../../vscode-node/features/diagnosticsBasedCompletions/diagnosticsCompletions';
14
import { DiagnosticsCollection } from '../../vscode-node/features/diagnosticsCompletionProcessor';
15
16
// Helper function to create a Diagnostic from a mock VS Code diagnostic
17
function createDiagnostic(message: string, range: OffsetRange): Diagnostic {
18
return new Diagnostic(new DiagnosticData(
19
URI.parse('file:///test/document.ts'),
20
message,
21
'error',
22
range,
23
undefined,
24
undefined
25
));
26
}
27
28
suite('DiagnosticsCollection', () => {
29
test('isEqualAndUpdate should return true for empty arrays', () => {
30
const collection = new DiagnosticsCollection();
31
const result = collection.isEqualAndUpdate([]);
32
assert.strictEqual(result, true);
33
});
34
test('isEqualAndUpdate should update diagnostics and return false when different', () => {
35
const collection = new DiagnosticsCollection();
36
const diagnostic = createDiagnostic(
37
'Test error',
38
new OffsetRange(0, 4)
39
);
40
41
const result = collection.isEqualAndUpdate([diagnostic]);
42
43
assert.strictEqual(result, false);
44
});
45
test('isEqualAndUpdate should return true when diagnostics are equal', () => {
46
const collection = new DiagnosticsCollection();
47
const diagnostic1 = createDiagnostic('Test error', new OffsetRange(0, 4));
48
const diagnostic2 = createDiagnostic('Test error', new OffsetRange(0, 4));
49
50
collection.isEqualAndUpdate([diagnostic1]);
51
const result = collection.isEqualAndUpdate([diagnostic2]);
52
53
assert.strictEqual(result, true);
54
});
55
test('isEqualAndUpdate should return false when a diagnostics is invalidated', () => {
56
const collection = new DiagnosticsCollection();
57
const diagnostic1 = createDiagnostic('Test error', new OffsetRange(0, 4));
58
const diagnostic2 = createDiagnostic('Test error', new OffsetRange(0, 4));
59
60
collection.isEqualAndUpdate([diagnostic1]);
61
62
diagnostic1.invalidate();
63
64
const result = collection.isEqualAndUpdate([diagnostic2]);
65
66
assert.strictEqual(result, false);
67
});
68
69
suite('applyEdit', () => {
70
test('should invalidate when typing numbers at the end of a diagnostic range', () => {
71
const collection = new DiagnosticsCollection();
72
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 17)); // "test" = positions 12-15 (0-based)
73
collection.isEqualAndUpdate([diagnostic]);
74
75
// Replace "test" with "test123"
76
const before = new StringText('hello world test');
77
const edit = StringEdit.replace(new OffsetRange(12, 17), 'test123'); // 0-based: 12-16
78
const after = edit.applyOnText(before);
79
80
const hasInvalidated = collection.applyEdit(before, edit, after);
81
assert.strictEqual(hasInvalidated, true);
82
assert.strictEqual(diagnostic.isValid(), false);
83
});
84
85
test('should invalidate diagnostic when range shrinks', () => {
86
const collection = new DiagnosticsCollection();
87
const diagnostic = createDiagnostic('Test error', new OffsetRange(6, 11)); // "world"
88
collection.isEqualAndUpdate([diagnostic]);
89
90
// Create an edit that removes "w"
91
const before = new StringText('hello world test');
92
const edit = StringEdit.replace(new OffsetRange(6, 7), ''); // Remove "w"
93
const after = edit.applyOnText(before);
94
95
const hasInvalidated = collection.applyEdit(before, edit, after);
96
97
assert.strictEqual(hasInvalidated, true);
98
assert.strictEqual(diagnostic.isValid(), false);
99
});
100
101
test('should update range when content stays the same and range length unchanged', () => {
102
const collection = new DiagnosticsCollection();
103
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16));
104
collection.isEqualAndUpdate([diagnostic]);
105
106
// Insert " big" without touching the diagnostic range
107
const before = new StringText('hello world test');
108
const edit = StringEdit.replace(new OffsetRange(6, 6), ' big');
109
const after = edit.applyOnText(before);
110
111
const hasInvalidated = collection.applyEdit(before, edit, after);
112
113
assert.strictEqual(hasInvalidated, false);
114
assert.strictEqual(diagnostic.isValid(), true);
115
});
116
117
test('should invalidate diagnostic when content at range changes with same length', () => {
118
const collection = new DiagnosticsCollection();
119
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test"
120
collection.isEqualAndUpdate([diagnostic]);
121
122
// Replace "test" with "best"
123
const before = new StringText('hello world test');
124
const edit = StringEdit.replace(new OffsetRange(12, 16), 'best');
125
const after = edit.applyOnText(before);
126
127
const hasInvalidated = collection.applyEdit(before, edit, after);
128
129
assert.strictEqual(hasInvalidated, true);
130
assert.strictEqual(diagnostic.isValid(), false);
131
});
132
test('should handle range growth with same prefix content', () => {
133
const collection = new DiagnosticsCollection();
134
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16));
135
collection.isEqualAndUpdate([diagnostic]);
136
137
// "test" becomes "test!" (non-alphanumeric edge)
138
const before = new StringText('hello world test');
139
const edit = StringEdit.replace(new OffsetRange(12, 16), 'test!');
140
const after = edit.applyOnText(before);
141
142
const hasInvalidated = collection.applyEdit(before, edit, after);
143
144
assert.strictEqual(hasInvalidated, false);
145
assert.strictEqual(diagnostic.isValid(), true);
146
147
// Range should still point to the original "test" part
148
assert.strictEqual(diagnostic.range.start, 12);
149
assert.strictEqual(diagnostic.range.endExclusive, 16);
150
});
151
152
test('should handle range growth with same suffix content', () => {
153
const collection = new DiagnosticsCollection();
154
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test"
155
collection.isEqualAndUpdate([diagnostic]);
156
157
const before = new StringText('hello world test');
158
const edit = StringEdit.replace(new OffsetRange(12, 12), 'ab');
159
const after = edit.applyOnText(before);
160
161
const hasInvalidated = collection.applyEdit(before, edit, after);
162
163
assert.strictEqual(hasInvalidated, true);
164
assert.strictEqual(diagnostic.isValid(), false);
165
});
166
167
test('should invalidate when edge character is alphanumeric with prefix match', () => {
168
const collection = new DiagnosticsCollection();
169
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test"
170
collection.isEqualAndUpdate([diagnostic]);
171
172
const before = new StringText('hello world test');
173
const edit = StringEdit.replace(new OffsetRange(16, 16), 'A');
174
const after = edit.applyOnText(before);
175
176
// Add A after "test"
177
178
const hasInvalidated = collection.applyEdit(before, edit, after);
179
180
assert.strictEqual(hasInvalidated, true);
181
assert.strictEqual(diagnostic.isValid(), false);
182
});
183
184
test('should not invalidate when edge character is non-alphanumeric with prefix match', () => {
185
const collection = new DiagnosticsCollection();
186
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test" = positions 12-15 (0-based)
187
collection.isEqualAndUpdate([diagnostic]);
188
189
// Replace "test" with "test!"
190
const before = new StringText('hello world test');
191
const edit = StringEdit.replace(new OffsetRange(12, 16), 'test!'); // 0-based: 12-15
192
const after = edit.applyOnText(before);
193
194
const hasInvalidated = collection.applyEdit(before, edit, after);
195
196
assert.strictEqual(hasInvalidated, false);
197
assert.strictEqual(diagnostic.isValid(), true);
198
});
199
200
test('should handle multiple diagnostics correctly', () => {
201
const collection = new DiagnosticsCollection();
202
const diagnostic1 = createDiagnostic('Error 1', new OffsetRange(0, 5)); // "hello" = positions 0-4 (0-based)
203
const diagnostic2 = createDiagnostic('Error 2', new OffsetRange(12, 16)); // "test" = positions 12-15 (0-based)
204
collection.isEqualAndUpdate([diagnostic1, diagnostic2]);
205
206
const before = new StringText('hello world test');
207
const edit = StringEdit.replace(new OffsetRange(6, 6), 'big ');
208
const after = edit.applyOnText(before);
209
210
const hasInvalidated = collection.applyEdit(before, edit, after);
211
212
assert.strictEqual(hasInvalidated, false);
213
assert.strictEqual(diagnostic1.isValid(), true);
214
assert.strictEqual(diagnostic2.isValid(), true);
215
216
// First diagnostic range should be unchanged
217
assert.strictEqual(diagnostic1.range.start, 0);
218
assert.strictEqual(diagnostic1.range.endExclusive, 5);
219
220
// Second diagnostic range should be shifted by 4 positions ("big ")
221
assert.strictEqual(diagnostic2.range.start, 16);
222
assert.strictEqual(diagnostic2.range.endExclusive, 20);
223
});
224
225
test('should handle edge case with empty edge character', () => {
226
const collection = new DiagnosticsCollection();
227
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test" = positions 12-15 (0-based)
228
collection.isEqualAndUpdate([diagnostic]);
229
230
const before = new StringText('hello world test');
231
const after = new StringText('hello world testx'); // Add 'x' at end
232
233
// Replace "test" with "testx"
234
const edit = StringEdit.replace(new OffsetRange(12, 16), 'testx'); // 0-based: 12-15
235
236
const hasInvalidated = collection.applyEdit(before, edit, after);
237
238
// Since 'x' is alphanumeric, should invalidate
239
assert.strictEqual(hasInvalidated, true);
240
assert.strictEqual(diagnostic.isValid(), false);
241
});
242
243
test('should handle suffix match with non-alphanumeric edge character', () => {
244
const collection = new DiagnosticsCollection();
245
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test" = positions 12-15 (0-based)
246
collection.isEqualAndUpdate([diagnostic]);
247
248
const before = new StringText('hello world test');
249
const after = new StringText('hello world .test'); // "test" becomes ".test"
250
251
// Replace "test" with ".test"
252
const edit = StringEdit.replace(new OffsetRange(12, 16), '.test'); // 0-based: 12-15
253
254
const hasInvalidated = collection.applyEdit(before, edit, after);
255
256
assert.strictEqual(hasInvalidated, false);
257
assert.strictEqual(diagnostic.isValid(), true);
258
// Range should point to the suffix "test" part
259
assert.strictEqual(diagnostic.range.start, 13);
260
assert.strictEqual(diagnostic.range.endExclusive, 17); // 17 + 1 (".")
261
});
262
263
test('should handle case where newOffsetRange is null', () => {
264
const collection = new DiagnosticsCollection();
265
const diagnostic = createDiagnostic('Test error', new OffsetRange(12, 16)); // "test" = positions 12-15 (0-based)
266
collection.isEqualAndUpdate([diagnostic]);
267
268
// Mock applyEditsToRanges to return null (would happen if range is completely removed)
269
const before = new StringText('hello world test');
270
const after = new StringText('hello world'); // "test" completely removed
271
272
// Remove " test" completely (0-based: positions 11-15)
273
const edit = StringEdit.replace(new OffsetRange(11, 16), '');
274
275
const hasInvalidated = collection.applyEdit(before, edit, after);
276
277
assert.strictEqual(hasInvalidated, true);
278
assert.strictEqual(diagnostic.isValid(), false);
279
});
280
});
281
});
282
283