summaryrefslogtreecommitdiff
path: root/pbt
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud.bailly@iohk.io>2025-01-25 18:31:41 +0100
committerArnaud Bailly <arnaud.bailly@iohk.io>2025-01-25 18:31:41 +0100
commit8bcaac40ee1afb8c36f98beabe0348ae3713d44d (patch)
tree0b4b6f1f399fcf21462dec3ae2bbf95a1b6f69c3 /pbt
parenta98aaf0232a159d403a7e2bc946c51c1fa490481 (diff)
downloadlambda-nantes-8bcaac40ee1afb8c36f98beabe0348ae3713d44d.tar.gz
Generate a random list
Diffstat (limited to 'pbt')
-rw-r--r--pbt/ts/package-lock.json20
-rw-r--r--pbt/ts/package.json9
-rw-r--r--pbt/ts/src/index.ts40
-rw-r--r--pbt/ts/src/property.ts53
-rw-r--r--pbt/ts/tsconfig.json2
5 files changed, 106 insertions, 18 deletions
diff --git a/pbt/ts/package-lock.json b/pbt/ts/package-lock.json
index 4e4aeff..56e87d3 100644
--- a/pbt/ts/package-lock.json
+++ b/pbt/ts/package-lock.json
@@ -5,6 +5,8 @@
"packages": {
"": {
"dependencies": {
+ "dotenv": "^16.4.7",
+ "prando": "^6.0.1",
"typescript": "^5.7.3"
},
"devDependencies": {
@@ -809,6 +811,18 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dotenv": {
+ "version": "16.4.7",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+ "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -2324,6 +2338,12 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/prando": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/prando/-/prando-6.0.1.tgz",
+ "integrity": "sha512-ghUWxQ1T9IJmPu6eshc3VU0OwveUtXQ33ZLXYUcz1Oc5ppKLDXKp0TBDj6b0epwhEctzcQSNGR2iHyvQSn4W5A==",
+ "license": "MIT"
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
diff --git a/pbt/ts/package.json b/pbt/ts/package.json
index 5aab336..c11b4ba 100644
--- a/pbt/ts/package.json
+++ b/pbt/ts/package.json
@@ -1,11 +1,13 @@
{
"dependencies": {
+ "dotenv": "^16.4.7",
+ "prando": "^6.0.1",
"typescript": "^5.7.3"
},
"devDependencies": {
+ "@types/node": "^22.7.5",
"gts": "^6.0.2",
- "typescript": "^5.6.3",
- "@types/node": "^22.7.5"
+ "typescript": "^5.6.3"
},
"scripts": {
"lint": "gts lint",
@@ -14,6 +16,7 @@
"fix": "gts fix",
"prepare": "npm run compile",
"pretest": "npm run compile",
- "posttest": "npm run lint"
+ "posttest": "npm run lint",
+ "app": "node build/src/index.js"
}
}
diff --git a/pbt/ts/src/index.ts b/pbt/ts/src/index.ts
index 3a71ccf..46454f0 100644
--- a/pbt/ts/src/index.ts
+++ b/pbt/ts/src/index.ts
@@ -1,20 +1,32 @@
-type Result = 'OK' | 'Falsified' | 'Exception';
+import "dotenv/config";
+import Prando from 'prando';
+import { Gen } from "./property";
-type TestResult<A> = {
- result: Result,
- seed: number,
- counterexample: A | null
-};
+let genint: Gen<number> = (rng: Prando) =>
+ (size: number) =>
+ rng.nextInt(-size, size);
-type Predicate<A> = (a: A) => boolean;
-type Gen<A> = (s: number) => (() => A);
+function genlist<A>(gen: Gen<A>): Gen<A[]> {
+ return (rng: Prando) => {
+ let g = gen(rng);
+ return (size: number) => {
+ let result = [];
+ for (let i = 0; i < size; i++) {
+ result.push(g(size));
+ }
+ return result;
+ };
+ };
+}
-type Shrinker<A> = (a: A) => [A];
+function generate<A>(gen: Gen<A>): A {
+ let rng = new Prando(Math.random() * 1000);
+ return gen(rng)(100);
+}
-function property<A>(seed: number,
- predicate: Predicate<A>,
- generator: Gen<A>,
- shrinker: Shrinker<A>): TestResult<A> {
- return {result: 'OK', seed, counterexample: null};
+async function main() {
+ console.log('list: ' + generate(genlist(genint)));
}
+
+main();
diff --git a/pbt/ts/src/property.ts b/pbt/ts/src/property.ts
new file mode 100644
index 0000000..e8d3a21
--- /dev/null
+++ b/pbt/ts/src/property.ts
@@ -0,0 +1,53 @@
+import Prando from "prando";
+
+type Result = 'OK' | 'Falsified' | 'Exception';
+
+type ShrinkResult<A> = { counterexample: A, shrinks: number };
+
+type TestResult<A> = {
+ result: Result,
+ counterexample: ShrinkResult<A> | null
+};
+
+type Predicate<A> = (a: A) => boolean;
+
+export type Gen<A> = (rng: Prando) => ((size: number) => A);
+
+type Shrinker<A> = (a: A) => [A];
+
+const MAX_SUCCESS = 100;
+
+function findMinimalCounterExample<A>(x: A,
+ predicate: Predicate<A>,
+ shrinker: Shrinker<A>,
+ depth: number = 0): ShrinkResult<A> {
+ let xs = shrinker(x);
+ let counterexample = x;
+ let shrinks = depth;
+ for (let y of xs) {
+ if (!predicate(y)) {
+ let shrink = findMinimalCounterExample(y, predicate, shrinker, depth + 1);
+ if (shrink.shrinks > depth) {
+ counterexample = shrink.counterexample;
+ shrinks = shrink.shrinks;
+ }
+ }
+ }
+ return { counterexample, shrinks };
+}
+
+export function property<A>(rng: Prando,
+ size: number,
+ predicate: Predicate<A>,
+ generator: Gen<A>,
+ shrinker: Shrinker<A>): TestResult<A> {
+ let gen = generator(rng);
+ for (let i = 0; i < MAX_SUCCESS; i++) {
+ let x = gen(size);
+ if (!predicate(x)) {
+ let counterexample = findMinimalCounterExample(x, predicate, shrinker);
+ return { result: 'Falsified', counterexample };
+ }
+ }
+ return { result: 'OK', counterexample: null };
+}
diff --git a/pbt/ts/tsconfig.json b/pbt/ts/tsconfig.json
index d1646f0..15fbe0f 100644
--- a/pbt/ts/tsconfig.json
+++ b/pbt/ts/tsconfig.json
@@ -7,5 +7,5 @@
"include": [
"src/**/*.ts",
"test/**/*.ts"
- ]
+, "src/property.ts~", "src/index.ts~" ]
}