From 83d63d6d3248666ebb23c7c29f0c58775f277482 Mon Sep 17 00:00:00 2001 From: Arnaud Bailly Date: Tue, 2 Dec 2025 04:43:49 +0100 Subject: adapt Bank interface to async --- pbt/ts/src/bank.test.ts | 18 +++++++++--------- pbt/ts/src/bank.ts | 20 +++++++++++--------- pbt/ts/src/property.test.ts | 6 ++++-- pbt/ts/src/property.ts | 20 ++++++++++++-------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/pbt/ts/src/bank.test.ts b/pbt/ts/src/bank.test.ts index f6aa7b0..5939034 100644 --- a/pbt/ts/src/bank.test.ts +++ b/pbt/ts/src/bank.test.ts @@ -61,20 +61,20 @@ const genOperations = (accounts: Map) => const correctBalance = (initialAccounts: Map) => - (ops: Operation[]): Promise => { + async (ops: Operation[]): Promise => { const expectedBalances = new Map(initialAccounts); const api = new SimpleBank(initialAccounts); for (const op of ops) { switch (op.op) { case 'GetBalance': { - const retrieved = toNullable(api.balance(op.account)); + const retrieved = toNullable(await api.balance(op.account)); const expected = expectedBalances.get(op.account); if (retrieved !== expected) { console.log( `Balance mismatch for account ${op.account}: expected ${expected}, got ${retrieved}`, ); - return Promise.resolve(false); + return false; } break; } @@ -95,24 +95,24 @@ const correctBalance = // finally check all balances for (const [account, expectedBal] of expectedBalances.entries()) { - const retrieved = toNullable(api.balance(account)); + const retrieved = toNullable(await api.balance(account)); if (retrieved !== expectedBal) { console.log( `Final balance mismatch for account ${account}: expected ${expectedBal}, got ${retrieved}`, ); - return Promise.resolve(false); + return false; } } - return Promise.resolve(true); + return true; }; describe('Bank Simulator', () => { test('can retrieve balance given account exists', async () => { - const prop = forall(genAccounts, accounts => { + const prop = forall(genAccounts, async accounts => { const api = new SimpleBank(accounts); - return property(keyValueOf(accounts), ([accountNr, bal]) => { - const retrieved = toNullable(api.balance(accountNr)); + return property(keyValueOf(accounts), async ([accountNr, bal]) => { + const retrieved = toNullable(await api.balance(accountNr)); return Promise.resolve(retrieved === bal); }); }); diff --git a/pbt/ts/src/bank.ts b/pbt/ts/src/bank.ts index 1f47739..f5981a4 100644 --- a/pbt/ts/src/bank.ts +++ b/pbt/ts/src/bank.ts @@ -4,7 +4,7 @@ import {Option, fromNullable, matchW} from 'fp-ts/lib/Option'; export type Account = string; export interface Bank { - balance: (account: Account) => Option; + balance: (account: Account) => Promise>; /// Deposit amount into account /// @@ -15,8 +15,8 @@ export interface Bank { /// /// @param account The account to deposit into /// @param amt The amount to deposit - deposit: (account: Account, amt: number) => void; - withdraw: (account: Account, amt: number) => void; + deposit: (account: Account, amt: number) => Promise; + withdraw: (account: Account, amt: number) => Promise; } export class SimpleBank implements Bank { @@ -27,12 +27,12 @@ export class SimpleBank implements Bank { this.accounts = new Map(accounts); } - balance(account: Account): Option { - return fromNullable(this.accounts.get(account)); + balance(account: Account): Promise> { + return Promise.resolve(fromNullable(this.accounts.get(account))); } - deposit(account: Account, amt: number): void { - const current = this.balance(account); + deposit(account: Account, amt: number): Promise { + const current = fromNullable(this.accounts.get(account)); matchW( () => { throw new Error(`Unknown account ${account}`); @@ -41,10 +41,11 @@ export class SimpleBank implements Bank { this.accounts.set(account, bal + amt); }, )(current); + return Promise.resolve(); } - withdraw(account: Account, amt: number): void { - const current = this.balance(account); + withdraw(account: Account, amt: number): Promise { + const current = fromNullable(this.accounts.get(account)); matchW( () => { throw new Error(`Unknown account ${account}`); @@ -53,6 +54,7 @@ export class SimpleBank implements Bank { this.accounts.set(account, bal - amt); }, )(current); + return Promise.resolve(); } } diff --git a/pbt/ts/src/property.test.ts b/pbt/ts/src/property.test.ts index addff34..67ea81d 100644 --- a/pbt/ts/src/property.test.ts +++ b/pbt/ts/src/property.test.ts @@ -12,7 +12,9 @@ const predicate1: (pair: [number, number]) => Promise = ([x, y]) => describe('Find minimal counterexample', () => { test('do not shrink example if no shrinker given', async () => { - const result = await property(pairOf(positiveInt), predicate1)(42, 1); + const result = await property(pairOf(positiveInt), predicate1).then(p => + p(42, 1), + ); expect(result.result).toBe('Falsified'); expect(result.counterexample).toBeNull; }); @@ -22,7 +24,7 @@ describe('Find minimal counterexample', () => { pairOf(positiveInt), predicate1, shrinkPair(shrinkPositive, shrinkPositive), - )(42, 1); + ).then(p => p(42, 1)); expect(result.result).toBe('Falsified'); if (result.counterexample !== null) { expect(result.counterexample.counterexample).toStrictEqual([10, 10]); diff --git a/pbt/ts/src/property.ts b/pbt/ts/src/property.ts index 56683c1..635e731 100644 --- a/pbt/ts/src/property.ts +++ b/pbt/ts/src/property.ts @@ -53,11 +53,11 @@ export function generate(gen: Gen): A { return gen(rng)(100); } -export function property( +export async function property( generator: Gen, predicate: Predicate, shrinker?: Shrinker, -): Property { +): Promise> { return async (seed: number, size: number) => { const rng = new Prando(seed); const gen = generator(rng); @@ -243,9 +243,10 @@ export function shrinkPair( } export const Property = { - run(prop: Property): Promise> { + async run(prop: Promise>): Promise> { const seed = Math.floor(Math.random() * 1000000); - return prop(seed, 0); + const p = await prop; + return await p(seed, 0); }, }; @@ -253,11 +254,14 @@ export const Property = { export function forall( gen: Gen, - k: (a: A) => Property, -): Property { - return (seed: number, size: number) => { + k: (a: A) => Promise>, +): Promise> { + const p = async (seed: number, size: number) => { const rng = new Prando(seed); const a = gen(rng)(size); - return k(a)(seed, size); + const p = await k(a); + return await p(seed, size); }; + + return Promise.resolve(p); } -- cgit v1.3.1