Backend conformance
Stash holds policy. Any object implementing the SPEC.md 9 method set can be handed to new Stash({ backend }), so a store on a filesystem this library does not ship -- an object store, a remote block device, whatever a deployment already trusts -- is a first-class backend the moment it passes the same behavioral cases the in-tree memory and disk backends pass.
runBackendConformance registers that behavioral suite against a backend factory, driving the shipped consumer path (stash.push(...), stash.pop(ref), stash.store(entry, bytes)) and asserting the frozen verdicts (ENOREF on absence, ECLAIMED on claim contention, E2BIG over maxSize, EFULL over maxEntries). It is test-runner-agnostic: the caller wires their own runner's test (and, optionally, an assert), so it never imports one at module load. The in-tree suite runs the identical cases against memory and disk, so a third-party backend earns the same interchangeability claim by running them too.
stash.conformance.runBackendConformance
runBackendConformance(factory, options) -> void
Register the SPEC.md 9 backend conformance suite against a backend factory -- { name, create() }, where create() returns a fresh backend per case. options.test is your runner's test function ((title, fn) => void); options.assert is a node:assert/strict-shaped assertion object, defaulting to the built-in when omitted. Every case drives the shipped Stash consumer path against a Stash wrapping the factory's backend, so passing the suite is proof the backend is interchangeable with the ones that ship. Zero dependencies, and no test runner is imported here -- the caller owns that choice.
Example
import { test } from "node:test";
import { runBackendConformance } from "@blamejs/stash/conformance";
import { MemoryBackend } from "@blamejs/stash/backends/memory";
runBackendConformance(
{ name: "my-backend", create: () => new MemoryBackend() },
{ test },
);
References
- spec SPEC.md 9
- spec SPEC.md 13