@demlik/tea 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/agent/index.d.ts +36 -23
- package/dist/agent/index.js +12 -10
- package/dist/{chunk-UHAQ4PI6.js → chunk-2A5XTKQQ.js} +205 -59
- package/dist/chunk-2A5XTKQQ.js.map +1 -0
- package/dist/{chunk-JAKM53JF.js → chunk-7K7SEYCH.js} +16 -15
- package/dist/chunk-7K7SEYCH.js.map +1 -0
- package/dist/{chunk-RKVUVALV.js → chunk-A3QPMX5M.js} +31 -9
- package/dist/chunk-A3QPMX5M.js.map +1 -0
- package/dist/{chunk-DVNXEB7V.js → chunk-BVFS3ICC.js} +3 -3
- package/dist/chunk-BVFS3ICC.js.map +1 -0
- package/dist/{chunk-FTCYY2DO.js → chunk-CPE5ZQXQ.js} +3 -3
- package/dist/{chunk-FTCYY2DO.js.map → chunk-CPE5ZQXQ.js.map} +1 -1
- package/dist/chunk-DEAPNMKO.js +11 -0
- package/dist/chunk-DEAPNMKO.js.map +1 -0
- package/dist/{chunk-XWIE5V7R.js → chunk-ETRNSJCR.js} +4 -4
- package/dist/{chunk-XWIE5V7R.js.map → chunk-ETRNSJCR.js.map} +1 -1
- package/dist/chunk-FXWDDNGD.js +98 -0
- package/dist/chunk-FXWDDNGD.js.map +1 -0
- package/dist/chunk-GFGOQIEC.js +10 -0
- package/dist/chunk-GFGOQIEC.js.map +1 -0
- package/dist/{chunk-2R62Q5UK.js → chunk-IAHEYPYJ.js} +3 -3
- package/dist/{chunk-2R62Q5UK.js.map → chunk-IAHEYPYJ.js.map} +1 -1
- package/dist/{chunk-NGYFBD5G.js → chunk-J5JNLXO7.js} +3 -3
- package/dist/{chunk-NGYFBD5G.js.map → chunk-J5JNLXO7.js.map} +1 -1
- package/dist/{chunk-72CN3VPY.js → chunk-NFOGYDRS.js} +5 -5
- package/dist/{chunk-72CN3VPY.js.map → chunk-NFOGYDRS.js.map} +1 -1
- package/dist/{chunk-A73IJ27X.js → chunk-R2YNDRGL.js} +3 -3
- package/dist/{chunk-A73IJ27X.js.map → chunk-R2YNDRGL.js.map} +1 -1
- package/dist/{chunk-5HVKDHY6.js → chunk-R5NXOPL2.js} +3 -3
- package/dist/{chunk-5HVKDHY6.js.map → chunk-R5NXOPL2.js.map} +1 -1
- package/dist/chunk-RMBZ7YH7.js +52 -0
- package/dist/chunk-RMBZ7YH7.js.map +1 -0
- package/dist/{chunk-AIXC33SE.js → chunk-SHXUSTHM.js} +62 -15
- package/dist/chunk-SHXUSTHM.js.map +1 -0
- package/dist/{chunk-TAKPC6SD.js → chunk-UGTC33VH.js} +4 -4
- package/dist/{chunk-TAKPC6SD.js.map → chunk-UGTC33VH.js.map} +1 -1
- package/dist/{chunk-EA47MI5Q.js → chunk-VH5MYJ2K.js} +4 -4
- package/dist/{chunk-EA47MI5Q.js.map → chunk-VH5MYJ2K.js.map} +1 -1
- package/dist/{chunk-2774I242.js → chunk-WZEDIUWR.js} +21 -20
- package/dist/chunk-WZEDIUWR.js.map +1 -0
- package/dist/{chunk-TGJLXZAU.js → chunk-ZRRET3RP.js} +11 -11
- package/dist/chunk-ZRRET3RP.js.map +1 -0
- package/dist/{core-CtvAyPpH.d.ts → core-DNDAEhO2.d.ts} +9 -12
- package/dist/devtools/index.d.ts +4 -4
- package/dist/do/index.d.ts +103 -38
- package/dist/do/index.js +40 -21
- package/dist/do/index.js.map +1 -1
- package/dist/{drive-loop-Dw1sGSsW.d.ts → drive-loop-DlOEv49c.d.ts} +2 -2
- package/dist/{durable-effects-Ump5lSdO.d.ts → durable-effects-wLWEdy9H.d.ts} +1 -1
- package/dist/effect/index.d.ts +121 -28
- package/dist/effect/index.js +45 -31
- package/dist/effect/index.js.map +1 -1
- package/dist/extension/index.d.ts +3 -3
- package/dist/extension/index.js +2 -2
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +17 -13
- package/dist/flow/index.js +15 -12
- package/dist/flow/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +3 -3
- package/dist/idempotency/index.js +3 -3
- package/dist/{index-CrcoVfd_.d.ts → index-9P1PaXIV.d.ts} +2 -2
- package/dist/{index-D3NY3VCN.d.ts → index-BBLI2WWN.d.ts} +1 -1
- package/dist/{index-Dl71V7kt.d.ts → index-C1WhBZ6a.d.ts} +4 -5
- package/dist/{index-CKtEKGyp.d.ts → index-C92SgNWz.d.ts} +3 -3
- package/dist/{index-CZZ3HI-Z.d.ts → index-CAsUE_d1.d.ts} +4 -4
- package/dist/{index-EIgfl83J.d.ts → index-CO34esWT.d.ts} +2 -2
- package/dist/{index-Bk2hBUdK.d.ts → index-COeX9Bmz.d.ts} +11 -9
- package/dist/{index-CVU7SK3a.d.ts → index-Cg0QXnzf.d.ts} +2 -2
- package/dist/index.d.ts +9 -9
- package/dist/index.js +2 -2
- package/dist/jev/index.d.ts +15 -15
- package/dist/jev/index.js +5 -5
- package/dist/jev/index.js.map +1 -1
- package/dist/laws-DTtCDDlU.d.ts +135 -0
- package/dist/loop-DReKGV1X.d.ts +70 -0
- package/dist/{machine-Dtre2TmN.d.ts → machine-C0WhOAyB.d.ts} +7 -7
- package/dist/machine-viz/index.d.ts +1 -1
- package/dist/machine-viz/index.js +2 -2
- package/dist/mem/index.d.ts +4 -3
- package/dist/mem/index.js +2 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +57 -9
- package/dist/node/index.js +175 -68
- package/dist/node/index.js.map +1 -1
- package/dist/otel/index.d.ts +28 -12
- package/dist/otel/index.js +25 -21
- package/dist/otel/index.js.map +1 -1
- package/dist/paginate/index.d.ts +4 -4
- package/dist/paginate/index.js +5 -5
- package/dist/parity/index.d.ts +11 -15
- package/dist/parity/index.js +4 -9
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +279 -67
- package/dist/pbt/index.js +299 -58
- package/dist/pbt/index.js.map +1 -1
- package/dist/persistence/index.d.ts +10 -12
- package/dist/persistence/index.js +4 -4
- package/dist/promise/index.d.ts +118 -21
- package/dist/promise/index.js +6 -4
- package/dist/react/index.d.ts +34 -21
- package/dist/react/index.js +271 -42
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +6 -6
- package/dist/resilience/index.js +5 -5
- package/dist/{run-fiBe7pOG.d.ts → run-Cnw4qXj2.d.ts} +105 -23
- package/dist/{runtime-types-DEluQgGO.d.ts → runtime-types-CP-ykwgf.d.ts} +157 -29
- package/dist/testing/effect/index.d.ts +162 -9
- package/dist/testing/effect/index.js +110 -10
- package/dist/testing/effect/index.js.map +1 -1
- package/dist/testing/index.d.ts +6 -8
- package/dist/testing/index.js +4 -24
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/promise/index.d.ts +4 -4
- package/dist/testing/promise/index.js +5 -5
- package/dist/timing/index.d.ts +4 -4
- package/dist/timing/index.js +4 -4
- package/dist/{types-CXNzlbAg.d.ts → types-S53WDy_h.d.ts} +1 -1
- package/dist/work-queue/index.d.ts +4 -4
- package/dist/work-queue/index.js +2 -2
- package/package.json +19 -17
- package/dist/chunk-2774I242.js.map +0 -1
- package/dist/chunk-AIXC33SE.js.map +0 -1
- package/dist/chunk-DVNXEB7V.js.map +0 -1
- package/dist/chunk-HX3C6LDK.js +0 -34
- package/dist/chunk-HX3C6LDK.js.map +0 -1
- package/dist/chunk-JAKM53JF.js.map +0 -1
- package/dist/chunk-RKVUVALV.js.map +0 -1
- package/dist/chunk-TGJLXZAU.js.map +0 -1
- package/dist/chunk-UHAQ4PI6.js.map +0 -1
package/dist/pbt/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import '../chunk-
|
|
2
|
-
|
|
3
|
-
import
|
|
1
|
+
import { MAX_PICK, resolveGuided, foldEvents, lawTerminates, lawInvariant, lawTrace } from '../chunk-FXWDDNGD.js';
|
|
2
|
+
export { foldEvents, lawInvariant, lawTerminates, lawTrace } from '../chunk-FXWDDNGD.js';
|
|
3
|
+
import '../chunk-BVFS3ICC.js';
|
|
4
|
+
import { msgKeysOf, structuralHash } from '../chunk-A3QPMX5M.js';
|
|
5
|
+
import * as fc3 from 'fast-check';
|
|
4
6
|
|
|
5
7
|
// src/pbt/arbitraries/ctx.ts
|
|
6
8
|
function stubCtxThrowingProxy() {
|
|
@@ -33,93 +35,332 @@ function arbMsg(table, opts) {
|
|
|
33
35
|
arbitrary: arb,
|
|
34
36
|
weight: weights?.[key] ?? 1
|
|
35
37
|
}));
|
|
36
|
-
return
|
|
38
|
+
return fc3.oneof(...weighted);
|
|
37
39
|
}
|
|
38
40
|
function arbConstantMsg(type) {
|
|
39
|
-
return
|
|
41
|
+
return fc3.constant({ type });
|
|
40
42
|
}
|
|
41
43
|
function arbRecordMsg(type, fields) {
|
|
42
44
|
const recordArbitraries = {
|
|
43
|
-
type:
|
|
45
|
+
type: fc3.constant(type),
|
|
44
46
|
...fields
|
|
45
47
|
};
|
|
46
|
-
return
|
|
48
|
+
return fc3.record(recordArbitraries);
|
|
47
49
|
}
|
|
48
50
|
function arbMsgSequence(msgArb, opts) {
|
|
49
51
|
const minLength = opts?.minLength ?? 0;
|
|
50
52
|
const maxLength = opts?.maxLength ?? 30;
|
|
51
53
|
const prefix = opts?.prefix ?? [];
|
|
52
|
-
const tail =
|
|
54
|
+
const tail = fc3.array(msgArb, { minLength, maxLength, size: opts?.size });
|
|
53
55
|
if (prefix.length === 0) return tail;
|
|
54
56
|
return tail.map((arr) => [...prefix, ...arr]);
|
|
55
57
|
}
|
|
56
|
-
function arbGuidedSequence(
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
function arbGuidedSequence(machine, ctx, cells, opts) {
|
|
59
|
+
const outside = Object.values(cells.outside ?? {});
|
|
60
|
+
const answers = Object.entries(cells.answers ?? {});
|
|
61
|
+
const answerers = answers.map(
|
|
62
|
+
([cmdType, cell]) => ({ cmdType, make: cell.make })
|
|
59
63
|
);
|
|
64
|
+
const arms = [];
|
|
65
|
+
if (outside.length > 0) {
|
|
66
|
+
arms.push({
|
|
67
|
+
weight: 1,
|
|
68
|
+
arbitrary: fc3.oneof(...outside).map((msg) => ({ kind: "outside", msg }))
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (answers.length > 0) {
|
|
72
|
+
arms.push({
|
|
73
|
+
weight: 2,
|
|
74
|
+
arbitrary: fc3.tuple(
|
|
75
|
+
fc3.nat(MAX_PICK),
|
|
76
|
+
fc3.tuple(...answers.map(([, cell]) => cell.draw))
|
|
77
|
+
).map(
|
|
78
|
+
([pick, values]) => ({
|
|
79
|
+
kind: "answer",
|
|
80
|
+
pick,
|
|
81
|
+
values
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (arms.length === 0) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
"@demlik/tea/pbt: arbGuidedSequence got no cells, in `outside` or `answers`, so it could only draw empty lists."
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const loaded = opts?.loaded ?? null;
|
|
92
|
+
return fc3.array(fc3.oneof(...arms), {
|
|
93
|
+
maxLength: opts?.maxLength ?? 60,
|
|
94
|
+
size: opts?.size ?? "max"
|
|
95
|
+
}).map((events) => resolveGuided(machine, ctx, loaded, answerers, events));
|
|
60
96
|
}
|
|
61
97
|
|
|
62
|
-
// src/pbt/runners/
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
// src/pbt/runners/msg-tally.ts
|
|
99
|
+
function outline(value) {
|
|
100
|
+
if (Array.isArray(value)) return "[";
|
|
101
|
+
if (typeof value === "object" && value !== null) {
|
|
102
|
+
const proto = Object.getPrototypeOf(value);
|
|
103
|
+
if (proto === Object.prototype || proto === null) return "{";
|
|
104
|
+
}
|
|
105
|
+
return structuralHash(value);
|
|
106
|
+
}
|
|
107
|
+
function differs(a, b) {
|
|
108
|
+
if (a === b) return false;
|
|
109
|
+
const shape = outline(a);
|
|
110
|
+
if (shape !== outline(b)) return true;
|
|
111
|
+
if (shape === "[") return listsDiffer(a, b);
|
|
112
|
+
if (shape === "{") {
|
|
113
|
+
return recordsDiffer(
|
|
114
|
+
a,
|
|
115
|
+
b
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
var slotsOf = (list) => list.length === 1 && !(0 in list) ? [] : list;
|
|
121
|
+
function listsDiffer(a, b) {
|
|
122
|
+
const left = slotsOf(a);
|
|
123
|
+
const right = slotsOf(b);
|
|
124
|
+
if (left.length !== right.length) return true;
|
|
125
|
+
for (let i = 0; i < left.length; i++) {
|
|
126
|
+
if (i in left !== i in right || differs(left[i], right[i])) return true;
|
|
77
127
|
}
|
|
78
|
-
return
|
|
128
|
+
return false;
|
|
79
129
|
}
|
|
130
|
+
var seenAt = (record2, key) => Object.prototype.propertyIsEnumerable.call(record2, key) ? record2[key] : void 0;
|
|
131
|
+
function recordsDiffer(a, b) {
|
|
132
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) {
|
|
133
|
+
if (differs(seenAt(a, key), seenAt(b, key))) return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
function classify(step) {
|
|
138
|
+
if (step.cmds.length > 0) return { acted: true, refusal: null };
|
|
139
|
+
try {
|
|
140
|
+
return { acted: differs(step.prev, step.next), refusal: null };
|
|
141
|
+
} catch (refusal) {
|
|
142
|
+
return { acted: true, refusal };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
var MsgTally = class {
|
|
146
|
+
#counts = /* @__PURE__ */ new Map();
|
|
147
|
+
#closed = false;
|
|
148
|
+
#refusal = null;
|
|
149
|
+
/** @param msgTypes The machine's Msg types, so one never drawn still reads zero. */
|
|
150
|
+
constructor(msgTypes) {
|
|
151
|
+
for (const type of msgTypes) this.#counts.set(type, { drawn: 0, acted: 0 });
|
|
152
|
+
}
|
|
153
|
+
/** Count one list's steps, unless the run has already failed. */
|
|
154
|
+
add(steps) {
|
|
155
|
+
if (this.#closed) return;
|
|
156
|
+
for (const step of steps) {
|
|
157
|
+
const { acted, refusal } = classify(step);
|
|
158
|
+
const count = this.#counts.get(step.msg.type) ?? { drawn: 0, acted: 0 };
|
|
159
|
+
this.#counts.set(step.msg.type, {
|
|
160
|
+
drawn: count.drawn + 1,
|
|
161
|
+
acted: count.acted + (acted ? 1 : 0)
|
|
162
|
+
});
|
|
163
|
+
this.#refusal ??= refusal;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** The run has failed. Whatever comes next is shrinking. */
|
|
167
|
+
close() {
|
|
168
|
+
this.#closed = true;
|
|
169
|
+
}
|
|
170
|
+
/** Each Msg type's count: the machine's types first, then any other drawn. */
|
|
171
|
+
get counts() {
|
|
172
|
+
return new Map(this.#counts);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* What `structuralHash` threw on the first value the comparison reached and
|
|
176
|
+
* couldn't read. Such a step counts as acted, since nothing shows it didn't, so
|
|
177
|
+
* "never acted" can't be trusted here.
|
|
178
|
+
*/
|
|
179
|
+
get refusal() {
|
|
180
|
+
return this.#refusal;
|
|
181
|
+
}
|
|
182
|
+
/** The Msg types at zero acted, each with what it drew. */
|
|
183
|
+
get neverActed() {
|
|
184
|
+
return [...this.#counts].filter(([, count]) => count.acted === 0);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
80
187
|
|
|
81
188
|
// src/pbt/runners/property.ts
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
189
|
+
var PropertyFailure = class extends Error {
|
|
190
|
+
constructor(report, run, options) {
|
|
191
|
+
super(report, options);
|
|
192
|
+
this.run = run;
|
|
193
|
+
}
|
|
194
|
+
run;
|
|
195
|
+
name = "PropertyFailure";
|
|
196
|
+
_tag = "PropertyFailure";
|
|
197
|
+
};
|
|
198
|
+
var BrokenLaw = class extends Error {
|
|
199
|
+
constructor(report, reason) {
|
|
200
|
+
super(`${report}
|
|
201
|
+
reason: ${reason}`);
|
|
202
|
+
this.report = report;
|
|
203
|
+
this.reason = reason;
|
|
204
|
+
this.name = "Error";
|
|
205
|
+
}
|
|
206
|
+
report;
|
|
207
|
+
reason;
|
|
208
|
+
toString() {
|
|
209
|
+
return `${this.name}: ${this.report}`;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function assertHolds(answer, report) {
|
|
213
|
+
if (answer === true || answer === null) return;
|
|
214
|
+
if (answer === false || answer === "") throw new Error(report());
|
|
215
|
+
throw new BrokenLaw(report(), answer);
|
|
216
|
+
}
|
|
217
|
+
function assertLaw(runner, broken) {
|
|
218
|
+
if (broken === null) return;
|
|
219
|
+
const report = `${runner}: ${broken.report}`;
|
|
220
|
+
throw broken.reason === null ? new Error(report) : new BrokenLaw(report, broken.reason);
|
|
221
|
+
}
|
|
222
|
+
function cmdFault(cmd, declared) {
|
|
223
|
+
const { type } = Object(cmd);
|
|
224
|
+
if (typeof cmd !== "object" || typeof type !== "string") {
|
|
225
|
+
return `${fc3.stringify(cmd)} isn't a Cmd: it has no string \`type\``;
|
|
226
|
+
}
|
|
227
|
+
if (declared === null || declared.has(type)) return null;
|
|
228
|
+
return `${fc3.stringify(cmd)} isn't in machine.cmds: [${[...declared].join(", ")}]`;
|
|
229
|
+
}
|
|
230
|
+
function assertSentCmds({ initCmds, steps }, declared) {
|
|
231
|
+
for (const cmd of initCmds) {
|
|
232
|
+
assertHolds(cmdFault(cmd, declared), () => "init sent a bad Cmd");
|
|
233
|
+
}
|
|
234
|
+
for (const { msg, cmds } of steps) {
|
|
235
|
+
for (const cmd of cmds) {
|
|
236
|
+
assertHolds(
|
|
237
|
+
cmdFault(cmd, declared),
|
|
238
|
+
() => `step msg=${fc3.stringify(msg)} sent a bad Cmd`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function isArbitrary(loaded) {
|
|
244
|
+
if (typeof loaded !== "object" || loaded === null) return false;
|
|
245
|
+
const { generate, shrink, canShrinkWithoutContext } = loaded;
|
|
246
|
+
return typeof generate === "function" && typeof shrink === "function" && typeof canShrinkWithoutContext === "function";
|
|
247
|
+
}
|
|
248
|
+
function withoutUndefined(settings) {
|
|
249
|
+
return Object.fromEntries(
|
|
250
|
+
Object.entries(settings).filter(([, value]) => value !== void 0)
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
function causeOf(details) {
|
|
254
|
+
const { errorWithCause, includeErrorInReport } = details.runConfiguration;
|
|
255
|
+
const major = Number(fc3.__version.split(".")[0]);
|
|
256
|
+
return (major >= 4 ? !includeErrorInReport : errorWithCause) ? { cause: details.errorInstance } : void 0;
|
|
257
|
+
}
|
|
258
|
+
function settle(details, tally) {
|
|
259
|
+
const run = {
|
|
260
|
+
numRuns: details.numRuns,
|
|
261
|
+
numShrinks: details.numShrinks,
|
|
262
|
+
seed: details.seed,
|
|
263
|
+
path: details.counterexamplePath,
|
|
264
|
+
msgCounts: tally.counts
|
|
86
265
|
};
|
|
266
|
+
const { reporter } = fc3.readConfigureGlobal();
|
|
267
|
+
if (reporter) {
|
|
268
|
+
reporter(details);
|
|
269
|
+
return run;
|
|
270
|
+
}
|
|
271
|
+
const report = fc3.defaultReportMessage(details);
|
|
272
|
+
if (report === void 0) return run;
|
|
273
|
+
const cause = causeOf(details);
|
|
274
|
+
const broken = details.errorInstance;
|
|
275
|
+
throw new PropertyFailure(
|
|
276
|
+
cause && broken instanceof BrokenLaw ? `${report}
|
|
277
|
+
|
|
278
|
+
reason: ${broken.reason}` : report,
|
|
279
|
+
run,
|
|
280
|
+
cause
|
|
281
|
+
);
|
|
87
282
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
283
|
+
function assertEveryTypeActed(run, tally) {
|
|
284
|
+
const { refusal, neverActed } = tally;
|
|
285
|
+
const ranOver = `after ${run.numRuns} runs, seed ${run.seed}`;
|
|
286
|
+
if (refusal !== null) {
|
|
287
|
+
const why = refusal instanceof Error ? refusal.message : String(refusal);
|
|
288
|
+
throw new PropertyFailure(
|
|
289
|
+
`Property failed ${ranOver}: failOnNeverActed can't tell what acted, because a state isn't plain data.
|
|
290
|
+
|
|
291
|
+
${why}`,
|
|
292
|
+
run
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
if (neverActed.length === 0) return;
|
|
296
|
+
const named = neverActed.map(
|
|
297
|
+
([type, { drawn }]) => ` ${type} (drawn ${drawn})`
|
|
298
|
+
);
|
|
299
|
+
throw new PropertyFailure(
|
|
300
|
+
`Property failed ${ranOver}: ${neverActed.length} Msg type(s) never acted:
|
|
301
|
+
${named.join("\n")}`,
|
|
302
|
+
run
|
|
94
303
|
);
|
|
95
304
|
}
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
305
|
+
function runProperty(machine, ctx, seqArb, opts, check2) {
|
|
306
|
+
const { loaded, failOnNeverActed, failOnUndeclaredCmd, ...settings } = opts ?? {};
|
|
307
|
+
const params = {
|
|
308
|
+
...withoutUndefined(settings),
|
|
309
|
+
numRuns: settings.numRuns ?? 200
|
|
310
|
+
};
|
|
311
|
+
const tally = new MsgTally(msgKeysOf(machine));
|
|
312
|
+
const declared = failOnUndeclaredCmd && machine.cmds ? new Set(machine.cmds.map((def) => def.cmdType)) : null;
|
|
313
|
+
const runList = (msgs, start) => {
|
|
314
|
+
let steps = [];
|
|
315
|
+
try {
|
|
316
|
+
const result = foldEvents(machine, ctx, start, msgs);
|
|
317
|
+
steps = result.steps;
|
|
318
|
+
assertSentCmds(result, declared);
|
|
319
|
+
check2(result);
|
|
320
|
+
} catch (error) {
|
|
321
|
+
if (!fc3.PreconditionFailure.isFailure(error)) {
|
|
322
|
+
tally.add(steps);
|
|
323
|
+
tally.close();
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
102
326
|
}
|
|
327
|
+
tally.add(steps);
|
|
328
|
+
};
|
|
329
|
+
const checkActed = failOnNeverActed && !settings.path;
|
|
330
|
+
const finish = (details) => {
|
|
331
|
+
const run = settle(details, tally);
|
|
332
|
+
if (checkActed && !details.failed) assertEveryTypeActed(run, tally);
|
|
333
|
+
return run;
|
|
334
|
+
};
|
|
335
|
+
return isArbitrary(loaded) ? finish(
|
|
336
|
+
fc3.check(
|
|
337
|
+
fc3.property(seqArb, loaded, (msgs, drawn) => {
|
|
338
|
+
runList(msgs, drawn);
|
|
339
|
+
}),
|
|
340
|
+
params
|
|
341
|
+
)
|
|
342
|
+
) : finish(
|
|
343
|
+
fc3.check(
|
|
344
|
+
fc3.property(seqArb, (msgs) => {
|
|
345
|
+
runList(msgs, loaded ?? null);
|
|
346
|
+
}),
|
|
347
|
+
params
|
|
348
|
+
)
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
function propertyTerminates(machine, ctx, seqArb, terminal, opts) {
|
|
352
|
+
return runProperty(machine, ctx, seqArb, opts, (fold) => {
|
|
353
|
+
assertLaw("propertyTerminates", lawTerminates(fold, terminal));
|
|
103
354
|
});
|
|
104
355
|
}
|
|
105
356
|
function propertyInvariant(machine, ctx, seqArb, invariant, opts) {
|
|
106
|
-
runProperty(machine, ctx, seqArb, opts, (
|
|
107
|
-
|
|
108
|
-
if (!invariant(step)) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
`propertyInvariant: failed at step msg=${JSON.stringify(step.msg)} prev=${JSON.stringify(step.prev)} next=${JSON.stringify(step.next)} cmds=${JSON.stringify(step.cmds)}`
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
357
|
+
return runProperty(machine, ctx, seqArb, opts, (fold) => {
|
|
358
|
+
assertLaw("propertyInvariant", lawInvariant(fold, invariant));
|
|
114
359
|
});
|
|
115
360
|
}
|
|
116
361
|
function propertyTrace(machine, ctx, seqArb, predicate, opts) {
|
|
117
|
-
runProperty(machine, ctx, seqArb, opts, (
|
|
118
|
-
|
|
119
|
-
throw new Error(
|
|
120
|
-
`propertyTrace: predicate failed on trace length=${steps.length}, final=${JSON.stringify(finalState)}`
|
|
121
|
-
);
|
|
122
|
-
}
|
|
362
|
+
return runProperty(machine, ctx, seqArb, opts, (fold) => {
|
|
363
|
+
assertLaw("propertyTrace", lawTrace(fold, predicate));
|
|
123
364
|
});
|
|
124
365
|
}
|
|
125
366
|
|
|
@@ -128,6 +369,6 @@ function msgTypeKeys(machine) {
|
|
|
128
369
|
return msgKeysOf(machine);
|
|
129
370
|
}
|
|
130
371
|
|
|
131
|
-
export { arbConstantMsg, arbGuidedSequence, arbMsg, arbMsgSequence, arbRecordMsg,
|
|
372
|
+
export { PropertyFailure, arbConstantMsg, arbGuidedSequence, arbMsg, arbMsgSequence, arbRecordMsg, msgTypeKeys, propertyInvariant, propertyTerminates, propertyTrace, stubCtxThrowingProxy };
|
|
132
373
|
//# sourceMappingURL=index.js.map
|
|
133
374
|
//# sourceMappingURL=index.js.map
|