/** * 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 { 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/); }); } });