@overkill-dev/model 0.0.1 → 0.0.2
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/LICENSE +21 -0
- package/model/model-authoring.d.ts +6 -0
- package/model/model-authoring.d.ts.map +1 -0
- package/model/model-authoring.js +25 -0
- package/model/model-authoring.js.map +1 -0
- package/model/model-definition.d.ts +26 -0
- package/model/model-definition.d.ts.map +1 -0
- package/model/model-execution.js +42 -0
- package/model/model-execution.js.map +1 -0
- package/model/model-trace.js +38 -0
- package/model/model-trace.js.map +1 -0
- package/package.json +34 -6
- package/packages/model/model.entry-point.d.ts +3 -0
- package/packages/model/model.entry-point.d.ts.map +1 -0
- package/packages/model/model.entry-point.js +2 -0
- package/packages/model/model.entry-point.js.map +1 -0
- package/readme.md +55 -5
- package/software-bill-of-materials.cyclonedx.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Overkill contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type PropertyInvocation } from '@overkill-dev/property';
|
|
2
|
+
import type { TestCase } from '@overkill-dev/engine';
|
|
3
|
+
import type { ModelDefinition, ModelScenarioDefinition } from './model-definition.ts';
|
|
4
|
+
export declare function modelScenario<State, Operation, System>(definition: ModelScenarioDefinition<State, Operation, System>): PropertyInvocation<readonly Operation[]>;
|
|
5
|
+
export declare function model<State, Operation, System>(definition: ModelDefinition<State, Operation, System>): TestCase;
|
|
6
|
+
//# sourceMappingURL=model-authoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-authoring.d.ts","sourceRoot":"","sources":["../../../../source/model/model-authoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,kBAAkB,EAAE,MAAM,wBAA8C,CAAC;AACjG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAA0C,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAItF,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAClD,UAAU,EAAE,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,GAC9D,kBAAkB,CAAC,SAAS,SAAS,EAAE,CAAC,CAiB1C;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,QAAQ,CAE/G"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { property } from "@overkill-dev/property";
|
|
2
|
+
import { modelTrace } from "./model-trace.js";
|
|
3
|
+
import { modelExecution } from "./model-execution.js";
|
|
4
|
+
export function modelScenario(definition) {
|
|
5
|
+
const snapshot = Object.freeze({
|
|
6
|
+
...definition,
|
|
7
|
+
length: Object.freeze({ ...definition.length }),
|
|
8
|
+
examples: Object.freeze(Array.from(definition.examples)),
|
|
9
|
+
coverage: Object.freeze(definition.coverage.map(function (requirement) {
|
|
10
|
+
return Object.freeze({ ...requirement });
|
|
11
|
+
}))
|
|
12
|
+
});
|
|
13
|
+
const generator = modelTrace(snapshot, snapshot.length);
|
|
14
|
+
const invocation = {
|
|
15
|
+
generator: snapshot.codec === null ? generator : generator.withCodec(snapshot.codec),
|
|
16
|
+
examples: snapshot.examples,
|
|
17
|
+
coverage: snapshot.coverage,
|
|
18
|
+
test: modelExecution(snapshot)
|
|
19
|
+
};
|
|
20
|
+
return Object.freeze(invocation);
|
|
21
|
+
}
|
|
22
|
+
export function model(definition) {
|
|
23
|
+
return property({ title: definition.title, settings: definition.settings, ...modelScenario(definition) });
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=model-authoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-authoring.js","sourceRoot":"","sources":["../../../../source/model/model-authoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAA2B,MAAM,wBAA8C,CAAC;AAGjG,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,aAAa,CACzB,UAA6D;IAE7D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QAC3B,GAAG,UAAU;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;QAC/C,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxD,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,WAAW;YACjE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;KACN,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG;QACf,SAAS,EAAE,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpF,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC;KACjC,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,KAAK,CAA2B,UAAqD;IACjG,OAAO,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;AAC9G,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Generator as PropertyGenerator, LengthBounds, PropertyCoverageRequirement, PropertyExample, PropertyInputCodec, PropertySampleScope, PropertySettings } from '@overkill-dev/property';
|
|
2
|
+
export type ModelTransition<State> = {
|
|
3
|
+
readonly kind: 'disabled';
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: 'enabled';
|
|
6
|
+
readonly state: State;
|
|
7
|
+
};
|
|
8
|
+
export type ModelMachine<State, Operation> = {
|
|
9
|
+
readonly initial: () => State;
|
|
10
|
+
readonly commands: (state: Readonly<State>) => PropertyGenerator<Operation> | null;
|
|
11
|
+
readonly transition: (state: Readonly<State>, operation: Readonly<Operation>) => ModelTransition<State>;
|
|
12
|
+
};
|
|
13
|
+
export type ModelScenarioDefinition<State, Operation, System> = ModelMachine<State, Operation> & {
|
|
14
|
+
readonly length: LengthBounds;
|
|
15
|
+
readonly codec: PropertyInputCodec<readonly Operation[]> | null;
|
|
16
|
+
readonly examples: readonly PropertyExample<readonly Operation[]>[];
|
|
17
|
+
readonly coverage: readonly PropertyCoverageRequirement[];
|
|
18
|
+
readonly create: (sample: PropertySampleScope<readonly Operation[]>) => Promise<System> | System;
|
|
19
|
+
readonly run: (operation: Operation, system: System, sample: PropertySampleScope<readonly Operation[]>) => Promise<void> | void;
|
|
20
|
+
readonly check: (state: Readonly<State>, system: System, sample: PropertySampleScope<readonly Operation[]>) => Promise<void> | void;
|
|
21
|
+
};
|
|
22
|
+
export type ModelDefinition<State, Operation, System> = ModelScenarioDefinition<State, Operation, System> & {
|
|
23
|
+
readonly title: string;
|
|
24
|
+
readonly settings: PropertySettings;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=model-definition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-definition.d.ts","sourceRoot":"","sources":["../../../../source/model/model-definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,SAAS,IAAI,iBAAiB,EAC9B,YAAY,EACZ,2BAA2B,EAC3B,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EACnB,MAAM,wBAA8C,CAAC;AAEtD,MAAM,MAAM,eAAe,CAAC,KAAK,IAAI;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAAE,GAAG;IAClE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,KAAK,EAAE,SAAS,IAAI;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,iBAAiB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IACnF,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,eAAe,CAAC,KAAK,CAAC,CAAC;CAC3G,CAAC;AAEF,MAAM,MAAM,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG;IAC7F,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,SAAS,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC;IAChE,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,CAAC,SAAS,SAAS,EAAE,CAAC,EAAE,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAC1D,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,SAAS,SAAS,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACjG,QAAQ,CAAC,GAAG,EAAE,CACV,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,mBAAmB,CAAC,SAAS,SAAS,EAAE,CAAC,KAChD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,CACZ,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,mBAAmB,CAAC,SAAS,SAAS,EAAE,CAAC,KAChD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG;IACxG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACvC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
function predictModelTrace(machine, operations, prediction, signal) {
|
|
2
|
+
const systemOperations = operations.values();
|
|
3
|
+
const initial = machine.initial();
|
|
4
|
+
let state = initial;
|
|
5
|
+
const steps = prediction.map(function predictOperation(operation, index) {
|
|
6
|
+
signal.throwIfAborted();
|
|
7
|
+
const systemOperation = systemOperations.next();
|
|
8
|
+
if (systemOperation.done === true) {
|
|
9
|
+
throw new TypeError('Model reconstruction changed the trace length.');
|
|
10
|
+
}
|
|
11
|
+
const next = machine.transition(state, operation);
|
|
12
|
+
if (next.kind === 'disabled') {
|
|
13
|
+
throw new TypeError(`Model trace contains a disabled operation at index ${index}.`);
|
|
14
|
+
}
|
|
15
|
+
state = next.state;
|
|
16
|
+
return { state, operation: systemOperation.value };
|
|
17
|
+
});
|
|
18
|
+
if (systemOperations.next().done !== true) {
|
|
19
|
+
throw new TypeError('Model reconstruction changed the trace length.');
|
|
20
|
+
}
|
|
21
|
+
return { initial, steps };
|
|
22
|
+
}
|
|
23
|
+
async function checkOperations(definition, steps, system, sample) {
|
|
24
|
+
for (const step of steps) {
|
|
25
|
+
sample.signal.throwIfAborted();
|
|
26
|
+
await definition.run(step.operation, system, sample);
|
|
27
|
+
sample.signal.throwIfAborted();
|
|
28
|
+
await definition.check(step.state, system, sample);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function modelExecution(definition) {
|
|
32
|
+
return async function evaluateModel(operations, sample) {
|
|
33
|
+
const prediction = predictModelTrace(definition, operations, sample.reconstructInput(), sample.signal);
|
|
34
|
+
sample.signal.throwIfAborted();
|
|
35
|
+
const system = await definition.create(sample);
|
|
36
|
+
sample.signal.throwIfAborted();
|
|
37
|
+
await definition.check(prediction.initial, system, sample);
|
|
38
|
+
await checkOperations(definition, prediction.steps, system, sample);
|
|
39
|
+
return sample.assert.collect();
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=model-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-execution.js","sourceRoot":"","sources":["../../../../source/model/model-execution.ts"],"names":[],"mappings":"AASA,SAAS,iBAAiB,CACtB,OAAuC,EACvC,UAAgC,EAChC,UAAgC,EAChC,MAAmB;IAEnB,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAClC,IAAI,KAAK,GAAG,OAAO,CAAC;IACpB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,gBAAgB,CAAC,SAAS,EAAE,KAAK;QACnE,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,eAAe,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAClD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3B,MAAM,IAAI,SAAS,CAAC,sDAAsD,KAAK,GAAG,CAAC,CAAC;QACxF,CAAC;QACD,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACnB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,KAAK,UAAU,eAAe,CAC1B,UAA6D,EAC7D,KAA6C,EAC7C,MAAc,EACd,MAAiD;IAEjD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAC1B,UAA6D;IAE7D,OAAO,KAAK,UAAU,aAAa,CAAC,UAAU,EAAE,MAAM;QAClD,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,gBAAgB,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACvG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3D,MAAM,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { gen } from "@overkill-dev/property";
|
|
2
|
+
function traceSuffix(machine, state, remaining) {
|
|
3
|
+
if (remaining === 0) {
|
|
4
|
+
return gen.constant(null).map(function () {
|
|
5
|
+
return [];
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
const commands = machine.commands(state);
|
|
9
|
+
if (commands === null) {
|
|
10
|
+
return gen.constant(null).map(function () {
|
|
11
|
+
return [];
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return commands
|
|
15
|
+
.filter(function enabled(operation) {
|
|
16
|
+
return machine.transition(state, operation).kind === 'enabled';
|
|
17
|
+
})
|
|
18
|
+
.flatMap(function extendTrace(operation) {
|
|
19
|
+
const next = machine.transition(state, operation);
|
|
20
|
+
if (next.kind !== 'enabled') {
|
|
21
|
+
throw new TypeError('Model transitions must be deterministic.');
|
|
22
|
+
}
|
|
23
|
+
return traceSuffix(machine, next.state, remaining - 1).map(function prependOperation(suffix) {
|
|
24
|
+
return [operation, ...suffix];
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export function modelTrace(machine, length) {
|
|
29
|
+
return gen
|
|
30
|
+
.array(gen.constant(null), length)
|
|
31
|
+
.flatMap(function generateTrace(slots) {
|
|
32
|
+
return traceSuffix(machine, machine.initial(), slots.length);
|
|
33
|
+
})
|
|
34
|
+
.filter(function meetsMinimum(trace) {
|
|
35
|
+
return trace.length >= length.minLength;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=model-trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-trace.js","sourceRoot":"","sources":["../../../../source/model/model-trace.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,GAAG,EAGN,MAAM,wBAA8C,CAAC;AAGtD,SAAS,WAAW,CAChB,OAAuC,EACvC,KAAY,EACZ,SAAiB;IAEjB,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAuB;YAChD,OAAO,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAuB;YAChD,OAAO,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC;IACD,OAAO,QAAQ;SACV,MAAM,CAAC,SAAS,OAAO,CAAC,SAAS;QAC9B,OAAO,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;IACnE,CAAC,CAAC;SACD,OAAO,CAAC,SAAS,WAAW,CAAC,SAAS;QACnC,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAClD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,GAAG,CACtD,SAAS,gBAAgB,CAAC,MAAM;YAC5B,OAAO,CAAE,SAAS,EAAE,GAAG,MAAM,CAAE,CAAC;QACpC,CAAC,CACJ,CAAC;IACN,CAAC,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,UAAU,CACtB,OAAuC,EACvC,MAAoB;IAEpB,OAAO,GAAG;SACL,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;SACjC,OAAO,CAAC,SAAS,aAAa,CAAC,KAAK;QACjC,OAAO,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACjE,CAAC,CAAC;SACD,MAAM,CAAC,SAAS,YAAY,CAAC,KAAK;QAC/B,OAAO,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC;IAC5C,CAAC,CAAC,CAAC;AACX,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
"author": "Christian Rackerseder <git@echooff.de>",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"url": "https://github.com/enormora/overkill/issues"
|
|
5
|
+
},
|
|
6
|
+
"description": "Sequential model-based testing above the Overkill property core.",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": "^26.9.0"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./packages/model/model.entry-point.js",
|
|
13
|
+
"types": "./packages/model/model.entry-point.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/enormora/overkill#readme",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"tdd",
|
|
19
|
+
"test",
|
|
20
|
+
"tests"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"name": "@overkill-dev/model",
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@overkill-dev/engine": "0.0.78",
|
|
26
|
+
"@overkill-dev/property": "0.0.3"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/enormora/overkill.git"
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"type": "module",
|
|
34
|
+
"version": "0.0.2"
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.entry-point.d.ts","sourceRoot":"","sources":["../../../../../source/packages/model/model.entry-point.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACtE,YAAY,EACR,eAAe,EACf,YAAY,EACZ,uBAAuB,EACvB,eAAe,EAClB,MAAM,iCAAiC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.entry-point.js","sourceRoot":"","sources":["../../../../../source/packages/model/model.entry-point.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC"}
|
package/readme.md
CHANGED
|
@@ -1,7 +1,57 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@overkill-dev/model`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Install separately with `npm install -D @overkill-dev/model`. Model tests use
|
|
4
|
+
`testFamily: 'property'` profiles and their normal budgets and supervision.
|
|
5
|
+
They cannot attach resources or access capabilities forbidden to properties.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```ts
|
|
8
|
+
import { model } from '@overkill-dev/model';
|
|
9
|
+
import { gen } from '@overkill-dev/property';
|
|
10
|
+
|
|
11
|
+
export const testNode = model({
|
|
12
|
+
title: 'counter matches its model',
|
|
13
|
+
settings: {},
|
|
14
|
+
initial: () => 0,
|
|
15
|
+
commands: () => gen.integer({ min: 1, max: 5 }),
|
|
16
|
+
transition: (state, operation) => ({ kind: 'enabled', state: state + operation }),
|
|
17
|
+
length: { minLength: 1, maxLength: 20 },
|
|
18
|
+
codec: null,
|
|
19
|
+
examples: [],
|
|
20
|
+
coverage: [],
|
|
21
|
+
create: () => ({ value: 0 }),
|
|
22
|
+
run(operation, system) {
|
|
23
|
+
system.value += operation;
|
|
24
|
+
},
|
|
25
|
+
check(state, system, sample) {
|
|
26
|
+
sample.assert.equal(system.value, state);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`initial`, `commands`, and `transition` are pure, synchronous, deterministic
|
|
32
|
+
callbacks. Initial state must be fresh. Transitions return a new expected state
|
|
33
|
+
without mutating their state or operation. Disabled transitions return
|
|
34
|
+
`{ kind: 'disabled' }`; generation rejects them rather than skipping commands.
|
|
35
|
+
Return `null` from `commands` for a terminal state. Short terminal traces must
|
|
36
|
+
still satisfy `minLength`. Property `maxSize` caps generated trace length.
|
|
37
|
+
|
|
38
|
+
Each evaluation reconstructs separate operation graphs for prediction and system
|
|
39
|
+
execution. Aliases and cycles remain intact within each graph. The scheduled
|
|
40
|
+
command sequence stays fixed when a payload refers back to its trace. System mutation
|
|
41
|
+
cannot change expected model state or retained witnesses. This relies on the
|
|
42
|
+
property reconstruction contract: factories cannot return shared mutable data.
|
|
43
|
+
Supply a versioned codec for the complete trace when operations use custom types.
|
|
44
|
+
|
|
45
|
+
`create`, `run`, and `check` may be asynchronous. Checks run initially and after
|
|
46
|
+
each operation. Register disposal through `sample.cleanup`; cleanup finishes
|
|
47
|
+
before another trial starts. Assertions retain ordinary `assert` and `require`
|
|
48
|
+
semantics, including zero-assertion detection. One model is one property case.
|
|
49
|
+
|
|
50
|
+
`modelScenario(definition)` omits `title` and `settings` and returns a property
|
|
51
|
+
invocation. Pass it to `scope.forall` inside `withProperties`, or spread it into
|
|
52
|
+
`property`. Preview its generator with `sampleGenerator`.
|
|
53
|
+
|
|
54
|
+
Shrinking, failure confirmation, witnesses, corpus promotion, and replay use
|
|
55
|
+
existing property APIs and commands. Stored traces replay without command
|
|
56
|
+
generation and independently of current generation length limits. Every stored
|
|
57
|
+
transition must remain enabled; incompatible traces fail before system creation.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
|
|
3
|
+
"bomFormat": "CycloneDX",
|
|
4
|
+
"specVersion": "1.6",
|
|
5
|
+
"version": 1,
|
|
6
|
+
"metadata": {
|
|
7
|
+
"tools": {
|
|
8
|
+
"components": [
|
|
9
|
+
{
|
|
10
|
+
"type": "application",
|
|
11
|
+
"name": "packtory",
|
|
12
|
+
"version": "0.0.124"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"component": {
|
|
17
|
+
"type": "library",
|
|
18
|
+
"name": "@overkill-dev/model",
|
|
19
|
+
"version": "0.0.2",
|
|
20
|
+
"bom-ref": "pkg:npm/@overkill-dev/model@0.0.2",
|
|
21
|
+
"purl": "pkg:npm/@overkill-dev/model@0.0.2"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"components": [
|
|
25
|
+
{
|
|
26
|
+
"type": "library",
|
|
27
|
+
"name": "@overkill-dev/engine",
|
|
28
|
+
"version": "0.0.78",
|
|
29
|
+
"bom-ref": "pkg:npm/@overkill-dev/engine@0.0.78",
|
|
30
|
+
"scope": "optional",
|
|
31
|
+
"licenses": [
|
|
32
|
+
{
|
|
33
|
+
"expression": "MIT"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"purl": "pkg:npm/@overkill-dev/engine@0.0.78"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "library",
|
|
40
|
+
"name": "@overkill-dev/property",
|
|
41
|
+
"version": "0.0.3",
|
|
42
|
+
"bom-ref": "pkg:npm/@overkill-dev/property@0.0.3",
|
|
43
|
+
"scope": "optional",
|
|
44
|
+
"licenses": [
|
|
45
|
+
{
|
|
46
|
+
"expression": "MIT"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"purl": "pkg:npm/@overkill-dev/property@0.0.3"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"dependencies": [
|
|
53
|
+
{
|
|
54
|
+
"ref": "pkg:npm/@overkill-dev/engine@0.0.78"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"ref": "pkg:npm/@overkill-dev/model@0.0.2",
|
|
58
|
+
"dependsOn": [
|
|
59
|
+
"pkg:npm/@overkill-dev/engine@0.0.78",
|
|
60
|
+
"pkg:npm/@overkill-dev/property@0.0.3"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"ref": "pkg:npm/@overkill-dev/property@0.0.3"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|