86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
import { PseudoRandomError } from "../errors/pseudo-random-error.js";
|
|
import { Xoshiro256PlusPlusRng } from "./xoshiro256.js";
|
|
|
|
describe("Xoshiro256PlusPlusRng", () => {
|
|
it("is deterministic", { timeout: 5000 }, () => {
|
|
const a = new Xoshiro256PlusPlusRng(123);
|
|
const b = new Xoshiro256PlusPlusRng(123);
|
|
for (let i = 0; i < 64; i += 1) {
|
|
expect(a.nextUint32()).toBe(b.nextUint32());
|
|
}
|
|
});
|
|
|
|
it("produces uint32 in range", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng("x");
|
|
for (let i = 0; i < 500; i += 1) {
|
|
const v = r.nextUint32();
|
|
expect(v).toBeGreaterThanOrEqual(0);
|
|
expect(v).toBeLessThan(2 ** 32);
|
|
}
|
|
});
|
|
|
|
it("nextFloat in [0,1)", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng("y");
|
|
for (let i = 0; i < 200; i += 1) {
|
|
const f = r.nextFloat();
|
|
expect(f).toBeGreaterThanOrEqual(0);
|
|
expect(f).toBeLessThan(1);
|
|
}
|
|
});
|
|
|
|
it("jump decorrelates streams", { timeout: 5000 }, () => {
|
|
const a = new Xoshiro256PlusPlusRng(1);
|
|
const b = new Xoshiro256PlusPlusRng(1);
|
|
b.jump();
|
|
const av = [a.nextUint32(), a.nextUint32()];
|
|
const bv = [b.nextUint32(), b.nextUint32()];
|
|
expect(av).not.toEqual(bv);
|
|
});
|
|
|
|
it("checkpoint/restore round-trip", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng(7);
|
|
r.skip(5);
|
|
const cp = r.checkpoint();
|
|
const exp = [r.nextUint32(), r.nextUint32(), r.nextUint32()];
|
|
r.restore(cp);
|
|
expect([r.nextUint32(), r.nextUint32(), r.nextUint32()]).toEqual(exp);
|
|
});
|
|
|
|
it("at doesn't mutate self", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng(8);
|
|
const ahead = r.at(5);
|
|
expect(r.position).toBe(0);
|
|
expect(ahead.position).toBe(5);
|
|
});
|
|
|
|
it("fork is independent", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng(9);
|
|
const c = r.fork("a");
|
|
expect(r.nextUint32()).not.toBe(c.nextUint32());
|
|
});
|
|
|
|
it("restore validates algorithm and state", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng(10);
|
|
expect(() =>
|
|
r.restore({ algorithm: "sfc32", state: [0, 0, 0, 0], counter: 0 })
|
|
).toThrow(PseudoRandomError);
|
|
expect(() =>
|
|
r.restore({ algorithm: "xoshiro256++", state: [], counter: 0 })
|
|
).toThrow(PseudoRandomError);
|
|
expect(() =>
|
|
r.restore({
|
|
algorithm: "xoshiro256++",
|
|
state: [0, 0, 0, 0, 0, 0, 0, Number.NaN],
|
|
counter: 0,
|
|
})
|
|
).toThrow(PseudoRandomError);
|
|
});
|
|
|
|
it("rejects bad skip/at args", { timeout: 5000 }, () => {
|
|
const r = new Xoshiro256PlusPlusRng(11);
|
|
expect(() => r.skip(-1)).toThrow(PseudoRandomError);
|
|
expect(() => r.at(-1)).toThrow(PseudoRandomError);
|
|
});
|
|
});
|