v0.5.0
A minor rather than a patch: a closing scope() verifies less than it did, and
two Arg:: factories now refuse a configuration they used to accept. Both are
behaviour toward the consumer's own test code, which Composer's caret already
treats as breaking on 0.x.
bin/consumer-smokenow carries the analyser parity matrix: eleven
idioms — ourArgunqualified, aliased and fully qualified, the static verb
form,rest()short and leaked, a captor capture in a specification and in a
real call, a namesakeArgunder two spellings, and a plain leak — checked
against one table of expectations by bothunderstudy-psalmand
understudy-phpstan. The two answer the same contract by opposite
mechanisms, and nothing compared them before; the analyser packages' own CI
runs these legs against their working tree. The phpunit leg gained the
composition hazard the adapter cannot defend against: a consumer class that
overridesassertPostConditions()without the documented alias loses
verification silently, and the README's recipe keeps it — both now executed
rather than described.- A closing
scope()no longer answers for the enclosing context. It
verified every live context of the test, so a self-contained nested scope
failed on a claim the caller had simply not got round to satisfying yet —
including the recommended use ofscope()to drop doubles holding OS
resources before the runner's teardown, which is exactly the position where
the enclosing expectations are still open. A close now verifies the context
it opened, and only that one; nothing is settled or forgiven, so
verifyAll(),checkpoint()and the runner adapter's teardown still report
the enclosing claims. A test that relied on a scope surfacing an outer
failure earlier will now see it at the end of the test instead. (#84) - A matcher that could never match is refused where it is written.
Arg::int(min: 5, max: 1)— and the same shape inArg::float()and
Arg::count()— describes an empty range, andArg::string('/[unclosed')is
not a pattern PCRE compiles. Both built a matcher that answered "no" to every
argument, so a typo surfaced as an expectation never met with nothing
pointing at its cause; the broken pattern also raised PHP's own warning on
every call from inside the code under test, which is the one thing a matcher
must not do. Both now raiseInvalidCallSpecification, and the pattern's
message carries PCRE's own reason. (#86) - Two decisions written down rather than changed. A predicate handed to
Arg::satisfies()is the test's own code, so an exception in it travels
instead of being read as a mismatch — unlikeArg::which(), which reaches
into the argument. AndverifySequence()with no calls asserts that nothing
happened, whereexpectSequence()refuses an empty protocol; both are now
stated in the docblocks and pinned by tests. - The mutation gate quoted in
README.md,README.ru.mdandAGENTS.mdsays
92, which is whatinfection.json5has required since #76. - Both READMEs and the failure-messages guide say what was only in the 0.1.0
changelog: the wording of a failure message is not public contract, and
anything acting on a failure readsFailureKindand the readonly fields of
VerificationFailure, which are frozen.