Skip to content

Commit

Permalink
Some e2e/smoke tests for our integration with sourcekit-lsp (#1259)
Browse files Browse the repository at this point in the history
* Some e2e/smoke tests for our integration with sourcekit-lsp

* Moving macros into common file with tests from #1236
* Fix some flakyness and failures

* Mark as slow

* Fix for new snippet file
  • Loading branch information
award999 authored Dec 12, 2024
1 parent 4acbbe6 commit 98519ba
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { expect } from "chai";
import { LanguageClientManager } from "../../../src/sourcekit-lsp/LanguageClientManager";
import { WorkspaceContext } from "../../../src/WorkspaceContext";
import { testAssetUri } from "../../fixtures";
import { FolderContext } from "../../../src/FolderContext";
import { executeTaskAndWaitForResult, waitForNoRunningTasks } from "../../utilities/tasks";
import { getBuildAllTask, SwiftTask } from "../../../src/tasks/SwiftTaskProvider";
import { Version } from "../../../src/utilities/version";
Expand All @@ -37,38 +36,43 @@ async function waitForClientState(
return clientState;
}

suite("Integration, Macros Functionality Support with Sourcekit-lsp", function () {
// Take around 60 seconds if running in isolation, longer than default timeout
this.timeout(2 * 60 * 1000);
async function buildProject(ctx: WorkspaceContext, name: string) {
await waitForNoRunningTasks();
const folderContext = await folderInRootWorkspace(name, ctx);
const task = (await getBuildAllTask(folderContext)) as SwiftTask;
const { exitCode, output } = await executeTaskAndWaitForResult(task);
expect(exitCode, `${output}`).to.equal(0);
}

suite("Language Client Integration Suite @slow", function () {
let clientManager: LanguageClientManager;
let workspaceContext: WorkspaceContext;
let folderContext: FolderContext;

activateExtensionForSuite({
async setup(ctx) {
this.timeout(5 * 60 * 1000);

workspaceContext = ctx;
// Expand Macro support in Swift started from 6.1
if (workspaceContext.swiftVersion.isLessThan(new Version(6, 1, 0))) {
this.skip();
}

// Wait for a clean starting point, and build all tasks for the fixture
await waitForNoRunningTasks();
folderContext = await folderInRootWorkspace("swift-macro", workspaceContext);
await workspaceContext.focusFolder(folderContext);
const tasks = (await getBuildAllTask(folderContext)) as SwiftTask;
const { exitCode, output } = await executeTaskAndWaitForResult(tasks);
expect(exitCode, `${output}`).to.equal(0);
if (workspaceContext.swiftVersion.isGreaterThanOrEqual(new Version(6, 1, 0))) {
await buildProject(ctx, "swift-macro");
}
await buildProject(ctx, "defaultPackage");

// Ensure lsp client is ready
clientManager = workspaceContext.languageClientManager;
clientManager = ctx.languageClientManager;
const clientState = await waitForClientState(clientManager, langclient.State.Running);
expect(clientState).to.equals(langclient.State.Running);
},
});

test("Expand Macro", async function () {
// Expand Macro support in Swift started from 6.1
if (workspaceContext.swiftVersion.isLessThan(new Version(6, 1, 0))) {
this.skip();
}

// Focus on the file of interest
const uri = testAssetUri("swift-macro/Sources/swift-macroClient/main.swift");
await vscode.window.showTextDocument(uri);
Expand Down Expand Up @@ -128,4 +132,68 @@ suite("Integration, Macros Functionality Support with Sourcekit-lsp", function (
const content = referenceDocument.getText();
expect(content).to.include(expectedMacro);
});

suite("Symbols", () => {
const uri = testAssetUri("defaultPackage/Sources/PackageExe/main.swift");
const expectedDefinitionUri = testAssetUri(
"defaultPackage/Sources/PackageLib/PackageLib.swift"
);
const snippetUri = testAssetUri("defaultPackage/Snippets/hello.swift");
// Position of the symbol 'a' in main.swift
const position = new vscode.Position(2, 6);

test("Goto Definition", async function () {
// Focus on the file of interest
const editor = await vscode.window.showTextDocument(uri);
const document = editor.document;

// Position of the symbol 'a' in main.swift
const definitionLocations = await vscode.commands.executeCommand<vscode.Location[]>(
"vscode.executeDefinitionProvider",
document.uri,
position
);

expect(definitionLocations).to.have.lengthOf(
1,
"There should be one definition of 'a'."
);

const definition = definitionLocations[0];

// Assert that the definition is in PackageLib.swift at line 0
expect(definition.uri.toString()).to.equal(expectedDefinitionUri.toString());
expect(definition.range.start.line).to.equal(0);
});

test("Find All References", async function () {
// Focus on the file of interest
const editor = await vscode.window.showTextDocument(uri);
const document = editor.document;

const referenceLocations = await vscode.commands.executeCommand<vscode.Location[]>(
"vscode.executeReferenceProvider",
document.uri,
position
);

// We expect 2 references - one in `main.swift` and one in `PackageLib.swift`
expect(referenceLocations).to.have.lengthOf(
3,
"There should be two references to 'a'."
);

// Extract reference URIs and sort them to have a predictable order
const referenceUris = referenceLocations.map(ref => ref.uri.toString());
const expectedUris = [
snippetUri.toString(),
uri.toString(), // Reference in main.swift
expectedDefinitionUri.toString(), // Reference in PackageLib.swift
];

for (const uri of expectedUris) {
expect(referenceUris).to.contain(uri);
}
});
});
});
30 changes: 13 additions & 17 deletions test/utilities/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,19 @@ export function mutable<T>(target: T): Mutable<T> {
export async function executeTaskAndWaitForResult(
fixture: SwiftTaskFixture | SwiftTask
): Promise<{ exitCode?: number; output: string }> {
const task = ("task" in fixture ? fixture.task : fixture) as SwiftTask;
let output = "";
const disposables = [task.execution.onDidWrite(e => (output += e))];
const promise = new Promise<number | undefined>(res =>
disposables.push(
task.execution.onDidClose(e => {
disposables.forEach(d => d.dispose());
res(typeof e === "number" ? e : undefined);
})
)
);
await vscode.tasks.executeTask(task);
const exitCode = await promise;
return {
output,
exitCode,
};
const task = "task" in fixture ? fixture.task : fixture;
const exitPromise = waitForEndTaskProcess(task);
return await vscode.tasks.executeTask(task).then(async execution => {
let output = "";
const runningTask = execution.task as SwiftTask;
const disposables = [runningTask.execution.onDidWrite(e => (output += e))];
const exitCode = await exitPromise;
disposables.forEach(d => d.dispose());
return {
output,
exitCode,
};
});
}

/**
Expand Down

0 comments on commit 98519ba

Please sign in to comment.