mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
134 lines
5.4 KiB
TypeScript
134 lines
5.4 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
const show = vi.fn();
|
|
vi.mock("@/workbench/contributions", async (orig) => ({
|
|
...(await orig<typeof import("@/workbench/contributions")>()),
|
|
toolWindowService: () => ({ show }),
|
|
}));
|
|
const referenceResponse = vi.fn();
|
|
const lspReferences = vi.fn(async (..._args: unknown[]) => ({ status: "ok", data: null }));
|
|
vi.mock("@/platform/ipc", async (orig) => {
|
|
const actual = await orig<typeof import("@/platform/ipc")>();
|
|
return { ...actual, commands: { ...actual.commands, lspReferences } };
|
|
});
|
|
vi.mock("./ipc", async (orig) => ({
|
|
...(await orig<typeof import("./ipc")>()),
|
|
caretContext: () => ({ doc: 1, path: "/p/a.rs", line: 0, col: 0, word: "used", view: null }),
|
|
lspRequest: (request: () => unknown) => {
|
|
request();
|
|
return referenceResponse();
|
|
},
|
|
readManyFileLines: async () => new Map([["/p/b.rs", ["", " used();", " used();"]]]),
|
|
}));
|
|
const channels: { onmessage: (refs: unknown) => void }[] = [];
|
|
vi.mock("@tauri-apps/api/core", async (orig) => ({
|
|
...(await orig<object>()),
|
|
Channel: class {
|
|
onmessage = () => {};
|
|
constructor() {
|
|
channels.push(this);
|
|
}
|
|
},
|
|
}));
|
|
|
|
const { activeUsageSearch, findUsages, openUsageTab, pinUsageTab, resetUsages, showUsageResults, useUsages } =
|
|
await import("./usages");
|
|
|
|
describe("showUsageResults", () => {
|
|
it("shows given usages in the Find Usages tool window", async () => {
|
|
const loc = { path: "/p/b.rs", range: { start: { line: 1, col: 4 }, end: { line: 1, col: 8 } } };
|
|
await showUsageResults({ symbol: "used", locations: [loc] });
|
|
expect(show).toHaveBeenCalledWith("usages");
|
|
const search = activeUsageSearch(useUsages.getState())!;
|
|
expect(search).toMatchObject({ symbol: "used", loading: false, error: null, rerun: null });
|
|
expect(search.groups).toEqual([
|
|
{ path: "/p/b.rs", usages: [{ path: "/p/b.rs", line: 1, col: 4, endCol: 8, text: " used();" }] },
|
|
]);
|
|
});
|
|
|
|
it("shows the lines the server gave along for files it does not read", async () => {
|
|
const lib = {
|
|
path: "jdt://contents/lib/Lib.class",
|
|
range: { start: { line: 3, col: 4 }, end: { line: 3, col: 8 } },
|
|
};
|
|
await showUsageResults({
|
|
symbol: "used",
|
|
locations: [lib],
|
|
classified: [{ location: lib, kind: "unknown", text: " used();" }],
|
|
});
|
|
expect(activeUsageSearch(useUsages.getState())!.groups[0]!.usages[0]!.text).toBe(" used();");
|
|
});
|
|
|
|
it("ignores malformed arguments", async () => {
|
|
show.mockClear();
|
|
await showUsageResults({ symbol: "x" });
|
|
expect(show).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("findUsages", () => {
|
|
it("searches Project Files, then Project and Libraries on request", async () => {
|
|
const at = { path: "/p/b.rs", range: { start: { line: 1, col: 4 }, end: { line: 1, col: 8 } } };
|
|
lspReferences.mockClear();
|
|
referenceResponse.mockResolvedValueOnce({ locations: [at], incomplete: null, librariesSkipped: true });
|
|
await findUsages();
|
|
const project = activeUsageSearch(useUsages.getState())!;
|
|
expect(project).toMatchObject({ loading: false, scope: "project" });
|
|
expect(lspReferences.mock.lastCall![5]).toBe(false);
|
|
referenceResponse.mockResolvedValueOnce({ locations: [at], incomplete: null });
|
|
project.searchLibraries!();
|
|
await vi.waitFor(() => expect(activeUsageSearch(useUsages.getState())!.loading).toBe(false));
|
|
expect(lspReferences.mock.lastCall![5]).toBe(true);
|
|
const all = activeUsageSearch(useUsages.getState())!;
|
|
expect(all.scope).toBe("libraries");
|
|
// Rerun keeps the scope.
|
|
referenceResponse.mockResolvedValueOnce({ locations: [at], incomplete: null });
|
|
all.rerun!();
|
|
await vi.waitFor(() => expect(lspReferences).toHaveBeenCalledTimes(3));
|
|
expect(lspReferences.mock.lastCall![5]).toBe(true);
|
|
resetUsages();
|
|
});
|
|
|
|
it("shows the usages found first while it searches for the rest", async () => {
|
|
const at = (line: number) => ({ path: "/p/b.rs", range: { start: { line, col: 4 }, end: { line, col: 8 } } });
|
|
let resolve!: (refs: unknown) => void;
|
|
referenceResponse.mockReturnValueOnce(new Promise((r) => (resolve = r)));
|
|
const search = findUsages();
|
|
await vi.waitFor(() => expect(channels).not.toHaveLength(0));
|
|
channels.at(-1)!.onmessage({ locations: [at(1)], incomplete: null });
|
|
await vi.waitFor(() => expect(activeUsageSearch(useUsages.getState())!.groups).toHaveLength(1));
|
|
expect(activeUsageSearch(useUsages.getState())).toMatchObject({ loading: true, error: null });
|
|
resolve({ locations: [at(1), at(2)], incomplete: null });
|
|
await search;
|
|
const done = activeUsageSearch(useUsages.getState())!;
|
|
expect(done.loading).toBe(false);
|
|
expect(done.groups[0]!.usages.map((u) => u.line)).toEqual([1, 2]);
|
|
resetUsages();
|
|
});
|
|
});
|
|
|
|
describe("usage tabs", () => {
|
|
const search = (id: number) => ({
|
|
id,
|
|
symbol: `s${id}`,
|
|
loading: false,
|
|
groups: [],
|
|
error: null,
|
|
note: null,
|
|
rerun: null,
|
|
});
|
|
|
|
it("replace the selected tab unless it is pinned", () => {
|
|
resetUsages();
|
|
openUsageTab(search(101));
|
|
openUsageTab(search(102));
|
|
expect(useUsages.getState().tabs.map((t) => t.id)).toEqual([102]);
|
|
pinUsageTab(102, true);
|
|
openUsageTab(search(103));
|
|
expect(useUsages.getState().tabs.map((t) => t.id)).toEqual([102, 103]);
|
|
expect(activeUsageSearch(useUsages.getState())?.id).toBe(103);
|
|
openUsageTab(search(104));
|
|
expect(useUsages.getState().tabs.map((t) => t.id)).toEqual([102, 104]);
|
|
});
|
|
});
|