Skip to main content

Module test_suites

Module test_suites 

Source
Expand description

Test/integration-suite checking (P5.4, design/tracks/semantics-in-the-checker.md §6) — closes category 7 of bynk-check/src/analysis.rs’s own residual-gap accounting, the last of the seven. bynk-emit/src/project/tests_emit.rs held process_tests/process_integration_tests, real production code (not fixture noise, despite the filename) checking + emitting suite/test integration bodies — but it ran only inside bynk-emit::run_checks (Mode::Analyse included), never inside bynk_check::analysis::analyse_project, the entry point the LSP now uses. That gap meant no diagnostics and no RefSink bindings (go-to-definition/find-references) for anything inside a test file, in the editor — see analysis.rs’s own module doc for the full accounting this closes.

What moved here — every check-only helper process_tests/ process_integration_tests used, plus every function that is genuinely dual-use: called both by this module’s own phase_test_bodies/ phase_integration_bodies (the checking half, real diagnostic/RefSink sinks) and by bynk-emit’s TypeScript lowering (throwaway sinks, needed only for the resolved-type view a body’s emission depends on). Dual-use functions are pub, and bynk-emit calls them qualified (bynk_check::test_suites::foo(...)) rather than duplicating them — see build_privileged_resolved, typecheck_case_body, check_history_binding, register_call_record_types, history_handlers, history_variant_name, prop_binding_generable and infer_participants for which and why (each names its own emit-side call sites). Duplicating a dual-use function instead of relocating it is exactly the drift risk this whole design track exists to close (§9, “Relocating checks risks a quiet R4.6/R4.11 regression”).

What stayed in bynk-emit (pure TypeScript emission, or verified emit-only by call-site count): block_uses_observation, target_service_handler_kinds, is_attackable_contract, numeric_or_scalar_base, attackable_contracts, json_codec_qual_for_target, prop_history_binding, prop_is_history, SystemCaseInput, RunnableTest, discovered_location, discovery_manifest, sanitise_suite, emit_integration_module and its http-driver/harness helpers, and the ~2,600-line TypeScript-codegen tail starting at emit_test_module (emit_stub_class, gen_ts_for_ty, emit_test_property_function, emit_test_history_property_function, and the rest).

bynk-emit/src/project/tests_emit.rs’s own process_tests/ process_integration_tests keep their exact signatures (run_checks’s callers need no change) — their bodies now call phase_test_bodies/phase_integration_bodies for the checking half, then proceed to their existing, unmoved Phase-5 emission logic using the “ready for emission” data these return.

bynk-emit depends on bynk-check (a production dependency, never the reverse), so this move has no circular-dependency subtlety to solve — unlike P5.3’s phase_platform_lock, which needed a from-scratch pure reimplementation because its old home reached into a bynk-emit TypeScript-codegen helper. This is a plain code-motion job, just a large one.

Structs§

ResolvedStub
v0.118: a capability seam with one or more stub overrides applied (testing track slice 6). Groups every stub Cap.method(…) clause — both suite-scoped and case-scoped — targeting the same capability cap. The resolved CapabilityDecl supplies each overridden method’s parameter names and return type for stub emission.
SuiteView
#1814: a test suite’s composed symbol tables, closed over the types its imported declarations reach. hidden names each type the closure added, with its owning commons: resolvable in the view, never nameable by the suite (resolver::check_hidden_type_names_in_suite), and imported by the test scaffold from that commons.

Enums§

StubScope
Which runs of a target’s test module a stub clause applies to (#291). Every suite targeting a unit is emitted into one module, so a clause’s scope is narrowed to its own suite whenever another suite shares the module (#1860).

Constants§

PROP_GEN_DEPTH
v0.114: the recursion cap for property-binding generability (mirrors the checker’s MOCK_DEPTH for bare Val).

Functions§

build_privileged_resolved
Build a resolver::ResolvedCommons backed by owning_unit’s privileged_view. The same shape used by the production pipeline. Returns the ResolvedCommons plus what the view’s closure found (#1814): its hidden types and its conflicts.
check_history_binding
v0.119 (testing track slice 7, ADR 0155): type-check a for all run: History[Agent] binding. The subject is a run of the agent — a generated, driven call-history — bound as an ordinary List[Step]. Validates the DECISION-B rules (agent-only, every handler parameter generable), registers the synthetic call-sum / step / state record types into resolved.types so the predicate’s List + value surface (.call is …, .old/.new, .accepted) type-checks, and returns the bound List[Step] type.
event_publisher
#2052 review: the context that publishes event to target’s subscribers, resolved as the target’s from Events(E) header resolves E: the target’s own declaration, else the one context among those it consumes (consumed) that declares it. Err lists the candidates when there is no unique one (none, or several). A same-named event in a context the target does not consume is never a candidate.
history_handlers
The agent’s drivable on call handlers — the ones a history sequences. Other handler kinds (http/cron/message/open/close) are not RPC entry points and are never part of a generated call-history.
history_variant_name
The .call variant tag for a handler: the handler name with its first letter upper-cased (spend → Spend, topUp → TopUp). The reader matches this with is / match (s.call is Spend).
infer_harness_participants
#1959: the contexts a system-tier suite’s harness stands up as Workers: infer_participants’ set, plus every context subscribing to an event one of them declares, plus its consumes closure, transitively. A subscriber consumes its publisher, and consumes cycles are refused, so no subscriber of the target is ever in the target’s own closure; without it here, the fan-out would deliver to nobody. Only the harness widens: a case still reaches just infer_participants’ set. Target first, then breadth order.
infer_participants
v0.118: infer a system-tier suite’s wired participants — the target’s transitive consumes closure (testing track slice 6). A BFS from the target following consumes edges; the returned list starts with the target and includes every context reachable through it (deterministic breadth order). #1856: contexts only. A unit consumed for its capabilities alone (consumes bynk { Clock }, an adapter) is provided in-process by the composition root: no Worker, no Service Binding, no wire to cross. The walk still passes through one, but it is no participant.
integration_view
#1814: a system case’s harness view: types, fns and methods from the suite’s uses commons (for constructing arguments), plus each participant’s types and methods (so return types rebrand and variant patterns resolve), closed over the types those declarations reach.
phase_integration_bodies
P5.4 (design/tracks/semantics-in-the-checker.md §6): the checking half of test integration "name" suite processing — participant inference, the system-needs-a-serialisation-edge gate, duplicate-case-name detection, the harness-root cross-context view, and per-case body type-checking (including the Wire/by Nobody tier gates). Formerly the pre-emission logic of bynk-emit’s own process_integration_tests; emission stays in bynk-emit::project::tests_emit::process_integration_tests, which calls this function for its checking half and then emits only for the groups this returns. Unlike phase_test_bodies’s ResolvedStub map, the only thing worth handing back here is the harness’s resolver::CrossContextInfo — it’s built from clone-heavy maps (harness_consumes/harness_uses), so recomputing it a second time on the emit side would be wasted work. participants/uses_targets/ case_inputs are cheap and pure (a BFS, a linear scan), so the emit-side loop recomputes those itself from parsed/unit_consumes, using the now-relocated infer_participants. bynk_check::analysis::analyse_project calls this too and discards the returned map — it never emits. Closes category 7 of bynk-check/src/analysis.rs’s own residual-gap accounting, alongside phase_test_bodies.
phase_test_bodies
P5.4 (design/tracks/semantics-in-the-checker.md §6): the checking half of test <target> suite processing — target resolution, duplicate-case- name detection, stub-clause resolution, and case/property body type-checking. Formerly Phases 2-4 of bynk-emit’s own process_tests; Phase 5 (TypeScript emission) stays in bynk-emit::project::tests_emit::process_tests, which calls this function for its checking half and then emits only for the targets this returns — every target this function resolves, has no duplicate case names, and whose bodies type-check clean is exactly “ready for emission”. bynk_check::analysis::analyse_project calls this too and discards the returned map — it never emits, so only the diagnostic/ RefSink side effects matter there. Closes category 7 of bynk-check/src/analysis.rs’s own residual-gap accounting, alongside phase_integration_bodies.
privileged_view
owning_unit’s privileged view: its types, fns, methods, plus those of every commons it uses, plus the types and instance methods of every consumed context. #1814: closed over the types those imported declarations reach, as the unit’s own table is, so a case is checked against the same types the target is.
prop_binding_generable
Whether a for all x: T binding’s type is refinement-generable: refined types must not carry a Matches predicate (no refinement-driven generator), and sums/records must have every component recursively generable within the depth cap. Mirrors the checker’s can_mock_bare.
register_call_record_types
Register a synthetic call-record type per capability operation of the target context (v0.117, testing track slice 5), so trace(Cap.op) — typed List[<CallRecord>] — supports field access on its records. The record’s fields are the operation’s parameters.
remote_clock_dependent
#2138 (track §3.4): bynk.test.remote_clock_dependent, a warning for a remote run. In process every Clock reads the harness clock; a real runtime’s Workers read wall-clock time, which the runner can’t reach. So an expect comparing an Instant built from constants can pass in process and fail remotely, and no --settle retry fixes that.
remote_unsupported
#2138 (end-to-end testing track §3.7): what a remote run can’t honour. Under bynk test --against, a system case runs against a real deployment, which only answers on its public http routes. Returns the bynk.test.remote_unsupported_* refusal for case, given the callees its body was checked with, or None when it uses only http addresses.
suite_ordinal
#1860: the ordinal of the suite at parsed[i] among the suites in indices (each index whose file is a suite), or None when i is not one. StubScope::Suite is keyed by it, so emission computes it the same way for each run.
typecheck_case_body
Type-check a test case/property body against the target unit’s privileges, returning the inferred expr_types map and the Callee classification recorded alongside it. The check path feeds real diagnostic/ref sinks; the emit path reuses it with throwaway sinks to give the case-body lowering full type information (so collection kernels — notably trace(Cap.op)’s List[…] methods — dispatch on the receiver’s checked type) and full Callee information (P6.21 review: the emit path’s own callees accumulator was previously built here and silently discarded — bynk-emit’s synthetic_typed_commons_for_target never received it, so Callee::Intrinsic/Store/etc. were never recorded for anything inside a .test.bynk body, even though this function computed them correctly all along).
typecheck_integration_case_body
Type-check one integration test case body. The body lives in a synthetic harness root that consumes every participant; entry calls (ctx.service(args)) are therefore ordinary cross-context calls. The body has type Effect[Result[(), ExpectationError]] (modelled as Effect[Result[(), ValidationError]], as in unit tests).
value_block
v0.118: wrap a single expression as a { tail: e } block, so a stub value can be type-checked or lowered in the same op-body position a provider operation’s tail occupies.