79 lines
3.0 KiB
TypeScript
79 lines
3.0 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
|
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
const root = fileURLToPath(new URL("../../../", import.meta.url));
|
|
const runNode = (source: string, ...arguments_: string[]): string =>
|
|
execFileSync(
|
|
process.execPath,
|
|
["--input-type=module", "-e", source, ...arguments_],
|
|
{ cwd: root, encoding: "utf8" },
|
|
);
|
|
|
|
describe("reverse-tools mutation configuration", () => {
|
|
it("loads nonempty targets from both actual Stryker configs", () => {
|
|
const result = runNode(
|
|
`const [mainUrl, semanticsUrl] = process.argv.slice(1);
|
|
const main = await import(mainUrl);
|
|
const semantics = await import(semanticsUrl);
|
|
process.stdout.write(JSON.stringify({
|
|
main: main.default.mutate.length,
|
|
semantics: semantics.default.mutate.length,
|
|
}));`,
|
|
pathToFileURL(join(root, "stryker.config.mjs")).href,
|
|
pathToFileURL(join(root, "stryker.semantics.config.mjs")).href,
|
|
);
|
|
const targets = JSON.parse(result) as {
|
|
main: number;
|
|
semantics: number;
|
|
};
|
|
expect(targets.main).toBeGreaterThan(0);
|
|
expect(targets.semantics).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("fails closed when an owned mutation method is missing", async () => {
|
|
const directory = await createTestTempDirectory("rea-mutation-selector-");
|
|
const source = join(directory, "source.ts");
|
|
await writeFile(source, "class Present { run() {} }\n");
|
|
|
|
const result = runNode(
|
|
`import { mutationRanges } from "./scripts/lib/reverse-tools-mutation-targets.mjs";
|
|
const [source] = process.argv.slice(1);
|
|
try {
|
|
mutationRanges(source, [{ kind: "method", owner: "Missing", name: "run" }]);
|
|
throw new Error("missing owner unexpectedly selected");
|
|
} catch (error) {
|
|
if (!(error instanceof Error) || !error.message.includes("found 0")) throw error;
|
|
process.stdout.write(error.message);
|
|
}`,
|
|
source,
|
|
);
|
|
expect(result).toMatch(/found 0/u);
|
|
});
|
|
|
|
it("fails closed when an owned mutation method is ambiguous", async () => {
|
|
const directory = await createTestTempDirectory("rea-mutation-selector-");
|
|
const source = join(directory, "source.ts");
|
|
await writeFile(source, "class Owner { run() {} run(value: string) {} }\n");
|
|
|
|
const result = runNode(
|
|
`import { mutationRanges } from "./scripts/lib/reverse-tools-mutation-targets.mjs";
|
|
const [source] = process.argv.slice(1);
|
|
try {
|
|
mutationRanges(source, [{ kind: "method", owner: "Owner", name: "run" }]);
|
|
throw new Error("ambiguous target unexpectedly selected");
|
|
} catch (error) {
|
|
if (!(error instanceof Error) || !error.message.includes("found 2")) throw error;
|
|
process.stdout.write(error.message);
|
|
}`,
|
|
source,
|
|
);
|
|
expect(result).toMatch(/found 2/u);
|
|
});
|
|
});
|