Skip to content

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 30 Aug 09:59
· 32 commits to master since this release
d8d57b2
  • verifyAll() renders the call log when an expectation goes unmet. Two
    code paths reported the same failure and only one showed the calls:
    verify() rendered through FailureReport, while the verification sweep
    had a sprintf of its own. Since verifyAll() is the path every runner
    adapter takes, the alias table and the * argument marks — the part that
    says WHICH call differed — were missing from almost every failure anyone
    saw. Both paths now render the same report, the failure carries
    observedCalls, and the sentence the two used to word differently ("but it
    was called never") is settled. A test asserting the exact text of an unmet
    expectation may need updating. (#77, #79)
  • Doubling a built-in interface no longer emits a deprecation notice.
    PHP's own interfaces carry tentative return types, which
    ReflectionMethod::getReturnType() reports as null, so
    Understudy::for(Repo::class, Countable::class) generated count(): mixed
    and PHP answered with should either be compatible with Countable::count(): int. The unifier reads the tentative type, which
    satisfies the contract exactly and needs no #[\ReturnTypeWillChange]. The
    defect was invisible for ArrayAccess and JsonSerializable, whose
    tentative type is mixed anyway. (#78, #80)
  • A documentation site for the whole family, at
    https://rasuvaeff.github.io/understudy/: the guide, migration guides from
    Mockery and PHPUnit, a cookbook of real incidents whose output the build
    diffs against the scripts that produce it, and an API reference reflected
    out of all five packages' src/ — free functions and analyser rule
    identifiers included, neither of which a class-only reference would show.
    MIGRATION.md at the root is generated from the same pages. (#82)
  • The README's Mockery table mapped ->atLeast()->once() to
    times(minimum: 1), which is not what that does.
    times() branches on
    the number of arguments it was given, so one argument is an exact count
    however it is spelled; the open range is times(1, null). Both READMEs now
    show all four forms and say why. (#81)
  • The escaped-mutant hunt: 240 → 158, MSI 90.4% → 94.0%, gate raised to 92
    (the full trajectory and the reason live next to the number in
    infection.json5). About sixty targeted tests and fixtures, each written
    from an escaped mutant's diff rather than from the line it sits on:
    constant defaults now assert their rendered SOURCE (\Cfg::LIMIT, uppercase
    SELF::/PARENT:: resolved through the declaring hierarchy) where the old
    tests compared values a mutant renders identically; static satisfaction
    gets its satisfied complements (a type-distinct variadic tail, untyped and
    union return contracts); by-reference detection is asserted at every
    parameter position; FinalStripper pins the glued-comment and bare
    final const boundaries; settle() is pinned to drop satisfied claims and
    keep every stub; Fiber routing is pinned for by-reference returns,
    callOriginal() and ordering claims; the structured failure fields
    (actualCount, both bounds of unused(), observedCalls filtering,
    expectedCalls as strings, both halves of allVerified()) are asserted
    exactly, as are six refusal messages formerly checked by fragments. Three
    more test classes attribute #[Covers] they exercised all along. Three
    manual arbitrations confirmed the remainder is dominated by genuine
    equivalents — redundant second guards, set-map values read through
    array_keys(), perf fastpaths, warning-only offsets.
  • Honest-coverage sweep after 0.4.0. Twelve targeted tests kill the
    escaped mutants the new code left behind (hooked-property collection and
    rendering, cross-Fiber property routing, forwarding write-through, captor
    registration, the specification-hole boundary, retired-scope invisibility),
    and three test classes now attribute #[Covers] they exercised all along —
    which is what let several of those mutants escape unmapped. A new matcher
    property pins "no matcher throws on a hostile argument, every one describes
    itself" across the whole Arg:: catalog, rest() and a captor's
    capture() included.
  • examples/ caught up with 0.4.0: Arg::rest() and a typed captor in
    basic-usage.php, delegate() and lean() in modes.php, and a new
    property-hooks.php (self-skipping on PHP 8.3). The Mockery migration
    table gains the makePartial()/withAnyArgs()/Mockery::capture() rows,
    and three edge behaviours are now stated: a capture() in an
    expectSequence() step matches without recording, lean() cannot release
    the stable slot behind a & return, and a clone does not carry written
    property values over.