@@ -25,27 +25,14 @@ import { Version } from "../../src/utilities/version";
2525import { folderContextPromise , globalWorkspaceContextPromise } from "./extension.test" ;
2626import { 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
5037const 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,51 @@ 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+ [ uri : string ] : vscode . Diagnostic [ ] ;
83+ } ;
84+
85+ // Wait for all the expected diagnostics to be recieved. This may happen over several `onChangeDiagnostics` events.
86+ const waitForDiagnostics = ( expectedDiagnostics : { [ uri : string ] : vscode . Diagnostic [ ] } ) => {
87+ return new Promise < void > ( resolve => {
88+ if ( diagnosticWaiterDisposable ) {
89+ console . warn (
90+ "Wait for diagnostics was called before the previous wait was resolved. Only one waitForDiagnostics should run per test."
91+ ) ;
92+ diagnosticWaiterDisposable ?. dispose ( ) ;
93+ }
94+ // Keep a lookup of diagnostics we haven't encountered yet. When all array values in
95+ // this lookup are empty then we've seen all diagnostics and we can resolve successfully.
96+ const expected = { ...expectedDiagnostics } ;
97+ diagnosticWaiterDisposable = vscode . languages . onDidChangeDiagnostics ( e => {
98+ const matchingPaths = Object . keys ( expectedDiagnostics ) . filter ( uri =>
99+ e . uris . some ( u => u . fsPath === uri )
100+ ) ;
101+ for ( const uri of matchingPaths ) {
102+ const actualDiagnostics = vscode . languages . getDiagnostics ( vscode . Uri . file ( uri ) ) ;
103+ expected [ uri ] = expected [ uri ] . filter ( expectedDiagnostic => {
104+ return ! actualDiagnostics . some ( actualDiagnostic =>
105+ isEqual ( actualDiagnostic , expectedDiagnostic )
106+ ) ;
107+ } ) ;
108+ remainingExpectedDiagnostics = expected ;
109+ }
110+
111+ const allDiagnosticsFulfilled = Object . values ( expected ) . every (
112+ diagnostics => diagnostics . length === 0
113+ ) ;
114+
115+ if ( allDiagnosticsFulfilled ) {
116+ diagnosticWaiterDisposable ?. dispose ( ) ;
117+ resolve ( ) ;
118+ }
119+ } ) ;
120+ } ) ;
121+ } ;
93122
94123 suiteSetup ( async function ( ) {
95- this . timeout ( 30000 ) ;
124+ this . timeout ( 60000 ) ;
96125
97126 workspaceContext = await globalWorkspaceContextPromise ;
98127 toolchain = workspaceContext . toolchain ;
@@ -111,6 +140,23 @@ suite("DiagnosticsManager Test Suite", async function () {
111140 ) ;
112141 } ) ;
113142
143+ teardown ( function ( ) {
144+ diagnosticWaiterDisposable ?. dispose ( ) ;
145+ const allDiagnosticsFulfilled = Object . values ( remainingExpectedDiagnostics ) . every (
146+ diagnostics => diagnostics . length === 0
147+ ) ;
148+ if ( ! allDiagnosticsFulfilled ) {
149+ const title = this . currentTest ?. fullTitle ( ) ?? "<unknown test>" ;
150+ const remainingDiagnostics = Object . entries ( remainingExpectedDiagnostics ) . filter (
151+ ( [ _uri , diagnostics ] ) => diagnostics . length > 0
152+ ) ;
153+ console . error (
154+ `${ title } - Not all diagnostics were fulfilled` ,
155+ JSON . stringify ( remainingDiagnostics , undefined , " " )
156+ ) ;
157+ }
158+ } ) ;
159+
114160 suite ( "Parse diagnostics" , async ( ) => {
115161 suite ( "Parse from task output" , async ( ) => {
116162 const expectedWarningDiagnostic = new vscode . Diagnostic (
@@ -152,21 +198,19 @@ suite("DiagnosticsManager Test Suite", async function () {
152198 await swiftConfig . update ( "diagnosticsStyle" , undefined ) ;
153199 } ) ;
154200
155- test ( "default diagnosticsStyle" , async ( ) => {
201+ test . only ( "default diagnosticsStyle" , async ( ) => {
156202 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 ( ) ;
163203
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
204+ await Promise . all ( [
205+ executeTaskAndWaitForResult ( createBuildAllTask ( folderContext ) ) ,
206+ waitForDiagnostics ( {
207+ [ mainUri . fsPath ] : [ expectedWarningDiagnostic , expectedMainErrorDiagnostic ] , // Should have parsed correct severity
208+ [ funcUri . fsPath ] : [ expectedFuncErrorDiagnostic ] , // Check parsed for other file
209+ } ) ,
210+ ] ) ;
211+
212+ await waitForNoRunningTasks ( ) ;
213+ } ) ;
170214
171215 test ( "swift diagnosticsStyle" , async function ( ) {
172216 // This is only supported in swift versions >=5.10.0
@@ -176,31 +220,29 @@ suite("DiagnosticsManager Test Suite", async function () {
176220 return ;
177221 }
178222 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 ;
223+ await Promise . all ( [
224+ executeTaskAndWaitForResult ( createBuildAllTask ( folderContext ) ) ,
225+ waitForDiagnostics ( {
226+ [ mainUri . fsPath ] : [ expectedWarningDiagnostic , expectedMainErrorDiagnostic ] , // Should have parsed correct severity
227+ [ funcUri . fsPath ] : [ expectedFuncErrorDiagnostic ] , // Check parsed for other file
228+ } ) ,
229+ ] ) ;
184230 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
231+ } ) ;
192232
193233 test ( "llvm diagnosticsStyle" , async ( ) => {
194234 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 ;
235+
236+ await Promise . all ( [
237+ executeTaskAndWaitForResult ( createBuildAllTask ( folderContext ) ) ,
238+ waitForDiagnostics ( {
239+ [ mainUri . fsPath ] : [ expectedWarningDiagnostic , expectedMainErrorDiagnostic ] , // Should have parsed correct severity
240+ [ funcUri . fsPath ] : [ expectedFuncErrorDiagnostic ] , // Check parsed for other file
241+ } ) ,
242+ ] ) ;
200243 await waitForNoRunningTasks ( ) ;
201244
202245 // Should have parsed severity
203- assertHasDiagnostic ( mainUri , expectedWarningDiagnostic ) ;
204246 const diagnostic = assertHasDiagnostic ( mainUri , expectedMainErrorDiagnostic ) ;
205247 // Should have parsed related note
206248 assert . equal ( diagnostic . relatedInformation ?. length , 1 ) ;
@@ -215,9 +257,7 @@ suite("DiagnosticsManager Test Suite", async function () {
215257 ) ,
216258 true
217259 ) ;
218- // Check parsed for other file
219- assertHasDiagnostic ( funcUri , expectedFuncErrorDiagnostic ) ;
220- } ) . timeout ( 2 * 60 * 1000 ) ; // Allow 2 minutes to build
260+ } ) ;
221261
222262 test ( "Parses C diagnostics" , async function ( ) {
223263 const swiftVersion = workspaceContext . toolchain . swiftVersion ;
@@ -228,12 +268,6 @@ suite("DiagnosticsManager Test Suite", async function () {
228268 }
229269
230270 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 ( ) ;
237271
238272 // Should have parsed severity
239273 const expectedDiagnostic1 = new vscode . Diagnostic (
@@ -249,8 +283,13 @@ suite("DiagnosticsManager Test Suite", async function () {
249283 ) ;
250284 expectedDiagnostic2 . source = "swiftc" ;
251285
252- assertHasDiagnostic ( cUri , expectedDiagnostic1 ) ;
253- assertHasDiagnostic ( cUri , expectedDiagnostic2 ) ;
286+ await Promise . all ( [
287+ executeTaskAndWaitForResult ( createBuildAllTask ( cFolderContext ) ) ,
288+ waitForDiagnostics ( {
289+ [ cUri . fsPath ] : [ expectedDiagnostic1 , expectedDiagnostic2 ] ,
290+ } ) ,
291+ ] ) ;
292+ await waitForNoRunningTasks ( ) ;
254293 } ) ;
255294
256295 test ( "Parses C++ diagnostics" , async function ( ) {
@@ -262,12 +301,6 @@ suite("DiagnosticsManager Test Suite", async function () {
262301 }
263302
264303 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 ( ) ;
271304
272305 // Should have parsed severity
273306 const expectedDiagnostic1 = new vscode . Diagnostic (
@@ -276,7 +309,6 @@ suite("DiagnosticsManager Test Suite", async function () {
276309 vscode . DiagnosticSeverity . Error
277310 ) ;
278311 expectedDiagnostic1 . source = "swiftc" ;
279- assertHasDiagnostic ( cppUri , expectedDiagnostic1 ) ;
280312
281313 // Should have parsed releated information
282314 const expectedDiagnostic2 = new vscode . Diagnostic (
@@ -285,6 +317,15 @@ suite("DiagnosticsManager Test Suite", async function () {
285317 vscode . DiagnosticSeverity . Error
286318 ) ;
287319 expectedDiagnostic2 . source = "swiftc" ;
320+
321+ await Promise . all ( [
322+ executeTaskAndWaitForResult ( createBuildAllTask ( cppFolderContext ) ) ,
323+ waitForDiagnostics ( {
324+ [ cppUri . fsPath ] : [ expectedDiagnostic1 , expectedDiagnostic2 ] ,
325+ } ) ,
326+ ] ) ;
327+ await waitForNoRunningTasks ( ) ;
328+
288329 const diagnostic = assertHasDiagnostic ( cppUri , expectedDiagnostic2 ) ;
289330 assert . equal (
290331 diagnostic . relatedInformation ! [ 0 ] . location . uri . fsPath ,
@@ -315,7 +356,7 @@ suite("DiagnosticsManager Test Suite", async function () {
315356 test ( "Parse partial line" , async ( ) => {
316357 const fixture = testSwiftTask ( "swift" , [ "build" ] , workspaceFolder , toolchain ) ;
317358 await vscode . tasks . executeTask ( fixture . task ) ;
318- const diagnosticsPromise = waitForDiagnostics ( [ mainUri ] ) ;
359+ const diagnosticsPromise = Promise . resolve ( ) ; // waitForDiagnostics([mainUri]);
319360 // Wait to spawn before writing
320361 fixture . process . write ( `${ mainUri . fsPath } :13:5: err` , "" ) ;
321362 fixture . process . write ( "or: Cannot find 'fo" , "" ) ;
@@ -331,7 +372,7 @@ suite("DiagnosticsManager Test Suite", async function () {
331372 test ( "Ignore duplicates" , async ( ) => {
332373 const fixture = testSwiftTask ( "swift" , [ "build" ] , workspaceFolder , toolchain ) ;
333374 await vscode . tasks . executeTask ( fixture . task ) ;
334- const diagnosticsPromise = waitForDiagnostics ( [ mainUri ] ) ;
375+ const diagnosticsPromise = Promise . resolve ( ) ; // waitForDiagnostics([mainUri]);
335376 // Wait to spawn before writing
336377 const output = `${ mainUri . fsPath } :13:5: error: Cannot find 'foo' in scope` ;
337378 fixture . process . write ( output ) ;
@@ -349,7 +390,7 @@ suite("DiagnosticsManager Test Suite", async function () {
349390 test ( "New set of swiftc diagnostics clear old list" , async ( ) => {
350391 let fixture = testSwiftTask ( "swift" , [ "build" ] , workspaceFolder , toolchain ) ;
351392 await vscode . tasks . executeTask ( fixture . task ) ;
352- let diagnosticsPromise = waitForDiagnostics ( [ mainUri ] ) ;
393+ let diagnosticsPromise = Promise . resolve ( ) ; // waitForDiagnostics([mainUri]);
353394 // Wait to spawn before writing
354395 fixture . process . write ( `${ mainUri . fsPath } :13:5: error: Cannot find 'foo' in scope` ) ;
355396 fixture . process . close ( 1 ) ;
@@ -363,7 +404,7 @@ suite("DiagnosticsManager Test Suite", async function () {
363404 // Run again but no diagnostics returned
364405 fixture = testSwiftTask ( "swift" , [ "build" ] , workspaceFolder , toolchain ) ;
365406 await vscode . tasks . executeTask ( fixture . task ) ;
366- diagnosticsPromise = waitForDiagnostics ( [ mainUri ] ) ;
407+ diagnosticsPromise = Promise . resolve ( ) ; // waitForDiagnostics([mainUri]);
367408 fixture . process . close ( 0 ) ;
368409 await waitForNoRunningTasks ( ) ;
369410 await diagnosticsPromise ;
@@ -920,7 +961,7 @@ suite("DiagnosticsManager Test Suite", async function () {
920961 await executeTaskAndWaitForResult ( task ) ;
921962
922963 // Open file
923- const promise = waitForDiagnostics ( [ mainUri ] , false ) ;
964+ const promise = Promise . resolve ( ) ; // waitForDiagnostics([mainUri], false);
924965 const document = await vscode . workspace . openTextDocument ( mainUri ) ;
925966 await vscode . languages . setTextDocumentLanguage ( document , "swift" ) ;
926967 await vscode . window . showTextDocument ( document ) ;
@@ -961,7 +1002,7 @@ suite("DiagnosticsManager Test Suite", async function () {
9611002 await executeTaskAndWaitForResult ( task ) ;
9621003
9631004 // Open file
964- const promise = waitForDiagnostics ( [ cUri ] , false ) ;
1005+ const promise = Promise . resolve ( ) ; // waitForDiagnostics([cUri], false);
9651006 const document = await vscode . workspace . openTextDocument ( cUri ) ;
9661007 await vscode . languages . setTextDocumentLanguage ( document , "c" ) ;
9671008 await vscode . window . showTextDocument ( document ) ;
0 commit comments