Skip to content

Commit be4ef5e

Browse files
committed
test: add unit tests for diagnostics with the scenario we fixed included
1 parent 44a1094 commit be4ef5e

File tree

1 file changed

+369
-0
lines changed

1 file changed

+369
-0
lines changed
Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
import * as vscode from "vscode"
2+
import { diagnosticsToProblemsString } from ".."
3+
4+
// Mock vscode module
5+
jest.mock("vscode", () => ({
6+
Uri: {
7+
file: jest.fn((path) => ({
8+
fsPath: path,
9+
toString: jest.fn(() => path),
10+
})),
11+
},
12+
Diagnostic: jest.fn().mockImplementation((range, message, severity) => ({
13+
range,
14+
message,
15+
severity,
16+
source: "test",
17+
})),
18+
Range: jest.fn().mockImplementation((startLine, startChar, endLine, endChar) => ({
19+
start: { line: startLine, character: startChar },
20+
end: { line: endLine, character: endChar },
21+
})),
22+
DiagnosticSeverity: {
23+
Error: 0,
24+
Warning: 1,
25+
Information: 2,
26+
Hint: 3,
27+
},
28+
FileType: {
29+
Unknown: 0,
30+
File: 1,
31+
Directory: 2,
32+
SymbolicLink: 64,
33+
},
34+
workspace: {
35+
fs: {
36+
stat: jest.fn(),
37+
},
38+
openTextDocument: jest.fn(),
39+
},
40+
}))
41+
42+
describe("diagnosticsToProblemsString", () => {
43+
beforeEach(() => {
44+
jest.clearAllMocks()
45+
})
46+
47+
it("should filter diagnostics by severity and include correct labels", async () => {
48+
// Mock file URI
49+
const fileUri = vscode.Uri.file("/path/to/file.ts")
50+
51+
// Create diagnostics with different severities
52+
const diagnostics = [
53+
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error message", vscode.DiagnosticSeverity.Error),
54+
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning message", vscode.DiagnosticSeverity.Warning),
55+
new vscode.Diagnostic(new vscode.Range(2, 0, 2, 10), "Info message", vscode.DiagnosticSeverity.Information),
56+
new vscode.Diagnostic(new vscode.Range(3, 0, 3, 10), "Hint message", vscode.DiagnosticSeverity.Hint),
57+
]
58+
59+
// Mock fs.stat to return file type
60+
const mockStat = {
61+
type: vscode.FileType.File,
62+
}
63+
vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
64+
65+
// Mock document content
66+
const mockDocument = {
67+
lineAt: jest.fn((line) => ({
68+
text: `Line ${line + 1} content`,
69+
})),
70+
}
71+
vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
72+
73+
// Test with Error and Warning severities only
74+
const result = await diagnosticsToProblemsString(
75+
[[fileUri, diagnostics]],
76+
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
77+
"/path/to",
78+
)
79+
80+
// Verify only Error and Warning diagnostics are included
81+
expect(result).toContain("Error message")
82+
expect(result).toContain("Warning message")
83+
expect(result).not.toContain("Info message")
84+
expect(result).not.toContain("Hint message")
85+
86+
// Verify correct severity labels are used
87+
expect(result).toContain("[test Error]")
88+
expect(result).toContain("[test Warning]")
89+
expect(result).not.toContain("[test Information]")
90+
expect(result).not.toContain("[test Hint]")
91+
92+
// Verify line content is included
93+
expect(result).toContain("Line 1 content")
94+
expect(result).toContain("Line 2 content")
95+
})
96+
97+
it("should handle directory URIs correctly without attempting to open as document", async () => {
98+
// Mock directory URI
99+
const dirUri = vscode.Uri.file("/path/to/directory/")
100+
101+
// Mock diagnostic for directory
102+
const diagnostic = new vscode.Diagnostic(
103+
new vscode.Range(0, 0, 0, 10),
104+
"Directory diagnostic message",
105+
vscode.DiagnosticSeverity.Error,
106+
)
107+
108+
// Mock fs.stat to return directory type
109+
const mockStat = {
110+
type: vscode.FileType.Directory,
111+
}
112+
vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
113+
114+
// Mock openTextDocument to ensure it's not called
115+
vscode.workspace.openTextDocument = jest.fn()
116+
117+
// Call the function
118+
const result = await diagnosticsToProblemsString(
119+
[[dirUri, [diagnostic]]],
120+
[vscode.DiagnosticSeverity.Error],
121+
"/path/to",
122+
)
123+
124+
// Verify fs.stat was called with the directory URI
125+
expect(vscode.workspace.fs.stat).toHaveBeenCalledWith(dirUri)
126+
127+
// Verify openTextDocument was not called
128+
expect(vscode.workspace.openTextDocument).not.toHaveBeenCalled()
129+
130+
// Verify the output contains the expected directory indicator
131+
expect(result).toContain("(directory)")
132+
expect(result).toContain("Directory diagnostic message")
133+
expect(result).toMatch(/directory\n- \[test Error\] 1 \| \(directory\) : Directory diagnostic message/)
134+
})
135+
136+
it("should correctly handle multiple diagnostics for the same file", async () => {
137+
// Mock file URI
138+
const fileUri = vscode.Uri.file("/path/to/file.ts")
139+
140+
// Create multiple diagnostics for the same file
141+
const diagnostics = [
142+
new vscode.Diagnostic(new vscode.Range(4, 0, 4, 10), "Later line error", vscode.DiagnosticSeverity.Error),
143+
new vscode.Diagnostic(
144+
new vscode.Range(0, 0, 0, 10),
145+
"First line warning",
146+
vscode.DiagnosticSeverity.Warning,
147+
),
148+
new vscode.Diagnostic(
149+
new vscode.Range(2, 0, 2, 10),
150+
"Middle line info",
151+
vscode.DiagnosticSeverity.Information,
152+
),
153+
]
154+
155+
// Mock fs.stat to return file type
156+
const mockStat = {
157+
type: vscode.FileType.File,
158+
}
159+
vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
160+
161+
// Mock document content with specific line texts for each test case
162+
const mockDocument = {
163+
lineAt: jest.fn((line: number) => {
164+
const lineTexts: Record<number, string> = {
165+
0: "Line 0 content for warning",
166+
2: "Line 2 content for info",
167+
4: "Line 4 content for error",
168+
}
169+
return { text: lineTexts[line] }
170+
}),
171+
}
172+
vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
173+
174+
// Call the function with all severities
175+
const result = await diagnosticsToProblemsString(
176+
[[fileUri, diagnostics]],
177+
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning, vscode.DiagnosticSeverity.Information],
178+
"/path/to",
179+
)
180+
181+
// Verify all diagnostics are included in the output
182+
expect(result).toContain("First line warning")
183+
expect(result).toContain("Middle line info")
184+
expect(result).toContain("Later line error")
185+
186+
// Verify line content is included for each diagnostic and matches the test case
187+
expect(result).toContain("Line 0 content for warning")
188+
expect(result).toContain("Line 2 content for info")
189+
expect(result).toContain("Line 4 content for error")
190+
191+
// Verify the output contains all severity labels
192+
expect(result).toContain("[test Warning]")
193+
expect(result).toContain("[test Information]")
194+
expect(result).toContain("[test Error]")
195+
196+
// Verify diagnostics appear in line number order (even though input wasn't sorted)
197+
// Verify exact output format
198+
expect(result).toBe(
199+
"file.ts\n" +
200+
"- [test Warning] 1 | Line 0 content for warning : First line warning\n" +
201+
"- [test Information] 3 | Line 2 content for info : Middle line info\n" +
202+
"- [test Error] 5 | Line 4 content for error : Later line error",
203+
)
204+
})
205+
206+
it("should correctly handle diagnostics from multiple files", async () => {
207+
// Mock URIs for different files
208+
const fileUri1 = vscode.Uri.file("/path/to/file1.ts")
209+
const fileUri2 = vscode.Uri.file("/path/to/subdir/file2.ts")
210+
211+
// Create diagnostics for each file
212+
const diagnostics1 = [
213+
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "File1 error", vscode.DiagnosticSeverity.Error),
214+
]
215+
216+
const diagnostics2 = [
217+
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "File2 warning", vscode.DiagnosticSeverity.Warning),
218+
new vscode.Diagnostic(new vscode.Range(2, 0, 2, 10), "File2 info", vscode.DiagnosticSeverity.Information),
219+
]
220+
221+
// Mock fs.stat to return file type for both files
222+
const mockStat = {
223+
type: vscode.FileType.File,
224+
}
225+
vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
226+
227+
// Mock document content with specific line texts for each test case
228+
const mockDocument1 = {
229+
lineAt: jest.fn((_line) => ({
230+
text: "Line 1 content for error",
231+
})),
232+
}
233+
const mockDocument2 = {
234+
lineAt: jest.fn((line) => {
235+
const lineTexts = ["Line 1 content", "Line 2 content for warning", "Line 3 content for info"]
236+
return { text: lineTexts[line] }
237+
}),
238+
}
239+
vscode.workspace.openTextDocument = jest
240+
.fn()
241+
.mockResolvedValueOnce(mockDocument1)
242+
.mockResolvedValueOnce(mockDocument2)
243+
244+
// Call the function with all severities
245+
const result = await diagnosticsToProblemsString(
246+
[
247+
[fileUri1, diagnostics1],
248+
[fileUri2, diagnostics2],
249+
],
250+
[vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning, vscode.DiagnosticSeverity.Information],
251+
"/path/to",
252+
)
253+
254+
// Verify file paths are correctly shown with relative paths
255+
expect(result).toContain("file1.ts")
256+
expect(result).toContain("subdir/file2.ts")
257+
258+
// Verify diagnostics are grouped under their respective files
259+
const file1Section = result.split("file1.ts")[1]
260+
expect(file1Section).toContain("File1 error")
261+
expect(file1Section).toContain("Line 1 content for error")
262+
263+
const file2Section = result.split("subdir/file2.ts")[1]
264+
expect(file2Section).toContain("File2 warning")
265+
expect(file2Section).toContain("Line 2 content for warning")
266+
expect(file2Section).toContain("File2 info")
267+
expect(file2Section).toContain("Line 3 content for info")
268+
269+
// Verify exact output format
270+
expect(result).toBe(
271+
"file1.ts\n" +
272+
"- [test Error] 1 | Line 1 content for error : File1 error\n\n" +
273+
"subdir/file2.ts\n" +
274+
"- [test Warning] 2 | Line 2 content for warning : File2 warning\n" +
275+
"- [test Information] 3 | Line 3 content for info : File2 info",
276+
)
277+
})
278+
279+
it("should return empty string when no diagnostics match the severity filter", async () => {
280+
// Mock file URI
281+
const fileUri = vscode.Uri.file("/path/to/file.ts")
282+
283+
// Create diagnostics with Error and Warning severities
284+
const diagnostics = [
285+
new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error message", vscode.DiagnosticSeverity.Error),
286+
new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning message", vscode.DiagnosticSeverity.Warning),
287+
]
288+
289+
// Mock fs.stat to return file type
290+
const mockStat = {
291+
type: vscode.FileType.File,
292+
}
293+
vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
294+
295+
// Mock document content (though it shouldn't be accessed in this case)
296+
const mockDocument = {
297+
lineAt: jest.fn((line) => ({
298+
text: `Line ${line + 1} content`,
299+
})),
300+
}
301+
vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
302+
303+
// Test with Information and Hint severities only (which don't match our diagnostics)
304+
const result = await diagnosticsToProblemsString(
305+
[[fileUri, diagnostics]],
306+
[vscode.DiagnosticSeverity.Information, vscode.DiagnosticSeverity.Hint],
307+
"/path/to",
308+
)
309+
310+
// Verify empty string is returned
311+
expect(result).toBe("")
312+
313+
// Verify no unnecessary calls were made
314+
expect(vscode.workspace.fs.stat).not.toHaveBeenCalled()
315+
expect(vscode.workspace.openTextDocument).not.toHaveBeenCalled()
316+
})
317+
318+
it("should correctly handle cwd parameter for relative file paths", async () => {
319+
// Mock file URI in a subdirectory
320+
const fileUri = vscode.Uri.file("/project/root/src/utils/file.ts")
321+
322+
// Create a diagnostic for the file
323+
const diagnostic = new vscode.Diagnostic(
324+
new vscode.Range(4, 0, 4, 10),
325+
"Relative path test error",
326+
vscode.DiagnosticSeverity.Error,
327+
)
328+
329+
// Mock fs.stat to return file type
330+
const mockStat = {
331+
type: vscode.FileType.File,
332+
}
333+
vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
334+
335+
// Mock document content matching test assertion
336+
const mockDocument = {
337+
lineAt: jest.fn((line) => ({
338+
text: `Line ${line + 1} content for error`,
339+
})),
340+
}
341+
vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
342+
343+
// Mock path.relative to return the expected relative path
344+
jest.mock("path", () => ({
345+
relative: jest.fn((cwd, fullPath) => {
346+
if (cwd === "/project/root" && fullPath === "/project/root/src/utils/file.ts") {
347+
return "src/utils/file.ts"
348+
}
349+
return fullPath
350+
}),
351+
}))
352+
353+
// Call the function with cwd set to the project root
354+
const result = await diagnosticsToProblemsString(
355+
[[fileUri, [diagnostic]]],
356+
[vscode.DiagnosticSeverity.Error],
357+
"/project/root",
358+
)
359+
360+
// Verify exact output format
361+
expect(result).toBe(
362+
"src/utils/file.ts\n" + "- [test Error] 5 | Line 5 content for error : Relative path test error",
363+
)
364+
365+
// Verify fs.stat and openTextDocument were called
366+
expect(vscode.workspace.fs.stat).toHaveBeenCalledWith(fileUri)
367+
expect(vscode.workspace.openTextDocument).toHaveBeenCalledWith(fileUri)
368+
})
369+
})

0 commit comments

Comments
 (0)