View Source Bond.Coverage (Bond v1.11.0)
Contract coverage: a test-time diagnostic that surfaces assertions which are checked but never observed to fail (#56).
The hardest contract bug to catch is the vacuous-but-passing assertion — one that runs at every call, always evaluates true, and so tells you nothing while looking like coverage. The compile-time assertion linter catches the structurally recognisable cases; this is the complementary dynamic signal: an assertion evaluated many times that has never once been false is a candidate for vacuity.
"Never failed" is a weak signal
A correct assertion over correct code, exercised by a passing suite, also never fails — that is what a green suite means. So
⚠ never failedis a prompt, not a verdict: either write a test that makes the assertion fail (proving it can — see the Writing Sound Assertions guide), or delete it. Coverage is an opt-in diagnostic you run deliberately, never an always-on warning.
Enabling
Coverage instrumentation is compile-time opt-in, so a build that does not enable it is byte-for-byte unchanged and pays nothing. Turn it on for the test environment:
# config/test.exs
config :bond, coverage: trueand print the report at the end of the suite by installing the reporter in test/test_helper.exs:
ExUnit.start()
Bond.Coverage.install_reporter()Then mix test prints a per-assertion table of how many times each contract was checked and how
many of those were failures. Recording itself needs no reporter — entries/0 and report/0 can
be read at any point.
Summary
Types
One assertion's accumulated coverage: its identifying metadata plus how many times it was
checked and how many of those checks failed.
Functions
Installs an ExUnit.after_suite/1 callback that prints report/0 once the suite finishes. Call
this in test/test_helper.exs after ExUnit.start().
Records a single evaluation of the assertion described by assertion_info (the map the runtime
check path already carries), classifying it as a failure when result is falsy.
Renders the accumulated coverage as a human-readable table, grouped by module and function.
Assertions that were checked at least once but never failed are flagged ⚠ never failed.
Clears all recorded coverage.
Types
@type entry() :: %{ assertion_id: term(), kind: atom(), label: term(), expression: String.t() | nil, module: module() | nil, function: term(), file: String.t() | nil, line: non_neg_integer() | nil, checked: non_neg_integer(), failed: non_neg_integer() }
One assertion's accumulated coverage: its identifying metadata plus how many times it was
checked and how many of those checks failed.
Functions
@spec entries() :: [entry()]
Returns the accumulated coverage as a list of entry/0, sorted by module, then line.
@spec install_reporter() :: :ok
Installs an ExUnit.after_suite/1 callback that prints report/0 once the suite finishes. Call
this in test/test_helper.exs after ExUnit.start().
Records a single evaluation of the assertion described by assertion_info (the map the runtime
check path already carries), classifying it as a failure when result is falsy.
Called from the coverage-recording variants of the runtime check helpers, which the compiler
emits only when coverage is enabled. Cheap and concurrency-safe: one :ets.update_counter keyed
by the assertion's stable :assertion_id.
@spec report() :: String.t()
Renders the accumulated coverage as a human-readable table, grouped by module and function.
Assertions that were checked at least once but never failed are flagged ⚠ never failed.
@spec reset() :: :ok
Clears all recorded coverage.