whiskers.git / crates / whiskers-conformance

whiskers-conformance

The in-memory reference adapter for whiskers-ports, and the conformance suite that every adapter of those ports must pass.

  • memory.rs is every port held in a Mutex and nothing else (MemBackend). It is the simplest honest implementation: it shows what each port means, it is what whiskers-service's tests run on, and the suite is proven against it before it is allowed to judge another adapter. The outbound ports (Judge, Embedder, Voice, Thinker) are scripted: a test says what they answer and reads how often they were asked.
  • suite/fixture.rs selects laws by capability: one fixture trait per capability (MemoryFixture, JournalFixture, ...) and a Suite whose method for a capability's laws applies only to a harness with that fixture, so an adapter runs exactly the laws for what it has and a law for a capability it lacks cannot be selected (the compile_fail example on Suite). Suite::complete runs every law and needs every fixture; MemFixtures is the in-memory adapter's.
  • suite/ is the contracts as functions generic over an adapter: hubs (convergent merge is order-independent and idempotent, a forgotten fact wins), the journal (device-scoped alignment, pull since a cursor, the rebuild-if-longer rule, the page bound, stored bytes), pictures (never replaced, byte-exact, names that could reach a path cannot be written), the allowance (the rolling thinking window, reserve and settle of the daily voice cap, frees-up-at), secrets (absent is not empty), the outbound ports with nothing to call with, and the timed voice (suite::timing: the laws of LineTiming and TimedAudio, and speaks_timed for a voice that may be asked to speak, which a paid adapter runs only when its operator agrees to the spend).

An adapter's own tests implement the fixture trait of each capability it has (a way to make a fresh port and, for the durable ones, to restart one on the same storage) and select its laws:

impl MemoryFixture for MyHarness { type Port = MyMemoryHub; fn fresh(&self) -> MyMemoryHub { .. } fn restart(&self, h: MyMemoryHub) -> MyMemoryHub { h.reopen() } }
Suite::new(MyHarness).memory();

The law functions under suite:: are public and unchanged for a harness that must run them one at a time (backend/http-conformance runs each law under its own catch_unwind over HTTP).

The native adapters in whiskersd are held to it in crates/whiskersd/tests/conformance.rs. A Worker adapter will run the same laws from its own harness. The suite uses no thread, clock or file, so it builds for wasm32-unknown-unknown as well.