86 lines
2.8 KiB
JavaScript
86 lines
2.8 KiB
JavaScript
import { describe, it, expect } from "vitest";
|
|
import { createHash } from "./create-hash.js";
|
|
|
|
// "abc" / empty SHA digests: NIST FIPS 180-4 worked examples (SHA_All.pdf).
|
|
// MD5: RFC 1321 §A.5 test suite.
|
|
const VECTORS = {
|
|
SHA1: {
|
|
empty: "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
|
abc: "a9993e364706816aba3e25717850c26c9cd0d89d",
|
|
},
|
|
SHA256: {
|
|
empty: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
abc: "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
|
},
|
|
SHA512: {
|
|
empty:
|
|
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
|
|
abc: "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
|
|
},
|
|
MD5: {
|
|
empty: "d41d8cd98f00b204e9800998ecf8427e",
|
|
abc: "900150983cd24fb0d6963f7d28e17f72",
|
|
},
|
|
};
|
|
|
|
describe("createHash", () => {
|
|
for (const [alg, vec] of Object.entries(VECTORS)) {
|
|
it(`${alg} digests "abc" correctly (hex)`, () => {
|
|
expect(createHash(alg).update("abc").digest("hex")).toBe(vec.abc);
|
|
});
|
|
}
|
|
|
|
it("handles empty input (no update calls)", () => {
|
|
expect(createHash("sha256").digest("hex")).toBe(VECTORS.SHA256.empty);
|
|
});
|
|
|
|
it("normalizes algorithm names (sha-256 -> SHA256)", () => {
|
|
expect(createHash("sha-256").update("abc").digest("hex")).toBe(
|
|
VECTORS.SHA256.abc,
|
|
);
|
|
});
|
|
|
|
it("digest() with no encoding returns raw bytes", () => {
|
|
const result = createHash("sha256").update("abc").digest();
|
|
expect(result).toBeInstanceOf(Uint8Array);
|
|
expect(result.length).toBe(32);
|
|
});
|
|
|
|
it("digest('base64') returns the base64 of the raw bytes", () => {
|
|
const result = createHash("sha256").update("abc").digest("base64");
|
|
expect(result).toBe("ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=");
|
|
});
|
|
|
|
it("supports multiple update() calls", () => {
|
|
const result = createHash("sha256")
|
|
.update("a")
|
|
.update("b")
|
|
.update("c")
|
|
.digest("hex");
|
|
expect(result).toBe(VECTORS.SHA256.abc);
|
|
});
|
|
|
|
it("throws on unsupported algorithm", () => {
|
|
expect(() => createHash("whirlpool")).toThrow(/Unsupported hash algorithm/);
|
|
});
|
|
|
|
it("throws on unsupported encoding", () => {
|
|
expect(() => createHash("sha256").update("abc").digest("utf8")).toThrow(
|
|
/Unsupported digest encoding/,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("digestAsync", () => {
|
|
it("SHA-256 async matches the sync result", async () => {
|
|
const h = createHash("sha256");
|
|
h.update("abc");
|
|
expect(await h.digestAsync("hex")).toBe(VECTORS.SHA256.abc);
|
|
});
|
|
|
|
it("MD5 async falls back to the sync hasher (SubtleCrypto doesn't support it)", async () => {
|
|
const h = createHash("md5");
|
|
h.update("abc");
|
|
expect(await h.digestAsync("hex")).toBe(VECTORS.MD5.abc);
|
|
});
|
|
});
|