@@ -24,7 +24,6 @@ interface TrackerState {
2424 stoppedEventReceived : boolean ;
2525 exitedEventReceived : boolean ;
2626 exitedBeforeStop : boolean ;
27- actualExitCode ?: number ;
2827}
2928
3029interface TrackerController {
@@ -59,7 +58,8 @@ async function setWindowsBuildEnvironment(): Promise<void> {
5958 } , 1000 ) ;
6059 await promise ;
6160 clearInterval ( timer ) ;
62- assert . strictEqual ( util . hasMsvcEnvironment ( ) , true , 'MSVC environment not set correctly.' ) ;
61+ const missingVars = util . getMissingMsvcEnvironmentVariables ( ) ;
62+ assert . strictEqual ( missingVars . length , 0 , `MSVC environment missing: ${ missingVars . join ( ', ' ) } ` ) ;
6363}
6464
6565async function compileProgram ( workspacePath : string , sourcePath : string , outputPath : string ) : Promise < void > {
@@ -86,11 +86,11 @@ async function compileProgram(workspacePath: string, sourcePath: string, outputP
8686 assert . fail ( `Unsupported test platform: ${ process . platform } ` ) ;
8787}
8888
89- async function createBreakpointAtReturnStatement ( sourceUri : vscode . Uri ) : Promise < vscode . SourceBreakpoint > {
89+ async function createBreakpointAtResultWriteStatement ( sourceUri : vscode . Uri ) : Promise < vscode . SourceBreakpoint > {
9090 const document = await vscode . workspace . openTextDocument ( sourceUri ) ;
91- const returnLine = document . getText ( ) . split ( / \r ? \n / ) . findIndex ( ( line ) => line . includes ( 'return 37;' ) ) ;
92- assert . notStrictEqual ( returnLine , - 1 , 'Unable to find expected return statement for breakpoint placement.' ) ;
93- const breakpoint = new vscode . SourceBreakpoint ( new vscode . Location ( sourceUri , new vscode . Position ( returnLine , 0 ) ) , true ) ;
91+ const resultWriteLine = document . getText ( ) . split ( / \r ? \n / ) . findIndex ( ( line ) => line . includes ( 'resultFile << 37;' ) ) ;
92+ assert . notStrictEqual ( resultWriteLine , - 1 , 'Unable to find expected result-write statement for breakpoint placement.' ) ;
93+ const breakpoint = new vscode . SourceBreakpoint ( new vscode . Location ( sourceUri , new vscode . Position ( resultWriteLine , 0 ) ) , true ) ;
9494 vscode . debug . addBreakpoints ( [ breakpoint ] ) ;
9595 return breakpoint ;
9696}
@@ -106,7 +106,7 @@ function createSessionTerminatedPromise(sessionName: string): Promise<void> {
106106 } ) ;
107107}
108108
109- function createTracker ( debugType : string , sessionName : string , programName : string , timeoutMs : number , timeoutMessage : string ) : TrackerController {
109+ function createTracker ( debugType : string , sessionName : string , timeoutMs : number , timeoutMessage : string ) : TrackerController {
110110 const state : TrackerState = {
111111 setBreakpointsRequestReceived : false ,
112112 stoppedEventReceived : false ,
@@ -150,37 +150,8 @@ function createTracker(debugType: string, sessionName: string, programName: stri
150150 resolve ( 'stopped' ) ;
151151 }
152152
153- // integratedTerminal scenarios may not send an 'exited' event if the terminal does not support shell integration.
154- // We have to close the terminal with the exit code to get the result.
155- if ( message . event === 'terminated' && ! state . exitedEventReceived ) {
153+ if ( ( message . event === 'terminated' || message . event === 'exited' ) && ! state . exitedEventReceived ) {
156154 state . exitedEventReceived = true ;
157- const disp = vscode . window . onDidCloseTerminal ( ( terminal ) => {
158- if ( terminal . name === programName ) {
159- state . exitedEventReceived = true ;
160- state . actualExitCode = terminal . exitStatus ?. code ;
161- if ( ! state . stoppedEventReceived ) {
162- state . exitedBeforeStop = true ;
163- }
164- if ( timeoutHandle ) {
165- clearTimeout ( timeoutHandle ) ;
166- timeoutHandle = undefined ;
167- }
168- disp . dispose ( ) ;
169- resolve ( 'exited' ) ;
170- }
171- } ) ;
172-
173- vscode . window . terminals . forEach ( ( terminal ) => {
174- if ( terminal . name === programName ) {
175- const exitCommand = isWindows ? 'exit /b %ErrorLevel%' : 'exit $?' ;
176- terminal . sendText ( exitCommand ) ;
177- }
178- } ) ;
179- }
180-
181- if ( message . event === 'exited' ) {
182- state . exitedEventReceived = true ;
183- state . actualExitCode = message . body ?. exitCode ;
184155 if ( ! state . stoppedEventReceived ) {
185156 state . exitedBeforeStop = true ;
186157 }
@@ -210,6 +181,32 @@ function createTracker(debugType: string, sessionName: string, programName: stri
210181 } ;
211182}
212183
184+ async function waitForResultFileValue ( filePath : string , timeoutMs : number ) : Promise < number > {
185+ const deadline = Date . now ( ) + timeoutMs ;
186+ let lastContents = '' ;
187+
188+ while ( Date . now ( ) < deadline ) {
189+ try {
190+ lastContents = await util . readFileText ( filePath , 'utf8' ) ;
191+ const trimmedContents = lastContents . trim ( ) ;
192+ if ( trimmedContents . length > 0 ) {
193+ const value = Number . parseInt ( trimmedContents , 10 ) ;
194+ if ( ! Number . isNaN ( value ) ) {
195+ return value ;
196+ }
197+ }
198+ } catch ( error ) {
199+ if ( ( error as NodeJS . ErrnoException ) . code !== 'ENOENT' ) {
200+ throw error ;
201+ }
202+ }
203+
204+ await new Promise < void > ( resolve => setTimeout ( resolve , 100 ) ) ;
205+ }
206+
207+ assert . fail ( `Timed out waiting for numeric result in ${ filePath } . Last contents: ${ lastContents } ` ) ;
208+ }
209+
213210suite ( 'Run Without Debugging Integration Test' , function ( ) : void {
214211 suiteSetup ( async function ( ) : Promise < void > {
215212 const extension : vscode . Extension < any > = vscode . extensions . getExtension ( 'ms-vscode.cpptools' ) || assert . fail ( 'Extension not found' ) ;
@@ -224,21 +221,23 @@ suite('Run Without Debugging Integration Test', function (): void {
224221 }
225222 } ) ;
226223
227- test ( 'Run Without Debugging should not break on breakpoints and emit expected exit code ' , async ( ) => {
228- const expectedExitCode = 37 ;
224+ test ( 'Run Without Debugging should not break on breakpoints and write the expected result file ' , async ( ) => {
225+ const expectedResultValue = 37 ;
229226 const workspaceFolder = vscode . workspace . workspaceFolders ?. [ 0 ] ?? assert . fail ( 'No workspace folder available' ) ;
230227 const workspacePath = workspaceFolder . uri . fsPath ;
231- const sourceFile = path . join ( workspacePath , 'exitCode .cpp' ) ;
228+ const sourceFile = path . join ( workspacePath , 'debugTest .cpp' ) ;
232229 const sourceUri = vscode . Uri . file ( sourceFile ) ;
233- const executableName = isWindows ? 'exitCodeProgram.exe' : 'exitCodeProgram' ;
230+ const resultFilePath = path . join ( workspacePath , 'runWithoutDebuggingResult.txt' ) ;
231+ const executableName = isWindows ? 'debugTestProgram.exe' : 'debugTestProgram' ;
234232 const executablePath = path . join ( workspacePath , executableName ) ;
235- const sessionName = 'Run Without Debugging Exit Code ' ;
233+ const sessionName = 'Run Without Debugging Result File ' ;
236234 const debugType = isWindows ? 'cppvsdbg' : 'cppdbg' ;
237235
236+ await util . deleteFile ( resultFilePath ) ;
238237 await compileProgram ( workspacePath , sourceFile , executablePath ) ;
239238
240- const breakpoint = await createBreakpointAtReturnStatement ( sourceUri ) ;
241- const tracker = createTracker ( debugType , sessionName , executablePath , 30000 , 'Timed out waiting for debugger event.' ) ;
239+ const breakpoint = await createBreakpointAtResultWriteStatement ( sourceUri ) ;
240+ const tracker = createTracker ( debugType , sessionName , 30000 , 'Timed out waiting for debugger event.' ) ;
242241 const debugSessionTerminated = createSessionTerminatedPromise ( sessionName ) ;
243242
244243 try {
@@ -260,34 +259,37 @@ suite('Run Without Debugging Integration Test', function (): void {
260259
261260 const lastEvent = await tracker . lastEvent ;
262261 await debugSessionTerminated ;
262+ const actualResultValue = await waitForResultFileValue ( resultFilePath , 10000 ) ;
263263
264264 assert . strictEqual ( lastEvent , 'exited' , 'No-debug launch should exit rather than stop on a breakpoint.' ) ;
265265 assert . strictEqual ( tracker . state . setBreakpointsRequestReceived , false , 'a "no debug" session should not send setBreakpoints requests.' ) ;
266266 assert . strictEqual ( tracker . state . stoppedEventReceived , false , 'a "no debug" session should not emit stopped events.' ) ;
267- assert . strictEqual ( tracker . state . actualExitCode , expectedExitCode , 'Unexpected exit code from run without debugging launch.' ) ;
267+ assert . strictEqual ( actualResultValue , expectedResultValue , 'Unexpected result value from run without debugging launch.' ) ;
268268 } finally {
269269 tracker . dispose ( ) ;
270270 vscode . debug . removeBreakpoints ( [ breakpoint ] ) ;
271+ await util . deleteFile ( resultFilePath ) ;
271272 }
272273 } ) ;
273274
274275 test ( 'Debug launch should bind and stop at the breakpoint' , async ( ) => {
275276 const workspaceFolder = vscode . workspace . workspaceFolders ?. [ 0 ] ?? assert . fail ( 'No workspace folder available' ) ;
276277 const workspacePath = workspaceFolder . uri . fsPath ;
277- const sourceFile = path . join ( workspacePath , 'exitCode .cpp' ) ;
278+ const sourceFile = path . join ( workspacePath , 'debugTest .cpp' ) ;
278279 const sourceUri = vscode . Uri . file ( sourceFile ) ;
279- const executableName = isWindows ? 'exitCodeProgram.exe' : 'exitCodeProgram' ;
280+ const resultFilePath = path . join ( workspacePath , 'runWithoutDebuggingResult.txt' ) ;
281+ const executableName = isWindows ? 'debugTestProgram.exe' : 'debugTestProgram' ;
280282 const executablePath = path . join ( workspacePath , executableName ) ;
281283 const sessionName = 'Debug Launch Breakpoint Stop' ;
282284 const debugType = isWindows ? 'cppvsdbg' : 'cppdbg' ;
283285 const miMode = isMacOS ? 'lldb' : 'gdb' ;
284286
285287 await compileProgram ( workspacePath , sourceFile , executablePath ) ;
286288
287- const breakpoint = await createBreakpointAtReturnStatement ( sourceUri ) ;
289+ const breakpoint = await createBreakpointAtResultWriteStatement ( sourceUri ) ;
288290
289291 let launchedSession : vscode . DebugSession | undefined ;
290- const tracker = createTracker ( debugType , sessionName , executablePath , 45000 , 'Timed out waiting for debugger event in normal debug mode.' ) ;
292+ const tracker = createTracker ( debugType , sessionName , 45000 , 'Timed out waiting for debugger event in normal debug mode.' ) ;
291293
292294 const startedSubscription = vscode . debug . onDidStartDebugSession ( ( session ) => {
293295 if ( session . name === sessionName ) {
@@ -331,6 +333,7 @@ suite('Run Without Debugging Integration Test', function (): void {
331333 startedSubscription . dispose ( ) ;
332334 tracker . dispose ( ) ;
333335 vscode . debug . removeBreakpoints ( [ breakpoint ] ) ;
336+ await util . deleteFile ( resultFilePath ) ;
334337 }
335338 } ) ;
336339} ) ;
0 commit comments