Skip to content

Commit 83fdec0

Browse files
authored
Add tests for swift-plugin tasks (swiftlang#1095)
* Wrote mostly unit tests for resolveTask and provideTasks * Wrote some integration tests to make sure the vscode task APIs like fetchTasks and executeTasks work with these tasks * Make sure can run a plugin task provided by the extension or resolved from the tasks.json Issue: swiftlang#1038
1 parent 285df87 commit 83fdec0

File tree

7 files changed

+435
-3
lines changed

7 files changed

+435
-3
lines changed

assets/test/.vscode/tasks.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@
2929
"group": "build",
3030
"label": "swift: Build All from tasks.json",
3131
"detail": "swift build --show-bin-path"
32+
},
33+
{
34+
"type": "swift-plugin",
35+
"command": "command_plugin",
36+
"args": ["--foo"],
37+
"cwd": "command-plugin",
38+
"problemMatcher": [
39+
"$swiftc"
40+
],
41+
"label": "swift: command-plugin from tasks.json",
42+
"detail": "swift package command_plugin --foo"
3243
}
3344
]
3445
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// swift-tools-version: 5.6
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "command-plugin",
8+
products: [
9+
// Products can be used to vend plugins, making them visible to other packages.
10+
.plugin(
11+
name: "command-plugin",
12+
targets: ["command-plugin"]),
13+
],
14+
targets: [
15+
// Targets are the basic building blocks of a package, defining a module or a test suite.
16+
// Targets can depend on other targets in this package and products from dependencies.
17+
.plugin(
18+
name: "command-plugin",
19+
capability: .command(intent: .custom(
20+
verb: "command_plugin",
21+
description: "prints hello world"
22+
))
23+
),
24+
]
25+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import PackagePlugin
2+
3+
@main
4+
struct command_plugin: CommandPlugin {
5+
// Entry point for command plugins applied to Swift Packages.
6+
func performCommand(context: PluginContext, arguments: [String]) async throws {
7+
print("Hello, World!")
8+
}
9+
}
10+
11+
#if canImport(XcodeProjectPlugin)
12+
import XcodeProjectPlugin
13+
14+
extension command_plugin: XcodeCommandPlugin {
15+
// Entry point for command plugins applied to Xcode projects.
16+
func performCommand(context: XcodePluginContext, arguments: [String]) throws {
17+
print("Hello, World!")
18+
}
19+
}
20+
21+
#endif

src/FolderContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export class FolderContext implements vscode.Disposable {
131131
/** Load Swift Plugins and store in Package */
132132
async loadSwiftPlugins() {
133133
const plugins = await SwiftPackage.loadPlugins(
134-
this.workspaceFolder.uri,
134+
this.folder,
135135
this.workspaceContext.toolchain
136136
);
137137
this.swiftPackage.plugins = plugins;

src/tasks/SwiftPluginTaskProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import configuration from "../configuration";
2020
import { swiftRuntimeEnv } from "../utilities/utilities";
2121
import { SwiftExecution } from "../tasks/SwiftExecution";
2222
import { resolveTaskCwd } from "../utilities/tasks";
23+
import { SwiftTask } from "./SwiftTaskProvider";
2324

2425
// Interface class for defining task configuration
2526
interface TaskConfig {
@@ -113,7 +114,7 @@ export class SwiftPluginTaskProvider implements vscode.TaskProvider {
113114
* @param config
114115
* @returns
115116
*/
116-
createSwiftPluginTask(plugin: PackagePlugin, config: TaskConfig): vscode.Task {
117+
createSwiftPluginTask(plugin: PackagePlugin, config: TaskConfig): SwiftTask {
117118
const swift = this.workspaceContext.toolchain.getToolchainExecutable("swift");
118119

119120
// Add relative path current working directory
@@ -155,7 +156,7 @@ export class SwiftPluginTaskProvider implements vscode.TaskProvider {
155156
}
156157
task.detail = `${prefix}swift ${swiftArgs.join(" ")}`;
157158
task.presentationOptions = presentation;
158-
return task;
159+
return task as SwiftTask;
159160
}
160161

161162
/**
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the VS Code Swift open source project
4+
//
5+
// Copyright (c) 2024 the VS Code Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of VS Code Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import * as vscode from "vscode";
16+
import * as assert from "assert";
17+
import { WorkspaceContext } from "../../../src/WorkspaceContext";
18+
import { folderContextPromise, globalWorkspaceContextPromise } from "../extension.test";
19+
import { SwiftPluginTaskProvider } from "../../../src/tasks/SwiftPluginTaskProvider";
20+
import { FolderContext } from "../../../src/FolderContext";
21+
import { executeTaskAndWaitForResult, mutable, waitForEndTaskProcess } from "../../utilities";
22+
23+
suite("SwiftPluginTaskProvider Test Suite", () => {
24+
let workspaceContext: WorkspaceContext;
25+
let folderContext: FolderContext;
26+
27+
suiteSetup(async () => {
28+
workspaceContext = await globalWorkspaceContextPromise;
29+
folderContext = await folderContextPromise("command-plugin");
30+
assert.notEqual(workspaceContext.folders.length, 0);
31+
await folderContext.loadSwiftPlugins();
32+
assert.notEqual(folderContext.swiftPackage.plugins.length, 0);
33+
});
34+
35+
suite("createSwiftPluginTask", () => {
36+
let taskProvider: SwiftPluginTaskProvider;
37+
38+
setup(() => {
39+
taskProvider = new SwiftPluginTaskProvider(workspaceContext);
40+
});
41+
42+
test("Exit code on success", async () => {
43+
const task = taskProvider.createSwiftPluginTask(folderContext.swiftPackage.plugins[0], {
44+
cwd: folderContext.folder,
45+
scope: folderContext.workspaceFolder,
46+
});
47+
const { exitCode, output } = await executeTaskAndWaitForResult(task);
48+
assert.equal(exitCode, 0);
49+
assert.equal(output.trim(), "Hello, World!");
50+
}).timeout(10000);
51+
52+
test("Exit code on failure", async () => {
53+
const task = taskProvider.createSwiftPluginTask(
54+
{
55+
command: "not_a_command",
56+
name: "not_a_command",
57+
package: "command-plugin",
58+
},
59+
{
60+
cwd: folderContext.folder,
61+
scope: folderContext.workspaceFolder,
62+
}
63+
);
64+
mutable(task.execution).command = "/definitely/not/swift";
65+
const { exitCode } = await executeTaskAndWaitForResult(task);
66+
assert.notEqual(exitCode, 0);
67+
}).timeout(10000);
68+
});
69+
70+
suite("provideTasks", () => {
71+
suite("includes command plugin provided by the extension", async () => {
72+
let task: vscode.Task | undefined;
73+
74+
setup(async () => {
75+
const tasks = await vscode.tasks.fetchTasks({ type: "swift-plugin" });
76+
task = tasks.find(t => t.name === "command-plugin");
77+
});
78+
79+
test("provides", () => {
80+
assert.equal(task?.detail, "swift package command_plugin");
81+
});
82+
83+
test("executes", async () => {
84+
assert(task);
85+
const exitPromise = waitForEndTaskProcess(task);
86+
await vscode.tasks.executeTask(task);
87+
const exitCode = await exitPromise;
88+
assert.equal(exitCode, 0);
89+
}).timeout(30000); // 30 seconds to run
90+
});
91+
92+
suite("includes command plugin provided by tasks.json", async () => {
93+
let task: vscode.Task | undefined;
94+
95+
setup(async () => {
96+
const tasks = await vscode.tasks.fetchTasks({ type: "swift-plugin" });
97+
task = tasks.find(t => t.name === "swift: command-plugin from tasks.json");
98+
});
99+
100+
test("provides", () => {
101+
assert.equal(task?.detail, "swift package command_plugin --foo");
102+
});
103+
104+
test("executes", async () => {
105+
assert(task);
106+
const exitPromise = waitForEndTaskProcess(task);
107+
await vscode.tasks.executeTask(task);
108+
const exitCode = await exitPromise;
109+
assert.equal(exitCode, 0);
110+
}).timeout(30000); // 30 seconds to run
111+
});
112+
});
113+
});

0 commit comments

Comments
 (0)