Initial Commit
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { SuaveplanError } from "@suaveplan/error";
|
||||
import { describe, expect, expectTypeOf, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
TPM_STRUCT_CODES,
|
||||
TpmStructError,
|
||||
type TpmStructErrorCode,
|
||||
tpmStructError,
|
||||
} from "./error-codes.js";
|
||||
|
||||
const SRC_ROOT = join(import.meta.dirname, "..");
|
||||
|
||||
describe("TPM_STRUCT_CODES", () => {
|
||||
it("contains exactly the 10 documented codes", { timeout: 5000 }, () => {
|
||||
const keys = Object.keys(TPM_STRUCT_CODES).sort();
|
||||
expect(keys).toEqual([
|
||||
"ALG_UNSUPPORTED",
|
||||
"ATTEST_TYPE_UNSUPPORTED",
|
||||
"CURVE_UNSUPPORTED",
|
||||
"MAGIC_INVALID",
|
||||
"MALFORMED",
|
||||
"NAME_ALG_NULL",
|
||||
"OBJECT_ATTRIBUTES_RESERVED_NONZERO",
|
||||
"PARAMETERS_INVALID",
|
||||
"TRUNCATED",
|
||||
"TYPE_MISMATCH",
|
||||
]);
|
||||
for (const k of keys) {
|
||||
expect(TPM_STRUCT_CODES[k as keyof typeof TPM_STRUCT_CODES]).toBe(
|
||||
`TPM_STRUCT.${k}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("every TPM_STRUCT code reachable from a production path", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const sources = readSrcSources(SRC_ROOT);
|
||||
for (const code of Object.values(TPM_STRUCT_CODES)) {
|
||||
const reason = (code as string).split(".")[1] as string;
|
||||
const found = sources.some(({ body }) => body.includes(reason));
|
||||
expect(found, `code ${code} not referenced in src/`).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("literal union pins to registry keys", { timeout: 5000 }, () => {
|
||||
expectTypeOf<TpmStructErrorCode>().toEqualTypeOf<
|
||||
| "TPM_STRUCT.MAGIC_INVALID"
|
||||
| "TPM_STRUCT.TRUNCATED"
|
||||
| "TPM_STRUCT.ALG_UNSUPPORTED"
|
||||
| "TPM_STRUCT.CURVE_UNSUPPORTED"
|
||||
| "TPM_STRUCT.TYPE_MISMATCH"
|
||||
| "TPM_STRUCT.MALFORMED"
|
||||
| "TPM_STRUCT.NAME_ALG_NULL"
|
||||
| "TPM_STRUCT.ATTEST_TYPE_UNSUPPORTED"
|
||||
| "TPM_STRUCT.PARAMETERS_INVALID"
|
||||
| "TPM_STRUCT.OBJECT_ATTRIBUTES_RESERVED_NONZERO"
|
||||
>();
|
||||
});
|
||||
});
|
||||
|
||||
describe("TpmStructError", () => {
|
||||
it("instances carry the TPM_STRUCT.* code literal", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const err = tpmStructError(TPM_STRUCT_CODES.MAGIC_INVALID, "test");
|
||||
expect(err).toBeInstanceOf(TpmStructError);
|
||||
expect(err).toBeInstanceOf(SuaveplanError);
|
||||
expect(err.code).toBe("TPM_STRUCT.MAGIC_INVALID");
|
||||
expect(err.message).toContain("TPM_STRUCT.MAGIC_INVALID");
|
||||
});
|
||||
|
||||
it("threads structured detail through the cause chain", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const err = tpmStructError(TPM_STRUCT_CODES.TRUNCATED, "short", {
|
||||
cursor: 5,
|
||||
requested: 4,
|
||||
});
|
||||
const cause = (
|
||||
err as unknown as {
|
||||
cause: Error & { detail?: Record<string, unknown> };
|
||||
}
|
||||
).cause;
|
||||
expect(cause).toBeInstanceOf(Error);
|
||||
expect(cause?.detail).toEqual({ cursor: 5, requested: 4 });
|
||||
});
|
||||
|
||||
it("constructor without options has no cause", { timeout: 5000 }, () => {
|
||||
const err = new TpmStructError(TPM_STRUCT_CODES.MALFORMED, "no opts");
|
||||
expect(err.code).toBe("TPM_STRUCT.MALFORMED");
|
||||
expect((err as unknown as { cause?: unknown }).cause).toBeUndefined();
|
||||
});
|
||||
|
||||
it("constructor accepts an Error cause directly", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const inner = new Error("inner");
|
||||
const err = new TpmStructError(TPM_STRUCT_CODES.MALFORMED, "outer", {
|
||||
cause: inner,
|
||||
});
|
||||
expect((err as unknown as { cause: Error }).cause).toBe(inner);
|
||||
});
|
||||
|
||||
it("constructor silently drops non-Error causes", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const err = new TpmStructError(TPM_STRUCT_CODES.MALFORMED, "outer", {
|
||||
cause: "string-not-error",
|
||||
});
|
||||
expect((err as unknown as { cause?: unknown }).cause).toBeUndefined();
|
||||
});
|
||||
|
||||
it("tpmStructError without detail has no cause", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const err = tpmStructError(TPM_STRUCT_CODES.MALFORMED, "bare");
|
||||
expect((err as unknown as { cause?: unknown }).cause).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
type SrcSource = { path: string; body: string };
|
||||
|
||||
function readSrcSources(root: string): SrcSource[] {
|
||||
const out: SrcSource[] = [];
|
||||
// biome lint hint: this is a test helper; readdirSync is the simplest walker
|
||||
const fs = require("node:fs") as typeof import("node:fs");
|
||||
function walk(dir: string): void {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (
|
||||
entry.name === "__fixtures__" ||
|
||||
entry.name === "__benchmarks__" ||
|
||||
entry.name === "__integration__"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
walk(full);
|
||||
} else if (
|
||||
entry.name.endsWith(".ts") &&
|
||||
!entry.name.endsWith(".test.ts") &&
|
||||
!entry.name.endsWith(".types.ts") &&
|
||||
!entry.name.endsWith(".bench.ts")
|
||||
) {
|
||||
out.push({ path: full, body: readFileSync(full, "utf8") });
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(root);
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user