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); }); });