Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/claude/common/test/ideMcpServer.spec.ts
13406 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 { beforeEach, describe, expect, it } from 'vitest';
7
import { TestLanguageDiagnosticsService } from '../../../../../platform/languages/common/testLanguageDiagnosticsService';
8
import { URI } from '../../../../../util/vs/base/common/uri';
9
import { DiagnosticSeverity, Range } from '../../../../../vscodeTypes';
10
import { getDiagnosticsHandler } from '../mcpServers/ideMcpServer';
11
12
describe('getDiagnosticsHandler', () => {
13
let diagnosticsService: TestLanguageDiagnosticsService;
14
15
const fileA = URI.file('/workspace/src/fileA.ts');
16
const fileB = URI.file('/workspace/src/fileB.ts');
17
const fileC = URI.file('/workspace/src/fileC.ts');
18
19
beforeEach(() => {
20
diagnosticsService = new TestLanguageDiagnosticsService();
21
});
22
23
it('returns all diagnostics when no uri is provided', () => {
24
diagnosticsService.setDiagnostics(fileA, [
25
{ message: 'error in A', range: new Range(0, 0, 0, 5), severity: DiagnosticSeverity.Error },
26
]);
27
diagnosticsService.setDiagnostics(fileB, [
28
{ message: 'warning in B', range: new Range(1, 0, 1, 10), severity: DiagnosticSeverity.Warning },
29
]);
30
31
const result = getDiagnosticsHandler(diagnosticsService, {});
32
33
expect(result).toHaveLength(2);
34
expect(result[0].diagnostics[0].message).toBe('error in A');
35
expect(result[1].diagnostics[0].message).toBe('warning in B');
36
});
37
38
it('scopes to a single file when uri is provided', () => {
39
diagnosticsService.setDiagnostics(fileA, [
40
{ message: 'error in A', range: new Range(0, 0, 0, 5), severity: DiagnosticSeverity.Error },
41
]);
42
diagnosticsService.setDiagnostics(fileB, [
43
{ message: 'warning in B', range: new Range(1, 0, 1, 10), severity: DiagnosticSeverity.Warning },
44
]);
45
46
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileA.toString() });
47
48
expect(result).toHaveLength(1);
49
expect(result[0].uri).toBe(fileA.toString());
50
expect(result[0].diagnostics[0].message).toBe('error in A');
51
});
52
53
it('returns empty array when no diagnostics exist', () => {
54
const result = getDiagnosticsHandler(diagnosticsService, {});
55
expect(result).toHaveLength(0);
56
});
57
58
it('filters out files with zero diagnostics', () => {
59
diagnosticsService.setDiagnostics(fileA, []);
60
diagnosticsService.setDiagnostics(fileB, [
61
{ message: 'warning', range: new Range(0, 0, 0, 1), severity: DiagnosticSeverity.Warning },
62
]);
63
64
const result = getDiagnosticsHandler(diagnosticsService, {});
65
66
expect(result).toHaveLength(1);
67
expect(result[0].uri).toBe(fileB.toString());
68
});
69
70
it('returns empty array for a file with no diagnostics when scoped by uri', () => {
71
diagnosticsService.setDiagnostics(fileC, []);
72
73
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileC.toString() });
74
75
expect(result).toHaveLength(0);
76
});
77
78
it('maps all severity levels correctly', () => {
79
diagnosticsService.setDiagnostics(fileA, [
80
{ message: 'err', range: new Range(0, 0, 0, 1), severity: DiagnosticSeverity.Error },
81
{ message: 'warn', range: new Range(1, 0, 1, 1), severity: DiagnosticSeverity.Warning },
82
{ message: 'info', range: new Range(2, 0, 2, 1), severity: DiagnosticSeverity.Information },
83
{ message: 'hint', range: new Range(3, 0, 3, 1), severity: DiagnosticSeverity.Hint },
84
]);
85
86
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileA.toString() });
87
88
expect(result).toHaveLength(1);
89
const severities = result[0].diagnostics.map(d => d.severity);
90
expect(severities).toEqual(['error', 'warning', 'information', 'hint']);
91
});
92
93
it('includes range, source, and code in output', () => {
94
diagnosticsService.setDiagnostics(fileA, [
95
{
96
message: 'unused variable',
97
range: new Range(5, 8, 5, 12),
98
severity: DiagnosticSeverity.Warning,
99
source: 'typescript',
100
code: 6133,
101
},
102
]);
103
104
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileA.toString() });
105
106
const diag = result[0].diagnostics[0];
107
expect(diag.range).toEqual({
108
start: { line: 5, character: 8 },
109
end: { line: 5, character: 12 },
110
});
111
expect(diag.source).toBe('typescript');
112
expect(diag.code).toBe(6133);
113
});
114
115
it('extracts code value from object-style codes', () => {
116
diagnosticsService.setDiagnostics(fileA, [
117
{
118
message: 'some lint error',
119
range: new Range(0, 0, 0, 1),
120
severity: DiagnosticSeverity.Error,
121
code: { value: 'no-unused-vars', target: URI.parse('https://eslint.org/rules/no-unused-vars') },
122
},
123
]);
124
125
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileA.toString() });
126
127
expect(result[0].diagnostics[0].code).toBe('no-unused-vars');
128
});
129
130
it('includes filePath in output', () => {
131
diagnosticsService.setDiagnostics(fileA, [
132
{ message: 'err', range: new Range(0, 0, 0, 1), severity: DiagnosticSeverity.Error },
133
]);
134
135
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileA.toString() });
136
137
expect(result[0].filePath).toBe(fileA.fsPath);
138
});
139
140
it('handles multiple diagnostics in a single file', () => {
141
diagnosticsService.setDiagnostics(fileA, [
142
{ message: 'first', range: new Range(0, 0, 0, 1), severity: DiagnosticSeverity.Error },
143
{ message: 'second', range: new Range(1, 0, 1, 1), severity: DiagnosticSeverity.Warning },
144
{ message: 'third', range: new Range(2, 0, 2, 1), severity: DiagnosticSeverity.Hint },
145
]);
146
147
const result = getDiagnosticsHandler(diagnosticsService, { uri: fileA.toString() });
148
149
expect(result).toHaveLength(1);
150
expect(result[0].diagnostics).toHaveLength(3);
151
expect(result[0].diagnostics.map(d => d.message)).toEqual(['first', 'second', 'third']);
152
});
153
154
it('treats empty string uri as no filter', () => {
155
diagnosticsService.setDiagnostics(fileA, [
156
{ message: 'err', range: new Range(0, 0, 0, 1), severity: DiagnosticSeverity.Error },
157
]);
158
159
const result = getDiagnosticsHandler(diagnosticsService, { uri: '' });
160
161
expect(result).toHaveLength(1);
162
expect(result[0].diagnostics[0].message).toBe('err');
163
});
164
165
it('accepts a non-file scheme URI', () => {
166
const result = getDiagnosticsHandler(diagnosticsService, { uri: 'untitled:Untitled-1' });
167
expect(result).toHaveLength(0);
168
});
169
170
it('accepts an absolute unix path', () => {
171
const result = getDiagnosticsHandler(diagnosticsService, { uri: '/workspace/src/fileA.ts' });
172
expect(result).toHaveLength(0);
173
});
174
175
it('accepts a file:// URI', () => {
176
const result = getDiagnosticsHandler(diagnosticsService, { uri: 'file:///workspace/src/fileA.ts' });
177
expect(result).toHaveLength(0);
178
});
179
});
180
181