From d68fdea59aaf05877438bfba669c96d716523765 Mon Sep 17 00:00:00 2001 From: Arnaud Bailly Date: Wed, 2 Sep 2026 22:27:04 +0200 Subject: Refactor generators to use a factory for passing bytes --- pbt/ts/src/gen.ts | 114 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 19 deletions(-) (limited to 'pbt/ts/src/gen.ts') diff --git a/pbt/ts/src/gen.ts b/pbt/ts/src/gen.ts index 7d8c6f1..587bca6 100644 --- a/pbt/ts/src/gen.ts +++ b/pbt/ts/src/gen.ts @@ -5,7 +5,20 @@ import Prando from 'prando'; // namely the sequence of generated values in order to be // able to backtrack and shrink. -type GenMode = 'gen' | 'shrink'; +export interface Generators { + + genInt(): Gen; + + genIntWithin(min: number, max: number): Gen; + + genBytes(): GenBytes; + + genString(): Gen; + + genList(generator: Gen): Gen; + + replay(): void; +} export interface Gen { generate(): A; @@ -13,11 +26,12 @@ export interface Gen { generateN(n: number): A[]; } -export interface GenBytes { +interface GenBytes { + reject(): void; generate(n: number): number[]; } -export class BytesGen implements GenBytes { +class BytesGen implements GenBytes { prng: Prando; bytes: number[][]; // the internal sequence of generated values @@ -54,7 +68,7 @@ export class BytesGen implements GenBytes { } } -export class ReplayBytes implements GenBytes { +class ReplayBytes implements GenBytes { bytes: number[][]; // the internal sequence of generated values index: number = 0; // the current index in the sequence of generated values @@ -77,13 +91,18 @@ export class ReplayBytes implements GenBytes { return chunk; } + + reject() { + if (this.index >= this.bytes.length) { + throw new Error('No more bytes to shrink'); + } + this.index++; + } } class GenInt implements Gen { - private bytes: BytesGen; - - constructor(seed: number | undefined = undefined) { - this.bytes = new BytesGen(new Prando(seed ? seed : Math.random() * 1000)); + constructor(private bytes: GenBytes) { + this.bytes = bytes; } generate(): number { @@ -102,10 +121,8 @@ class GenInt implements Gen { } class GenIntWithin implements Gen { - private bytes: BytesGen; - - constructor(private min: number, private max: number, seed: number | undefined = undefined) { - this.bytes = new BytesGen(new Prando(seed ? seed : Math.random() * 1000000000)); + constructor(private bytes: GenBytes, private min: number, private max: number) { + this.bytes = bytes; this.min = min; this.max = max; } @@ -148,10 +165,8 @@ class GenIntWithin implements Gen { } class GenASCIIString implements Gen { - private bytes: BytesGen; - - constructor(seed: number | undefined = undefined) { - this.bytes = new BytesGen(new Prando(seed ? seed : Math.random() * 1000)); + constructor(private bytes: GenBytes) { + this.bytes = bytes } generate(): string { @@ -169,8 +184,69 @@ class GenASCIIString implements Gen { } } -export const genInt = (seed: number | undefined = undefined) => new GenInt(seed); +class Seeded implements Generators { + + constructor(private bytes: BytesGen) { + this.bytes = bytes; + } + + replay(): Generators { + return new Replayed(this.bytes); + } + + genInt(): Gen { + return new GenInt(this.bytes); + } + genIntWithin(min: number, max: number): Gen { + return new GenIntWithin(this.bytes, min, max); + } + genBytes(): GenBytes { + return this.bytes; + } + genString(): Gen { + return new GenASCIIString(this.bytes); + } + genList(generator: Gen): Gen { + throw new Error('Method not implemented.'); + } + +} + +class Replayed implements Generators { + bytes : GenBytes; + + constructor (bytes: BytesGen) { + this.bytes = bytes.replay(); + } + + replay(): Generators { + throw new Error('Cannot replay a replayed generator'); + } + + genInt(): Gen { + return new GenInt(this.bytes); + } + genIntWithin(min: number, max: number): Gen { + return new GenIntWithin(this.bytes, min, max); + } + genBytes(): GenBytes { + return this.bytes; + } + genString(): Gen { + return new GenASCIIString(this.bytes); + } + genList(generator: Gen): Gen { + throw new Error('Method not implemented.'); + } + +} + + +const generators = (seed: number | undefined = undefined) => { + const prng = new Prando(seed ? seed : Math.random() * 10000000); + const bytes = new BytesGen(prng); -export const genIntWithin = (min: number, max: number, seed: number | undefined = undefined) => new GenIntWithin(min, max, seed); + return new Seeded(bytes); +}; -export const genASCIIString = (seed: number | undefined = undefined) => new GenASCIIString(seed); +export default generators; -- cgit v1.3.1