std/uuid/unstable_v7_test.ts

95 lines
2.8 KiB
TypeScript
Raw Normal View History

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals, assertThrows } from "@std/assert";
import { extractTimestamp, generate, validate } from "./unstable_v7.ts";
import { stub } from "../testing/mock.ts";
Deno.test("generate() generates a non-empty string", () => {
const u1 = generate();
assertEquals(typeof u1, "string", "returns a string");
assert(u1 !== "", "return string is not empty");
});
Deno.test("generate() generates UUIDs in version 7 format", () => {
for (let i = 0; i < 10000; i++) {
const u = generate();
assert(validate(u), `${u} is not a valid uuid v7`);
}
});
Deno.test("generate() generates a UUIDv7 matching the example test vector", () => {
/**
* Example test vector from the RFC:
* {@see https://www.rfc-editor.org/rfc/rfc9562.html#appendix-A.6}
*/
const timestamp = 0x017F22E279B0;
const random = new Uint8Array([
// rand_a = 0xCC3
0xC,
0xC3,
// rand_b = 0b01, 0x8C4DC0C0C07398F
0x18,
0xC4,
0xDC,
0x0C,
0x0C,
0x07,
0x39,
0x8F,
]);
using _getRandomValuesStub = stub(crypto, "getRandomValues", (array) => {
for (let index = 0; index < (random.length); index++) {
array[index] = random[index]!;
}
return random;
});
const u = generate(timestamp);
assertEquals(u, "017f22e2-79b0-7cc3-98c4-dc0c0c07398f");
});
Deno.test("generate() throws on invalid timestamp", () => {
assertThrows(
() => generate(-1),
RangeError,
"Cannot generate UUID as timestamp must be a non-negative integer: timestamp -1",
);
assertThrows(
() => generate(NaN),
RangeError,
"Cannot generate UUID as timestamp must be a non-negative integer: timestamp NaN",
);
assertThrows(
() => generate(2.3),
RangeError,
"Cannot generate UUID as timestamp must be a non-negative integer: timestamp 2.3",
);
});
Deno.test("validate() checks if a string is a valid v7 UUID", () => {
const u = generate();
const t = "017f22e2-79b0-7cc3-98c4-dc0c0c07398f";
assert(validate(u), `generated ${u} should be valid`);
assert(validate(t), `${t} should be valid`);
});
Deno.test("extractTimestamp(uuid) extracts the timestamp from a UUIDv7", () => {
const u = "017f22e2-79b0-7cc3-98c4-dc0c0c07398f";
const now = Date.now();
const u2 = generate(now);
assertEquals(extractTimestamp(u), 1645557742000);
assertEquals(extractTimestamp(u2), now);
});
Deno.test("extractTimestamp(uuid) throws on invalid UUID", () => {
assertThrows(
() => extractTimestamp("invalid-uuid"),
TypeError,
`Cannot extract timestamp because the UUID is not a valid UUIDv7: uuid is "invalid-uuid"`,
);
assertThrows(
() => extractTimestamp(crypto.randomUUID()),
TypeError,
`Cannot extract timestamp because the UUID is not a valid UUIDv7:`,
);
});