94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
/**
|
|
* Spec-conformance tests for `openspec/specs/crypto-hash/spec.md`.
|
|
*
|
|
* Pins the structural scenarios that the regular per-primitive
|
|
* unit tests do not cover directly: package-name identity, every
|
|
* primitive having both `noble` and `native` impl files, generated
|
|
* banner on `*.select.ts`, and absence of `@suaveplan/hash` import
|
|
* specifiers anywhere in the workspace.
|
|
*/
|
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
|
|
const ROOT = join(__dirname, "..");
|
|
const SRC = join(ROOT, "src");
|
|
const PRIMITIVES = join(SRC, "primitives");
|
|
const _REPO_ROOT = join(ROOT, "..", "..", "..", "..");
|
|
|
|
const PRIMITIVE_IDS = [
|
|
"sha256",
|
|
"sha384",
|
|
"sha512",
|
|
"hmac",
|
|
"hkdf",
|
|
"pbkdf2",
|
|
"argon2id",
|
|
] as const;
|
|
|
|
function* _walk(dir: string): Generator<string> {
|
|
for (const entry of readdirSync(dir)) {
|
|
const full = join(dir, entry);
|
|
const st = statSync(full);
|
|
if (
|
|
st.isDirectory() &&
|
|
!full.includes("node_modules") &&
|
|
!full.includes("dist") &&
|
|
!full.endsWith("/.git")
|
|
) {
|
|
yield* _walk(full);
|
|
} else if (
|
|
(full.endsWith(".ts") || full.endsWith(".json")) &&
|
|
!full.endsWith(".test.ts")
|
|
) {
|
|
yield full;
|
|
}
|
|
}
|
|
}
|
|
|
|
describe("crypto-hash — package identity", () => {
|
|
it("package.json name is @suaveplan/crypto-hash", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const pkg = JSON.parse(
|
|
readFileSync(join(ROOT, "package.json"), "utf8")
|
|
);
|
|
expect(pkg.name).toBe("@suaveplan/crypto-hash");
|
|
});
|
|
});
|
|
|
|
describe("crypto-hash — per-primitive replaceability layout", () => {
|
|
for (const id of PRIMITIVE_IDS) {
|
|
it(`${id} has both noble.ts and native.ts impl files`, {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const noble = join(
|
|
PRIMITIVES,
|
|
id,
|
|
"impl",
|
|
`${id}.noble`,
|
|
`${id}.noble.ts`
|
|
);
|
|
const native = join(
|
|
PRIMITIVES,
|
|
id,
|
|
"impl",
|
|
`${id}.native`,
|
|
`${id}.native.ts`
|
|
);
|
|
expect(existsSync(noble)).toBe(true);
|
|
expect(existsSync(native)).toBe(true);
|
|
});
|
|
|
|
it(`${id}.select.ts carries the GENERATED banner`, {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const sel = join(PRIMITIVES, id, `${id}.select`, `${id}.select.ts`);
|
|
expect(existsSync(sel)).toBe(true);
|
|
const content = readFileSync(sel, "utf8");
|
|
expect(content).toMatch(/GENERATED/);
|
|
expect(content).toMatch(/DO NOT EDIT/);
|
|
});
|
|
}
|
|
});
|