Initial Commit
This commit is contained in:
103
packages/security-stack/security/srp/src/errors/errors.test.ts
Normal file
103
packages/security-stack/security/srp/src/errors/errors.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { SuaveplanError } from "@suaveplan/error";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { SRP_CODES, SrpError, srpError } from "./errors.js";
|
||||
|
||||
const SRC_ROOT = join(import.meta.dirname, "..");
|
||||
|
||||
describe("SRP_CODES", () => {
|
||||
it("contains exactly the 6 documented codes", { timeout: 5000 }, () => {
|
||||
const keys = Object.keys(SRP_CODES).sort();
|
||||
expect(keys).toEqual([
|
||||
"AUTH_FAILED",
|
||||
"GROUP_UNSUPPORTED",
|
||||
"HASH_UNSUPPORTED",
|
||||
"INVALID_PARAMS",
|
||||
"MUTUAL_AUTH_FAILED",
|
||||
"PUBLIC_KEY_INVALID",
|
||||
]);
|
||||
for (const k of keys) {
|
||||
expect(SRP_CODES[k as keyof typeof SRP_CODES]).toBe(`SRP.${k}`);
|
||||
}
|
||||
});
|
||||
|
||||
it("every SRP code reachable from a production path", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
// Recursively read every .ts under src/ excluding test files, fixtures,
|
||||
// and *.types.ts. For each registered code, assert at least one
|
||||
// production file mentions the code literal.
|
||||
const sources = readSrcSources(SRC_ROOT);
|
||||
for (const code of Object.values(SRP_CODES)) {
|
||||
const reason = code.split(".")[1];
|
||||
const found = sources.some(({ body }) => body.includes(reason!));
|
||||
expect(found).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("SrpError", () => {
|
||||
it("instances carry the SRP.* code literal", { timeout: 5000 }, () => {
|
||||
const err = srpError(SRP_CODES.AUTH_FAILED, "test");
|
||||
expect(err).toBeInstanceOf(SrpError);
|
||||
expect(err).toBeInstanceOf(SuaveplanError);
|
||||
expect(err.code).toBe("SRP.AUTH_FAILED");
|
||||
expect(err.message).toContain("SRP.AUTH_FAILED");
|
||||
});
|
||||
|
||||
it("srpError threads through Error cause", { timeout: 5000 }, () => {
|
||||
const cause = new Error("inner");
|
||||
const err = srpError(SRP_CODES.INVALID_PARAMS, "outer", { cause });
|
||||
expect((err as unknown as { cause: Error }).cause).toBe(cause);
|
||||
});
|
||||
|
||||
it("SrpError constructor uses default empty options", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const err = new SrpError(SRP_CODES.INVALID_PARAMS, "no opts");
|
||||
expect(err.code).toBe("SRP.INVALID_PARAMS");
|
||||
});
|
||||
|
||||
it("srpError called without options argument", { timeout: 5000 }, () => {
|
||||
const err = srpError(SRP_CODES.AUTH_FAILED, "no opts");
|
||||
expect(err.code).toBe("SRP.AUTH_FAILED");
|
||||
});
|
||||
|
||||
it("srpError ignores non-Error cause silently", { timeout: 5000 }, () => {
|
||||
const err = srpError(SRP_CODES.INVALID_PARAMS, "outer", {
|
||||
cause: "string",
|
||||
});
|
||||
expect(err.code).toBe("SRP.INVALID_PARAMS");
|
||||
});
|
||||
});
|
||||
|
||||
type SrcSource = { path: string; body: string };
|
||||
|
||||
function readSrcSources(root: string): SrcSource[] {
|
||||
const out: SrcSource[] = [];
|
||||
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__"
|
||||
) {
|
||||
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