diff --git a/assets/test/defaultPackage/Package.swift b/assets/test/defaultPackage/Package.swift index 277eda1df..6ea1984f1 100644 --- a/assets/test/defaultPackage/Package.swift +++ b/assets/test/defaultPackage/Package.swift @@ -5,6 +5,11 @@ import PackageDescription let package = Package( name: "defaultPackage", + products: [ + .library( + name: "PackageLib", + targets: ["PackageLib"]), + ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. diff --git a/assets/test/defaultPackage/Package@swift-6.0.swift b/assets/test/defaultPackage/Package@swift-6.0.swift index e855e5e3e..838242e8c 100644 --- a/assets/test/defaultPackage/Package@swift-6.0.swift +++ b/assets/test/defaultPackage/Package@swift-6.0.swift @@ -8,6 +8,11 @@ let package = Package( platforms: [ .macOS(.v13) ], + products: [ + .library( + name: "PackageLib", + targets: ["PackageLib"]), + ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. diff --git a/assets/test/defaultPackage/Snippets/hello.swift b/assets/test/defaultPackage/Snippets/hello.swift new file mode 100644 index 000000000..98cb0a220 --- /dev/null +++ b/assets/test/defaultPackage/Snippets/hello.swift @@ -0,0 +1,3 @@ +import PackageLib + +print("hello \(a)") \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 76a3ee88e..b14850f46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@types/xml2js": "^0.4.14", "@typescript-eslint/eslint-plugin": "^8.16.0", "@typescript-eslint/parser": "^8.16.0", + "@vscode/debugprotocol": "^1.68.0", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^2.32.0", @@ -1359,6 +1360,12 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@vscode/debugprotocol": { + "version": "1.68.0", + "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz", + "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==", + "dev": true + }, "node_modules/@vscode/test-cli": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.10.tgz", @@ -6828,6 +6835,12 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "@vscode/debugprotocol": { + "version": "1.68.0", + "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz", + "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==", + "dev": true + }, "@vscode/test-cli": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.10.tgz", diff --git a/package.json b/package.json index 54f7e7936..0f996e748 100644 --- a/package.json +++ b/package.json @@ -1311,6 +1311,7 @@ "@types/xml2js": "^0.4.14", "@typescript-eslint/eslint-plugin": "^8.16.0", "@typescript-eslint/parser": "^8.16.0", + "@vscode/debugprotocol": "^1.68.0", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^2.32.0", diff --git a/src/SwiftSnippets.ts b/src/SwiftSnippets.ts index 0685fc434..511283c40 100644 --- a/src/SwiftSnippets.ts +++ b/src/SwiftSnippets.ts @@ -49,22 +49,22 @@ export function setSnippetContextKey(ctx: WorkspaceContext) { * If current file is a Swift Snippet run it * @param ctx Workspace Context */ -export async function runSnippet(ctx: WorkspaceContext) { - await debugSnippetWithOptions(ctx, { noDebug: true }); +export async function runSnippet(ctx: WorkspaceContext): Promise { + return await debugSnippetWithOptions(ctx, { noDebug: true }); } /** * If current file is a Swift Snippet run it in the debugger * @param ctx Workspace Context */ -export async function debugSnippet(ctx: WorkspaceContext) { - await debugSnippetWithOptions(ctx, {}); +export async function debugSnippet(ctx: WorkspaceContext): Promise { + return await debugSnippetWithOptions(ctx, {}); } export async function debugSnippetWithOptions( ctx: WorkspaceContext, options: vscode.DebugSessionOptions -) { +): Promise { const folderContext = ctx.currentFolder; if (!ctx.currentDocument || !folderContext) { return; @@ -89,7 +89,7 @@ export async function debugSnippetWithOptions( try { // queue build task and when it is complete run executable in the debugger - await folderContext.taskQueue + return await folderContext.taskQueue .queueOperation(new TaskOperation(snippetBuildTask)) .then(result => { if (result === 0) { @@ -106,5 +106,6 @@ export async function debugSnippetWithOptions( }); } catch { // ignore error if task failed to run + return; } } diff --git a/test/integration-tests/BackgroundCompilation.test.ts b/test/integration-tests/BackgroundCompilation.test.ts index 54f4d4456..90c8660a4 100644 --- a/test/integration-tests/BackgroundCompilation.test.ts +++ b/test/integration-tests/BackgroundCompilation.test.ts @@ -16,7 +16,7 @@ import * as assert from "assert"; import * as vscode from "vscode"; import { WorkspaceContext } from "../../src/WorkspaceContext"; import { testAssetUri } from "../fixtures"; -import { waitForNoRunningTasks } from "../utilities"; +import { waitForNoRunningTasks } from "../utilities/tasks"; import { Workbench } from "../../src/utilities/commands"; import { activateExtensionForTest, updateSettings } from "./utilities/testutilities"; diff --git a/test/integration-tests/DiagnosticsManager.test.ts b/test/integration-tests/DiagnosticsManager.test.ts index 03f1e82f6..a075e421c 100644 --- a/test/integration-tests/DiagnosticsManager.test.ts +++ b/test/integration-tests/DiagnosticsManager.test.ts @@ -15,7 +15,7 @@ import * as assert from "assert"; import * as vscode from "vscode"; import { SwiftToolchain } from "../../src/toolchain/toolchain"; -import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../utilities"; +import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../utilities/tasks"; import { WorkspaceContext } from "../../src/WorkspaceContext"; import { testAssetWorkspaceFolder, testSwiftTask } from "../fixtures"; import { createBuildAllTask } from "../../src/tasks/SwiftTaskProvider"; diff --git a/test/integration-tests/SwiftSnippet.test.ts b/test/integration-tests/SwiftSnippet.test.ts new file mode 100644 index 000000000..9cfbbed25 --- /dev/null +++ b/test/integration-tests/SwiftSnippet.test.ts @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the VS Code Swift open source project +// +// Copyright (c) 2024 the VS Code Swift project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of VS Code Swift project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import * as vscode from "vscode"; +import { testAssetPath, testAssetUri } from "../fixtures"; +import { waitForNoRunningTasks } from "../utilities/tasks"; +import { expect } from "chai"; +import { + continueSession, + waitForDebugAdapterRequest, + waitUntilDebugSessionTerminates, +} from "../utilities/debug"; +import { Version } from "../../src/utilities/version"; +import { activateExtensionForSuite, folderInRootWorkspace } from "./utilities/testutilities"; +import { WorkspaceContext } from "../../src/WorkspaceContext"; +import { join } from "path"; +import { closeAllEditors } from "../utilities/commands"; + +function normalizePath(...segments: string[]): string { + let path = join(...segments); + if (process.platform === "win32") { + path = path.endsWith(".exe") ? path : path + ".exe"; + path = path.replace(/\//g, "\\"); + } + return path.toLocaleLowerCase(); // Windows may use d:\ or D:\ +} + +suite("SwiftSnippet Test Suite @slow", function () { + this.timeout(120000); + + const uri = testAssetUri("defaultPackage/Snippets/hello.swift"); + const breakpoints = [ + new vscode.SourceBreakpoint(new vscode.Location(uri, new vscode.Position(2, 0))), + ]; + let workspaceContext: WorkspaceContext; + + activateExtensionForSuite({ + async setup(ctx) { + workspaceContext = ctx; + + const folder = await folderInRootWorkspace("defaultPackage", workspaceContext); + if (folder.workspaceContext.toolchain.swiftVersion.isLessThan(new Version(6, 0, 0))) { + this.skip(); + } + await waitForNoRunningTasks(); + + // File needs to be open for command to be enabled + const doc = await vscode.workspace.openTextDocument(uri.fsPath); + await vscode.window.showTextDocument(doc); + + // Set a breakpoint + vscode.debug.addBreakpoints(breakpoints); + }, + }); + + suiteTeardown(async () => { + closeAllEditors(); + vscode.debug.removeBreakpoints(breakpoints); + }); + + test("Run `Swift: Run Swift Snippet` command for snippet file", async () => { + const sessionPromise = waitUntilDebugSessionTerminates("Run hello"); + + const succeeded = await vscode.commands.executeCommand("swift.runSnippet"); + + expect(succeeded).to.be.true; + const session = await sessionPromise; + expect(normalizePath(session.configuration.program)).to.equal( + normalizePath(testAssetPath("defaultPackage"), ".build", "debug", "hello") + ); + expect(session.configuration).to.have.property("noDebug", true); + }); + + test("Run `Swift: Debug Swift Snippet` command for snippet file", async () => { + const bpPromise = waitForDebugAdapterRequest("Run hello", "stackTrace"); + const sessionPromise = waitUntilDebugSessionTerminates("Run hello"); + + const succeeded = vscode.commands.executeCommand("swift.debugSnippet"); + + // Once bp is hit, continue + await bpPromise.then(() => continueSession()); + + await expect(succeeded).to.eventually.be.true; + + const session = await sessionPromise; + expect(normalizePath(session.configuration.program)).to.equal( + normalizePath(testAssetPath("defaultPackage"), ".build", "debug", "hello") + ); + expect(session.configuration).to.not.have.property("noDebug"); + }); +}); diff --git a/test/integration-tests/commands/build.test.ts b/test/integration-tests/commands/build.test.ts index 00d45f8b1..77c47540e 100644 --- a/test/integration-tests/commands/build.test.ts +++ b/test/integration-tests/commands/build.test.ts @@ -16,14 +16,14 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; import * as path from "path"; import { expect } from "chai"; -import { waitForNoRunningTasks } from "../../utilities"; +import { waitForNoRunningTasks } from "../../utilities/tasks"; import { testAssetUri } from "../../fixtures"; import { FolderContext } from "../../../src/FolderContext"; import { WorkspaceContext } from "../../../src/WorkspaceContext"; import { Commands } from "../../../src/commands"; import { makeDebugConfigurations } from "../../../src/debugger/launch"; import { Workbench } from "../../../src/utilities/commands"; -import { continueSession, waitForDebugAdapterCommand } from "../../utilities/debug"; +import { continueSession, waitForDebugAdapterRequest } from "../../utilities/debug"; import { activateExtensionForSuite, folderInRootWorkspace, @@ -97,10 +97,9 @@ suite("Build Commands", function () { // Promise used to indicate we hit the break point. // NB: "stopped" is the exact command when debuggee has stopped due to break point, // but "stackTrace" is the deterministic sync point we will use to make sure we can execute continue - const bpPromise = waitForDebugAdapterCommand( + const bpPromise = waitForDebugAdapterRequest( "Debug PackageExe (defaultPackage)", - "stackTrace", - workspaceContext + "stackTrace" ); const result = vscode.commands.executeCommand(Commands.DEBUG); diff --git a/test/integration-tests/commands/dependency.test.ts b/test/integration-tests/commands/dependency.test.ts index b5b9ec2d3..ec8c312f2 100644 --- a/test/integration-tests/commands/dependency.test.ts +++ b/test/integration-tests/commands/dependency.test.ts @@ -18,7 +18,7 @@ import { PackageDependenciesProvider, PackageNode, } from "../../../src/ui/PackageDependencyProvider"; -import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities"; +import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities/tasks"; import { getBuildAllTask, SwiftTask } from "../../../src/tasks/SwiftTaskProvider"; import { testAssetUri } from "../../fixtures"; import { FolderContext } from "../../../src/FolderContext"; diff --git a/test/integration-tests/language/macro.test.ts b/test/integration-tests/language/macro.test.ts index ae2a47cbe..9defec831 100644 --- a/test/integration-tests/language/macro.test.ts +++ b/test/integration-tests/language/macro.test.ts @@ -19,7 +19,7 @@ import { LanguageClientManager } from "../../../src/sourcekit-lsp/LanguageClient import { WorkspaceContext } from "../../../src/WorkspaceContext"; import { testAssetUri } from "../../fixtures"; import { FolderContext } from "../../../src/FolderContext"; -import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities"; +import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities/tasks"; import { getBuildAllTask, SwiftTask } from "../../../src/tasks/SwiftTaskProvider"; import { Version } from "../../../src/utilities/version"; import { activateExtensionForSuite, folderInRootWorkspace } from "../utilities/testutilities"; diff --git a/test/integration-tests/tasks/SwiftExecution.test.ts b/test/integration-tests/tasks/SwiftExecution.test.ts index 7558a8912..a4d7867e2 100644 --- a/test/integration-tests/tasks/SwiftExecution.test.ts +++ b/test/integration-tests/tasks/SwiftExecution.test.ts @@ -16,7 +16,7 @@ import * as vscode from "vscode"; import * as assert from "assert"; import { testSwiftTask } from "../../fixtures"; import { WorkspaceContext } from "../../../src/WorkspaceContext"; -import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities"; +import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities/tasks"; import { SwiftToolchain } from "../../../src/toolchain/toolchain"; import { activateExtensionForSuite } from "../utilities/testutilities"; diff --git a/test/integration-tests/tasks/SwiftPluginTaskProvider.test.ts b/test/integration-tests/tasks/SwiftPluginTaskProvider.test.ts index 23dc46d67..38f2ef637 100644 --- a/test/integration-tests/tasks/SwiftPluginTaskProvider.test.ts +++ b/test/integration-tests/tasks/SwiftPluginTaskProvider.test.ts @@ -22,9 +22,9 @@ import { activateExtensionForSuite, folderInRootWorkspace } from "../utilities/t import { cleanOutput, executeTaskAndWaitForResult, - mutable, waitForEndTaskProcess, -} from "../../utilities"; +} from "../../utilities/tasks"; +import { mutable } from "../../utilities/types"; suite("SwiftPluginTaskProvider Test Suite", () => { let workspaceContext: WorkspaceContext; diff --git a/test/integration-tests/tasks/SwiftPseudoterminal.test.ts b/test/integration-tests/tasks/SwiftPseudoterminal.test.ts index a88863ffe..92f5a6ea9 100644 --- a/test/integration-tests/tasks/SwiftPseudoterminal.test.ts +++ b/test/integration-tests/tasks/SwiftPseudoterminal.test.ts @@ -15,7 +15,7 @@ import * as assert from "assert"; import * as vscode from "vscode"; import { TestSwiftProcess } from "../../fixtures"; -import { waitForClose, waitForWrite } from "../../utilities"; +import { waitForClose, waitForWrite } from "../../utilities/tasks"; import { SwiftPseudoterminal } from "../../../src/tasks/SwiftPseudoterminal"; suite("SwiftPseudoterminal Tests Suite", () => { diff --git a/test/integration-tests/tasks/SwiftTaskProvider.test.ts b/test/integration-tests/tasks/SwiftTaskProvider.test.ts index 291ebbefe..d28657fac 100644 --- a/test/integration-tests/tasks/SwiftTaskProvider.test.ts +++ b/test/integration-tests/tasks/SwiftTaskProvider.test.ts @@ -27,7 +27,7 @@ import { executeTaskAndWaitForResult, waitForEndTaskProcess, waitForNoRunningTasks, -} from "../../utilities"; +} from "../../utilities/tasks"; import { Version } from "../../../src/utilities/version"; import { FolderContext } from "../../../src/FolderContext"; import { mockGlobalObject } from "../../MockUtils"; diff --git a/test/integration-tests/tasks/TaskManager.test.ts b/test/integration-tests/tasks/TaskManager.test.ts index 9f6cae9b1..bb05883e7 100644 --- a/test/integration-tests/tasks/TaskManager.test.ts +++ b/test/integration-tests/tasks/TaskManager.test.ts @@ -16,8 +16,8 @@ import * as vscode from "vscode"; import * as assert from "assert"; import { TaskManager } from "../../../src/tasks/TaskManager"; import { WorkspaceContext } from "../../../src/WorkspaceContext"; -import { waitForNoRunningTasks } from "../../utilities"; import { activateExtensionForSuite } from "../utilities/testutilities"; +import { waitForNoRunningTasks } from "../../utilities/tasks"; suite("TaskManager Test Suite", () => { let workspaceContext: WorkspaceContext; diff --git a/test/integration-tests/tasks/TaskQueue.test.ts b/test/integration-tests/tasks/TaskQueue.test.ts index b80c28af6..113d3ce7a 100644 --- a/test/integration-tests/tasks/TaskQueue.test.ts +++ b/test/integration-tests/tasks/TaskQueue.test.ts @@ -17,7 +17,7 @@ import * as assert from "assert"; import { testAssetPath } from "../../fixtures"; import { WorkspaceContext } from "../../../src/WorkspaceContext"; import { SwiftExecOperation, TaskOperation, TaskQueue } from "../../../src/tasks/TaskQueue"; -import { waitForNoRunningTasks } from "../../utilities"; +import { waitForNoRunningTasks } from "../../utilities/tasks"; import { activateExtensionForSuite } from "../utilities/testutilities"; suite("TaskQueue Test Suite", () => { diff --git a/test/integration-tests/ui/PackageDependencyProvider.test.ts b/test/integration-tests/ui/PackageDependencyProvider.test.ts index bec1e9903..6eb79235b 100644 --- a/test/integration-tests/ui/PackageDependencyProvider.test.ts +++ b/test/integration-tests/ui/PackageDependencyProvider.test.ts @@ -19,7 +19,7 @@ import { PackageDependenciesProvider, PackageNode, } from "../../../src/ui/PackageDependencyProvider"; -import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities"; +import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities/tasks"; import { getBuildAllTask, SwiftTask } from "../../../src/tasks/SwiftTaskProvider"; import { testAssetPath } from "../../fixtures"; import { activateExtensionForSuite, folderInRootWorkspace } from "../utilities/testutilities"; diff --git a/test/integration-tests/utilities/testutilities.ts b/test/integration-tests/utilities/testutilities.ts index 7dbd044f1..39b19fd16 100644 --- a/test/integration-tests/utilities/testutilities.ts +++ b/test/integration-tests/utilities/testutilities.ts @@ -19,7 +19,8 @@ import { Api } from "../../../src/extension"; import { testAssetUri } from "../../fixtures"; import { WorkspaceContext } from "../../../src/WorkspaceContext"; import { FolderContext } from "../../../src/FolderContext"; -import { waitForNoRunningTasks } from "../../utilities"; +import { waitForNoRunningTasks } from "../../utilities/tasks"; +import { closeAllEditors } from "../../utilities/commands"; function getRootWorkspaceFolder(): vscode.WorkspaceFolder { const result = vscode.workspace.workspaceFolders?.at(0); @@ -175,7 +176,7 @@ const extensionBootstrapper = (() => { await waitForNoRunningTasks({ timeout: 10000 }); // Close all editors before deactivating the extension. - await vscode.commands.executeCommand("workbench.action.closeAllEditors"); + closeAllEditors(); await activatedAPI.workspaceContext?.removeWorkspaceFolder(getRootWorkspaceFolder()); await activatedAPI.deactivate(); diff --git a/test/utilities/commands.ts b/test/utilities/commands.ts new file mode 100644 index 000000000..0b52378d4 --- /dev/null +++ b/test/utilities/commands.ts @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the VS Code Swift open source project +// +// Copyright (c) 2024 the VS Code Swift project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of VS Code Swift project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import * as vscode from "vscode"; +import { Workbench } from "../../src/utilities/commands"; + +export async function closeAllEditors() { + await vscode.commands.executeCommand(Workbench.ACTION_CLOSEALLEDITORS); +} diff --git a/test/utilities/debug.ts b/test/utilities/debug.ts index 083438ab2..a1a5304b7 100644 --- a/test/utilities/debug.ts +++ b/test/utilities/debug.ts @@ -12,9 +12,8 @@ // //===----------------------------------------------------------------------===// import * as vscode from "vscode"; +import { DebugProtocol } from "@vscode/debugprotocol"; import { Workbench } from "../../src/utilities/commands"; -import { DebugAdapter } from "../../src/debugger/debugAdapter"; -import { WorkspaceContext } from "../../src/WorkspaceContext"; export async function continueSession(): Promise { await vscode.commands.executeCommand(Workbench.ACTION_DEBUG_CONTINUE); @@ -28,35 +27,47 @@ export async function continueSession(): Promise { * @param workspaceContext The workspace context containing toolchain information. * @returns A promise that resolves with the matching message. */ -export async function waitForDebugAdapterMessage( +export async function waitForDebugAdapterMessage( name: string, - matches: (message: any) => boolean, - workspaceContext: WorkspaceContext -): Promise { - return await new Promise(res => { - const disposable = vscode.debug.registerDebugAdapterTrackerFactory( - DebugAdapter.getLaunchConfigType(workspaceContext.toolchain.swiftVersion), - { - createDebugAdapterTracker: function ( - session: vscode.DebugSession - ): vscode.ProviderResult { - if (session.name !== name) { - return; - } - return { - onDidSendMessage(message) { - if (matches(message)) { - disposable.dispose(); - res(message); - } - }, - }; - }, - } - ); + matches: (message: T) => boolean +): Promise { + return await new Promise(res => { + const disposable = vscode.debug.registerDebugAdapterTrackerFactory("swift-lldb", { + createDebugAdapterTracker: function ( + session: vscode.DebugSession + ): vscode.ProviderResult { + if (session.name !== name) { + return; + } + return { + onDidSendMessage(message) { + if (matches(message)) { + disposable.dispose(); + res(message); + } + }, + }; + }, + }); }); } +/** + * Waits for a specific debug session to terminate. + * + * @param name The name of the debug session to wait for. + * @returns the terminated DebugSession + */ +export async function waitUntilDebugSessionTerminates(name: string): Promise { + return await new Promise(res => + vscode.debug.onDidTerminateDebugSession(e => { + if (e.name === name) { + res(e); + } + }) + ); +} + /** * Waits for a specific command to be sent by the debug adapter. * @@ -65,14 +76,38 @@ export async function waitForDebugAdapterMessage( * @param workspaceContext The workspace context containing toolchain information. * @returns A promise that resolves with the matching command message. */ -export async function waitForDebugAdapterCommand( +export async function waitForDebugAdapterRequest( name: string, - command: string, - workspaceContext: WorkspaceContext -): Promise { + command: string +): Promise { return await waitForDebugAdapterMessage( name, - (m: any) => m.command === command, - workspaceContext + (m: DebugProtocol.Request) => m.command === command ); } + +/** + * Waits for a specific event to be sent by the debug adapter. + * + * @param name The name of the debug session to wait for. + * @param command The command to wait for. + * @param workspaceContext The workspace context containing toolchain information. + * @returns A promise that resolves with the matching command event. + */ +export async function waitForDebugAdapterEvent( + name: string, + event: string +): Promise { + return await waitForDebugAdapterMessage(name, (m: DebugProtocol.Event) => m.event === event); +} + +/** + * Waits for a debug adapter for the specified DebugSession name to terminate. + * + * @param name The name of the debug session to wait for. + * @returns exit code of the DAP + */ +export async function waitForDebugAdapterExit(name: string): Promise { + const message = await waitForDebugAdapterEvent(name, "exited"); + return message.body.exitCode; +} diff --git a/test/utilities.ts b/test/utilities/tasks.ts similarity index 97% rename from test/utilities.ts rename to test/utilities/tasks.ts index 92ade71a4..ecdaa8cc0 100644 --- a/test/utilities.ts +++ b/test/utilities/tasks.ts @@ -15,8 +15,8 @@ import * as vscode from "vscode"; // eslint-disable-next-line @typescript-eslint/no-require-imports import stripAnsi = require("strip-ansi"); -import { SwiftTaskFixture } from "./fixtures"; -import { SwiftTask } from "../src/tasks/SwiftTaskProvider"; +import { SwiftTaskFixture } from "../fixtures"; +import { SwiftTask } from "../../src/tasks/SwiftTaskProvider"; export type Mutable = { -readonly [K in keyof T]: T[K]; diff --git a/test/utilities/types.ts b/test/utilities/types.ts new file mode 100644 index 000000000..f2547ee7c --- /dev/null +++ b/test/utilities/types.ts @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the VS Code Swift open source project +// +// Copyright (c) 2024 the VS Code Swift project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of VS Code Swift project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +export type Mutable = { + -readonly [K in keyof T]: T[K]; +}; + +export function mutable(target: T): Mutable { + return target; +}