Initial Commit
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { PseudoRandomError } from "../errors/pseudo-random-error.js";
|
||||
import { Sfc32Rng } from "./sfc32.js";
|
||||
|
||||
describe("Sfc32Rng", () => {
|
||||
it("is deterministic", { timeout: 5000 }, () => {
|
||||
const a = new Sfc32Rng("abc");
|
||||
const b = new Sfc32Rng("abc");
|
||||
for (let i = 0; i < 100; i += 1) {
|
||||
expect(a.nextUint32()).toBe(b.nextUint32());
|
||||
}
|
||||
});
|
||||
|
||||
it("produces uint32 in range", { timeout: 5000 }, () => {
|
||||
const r = new Sfc32Rng(1);
|
||||
for (let i = 0; i < 1000; i += 1) {
|
||||
const v = r.nextUint32();
|
||||
expect(v).toBeGreaterThanOrEqual(0);
|
||||
expect(v).toBeLessThan(2 ** 32);
|
||||
}
|
||||
});
|
||||
|
||||
it("skip === repeated nextUint32", { timeout: 5000 }, () => {
|
||||
const a = new Sfc32Rng(2);
|
||||
const b = new Sfc32Rng(2);
|
||||
a.skip(50);
|
||||
for (let i = 0; i < 50; i += 1) b.nextUint32();
|
||||
expect(a.nextUint32()).toBe(b.nextUint32());
|
||||
});
|
||||
|
||||
it("at doesn't mutate self", { timeout: 5000 }, () => {
|
||||
const a = new Sfc32Rng(3);
|
||||
const ahead = a.at(10);
|
||||
expect(a.position).toBe(0);
|
||||
expect(ahead.position).toBe(10);
|
||||
});
|
||||
|
||||
it("checkpoint/restore round-trip", { timeout: 5000 }, () => {
|
||||
const r = new Sfc32Rng(4);
|
||||
r.skip(7);
|
||||
const cp = r.checkpoint();
|
||||
const exp = [r.nextUint32(), r.nextUint32()];
|
||||
r.restore(cp);
|
||||
expect([r.nextUint32(), r.nextUint32()]).toEqual(exp);
|
||||
});
|
||||
|
||||
it("restore rejects foreign algorithm", { timeout: 5000 }, () => {
|
||||
const r = new Sfc32Rng(5);
|
||||
expect(() =>
|
||||
r.restore({ algorithm: "mulberry32", state: [0], counter: 0 })
|
||||
).toThrow(PseudoRandomError);
|
||||
});
|
||||
|
||||
it("restore rejects bad state length or non-finite words", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const r = new Sfc32Rng(6);
|
||||
expect(() =>
|
||||
r.restore({ algorithm: "sfc32", state: [1, 2], counter: 0 })
|
||||
).toThrow(PseudoRandomError);
|
||||
expect(() =>
|
||||
r.restore({
|
||||
algorithm: "sfc32",
|
||||
state: [1, 2, 3, Number.NaN],
|
||||
counter: 0,
|
||||
})
|
||||
).toThrow(PseudoRandomError);
|
||||
});
|
||||
|
||||
it("rejects invalid skip/at", { timeout: 5000 }, () => {
|
||||
const r = new Sfc32Rng(7);
|
||||
expect(() => r.skip(-1)).toThrow(PseudoRandomError);
|
||||
expect(() => r.at(-1)).toThrow(PseudoRandomError);
|
||||
});
|
||||
|
||||
it("fork yields distinct stream", { timeout: 5000 }, () => {
|
||||
const parent = new Sfc32Rng(8);
|
||||
const child = parent.fork("x");
|
||||
const a = [parent.nextUint32(), parent.nextUint32()];
|
||||
const b = [child.nextUint32(), child.nextUint32()];
|
||||
expect(a).not.toEqual(b);
|
||||
});
|
||||
|
||||
it("nextFloat is in [0,1)", { timeout: 5000 }, () => {
|
||||
const r = new Sfc32Rng(9);
|
||||
for (let i = 0; i < 200; i += 1) {
|
||||
const f = r.nextFloat();
|
||||
expect(f).toBeGreaterThanOrEqual(0);
|
||||
expect(f).toBeLessThan(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user