Skip to content

Commit 48d156b

Browse files
committed
Implement an explain feature
1 parent fe0ac2d commit 48d156b

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

lib/core/src/__tests__/spec.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,10 @@ describe('composing predicates', () => {
2626
expect(s.isValid(bigEven, 10000)).toBe(true);
2727
})
2828
});
29+
30+
describe('explains', () => {
31+
test('explain scalar', () => {
32+
const bigEven = s.and(x => !isNaN(Number(x)), x => x%2 === 0, x => x > 1000);
33+
const res = s.explain(bigEven, "foo")
34+
});
35+
})

lib/core/src/base.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@ class Spec {
3434
}
3535
}
3636

37+
function dt(pred, x, form, cpred) {
38+
if (!pred) return x;
39+
40+
return conform(pred, x);
41+
}
42+
43+
function explainPredList(forms, preds, path, via, in_, x) {
44+
let ret = x;
45+
for (let i = 0; i < preds.length; i++) {
46+
const nret = dt(preds[i], ret, forms[i]);
47+
if (nret === INVALID) {
48+
return specize(preds[i]).explain(path, via, in_, ret);
49+
}
50+
ret = nret;
51+
}
52+
return null;
53+
}
54+
3755
class ScalarSpec extends Spec {
3856
constructor(form, pred, gfn, cpred) {
3957
super(gfn);
@@ -173,8 +191,12 @@ class ObjectSpec extends Spec {
173191
gen(overrides, path, rmap) {
174192
if (this.gfn) return this.gfn();
175193
const generators = {};
176-
for (const k in this.predObj) {
177-
generators[k] = gensub(this.predObj[k], overrides, [...path, k], rmap, this.predObj[k]);
194+
for (const k in this.required) {
195+
generators[k] = gensub(this.required[k], overrides, [...path, k], rmap, this.required[k]);
196+
}
197+
// TODO optional keys
198+
for (const k in this.optional) {
199+
178200
}
179201
return g.genObject(generators);
180202
}
@@ -183,7 +205,20 @@ class ObjectSpec extends Spec {
183205
if (typeof x !== 'object') {
184206
return [{path, via, pred: (x) => x === 'object', val: x, in: in_}];
185207
}
186-
return null;
208+
const explains = [];
209+
for(let k in obj) {
210+
const pred = this.optional[k] || this.required[k];
211+
if (pred && !pred(obj[k])) {
212+
explains.push({
213+
path: [...path, k],
214+
via,
215+
pred,
216+
val: x,
217+
in: in_
218+
});
219+
}
220+
}
221+
return explains;
187222
}
188223
}
189224

lib/testcheck/src/generators.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ function collDistinctBy_(emptyColl, keyFn, shuffleFn, gen, rng, size, numElement
7474
let s = size;
7575
for (let tries = 0; tries <= maxTries && numElements != res.length; tries++) {
7676
const v = callGen(gen, rng, size);
77-
console.log(res);
7877
if (res.includes(v)) {
7978
s += 1;
8079
} else {
@@ -158,6 +157,7 @@ const generators = {
158157
get string() { return fmap(join, vector(this.char)) },
159158
get stringAscii() { return fmap(join, vector(this.charAscii)) },
160159
get stringAlphanumeric() { return fmap(join, vector(this.charAlphanumeric)) },
160+
get stringAlpha() { return fmap(join, vector(this.charAlpha)) },
161161
get largeInteger() { return largeInteger_({}) },
162162
}
163163

specs/basic/src/__tests__/basic.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('generation', () => {
4444
x => gen.fmap(([s1, s2, s3]) => `${s1}@${s2}.${s3}`,
4545
gen.tuple(gen.generators.stringAlphanumeric,
4646
gen.generators.stringAlphanumeric,
47-
gen.generators.stringAlphanumeric))))
47+
gen.generators.stringAlpha))))
4848
}
4949
});
5050
const res = gen.sample(s.gen(person));

0 commit comments

Comments
 (0)