ExSandbox.Conformance.Group (ExSandbox v1.0.1)

Copy Markdown View Source

Emits one conformance check as an ExUnit test (012 T034).

Every check in every group goes through check/2, which is the single place the third outcome is turned into something a test run can show. A group that emitted test/2 directly would have to decide, per check, what to do with a CapabilityUnavailable — and the tempting answer is "rescue it and return :ok", which reports as green. That is FR-012b's exact failure mode wearing the costume of a careful handler.

Why the third outcome is not an ExUnit skip

ExUnit's skip tag is resolved before the test runs, and ExSandbox.Capability answers only at runtime — the whole point of FR-016. There is no runtime skip in ExUnit, so the choice is between reporting unavailable as a pass or as a failure. It is reported as a failure, with a message that says plainly it is the third outcome and what would make it a pass.

Erring this way is deliberate. A suite that goes green on a host where nothing was demonstrated is the artefact SC-008 exists to prevent; a suite that goes red until you read why costs an engineer five minutes.

Summary

Functions

Defines a conformance check named name.

Wraps a group's setup so an unavailable capability is framed as the third outcome rather than as a bare exception (T043a).

The shared framing for an undemonstrable check.

Functions

check(name, list)

(macro)

Defines a conformance check named name.

A ExSandbox.Conformance.CapabilityUnavailable raised inside body is re-raised as a failure tagged as the third outcome — never swallowed.

guarded_setup(list)

(macro)

Wraps a group's setup so an unavailable capability is framed as the third outcome rather than as a bare exception (T043a).

⚠️ check/2's rescue covers the test body only. A setup block runs before it, so a CapabilityUnavailable raised while provisioning escaped unframed: the verdict was identical -- deliberately a failure, since ExUnit has no runtime skip -- but it was reported without the explanation that it is neither a pass nor a mechanism defect, which is precisely the distinction the suite exists to keep visible.

not_demonstrated(unavailable)

@spec not_demonstrated(Exception.t()) :: String.t()

The shared framing for an undemonstrable check.

Public so check/2 and guarded_setup/1 cannot drift apart: the whole point is that a capability gap reads the same however it was raised.