Statifier.Testing.Case (Statifier v2.1.1)

Copy Markdown View Source

Test case template for the SCION and W3C conformance corpora.

Test-side surface for chart authors, versioned with the engine: no module in lib/ outside Statifier.Testing.* may reference anything inside it, so the engine never consults the test harness to decide behavior (ADR-0053, amending ADR-0006). This module is also the supported entry point for a downstream application testing its own charts, not only the corpus's driver

  • use Statifier.Testing.Case works the same way outside this repository as it does inside it.

Every generated corpus test goes through test_scxml/4 and nothing else, so this module is the entire coupling surface between the corpus and the library (ADR-0006). It needs exactly four things from Statifier to drive a chart:

  1. parse an SCXML document,
  2. build and initialize a state chart from it,
  3. send an event synchronously and get the next state chart back,
  4. read the active leaf-state set.

Each of those lives in its own private helper below - parse_document/1, initialize/1, send_event/2, active_leaf_states/1 - and each is a thin adapter over Statifier's four-function API (Statifier.compile/1, Statifier.initialize/2, Statifier.send_event/2, Statifier.active_leaf_states/1): unwrapping the {:ok, _} / {:error, _} tuples and translating the corpus's event map into the shape Statifier expects. The four-function contract stays a hard constraint on the library surface rather than something the corpus can widen.

The assertion path reads two more things, both because a terminated chart's configuration is empty by construction (exit_interpreter/1, Appendix D) and the harness still has to say what the chart's leaves were at exit:

  • initialize/1 and send_event/2 now also return the call's effect list. assert_configuration/3 looks for a {:done, _} effect in it and, when found, restores that effect's configuration field - Effect.Done carries the terminal configuration - onto the %MachineState{} before reading leaves off it - so the terminal position is observed instead of the post-exit emptiness. This is still driving-side plumbing routed to the assertion, not a fifth driving function.
  • Statifier.MachineState.active_leaf_states/1 (the untranslated, index-keyed version behind Statifier.active_leaf_states/1) is read directly by assert_every_leaf_named/2 to compare its size against the id-translated set, catching a nameless active leaf that the id-based comparison would silently drop. This is an inspection of a value the harness already holds, not a new way to drive the chart.

Documents using features v2 does not support flunk with the feature named (Statifier.Testing.FeatureDetector) - they never skip, so an unimplemented feature can never masquerade as a passing test. Both suites are excluded by default (:scion, :scxml_w3), so mix test stays green while test.regression's ratchet is the thing that grows.

Two driving paths, one closed contract

test_scxml/4 routes each document, on the same detected feature set, to one of two private paths. Documents that need real delivery, wall-clock timers, or child sessions (@session_features below) drive through a Statifier.Session; every other document drives synchronously through the four functions this moduledoc opens with. The session path keeps Statifier.compile/1 and Statifier.active_leaf_states/1 exactly as they were and replaces the other two with five: initialize becomes Statifier.start_session/2, send_event becomes Statifier.Session.send_event/2, and driving a live session additionally needs Statifier.Session.snapshot/1 to read a configuration, Statifier.Session.status/1 to know when it has settled, and Statifier.Session.stop/2 to tear it down. Nine functions across the two paths, enumerated in ADR-0006 and closed: adding a tenth, or a third driving path, reopens that record rather than being a harness change. Either way the corpus still cannot widen the library surface, because every one of the nine is public API carried by its own record.

v1's StateMachine and logging helpers are deliberately not ported: the subsystems they drove do not exist in v2, and reintroducing them here would grow the coupling surface this module exists to hold flat.

Summary

Functions

Whether a document needs the session layer to reach its expected configurations. Public so the routing decision can be asserted directly; test_scxml/4 is the only caller in the corpus.

Functions

session_required?(xml)

@spec session_required?(xml_or_detected :: String.t() | MapSet.t(atom())) :: boolean()

Whether a document needs the session layer to reach its expected configurations. Public so the routing decision can be asserted directly; test_scxml/4 is the only caller in the corpus.

test_scxml(xml, description, expected_initial_config, events, opts \\ [])

@spec test_scxml(
  xml :: String.t(),
  description :: String.t(),
  expected_initial_config :: [String.t()],
  events :: [{map(), [String.t()]}],
  opts :: keyword()
) :: :ok

Tests SCXML state chart behavior.

  • xml - SCXML document string
  • description - test description, for debugging
  • expected_initial_config - active leaf state IDs expected after initialize
  • events - list of {event_map, expected_states} tuples, where event_map carries the event name under "name"
  • opts - see Options below

Flunks with the feature named if the document depends on an SCXML feature v2 does not support yet, rather than reporting a false pass.

Options

Both default to values tuned for this repo's conformance corpus. A downstream chart whose load-bearing delay is longer than the corpus's needs the knob. Both are ignored on the synchronous path, which has no timing to tune.

  • :settle_window_ms (default 100) - how long to wait for pending timers to drain before sending the next event. Long enough to drain load-bearing intermediate delays, short enough never to let a guard send fire.
  • :configuration_deadline_ms (default 4000) - upper bound on waiting for a session to reach an expected configuration. Bounds only the wrong answer: a chart that cannot change again exits the poll immediately.