summaryrefslogtreecommitdiff
path: root/pbt/ts/src/property.ts
diff options
context:
space:
mode:
Diffstat (limited to 'pbt/ts/src/property.ts')
-rw-r--r--pbt/ts/src/property.ts45
1 files changed, 42 insertions, 3 deletions
diff --git a/pbt/ts/src/property.ts b/pbt/ts/src/property.ts
index 7b3ee59..500c423 100644
--- a/pbt/ts/src/property.ts
+++ b/pbt/ts/src/property.ts
@@ -20,7 +20,7 @@ type Property<A> = (seed: number, size: number) => TestResult<A>;
const MAX_SUCCESS = 100;
-function findMinimalCounterExample<A>(
+export function findMinimalCounterExample<A>(
x: A,
predicate: Predicate<A>,
shrinker: Shrinker<A>,
@@ -117,6 +117,7 @@ export function mapOf1<K, V>(genK: Gen<K>, genV: Gen<V>): Gen<Map<K, V>> {
};
}
+/// Select randomly one element from given list
export function elements<A>(arr: A[]): Gen<A> {
return (rng: Prando) => (_size: number) => {
let index = rng.nextInt(0, arr.length - 1);
@@ -124,6 +125,7 @@ export function elements<A>(arr: A[]): Gen<A> {
};
}
+/// Select one key-value pair from given map
export function keyValueOf<K, V>(map: Map<K, V>): Gen<[K, V]> {
let keys = Array.from(map.keys());
return (rng: Prando) => {
@@ -136,12 +138,27 @@ export function keyValueOf<K, V>(map: Map<K, V>): Gen<[K, V]> {
};
}
+/// Choose number between some bounds.
export function choose(min: number, max: number): Gen<number> {
return (rng: Prando) => (size: number) => rng.nextInt(min, max);
}
-export let someInt: Gen<number> = (rng: Prando) => (size: number) =>
- rng.nextInt(-size, size);
+/// Choose some random integer.
+export let someInt: Gen<number> = (rng: Prando) => (size: number) => {
+ const bound = Math.pow(2, size);
+ return rng.nextInt(-bound, bound);
+};
+
+/// Choose some random positive integer.
+export let positiveInt: Gen<number> = (rng: Prando) => (size: number) => {
+ const bound = Math.pow(2, Math.round(Math.sqrt(size)));
+ return rng.nextInt(0, bound);
+};
+
+/// Generate a pair of generated values
+export function pairOf<A>(gen: Gen<A>): Gen<[A, A]> {
+ return (rng: Prando) => (size: number) => [gen(rng)(size), gen(rng)(size)];
+}
// basic shrinkers
export function shrinklist<A>(arr: A[]): A[][] {
@@ -162,6 +179,28 @@ export function shrinklist<A>(arr: A[]): A[][] {
return result;
}
+export function shrinkPositive(i: number): number[] {
+ if (i == 0) return [];
+
+ return [i - 1, Math.round(Math.sqrt(i))];
+}
+
+// shrink pair
+export function shrinkPair<A, B>(
+ shrinkA: Shrinker<A>,
+ shrinkB: Shrinker<B>,
+): Shrinker<[A, B]> {
+ return ([x, y]) => {
+ const shrinkx = shrinkA(x);
+ const shrinky = shrinkB(y);
+ // assumes x >= y
+ const resulta: [A, B][] = shrinkx.map(e => [e, y]);
+ const resultb: [A, B][] = shrinky.map(e => [x, e]);
+ const resultboth: [A, B][] = shrinkx.map((e, i) => [e, shrinky[i]]);
+ return resulta.concat(resultb, resultboth);
+ };
+}
+
export const Property = {
run<A>(prop: Property<A>): TestResult<A> {
let seed = Math.floor(Math.random() * 1000000);