diff --git a/src/TestExplorer/TestRunner.ts b/src/TestExplorer/TestRunner.ts index e6cccbd15..6309dcdaf 100644 --- a/src/TestExplorer/TestRunner.ts +++ b/src/TestExplorer/TestRunner.ts @@ -449,6 +449,8 @@ export class TestRunner { private testArgs: TestRunArguments; private xcTestOutputParser: IXCTestOutputParser; private swiftTestOutputParser: SwiftTestingOutputParser; + private debugSessionTerminatedEmitter = new vscode.EventEmitter(); + public onDebugSessionTerminated: vscode.Event; private static CANCELLATION_ERROR = "Test run cancelled."; /** @@ -487,6 +489,7 @@ export class TestRunner { this.testRun.addParameterizedTestCase, this.testRun.addAttachment ); + this.onDebugSessionTerminated = this.debugSessionTerminatedEmitter.event; } /** @@ -1158,8 +1161,13 @@ export class TestRunner { LoggingDebugAdapterTracker.setDebugSessionCallback( session, this.workspaceContext.logger, - output => { - outputHandler(output); + output => outputHandler(output), + exitCode => { + // Debug session is stopped with exitCode 9 (SIGKILL) + // when the user terminates it manually. + if (exitCode === 9) { + this.debugSessionTerminatedEmitter.fire(); + } } ); diff --git a/src/commands/testMultipleTimes.ts b/src/commands/testMultipleTimes.ts index a6f3dad99..9986e0638 100644 --- a/src/commands/testMultipleTimes.ts +++ b/src/commands/testMultipleTimes.ts @@ -59,6 +59,10 @@ export async function runTestMultipleTimes( token.token ); + // If the user terminates a debugging session we want + // to cancel the remaining iterations. + const terminationListener = runner.onDebugSessionTerminated(() => token.cancel()); + testExplorer.onDidCreateTestRunEmitter.fire(runner.testRun); const testRunState = new TestRunnerTestRunState(runner.testRun); @@ -91,6 +95,7 @@ export async function runTestMultipleTimes( } } await runner.testRun.end(); + terminationListener.dispose(); return runStates; } diff --git a/src/debugger/logTracker.ts b/src/debugger/logTracker.ts index df6004c96..548bf3649 100644 --- a/src/debugger/logTracker.ts +++ b/src/debugger/logTracker.ts @@ -30,6 +30,7 @@ export class LoggingDebugAdapterTrackerFactory implements vscode.DebugAdapterTra interface OutputEventBody { category: string; output: string; + exitCode: number | undefined; } interface DebugMessage { @@ -68,7 +69,9 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { private static debugSessionIdMap: { [id: string]: LoggingDebugAdapterTracker } = {}; private cb?: (output: string) => void; + private exitHandler?: (exitCode: number) => void; private output: string[] = []; + private exitCode: number | undefined; constructor(public id: string) { LoggingDebugAdapterTracker.debugSessionIdMap[id] = this; @@ -77,41 +80,54 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { static setDebugSessionCallback( session: vscode.DebugSession, logger: SwiftLogger, - cb: (log: string) => void + cb: (log: string) => void, + exitHandler: (exitCode: number) => void ) { const loggingDebugAdapter = this.debugSessionIdMap[session.id]; if (loggingDebugAdapter) { - loggingDebugAdapter.cb = cb; + loggingDebugAdapter.setCallbacks(cb, exitHandler); for (const o of loggingDebugAdapter.output) { cb(o); } + if (loggingDebugAdapter.exitCode) { + exitHandler(loggingDebugAdapter.exitCode); + } loggingDebugAdapter.output = []; + loggingDebugAdapter.exitCode = undefined; } else { logger.error("Could not find debug adapter for session: " + session.id); } } + setCallbacks(handleOutput: (output: string) => void, handleExit: (exitCode: number) => void) { + this.cb = handleOutput; + this.exitHandler = handleExit; + } + /** * The debug adapter has sent a Debug Adapter Protocol message to the editor. Check * it is a output message and is not being sent to the console */ onDidSendMessage(message: unknown): void { const debugMessage = message as DebugMessage; - if ( - !( - debugMessage && - debugMessage.type === "event" && - debugMessage.event === "output" && - debugMessage.body.category !== "console" - ) - ) { + if (!debugMessage) { return; } - const output = debugMessage.body.output; - if (this.cb) { - this.cb(output); - } else { - this.output.push(output); + + if (debugMessage.event === "exited" && debugMessage.body.exitCode) { + this.exitCode = debugMessage.body.exitCode; + this.exitHandler?.(debugMessage.body.exitCode); + } else if ( + debugMessage.type === "event" && + debugMessage.event === "output" && + debugMessage.body.category !== "console" + ) { + const output = debugMessage.body.output; + if (this.cb) { + this.cb(output); + } else { + this.output.push(output); + } } } @@ -119,7 +135,7 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker { * The debug adapter session is about to be stopped. Delete the session from * the tracker */ - onWillStopSession?(): void { + onWillStopSession(): void { delete LoggingDebugAdapterTracker.debugSessionIdMap[this.id]; } }