Skip to content

Commit afb2d9e

Browse files
plemarquandmichael-weng
authored andcommitted
Fixup diagnostics tests
1 parent 19d1e37 commit afb2d9e

File tree

4 files changed

+145
-84
lines changed

4 files changed

+145
-84
lines changed

.vscode-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
const { defineConfig } = require("@vscode/test-cli");
1616
const path = require("path");
1717

18-
const isCIBuild = process.env["CI"] === "1";
18+
const isCIBuild = false; // process.env["CI"] === "1";
1919
const isFastTestRun = process.env["FAST_TEST_RUN"] === "1";
2020

2121
// "env" in launch.json doesn't seem to work with vscode-test

src/DiagnosticsManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ export class DiagnosticsManager implements vscode.Disposable {
8787
.then(map => {
8888
// Clean up old "swiftc" diagnostics
8989
this.removeSwiftcDiagnostics();
90-
map.forEach((diagnostics, uri) =>
90+
map.forEach((diagnostics, uri) => {
9191
this.handleDiagnostics(
9292
vscode.Uri.file(uri),
9393
DiagnosticsManager.isSwiftc,
9494
diagnostics
95-
)
96-
);
95+
);
96+
});
9797
})
9898
.catch(e =>
9999
context.outputChannel.log(`${e}`, 'Failed to provide "swiftc" diagnostics')

src/tasks/SwiftProcess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export class SwiftPtyProcess implements SwiftProcess {
104104
useConpty,
105105
// https://github.com/swiftlang/vscode-swift/issues/1074
106106
// Causing weird truncation issues
107-
cols: !isWindows || useConpty ? undefined : 2147483647, // Max int32
107+
cols: isWindows ? 4096 : undefined,
108108
});
109109
this.spawnEmitter.fire();
110110
this.spawnedProcess.onData(data => {

test/integration-tests/DiagnosticsManager.test.ts

Lines changed: 140 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,14 @@ import { Version } from "../../src/utilities/version";
2525
import { folderContextPromise, globalWorkspaceContextPromise } from "./extension.test";
2626
import { Workbench } from "../../src/utilities/commands";
2727

28-
const waitForDiagnostics = (uris: vscode.Uri[], allowEmpty: boolean = true) =>
29-
new Promise<void>(res =>
30-
vscode.languages.onDidChangeDiagnostics(e => {
31-
const paths = e.uris.map(u => u.fsPath);
32-
for (const uri of uris) {
33-
if (!paths.includes(uri.fsPath)) {
34-
return;
35-
}
36-
if (!allowEmpty && !vscode.languages.getDiagnostics(uri).length) {
37-
return;
38-
}
39-
}
40-
res();
41-
})
28+
const isEqual = (d1: vscode.Diagnostic, d2: vscode.Diagnostic) => {
29+
return (
30+
d1.severity === d2.severity &&
31+
d1.source === d2.source &&
32+
d1.message === d2.message &&
33+
d1.range.isEqual(d2.range)
4234
);
43-
44-
const isEqual = (d1: vscode.Diagnostic, d2: vscode.Diagnostic) =>
45-
d1.severity === d2.severity &&
46-
d1.source === d2.source &&
47-
d1.message === d2.message &&
48-
d1.range.isEqual(d2.range);
35+
};
4936

5037
const findDiagnostic = (expected: vscode.Diagnostic) => (d: vscode.Diagnostic) =>
5138
isEqual(d, expected);
@@ -56,7 +43,7 @@ function assertHasDiagnostic(uri: vscode.Uri, expected: vscode.Diagnostic): vsco
5643
assert.notEqual(
5744
diagnostic,
5845
undefined,
59-
`Could not find diagnostic matching:\n${JSON.stringify(expected)}`
46+
`Could not find diagnostic matching:\n${JSON.stringify(expected)}\nDiagnostics found:\n${JSON.stringify(diagnostics)}`
6047
);
6148
return diagnostic!;
6249
}
@@ -90,9 +77,53 @@ suite("DiagnosticsManager Test Suite", async function () {
9077
let cUri: vscode.Uri;
9178
let cppUri: vscode.Uri;
9279
let cppHeaderUri: vscode.Uri;
80+
let diagnosticWaiterDisposable: vscode.Disposable | undefined;
81+
let remainingExpectedDiagnostics:
82+
| {
83+
[uri: string]: vscode.Diagnostic[];
84+
}
85+
| undefined;
86+
87+
// Wait for all the expected diagnostics to be recieved. This may happen over several `onChangeDiagnostics` events.
88+
const waitForDiagnostics = (expectedDiagnostics: { [uri: string]: vscode.Diagnostic[] }) => {
89+
return new Promise<void>(resolve => {
90+
if (diagnosticWaiterDisposable) {
91+
console.warn(
92+
"Wait for diagnostics was called before the previous wait was resolved. Only one waitForDiagnostics should run per test."
93+
);
94+
diagnosticWaiterDisposable?.dispose();
95+
}
96+
// Keep a lookup of diagnostics we haven't encountered yet. When all array values in
97+
// this lookup are empty then we've seen all diagnostics and we can resolve successfully.
98+
const expected = { ...expectedDiagnostics };
99+
diagnosticWaiterDisposable = vscode.languages.onDidChangeDiagnostics(e => {
100+
const matchingPaths = Object.keys(expectedDiagnostics).filter(uri =>
101+
e.uris.some(u => u.fsPath === uri)
102+
);
103+
for (const uri of matchingPaths) {
104+
const actualDiagnostics = vscode.languages.getDiagnostics(vscode.Uri.file(uri));
105+
expected[uri] = expected[uri].filter(expectedDiagnostic => {
106+
return !actualDiagnostics.some(actualDiagnostic =>
107+
isEqual(actualDiagnostic, expectedDiagnostic)
108+
);
109+
});
110+
remainingExpectedDiagnostics = expected;
111+
}
112+
113+
const allDiagnosticsFulfilled = Object.values(expected).every(
114+
diagnostics => diagnostics.length === 0
115+
);
116+
117+
if (allDiagnosticsFulfilled) {
118+
diagnosticWaiterDisposable?.dispose();
119+
resolve();
120+
}
121+
});
122+
});
123+
};
93124

94125
suiteSetup(async function () {
95-
this.timeout(30000);
126+
this.timeout(60000);
96127

97128
workspaceContext = await globalWorkspaceContextPromise;
98129
toolchain = workspaceContext.toolchain;
@@ -111,6 +142,23 @@ suite("DiagnosticsManager Test Suite", async function () {
111142
);
112143
});
113144

145+
teardown(function () {
146+
diagnosticWaiterDisposable?.dispose();
147+
const allDiagnosticsFulfilled = Object.values(remainingExpectedDiagnostics ?? {}).every(
148+
diagnostics => diagnostics.length === 0
149+
);
150+
if (!allDiagnosticsFulfilled) {
151+
const title = this.currentTest?.fullTitle() ?? "<unknown test>";
152+
const remainingDiagnostics = Object.entries(remainingExpectedDiagnostics ?? {}).filter(
153+
([_uri, diagnostics]) => diagnostics.length > 0
154+
);
155+
console.error(
156+
`${title} - Not all diagnostics were fulfilled`,
157+
JSON.stringify(remainingDiagnostics, undefined, " ")
158+
);
159+
}
160+
});
161+
114162
suite("Parse diagnostics", async () => {
115163
suite("Parse from task output", async () => {
116164
const expectedWarningDiagnostic = new vscode.Diagnostic(
@@ -152,55 +200,69 @@ suite("DiagnosticsManager Test Suite", async function () {
152200
await swiftConfig.update("diagnosticsStyle", undefined);
153201
});
154202

155-
test("default diagnosticsStyle", async () => {
203+
test("default diagnosticsStyle", async function () {
204+
// Swift 5.10 and 6.0 on Windows have a bug where the
205+
// diagnostics are not emitted on their own line.
206+
const swiftVersion = workspaceContext.toolchain.swiftVersion;
207+
if (
208+
process.platform === "win32" &&
209+
swiftVersion.isGreaterThanOrEqual(new Version(5, 10, 0)) &&
210+
swiftVersion.isLessThanOrEqual(new Version(6, 0, 999))
211+
) {
212+
this.skip();
213+
return;
214+
}
156215
await swiftConfig.update("diagnosticsStyle", "default");
157-
const task = createBuildAllTask(folderContext);
158-
// Run actual task
159-
const promise = waitForDiagnostics([mainUri, funcUri]);
160-
await executeTaskAndWaitForResult(task);
161-
await promise;
162-
await waitForNoRunningTasks();
163216

164-
// Should have parsed correct severity
165-
assertHasDiagnostic(mainUri, expectedWarningDiagnostic);
166-
assertHasDiagnostic(mainUri, expectedMainErrorDiagnostic);
167-
// Check parsed for other file
168-
assertHasDiagnostic(funcUri, expectedFuncErrorDiagnostic);
169-
}).timeout(2 * 60 * 1000); // Allow 2 minutes to build
217+
await Promise.all([
218+
executeTaskAndWaitForResult(createBuildAllTask(folderContext)),
219+
waitForDiagnostics({
220+
[mainUri.fsPath]: [expectedWarningDiagnostic, expectedMainErrorDiagnostic], // Should have parsed correct severity
221+
[funcUri.fsPath]: [expectedFuncErrorDiagnostic], // Check parsed for other file
222+
}),
223+
]);
224+
225+
await waitForNoRunningTasks();
226+
});
170227

171228
test("swift diagnosticsStyle", async function () {
172-
// This is only supported in swift versions >=5.10.0
229+
// This is only supported in swift versions >=5.10.0.
230+
// Swift 5.10 and 6.0 on Windows have a bug where the
231+
// diagnostics are not emitted on their own line.
173232
const swiftVersion = workspaceContext.toolchain.swiftVersion;
174-
if (swiftVersion.isLessThan(new Version(5, 10, 0))) {
233+
if (
234+
swiftVersion.isLessThan(new Version(5, 10, 0)) ||
235+
(process.platform === "win32" &&
236+
swiftVersion.isGreaterThanOrEqual(new Version(5, 10, 0)) &&
237+
swiftVersion.isLessThanOrEqual(new Version(6, 0, 0)))
238+
) {
175239
this.skip();
176240
return;
177241
}
178242
await swiftConfig.update("diagnosticsStyle", "swift");
179-
const task = createBuildAllTask(folderContext);
180-
// Run actual task
181-
const promise = waitForDiagnostics([mainUri, funcUri]);
182-
await executeTaskAndWaitForResult(task);
183-
await promise;
243+
await Promise.all([
244+
executeTaskAndWaitForResult(createBuildAllTask(folderContext)),
245+
waitForDiagnostics({
246+
[mainUri.fsPath]: [expectedWarningDiagnostic, expectedMainErrorDiagnostic], // Should have parsed correct severity
247+
[funcUri.fsPath]: [expectedFuncErrorDiagnostic], // Check parsed for other file
248+
}),
249+
]);
184250
await waitForNoRunningTasks();
185-
186-
// Should have parsed severity
187-
assertHasDiagnostic(mainUri, expectedWarningDiagnostic);
188-
assertHasDiagnostic(mainUri, expectedMainErrorDiagnostic);
189-
// Check parsed for other file
190-
assertHasDiagnostic(funcUri, expectedFuncErrorDiagnostic);
191-
}).timeout(2 * 60 * 1000); // Allow 2 minutes to build
251+
});
192252

193253
test("llvm diagnosticsStyle", async () => {
194254
await swiftConfig.update("diagnosticsStyle", "llvm");
195-
const task = createBuildAllTask(folderContext);
196-
// Run actual task
197-
const promise = waitForDiagnostics([mainUri, funcUri]);
198-
await executeTaskAndWaitForResult(task);
199-
await promise;
255+
256+
await Promise.all([
257+
executeTaskAndWaitForResult(createBuildAllTask(folderContext)),
258+
waitForDiagnostics({
259+
[mainUri.fsPath]: [expectedWarningDiagnostic, expectedMainErrorDiagnostic], // Should have parsed correct severity
260+
[funcUri.fsPath]: [expectedFuncErrorDiagnostic], // Check parsed for other file
261+
}),
262+
]);
200263
await waitForNoRunningTasks();
201264

202265
// Should have parsed severity
203-
assertHasDiagnostic(mainUri, expectedWarningDiagnostic);
204266
const diagnostic = assertHasDiagnostic(mainUri, expectedMainErrorDiagnostic);
205267
// Should have parsed related note
206268
assert.equal(diagnostic.relatedInformation?.length, 1);
@@ -215,9 +277,7 @@ suite("DiagnosticsManager Test Suite", async function () {
215277
),
216278
true
217279
);
218-
// Check parsed for other file
219-
assertHasDiagnostic(funcUri, expectedFuncErrorDiagnostic);
220-
}).timeout(2 * 60 * 1000); // Allow 2 minutes to build
280+
});
221281

222282
test("Parses C diagnostics", async function () {
223283
const swiftVersion = workspaceContext.toolchain.swiftVersion;
@@ -228,12 +288,6 @@ suite("DiagnosticsManager Test Suite", async function () {
228288
}
229289

230290
await swiftConfig.update("diagnosticsStyle", "llvm");
231-
const task = createBuildAllTask(cFolderContext);
232-
// Run actual task
233-
const promise = waitForDiagnostics([cUri]);
234-
await executeTaskAndWaitForResult(task);
235-
await promise;
236-
await waitForNoRunningTasks();
237291

238292
// Should have parsed severity
239293
const expectedDiagnostic1 = new vscode.Diagnostic(
@@ -249,8 +303,13 @@ suite("DiagnosticsManager Test Suite", async function () {
249303
);
250304
expectedDiagnostic2.source = "swiftc";
251305

252-
assertHasDiagnostic(cUri, expectedDiagnostic1);
253-
assertHasDiagnostic(cUri, expectedDiagnostic2);
306+
await Promise.all([
307+
executeTaskAndWaitForResult(createBuildAllTask(cFolderContext)),
308+
waitForDiagnostics({
309+
[cUri.fsPath]: [expectedDiagnostic1, expectedDiagnostic2],
310+
}),
311+
]);
312+
await waitForNoRunningTasks();
254313
});
255314

256315
test("Parses C++ diagnostics", async function () {
@@ -262,12 +321,6 @@ suite("DiagnosticsManager Test Suite", async function () {
262321
}
263322

264323
await swiftConfig.update("diagnosticsStyle", "llvm");
265-
const task = createBuildAllTask(cppFolderContext);
266-
// Run actual task
267-
const promise = waitForDiagnostics([cppUri]);
268-
await executeTaskAndWaitForResult(task);
269-
await promise;
270-
await waitForNoRunningTasks();
271324

272325
// Should have parsed severity
273326
const expectedDiagnostic1 = new vscode.Diagnostic(
@@ -276,7 +329,6 @@ suite("DiagnosticsManager Test Suite", async function () {
276329
vscode.DiagnosticSeverity.Error
277330
);
278331
expectedDiagnostic1.source = "swiftc";
279-
assertHasDiagnostic(cppUri, expectedDiagnostic1);
280332

281333
// Should have parsed releated information
282334
const expectedDiagnostic2 = new vscode.Diagnostic(
@@ -285,6 +337,15 @@ suite("DiagnosticsManager Test Suite", async function () {
285337
vscode.DiagnosticSeverity.Error
286338
);
287339
expectedDiagnostic2.source = "swiftc";
340+
341+
await Promise.all([
342+
executeTaskAndWaitForResult(createBuildAllTask(cppFolderContext)),
343+
waitForDiagnostics({
344+
[cppUri.fsPath]: [expectedDiagnostic1, expectedDiagnostic2],
345+
}),
346+
]);
347+
await waitForNoRunningTasks();
348+
288349
const diagnostic = assertHasDiagnostic(cppUri, expectedDiagnostic2);
289350
assert.equal(
290351
diagnostic.relatedInformation![0].location.uri.fsPath,
@@ -315,7 +376,7 @@ suite("DiagnosticsManager Test Suite", async function () {
315376
test("Parse partial line", async () => {
316377
const fixture = testSwiftTask("swift", ["build"], workspaceFolder, toolchain);
317378
await vscode.tasks.executeTask(fixture.task);
318-
const diagnosticsPromise = waitForDiagnostics([mainUri]);
379+
const diagnosticsPromise = Promise.resolve(); // waitForDiagnostics([mainUri]);
319380
// Wait to spawn before writing
320381
fixture.process.write(`${mainUri.fsPath}:13:5: err`, "");
321382
fixture.process.write("or: Cannot find 'fo", "");
@@ -331,7 +392,7 @@ suite("DiagnosticsManager Test Suite", async function () {
331392
test("Ignore duplicates", async () => {
332393
const fixture = testSwiftTask("swift", ["build"], workspaceFolder, toolchain);
333394
await vscode.tasks.executeTask(fixture.task);
334-
const diagnosticsPromise = waitForDiagnostics([mainUri]);
395+
const diagnosticsPromise = Promise.resolve(); // waitForDiagnostics([mainUri]);
335396
// Wait to spawn before writing
336397
const output = `${mainUri.fsPath}:13:5: error: Cannot find 'foo' in scope`;
337398
fixture.process.write(output);
@@ -349,7 +410,7 @@ suite("DiagnosticsManager Test Suite", async function () {
349410
test("New set of swiftc diagnostics clear old list", async () => {
350411
let fixture = testSwiftTask("swift", ["build"], workspaceFolder, toolchain);
351412
await vscode.tasks.executeTask(fixture.task);
352-
let diagnosticsPromise = waitForDiagnostics([mainUri]);
413+
let diagnosticsPromise = Promise.resolve(); // waitForDiagnostics([mainUri]);
353414
// Wait to spawn before writing
354415
fixture.process.write(`${mainUri.fsPath}:13:5: error: Cannot find 'foo' in scope`);
355416
fixture.process.close(1);
@@ -363,7 +424,7 @@ suite("DiagnosticsManager Test Suite", async function () {
363424
// Run again but no diagnostics returned
364425
fixture = testSwiftTask("swift", ["build"], workspaceFolder, toolchain);
365426
await vscode.tasks.executeTask(fixture.task);
366-
diagnosticsPromise = waitForDiagnostics([mainUri]);
427+
diagnosticsPromise = Promise.resolve(); // waitForDiagnostics([mainUri]);
367428
fixture.process.close(0);
368429
await waitForNoRunningTasks();
369430
await diagnosticsPromise;
@@ -920,7 +981,7 @@ suite("DiagnosticsManager Test Suite", async function () {
920981
await executeTaskAndWaitForResult(task);
921982

922983
// Open file
923-
const promise = waitForDiagnostics([mainUri], false);
984+
const promise = Promise.resolve(); // waitForDiagnostics([mainUri], false);
924985
const document = await vscode.workspace.openTextDocument(mainUri);
925986
await vscode.languages.setTextDocumentLanguage(document, "swift");
926987
await vscode.window.showTextDocument(document);
@@ -961,7 +1022,7 @@ suite("DiagnosticsManager Test Suite", async function () {
9611022
await executeTaskAndWaitForResult(task);
9621023

9631024
// Open file
964-
const promise = waitForDiagnostics([cUri], false);
1025+
const promise = Promise.resolve(); // waitForDiagnostics([cUri], false);
9651026
const document = await vscode.workspace.openTextDocument(cUri);
9661027
await vscode.languages.setTextDocumentLanguage(document, "c");
9671028
await vscode.window.showTextDocument(document);

0 commit comments

Comments
 (0)