Skip to content

fix(lifecycle): locate function-case hooks from the case file, not surviving tests - #315

Merged
roxblnfk merged 1 commit into
php-testo:1.xfrom
Meacue:fix/lifecycle-functional-case-hooks
Sep 4, 2026
Merged

fix(lifecycle): locate function-case hooks from the case file, not surviving tests#315
roxblnfk merged 1 commit into
php-testo:1.xfrom
Meacue:fix/lifecycle-functional-case-hooks

Conversation

@Meacue

@Meacue Meacue commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What was changed

Hook discovery for a function-based case now reads the source path from CaseDefinition::$file instead of scanning the surviving test functions for it. A definition without a real source file yields no hooks. Covered by a unit regression test that fails on the previous code.

Why?

Any outer case interceptor may prune tests from a case before LifecycleInterceptor collects its hooks. When every test of a function-based case was pruned, the scan found no path and the case silently lost its #[BeforeClass]/#[AfterClass] hooks. The scan simply predates CaseDefinition::$file and was never migrated: whenever a test survives, both sources give the same path, so behavior only changes for the fully pruned case. The first in-tree interceptor that prunes at case level is #[Skip] (#314), which depends on this fix, so it lands separately with a Skip-independent test.

Checklist

…rviving tests

Hook discovery for a function-based case took the source path from the first
surviving test function. Any outer case interceptor may prune tests from the
case before LifecycleInterceptor runs, and a fully pruned case then silently
lost its #[BeforeClass]/#[AfterClass] hooks. Read the path from
CaseDefinition::$file instead: the property postdates the scan and carries the
same path whenever a test survives, so behavior only changes for the fully
pruned case. A definition without a real source file yields no hooks.

Covered by a unit regression test driving runTestCase() over a function-based
case with an emptied test set: all four hook groups are discovered from the
case file and published to the inner pipeline, the class-level hooks fire
exactly once around it, and a synthetic definition without a real file passes
through.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
@Meacue
Meacue marked this pull request as ready for review September 3, 2026 14:50
@Meacue
Meacue requested a review from a team as a code owner September 3, 2026 14:50
@roxblnfk
roxblnfk requested a lite review from Copilot September 3, 2026 20:57
@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is narrowly scoped, aligns with the stated lifecycle semantics for pruned cases, and is covered by a focused regression test plus a missing-file safety test.

Pull request overview

This PR fixes lifecycle hook discovery for function-based test cases when an outer case interceptor prunes all tests before LifecycleInterceptor runs. Instead of inferring the source file from surviving test functions (which fails when none survive), it now uses CaseDefinition::$file, and it safely yields “no hooks” when the definition has no real source file.

Changes:

  • Update LifecycleInterceptor to discover function-case hooks from CaseDefinition::$file (and short-circuit to no hooks when the file is not present on disk).
  • Add a regression test covering the “fully pruned function-case still runs BeforeClass/AfterClass” scenario.
  • Add a fixture defining lifecycle-annotated free functions with counters to validate hook execution.
File summaries
File Description
plugin/lifecycle/src/Internal/LifecycleInterceptor.php Switch function-case hook discovery to use CaseDefinition::$file and return no hooks when the file doesn’t exist.
plugin/lifecycle/tests/Unit/Internal/LifecycleInterceptorTest.php Add regression coverage for fully pruned function-based cases and for synthetic missing-source definitions.
plugin/lifecycle/tests/Unit/Fixture/PrunedFunctionsWithLifecycle.php Add fixture with lifecycle free functions and counter state to assert hook execution order/count.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@roxblnfk
roxblnfk merged commit f0ae7de into php-testo:1.x Sep 4, 2026
12 of 14 checks passed
@roxblnfk roxblnfk mentioned this pull request Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants