From 57472750c9cd14b9907895e5269b3be01819c7b3 Mon Sep 17 00:00:00 2001 From: Arnaud Bailly Date: Sat, 15 Nov 2025 09:33:09 +0100 Subject: [pbt] expose simpler interface Property.run --- pbt/ts/src/index.test.ts | 4 ++-- pbt/ts/src/index.ts | 7 +++---- pbt/ts/src/property.ts | 47 ++++++++++++++++++++++++++++------------------- 3 files changed, 33 insertions(+), 25 deletions(-) (limited to 'pbt/ts/src') diff --git a/pbt/ts/src/index.test.ts b/pbt/ts/src/index.test.ts index deb55ec..58f5119 100644 --- a/pbt/ts/src/index.test.ts +++ b/pbt/ts/src/index.test.ts @@ -1,9 +1,9 @@ -import Prando from 'prando'; import { prop_reverse_with_two_lists } from './index'; +import { Property } from './property'; describe('testing lists reversal', () => { test('reverse of two appended lists is append of each list reversed', () => { - let reverse_append_result = prop_reverse_with_two_lists(new Prando(Math.random() * 1000), 0); + let reverse_append_result = Property.run(prop_reverse_with_two_lists); expect(reverse_append_result).toBe(true); }); }); diff --git a/pbt/ts/src/index.ts b/pbt/ts/src/index.ts index cb7fd6e..25b97aa 100644 --- a/pbt/ts/src/index.ts +++ b/pbt/ts/src/index.ts @@ -1,6 +1,6 @@ import "dotenv/config"; import Prando from 'prando'; -import { Gen, listOf, property, shrinklist, someInt } from "./property"; +import { Gen, Property, listOf, property, shrinklist, someInt } from "./property"; function arrayEquals(a: A[], b: A[]): boolean { return Array.isArray(a) && @@ -54,9 +54,8 @@ let prop_reverse_is_self_inverse = property(reverse_is_self_inverse, listOf(someInt), shrinklist); async function main() { - let rng = new Prando(Math.random() * 1000); - let reverse_append_result = prop_reverse_with_two_lists(rng, 0); - let reverse_reverse_result = prop_reverse_is_self_inverse(rng, 0); + let reverse_append_result = Property.run(prop_reverse_with_two_lists); + let reverse_reverse_result = Property.run(prop_reverse_is_self_inverse); console.log('reverse_append_result: ' + JSON.stringify(reverse_append_result)); console.log('reverse_reverse_result: ' + JSON.stringify(reverse_reverse_result)); }; diff --git a/pbt/ts/src/property.ts b/pbt/ts/src/property.ts index d4eea28..7714747 100644 --- a/pbt/ts/src/property.ts +++ b/pbt/ts/src/property.ts @@ -5,6 +5,7 @@ type Result = 'OK' | 'Falsified' | 'Exception'; type ShrinkResult = { counterexample: A, shrinks: number }; type TestResult = { + seed: number | null, result: Result, counterexample: ShrinkResult | null }; @@ -15,8 +16,8 @@ export type Gen = (rng: Prando) => ((size: number) => A); type Shrinker = (a: A) => A[]; -type Property = (rng: Prando, - size: number) => TestResult; +type Property = (seed: number, + size: number) => TestResult; const MAX_SUCCESS = 100; @@ -49,20 +50,21 @@ export function property( predicate: Predicate, generator: Gen, shrinker: Shrinker): Property { - return (rng: Prando, - size: number) => { - let gen = generator(rng); - let i = 0; - for (; i < MAX_SUCCESS; i++) { - let x = gen(size); - if (!predicate(x)) { - let counterexample = findMinimalCounterExample(x, predicate, shrinker); - return { result: 'Falsified', tests: i+1, counterexample }; - } - size++; - } - return { result: 'OK', tests: i, counterexample: null }; - }; + return (seed: number, + size: number) => { + let rng = new Prando(seed); + let gen = generator(rng); + let i = 0; + for (; i < MAX_SUCCESS; i++) { + let x = gen(size); + if (!predicate(x)) { + let counterexample = findMinimalCounterExample(x, predicate, shrinker); + return { seed, result: 'Falsified', tests: i + 1, counterexample }; + } + size++; + } + return { seed, result: 'OK', tests: i, counterexample: null }; + }; } // basic generators @@ -86,9 +88,9 @@ export function shrinklist(arr: A[]): A[][] { let tail = arr.slice(1); let keep1 = arr.slice(); keep1.splice(1, 1); - result.push(tail,keep1); + result.push(tail, keep1); - if (arr.length >3) { + if (arr.length > 3) { let half = Math.floor(arr.length / 2); let copy = arr.slice(); let secondHalf = copy.slice(half); @@ -98,6 +100,13 @@ export function shrinklist(arr: A[]): A[][] { return result; } -export let someInt : Gen = (rng: Prando) => +export let someInt: Gen = (rng: Prando) => (size: number) => rng.nextInt(-size, size); + +export const Property = { + run(prop: Property): TestResult { + let seed = Math.floor(Math.random() * 1000000); + return prop(seed, 0); + } +}; -- cgit v1.3.1