-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtests.wit
More file actions
101 lines (93 loc) · 4.91 KB
/
Copy pathtests.wit
File metadata and controls
101 lines (93 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/// `polymorph:test` is the contract between test *suites* — components
/// that carry test cases — and test *runners* — components or hosts that
/// execute the cases and report results. A suite exports `tests` and imports
/// `test-context`; a runner imports `tests` and arranges for `test-context`
/// to be provided (typically by composing in a context-provider component).
/// Composing the pieces yields something executable.
///
/// Feature marks are NOT part of this contract: cases are gated on target
/// capability manifests declaratively, from static metadata carried
/// alongside the suite (see the repo's README), and a case that does not
/// apply to a target is never materialized for it. `run` is feature-blind.
package polymorph:test@0.1.0;
/// The runner-provided sideband a test case can talk to while running.
///
/// This interface is the contract's runner-side growth surface: the
/// Component Model permits an exporter to add exports compatibly, so new
/// capabilities (attachments, subtests, timing marks, ...) arrive as new
/// methods here — old suites keep linking against newer providers.
/// (Suite-side growth happens as new optional interfaces alongside
/// `tests`.) Nothing in return position anywhere in this package can
/// grow.
interface test-context {
/// A per-run handle implemented by the runner side. Calls on it are
/// sideband only: they never alter the verdict returned by `run`.
resource context {
/// Report a free-form diagnostic message associated with the
/// running case (e.g. progress notes, observed values). Runners
/// surface these with the case's results. May block cooperatively
/// (e.g. on delivery backpressure); runners observing diagnostics
/// must consume them concurrently with the case's `run`.
diagnostic: async func(msg: string);
}
}
/// The enumeration-and-execution surface a test suite exports.
interface tests {
use test-context.{context};
/// Why an executed test case did not pass.
variant outcome {
/// The observed behavior diverged; the payload says how, in one
/// line.
failed(string),
/// The case ran but could not reach its subject (a run-stable
/// target fact turned out not to hold at run time — e.g. a
/// declared hardware token was unavailable). The payload says
/// what the case asserted instead. This is an exceptional escape
/// hatch: gating that is knowable before the run belongs in
/// feature marks, which never reach this code path.
skipped(string),
}
/// One test case.
resource test-case {
/// Stable identity, unique within the suite: hierarchical
/// `/`-separated segments (e.g. `group/source/case`), each segment
/// 1–64 bytes of `[a-z0-9._-]` (never `.` or `..`), whole name at
/// most 256 bytes; every segment except the last is additionally a
/// valid WIT label (kebab-case). Stable across calls and across
/// instances of the same suite artifact; compared by byte
/// equality. Duplicates within a suite are a harness bug. Runners
/// and reporting tools group by prefix.
name: func() -> string;
/// Run the case. The returned result is the sole verdict — `ok` is
/// a pass — and calls on `ctx` never change it. Expectation
/// mismatches are reported as `failed`, never as traps, so a run
/// always yields a verdict. A runner treats a trap as this case's
/// failure and the suite instance as poisoned; a runner-imposed
/// timeout is treated the same way.
run: async func(ctx: borrow<context>) -> result<_, outcome>;
}
/// Enumerate the suite: every case, in suite order, unconditionally.
/// Deterministic: a given suite artifact (the same component binary)
/// yields the same cases in the same order on every call, in every
/// instance (lockfiles depend on this). Target-applicability filtering
/// happens outside this contract, from static feature-mark metadata.
/// `async` so that implementations may block (e.g. dynamically
/// constructed suites, or adapters draining another enumeration
/// source); sync implementations remain legal as always.
all: async func() -> list<test-case>;
}
/// A test suite: carries cases and exports them to a runner.
world suite {
import test-context;
export tests;
}
/// A test runner: imports a suite and executes it. Concrete runners extend
/// this world with the transport they report over (`wasi:cli/run`,
/// `wasi:http/incoming-handler`, ...). Because instantiation is acyclic, a
/// single component cannot both provide `test-context` to the suite and
/// import the suite's `tests`; instead, a suite is first bundled with a
/// context provider (re-exporting `tests` and the provider's interfaces),
/// and the bundle is then plugged into a runner core.
world runner {
import tests;
}