rea/tests/boundary/cli/referenceSourceUtf8.test.ts

222 lines
7.1 KiB
TypeScript
Raw Permalink Blame History

import { createHash } from "node:crypto";
import {
mkdir,
readFile,
readlink,
symlink,
writeFile,
} from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { historicalSourceGraphSchema } from "../../../src/domain/referenceSourceGraph.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
"retains malformed source bytes without inventing decoded import targets",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-reference-utf8-");
const sources = new Map([
[
"invalid.mjs",
Buffer.concat([
Buffer.from('import "./caf'),
Buffer.from([0xff]),
Buffer.from('.js";\n'),
]),
],
[
"comment.ts",
Buffer.concat([
Buffer.from('import "./dep.js"; // '),
Buffer.from([0xc0, 0xaf]),
]),
],
["valid.mjs", Buffer.from('import "./caf<61>.js";\n')],
["caf<61>.js", Buffer.from("export const value = 1;\n")],
["dep.js", Buffer.from("export const value = 2;\n")],
]);
await Promise.all(
[...sources].map(([path, bytes]) => writeFile(join(root, path), bytes)),
);
const result = await cli.run({
arguments: ["import-reference-source", root, "--json"],
environment: { HOME: root, XDG_CONFIG_HOME: root, XDG_CACHE_HOME: root },
});
expect(result.exitCode, result.stderr + JSON.stringify(result.json)).toBe(
0,
);
const graph = historicalSourceGraphSchema.parse(result.json);
expect(graph.parse_failures).toEqual([
{
path: "comment.ts",
parser: "utf-8",
reason:
"Source bytes are not valid UTF-8; import targets were not parsed.",
},
{
path: "invalid.mjs",
parser: "utf-8",
reason:
"Source bytes are not valid UTF-8; import targets were not parsed.",
},
]);
expect(graph.relationships).toEqual([
{
from_path: "valid.mjs",
to: "caf<61>.js",
kind: "imports",
resolution: "internal",
parse_state: "parsed",
},
]);
for (const [path, bytes] of sources)
expect(graph.entries).toContainEqual(
expect.objectContaining({
path,
sha256: createHash("sha256").update(bytes).digest("hex"),
size: bytes.length,
content_state: "hashed",
}),
);
},
);
cliTest.skipIf(process.platform === "win32")(
"preserves historical literal-backslash entries and their exact owning import base",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-reference-literal-paths-");
const config = await createTestTempDirectory(
"rea-reference-literal-config-",
);
await mkdir(join(root, "literal"));
await mkdir(join(root, "literal\\dir"));
const sources = new Map([
["literal\\name.js", "export const value = 'literal';\n"],
["literal/name.js", "export const value = 'slash';\n"],
["literal\\dir/main.js", 'import "./dep.js";\n'],
["literal\\dir/dep.js", "export const value = 'owned';\n"],
]);
for (const [path, bytes] of sources)
await writeFile(join(root, path), bytes);
const result = await cli.run({
arguments: ["import-reference-source", root, "--json"],
environment: {
HOME: config,
XDG_CONFIG_HOME: config,
XDG_CACHE_HOME: config,
},
});
expect(result.exitCode, result.stderr + JSON.stringify(result.json)).toBe(
0,
);
const graph = historicalSourceGraphSchema.parse(result.json);
for (const [path, bytes] of sources)
expect(graph.entries).toContainEqual(
expect.objectContaining({
path,
sha256: createHash("sha256").update(bytes).digest("hex"),
content_state: "hashed",
}),
);
for (const [path, bytes] of sources)
expect(await readFile(join(root, path), "utf8")).toBe(bytes);
expect(graph.relationships).toContainEqual({
from_path: "literal\\dir/main.js",
to: "literal\\dir/dep.js",
kind: "imports",
resolution: "internal",
parse_state: "parsed",
});
},
);
cliTest.skipIf(process.platform === "win32")(
"preserves an observed historical symlink target with a literal backslash",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-reference-literal-link-");
const config = await createTestTempDirectory(
"rea-reference-literal-link-config-",
);
await writeFile(
join(root, "literal\\name.js"),
"export const value = 42;\n",
);
await symlink("literal\\name.js", join(root, "link.js"));
const result = await cli.run({
arguments: ["import-reference-source", root, "--json"],
environment: {
HOME: config,
XDG_CONFIG_HOME: config,
XDG_CACHE_HOME: config,
},
});
expect(result.exitCode, result.stderr + JSON.stringify(result.json)).toBe(
0,
);
const graph = historicalSourceGraphSchema.parse(result.json);
expect(await readlink(join(root, "link.js"))).toBe("literal\\name.js");
expect(await readFile(join(root, "literal\\name.js"), "utf8")).toBe(
"export const value = 42;\n",
);
expect(graph.entries).toContainEqual(
expect.objectContaining({
kind: "symlink",
path: "link.js",
target: "literal\\name.js",
target_state: "internal",
}),
);
},
);
cliTest.skipIf(process.platform === "win32")(
"imports an inventory-owned POSIX UNC-looking symlink target",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-reference-unc-literal-");
const config = await createTestTempDirectory("rea-reference-unc-config-");
const literal = "\\\\server\\share.js";
const literalBytes = "export const value = 'literal';\n";
const slashBytes = "export const value = 'slash';\n";
await mkdir(join(root, "server"));
await writeFile(join(root, literal), literalBytes);
await writeFile(join(root, "server", "share.js"), slashBytes);
await symlink(literal, join(root, "link.js"));
const result = await cli.run({
arguments: ["import-reference-source", root, "--json"],
environment: {
HOME: config,
XDG_CONFIG_HOME: config,
XDG_CACHE_HOME: config,
},
});
expect(result.exitCode, result.stderr + JSON.stringify(result.json)).toBe(
0,
);
const graph = historicalSourceGraphSchema.parse(result.json);
expect(graph.entries).toContainEqual(
expect.objectContaining({
kind: "symlink",
path: "link.js",
target: literal,
target_state: "internal",
}),
);
for (const [path, bytes] of [
[literal, literalBytes],
["server/share.js", slashBytes],
]) {
expect(graph.entries).toContainEqual(
expect.objectContaining({
path,
sha256: createHash("sha256").update(bytes!).digest("hex"),
}),
);
expect(await readFile(join(root, path!), "utf8")).toBe(bytes);
}
expect(await readlink(join(root, "link.js"))).toBe(literal);
},
);