Skip to content

Commit 3398bd2

Browse files
authored
Fix macro expansion test (#1301)
* Fix macro expansion test Wait for document to be indexed before proceeding Issue: #1286 * Catch unexpected errors * Use _pollIndex request * Some cleanup
1 parent 182a0d7 commit 3398bd2

File tree

3 files changed

+105
-22
lines changed

3 files changed

+105
-22
lines changed

assets/test/swift-macro/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ let package = Package(
1919
),
2020
],
2121
dependencies: [
22-
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0-latest"),
22+
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.1"),
2323
],
2424
targets: [
2525
// Targets are the basic building blocks of a package, defining a module or a test suite.

test/integration-tests/language/LanguageClientIntegration.test.ts

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,51 +22,45 @@ import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilit
2222
import { getBuildAllTask, SwiftTask } from "../../../src/tasks/SwiftTaskProvider";
2323
import { Version } from "../../../src/utilities/version";
2424
import { activateExtensionForSuite, folderInRootWorkspace } from "../utilities/testutilities";
25-
26-
async function waitForClientState(
27-
languageClientManager: LanguageClientManager,
28-
expectedState: langclient.State
29-
): Promise<langclient.State> {
30-
let clientState = undefined;
31-
while (clientState !== expectedState) {
32-
clientState = await languageClientManager.useLanguageClient(async client => client.state);
33-
console.warn("Language client is not ready yet. Retrying in 100 ms...");
34-
await new Promise(resolve => setTimeout(resolve, 100));
35-
}
36-
return clientState;
37-
}
25+
import { FolderContext } from "../../../src/FolderContext";
26+
import { waitForClientState, waitForCodeActions, waitForIndex } from "../utilities/lsputilities";
3827

3928
async function buildProject(ctx: WorkspaceContext, name: string) {
4029
await waitForNoRunningTasks();
4130
const folderContext = await folderInRootWorkspace(name, ctx);
4231
const task = (await getBuildAllTask(folderContext)) as SwiftTask;
4332
const { exitCode, output } = await executeTaskAndWaitForResult(task);
4433
expect(exitCode, `${output}`).to.equal(0);
34+
return folderContext;
4535
}
4636

4737
suite("Language Client Integration Suite @slow", function () {
38+
this.timeout(5 * 60 * 1000);
39+
4840
let clientManager: LanguageClientManager;
4941
let workspaceContext: WorkspaceContext;
42+
let macroFolderContext: FolderContext;
5043

5144
activateExtensionForSuite({
5245
async setup(ctx) {
53-
this.timeout(5 * 60 * 1000);
54-
5546
workspaceContext = ctx;
5647

5748
// Wait for a clean starting point, and build all tasks for the fixture
5849
if (workspaceContext.swiftVersion.isGreaterThanOrEqual(new Version(6, 1, 0))) {
59-
await buildProject(ctx, "swift-macro");
50+
macroFolderContext = await buildProject(ctx, "swift-macro");
6051
}
6152
await buildProject(ctx, "defaultPackage");
6253

6354
// Ensure lsp client is ready
6455
clientManager = ctx.languageClientManager;
65-
const clientState = await waitForClientState(clientManager, langclient.State.Running);
66-
expect(clientState).to.equals(langclient.State.Running);
56+
await waitForClientState(clientManager, langclient.State.Running);
6757
},
6858
});
6959

60+
setup(async () => {
61+
await waitForIndex(workspaceContext.languageClientManager);
62+
});
63+
7064
test("Expand Macro", async function () {
7165
// Expand Macro support in Swift started from 6.1
7266
if (workspaceContext.swiftVersion.isLessThan(new Version(6, 1, 0))) {
@@ -76,12 +70,15 @@ suite("Language Client Integration Suite @slow", function () {
7670
// Focus on the file of interest
7771
const uri = testAssetUri("swift-macro/Sources/swift-macroClient/main.swift");
7872
await vscode.window.showTextDocument(uri);
73+
await workspaceContext.focusFolder(macroFolderContext);
7974

8075
// Beginning of macro, #
8176
const position = new vscode.Position(5, 21);
8277

8378
// Create a range starting and ending at the specified position
84-
const range = new vscode.Range(position, position);
79+
const range = new vscode.Selection(position, position.with({ character: 22 }));
80+
81+
await waitForCodeActions(workspaceContext.languageClientManager, uri, range);
8582

8683
// Execute the code action provider command
8784
const codeActions = await vscode.commands.executeCommand<vscode.CodeAction[]>(
@@ -90,8 +87,6 @@ suite("Language Client Integration Suite @slow", function () {
9087
range
9188
);
9289

93-
const expectedMacro = '(a + b, "a + b")';
94-
9590
// Find the "expand.macro.command" action
9691
const expandMacroAction = codeActions.find(
9792
action => action.command?.command === "expand.macro.command"
@@ -129,6 +124,7 @@ suite("Language Client Integration Suite @slow", function () {
129124
expect(referenceDocument).to.not.be.undefined;
130125

131126
// Assert that the content contains the expected result
127+
const expectedMacro = '(a + b, "a + b")';
132128
const content = referenceDocument.getText();
133129
expect(content).to.include(expectedMacro);
134130
});
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the VS Code Swift open source project
4+
//
5+
// Copyright (c) 2025 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 langclient from "vscode-languageclient/node";
17+
import { LanguageClientManager } from "../../../src/sourcekit-lsp/LanguageClientManager";
18+
19+
export async function waitForClient<Result>(
20+
languageClientManager: LanguageClientManager,
21+
getResult: (
22+
c: langclient.LanguageClient,
23+
token: langclient.CancellationToken
24+
) => Promise<Result>,
25+
match: (r: Result | undefined) => boolean
26+
): Promise<Result | undefined> {
27+
let result: Result | undefined = undefined;
28+
while (!match(result)) {
29+
result = await languageClientManager.useLanguageClient<Result>(getResult);
30+
console.warn("Language client is not ready yet. Retrying in 100 ms...");
31+
await new Promise(resolve => setTimeout(resolve, 100));
32+
}
33+
return result;
34+
}
35+
36+
// eslint-disable-next-line @typescript-eslint/no-namespace
37+
export namespace PollIndexRequest {
38+
export const method = "workspace/_pollIndex" as const;
39+
export const messageDirection: langclient.MessageDirection =
40+
langclient.MessageDirection.clientToServer;
41+
export const type = new langclient.RequestType<object, object, never>(method);
42+
}
43+
44+
export async function waitForIndex(languageClientManager: LanguageClientManager): Promise<void> {
45+
await languageClientManager.useLanguageClient(async (client, token) =>
46+
client.sendRequest(PollIndexRequest.type, {}, token)
47+
);
48+
}
49+
50+
export async function waitForClientState(
51+
languageClientManager: LanguageClientManager,
52+
expectedState: langclient.State
53+
): Promise<langclient.State | undefined> {
54+
return await waitForClient(
55+
languageClientManager,
56+
async c => c.state,
57+
s => s === expectedState
58+
);
59+
}
60+
61+
export async function waitForCodeActions(
62+
languageClientManager: LanguageClientManager,
63+
uri: vscode.Uri,
64+
range: vscode.Range
65+
): Promise<(langclient.CodeAction | langclient.Command)[]> {
66+
return (
67+
(await waitForClient(
68+
languageClientManager,
69+
async (client, token) => {
70+
try {
71+
return client.sendRequest(
72+
langclient.CodeActionRequest.type,
73+
{
74+
context: langclient.CodeActionContext.create([]),
75+
textDocument: langclient.TextDocumentIdentifier.create(uri.toString()),
76+
range,
77+
},
78+
token
79+
);
80+
} catch (e) {
81+
// Ignore
82+
}
83+
},
84+
s => (s || []).length > 0
85+
)) || []
86+
);
87+
}

0 commit comments

Comments
 (0)