import { Buffer } from "node:buffer" ;
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest" ;
const cryptoMocks = vi.hoisted(() => ({
randomBytes: vi.fn((bytes: number) => Buffer.alloc(bytes, 0 xab)),
randomInt: vi.fn(),
randomUUID: vi.fn(),
}));
vi.mock("node:crypto" , () => ({
randomBytes: cryptoMocks.randomBytes,
randomInt: cryptoMocks.randomInt,
randomUUID: cryptoMocks.randomUUID,
}));
let generateSecureFraction: typeof import ("./secure-random.js" ).generateSecureFraction;
let generateSecureHex: typeof import ("./secure-random.js" ).generateSecureHex;
let generateSecureInt: typeof import ("./secure-random.js" ).generateSecureInt;
let generateSecureToken: typeof import ("./secure-random.js" ).generateSecureToken;
let generateSecureUuid: typeof import ("./secure-random.js" ).generateSecureUuid;
beforeAll(async () => {
({
generateSecureFraction,
generateSecureHex,
generateSecureInt,
generateSecureToken,
generateSecureUuid,
} = await import ("./secure-random.js" ));
});
beforeEach(() => {
cryptoMocks.randomBytes.mockClear();
cryptoMocks.randomUUID.mockReset();
});
describe("secure-random" , () => {
it("delegates UUID generation to crypto.randomUUID" , () => {
cryptoMocks.randomUUID.mockReturnValueOnce("uuid-1" ).mockReturnValueOnce("uuid-2" );
expect(generateSecureUuid()).toBe("uuid-1" );
expect(generateSecureUuid()).toBe("uuid-2" );
expect(cryptoMocks.randomUUID).toHaveBeenCalledTimes(2 );
});
it.each([
{
name: "uses the default byte count" ,
byteCount: undefined,
expectedBytes: 16 ,
expectedToken: Buffer.alloc(16 , 0 xab).toString("base64url" ),
},
{
name: "passes custom byte counts through" ,
byteCount: 18 ,
expectedBytes: 18 ,
expectedToken: Buffer.alloc(18 , 0 xab).toString("base64url" ),
},
{
name: "supports zero-byte tokens" ,
byteCount: 0 ,
expectedBytes: 0 ,
expectedToken: "" ,
},
])("generates url-safe tokens when $name" , ({ byteCount, expectedBytes, expectedToken }) => {
cryptoMocks.randomBytes.mockClear();
const token = byteCount === undefined ? generateSecureToken() : generateSecureToken(byteCount);
expect(cryptoMocks.randomBytes).toHaveBeenCalledWith(expectedBytes);
expect(token).toBe(expectedToken);
expect(token).toMatch(/^[A-Za-z0-9 _-]*$/);
});
it("generates secure hex strings" , () => {
cryptoMocks.randomBytes.mockClear();
expect(generateSecureHex(4 )).toBe(Buffer.alloc(4 , 0 xab).toString("hex" ));
expect(cryptoMocks.randomBytes).toHaveBeenCalledWith(4 );
});
it("maps random bytes into a unit interval fraction" , () => {
cryptoMocks.randomBytes.mockReturnValueOnce(Buffer.from([0 x80, 0 x00, 0 x00, 0 x00]));
expect(generateSecureFraction()).toBe(0 .5 );
expect(cryptoMocks.randomBytes).toHaveBeenCalledWith(4 );
});
it("delegates bounded integer generation to crypto.randomInt" , () => {
cryptoMocks.randomInt.mockReturnValueOnce(2 ).mockReturnValueOnce(7 );
expect(generateSecureInt(5 )).toBe(2 );
expect(generateSecureInt(3 , 9 )).toBe(7 );
expect(cryptoMocks.randomInt).toHaveBeenNthCalledWith(1 , 5 );
expect(cryptoMocks.randomInt).toHaveBeenNthCalledWith(2 , 3 , 9 );
});
});
Messung V0.5 in Prozent C=99 H=97 G=97
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland