Skip to content

Add two-tier PHP test harness (#1051)#1064

Merged
donnchawp merged 6 commits into
trunkfrom
add/php-test-harness-1051
Jun 17, 2026
Merged

Add two-tier PHP test harness (#1051)#1064
donnchawp merged 6 commits into
trunkfrom
add/php-test-harness-1051

Conversation

@donnchawp

@donnchawp donnchawp commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

This PR description was generated by AI.

Closes #1051.

Makes the procedural caching functions reachable from PHPUnit, split into two tiers by what they need to run. Both tiers run on PHPUnit 9.6 — see the version note below.

Smoke tier — CI, no database, no WordPress runtime

  • tests/php/bootstrap-smoke.php loads the procedural caching files and provides a minimal, pure-PHP filter registry (add_filter / apply_filters / remove_all_filters) standing in for WordPress's hook system — enough to test WordPress-free functions and to inject filter input.
  • New tests in tests/php/smoke/:
    • SupercacheFilenameTestRestrict supercache filename to a safe character set #1050 filename-sanitization regression guard (hostile supercache_filename_str filter output is reduced to a single, separator-free path segment).
    • WpscRealpathTestwpsc_get_realpath() + wpsc_is_in_cache_directory() path containment, against real temp dirs.
    • GetWpCacheKeyTest — cache-key composition.
    • WpscParseAcceptHeaderTest — moved in from tests/php/.
  • phpunit.9.xml.dist targets the smoke bootstrap and tests/php/smoke.
  • CI shape is unchanged: still composer test-php across PHP 8.2–8.5, no MySQL service.

Integration tier — local only, via make test-integration

  • tests/php/bootstrap-integration.php loads the WordPress test library (wp-phpunit/wp-phpunit) and the procedural files under a real WP runtime + database. No apply_filters stub — WordPress core defines the real one.
  • Runs inside the wp-env Docker environment. tests/php/wp-tests-config.php is environment-driven with wp-env defaults.
  • phpunit-integration.9.xml.dist + an example WP_UnitTestCase test demonstrating the copyable pattern.

Why PHPUnit 9.6 for everything

WordPress's WP_UnitTestCase calls PHPUnit\Util\Test::parseTestMethodAnnotations(), removed in PHPUnit 10+, so the integration tier is capped at PHPUnit 9.6 (verified: PHPUnit 10.5 and 12.5 both fatal with the latest wp-phpunit 6.9.4). Since the integration tier can't move past 9.6 regardless, the whole project is pinned to PHPUnit 9.6 — one version, no isolated toolchain, matching the version WordPress core itself tests against. (An earlier revision of this PR ran the smoke tier on modern PHPUnit with a separate 9.x toolchain for integration; that split has been removed in favour of this simpler unified setup.)

Other

  • Makefile: make test (smoke, no Docker) and make test-integration (auto-starts wp-env).
  • .wp-env.json: dropped the deprecated testsEnvironment key; bumped phpVersion 8.1 → 8.3.
  • tests/php/README.md documents how to add a test to each tier.

Verification

  • composer test-phpOK (34 tests, 42 assertions) on PHP 8.5 / PHPUnit 9.6.
  • make test-integrationOK (2 tests, 2 assertions) under real WordPress + database.
  • composer lint → clean; php -l clean on all new files.

Out of scope (per the issue)

Make the procedural caching functions reachable from PHPUnit, split into
two tiers by what they need to run:

Smoke tier (CI, no database, no WordPress runtime):
- tests/php/bootstrap-smoke.php loads the procedural files and provides a
  minimal pure-PHP filter registry (add_filter/apply_filters/
  remove_all_filters) standing in for WordPress's hook system.
- Tests in tests/php/smoke/ for supercache_filename() (a #1050
  filename-sanitization regression guard), wpsc_get_realpath() +
  wpsc_is_in_cache_directory(), get_wp_cache_key(), plus the existing
  accept-header test moved in.
- phpunit.{9,11,12}.xml.dist now target the smoke bootstrap + tests/php/smoke.

Integration tier (local only, via `make test-integration`):
- tests/php/bootstrap-integration.php loads the WordPress test library and
  the procedural files under a real WP runtime + database. No apply_filters
  stub — WordPress core defines the real one.
- Runs in the wp-env Docker environment. Because WP_UnitTestCase is not
  PHPUnit 10+ compatible while the smoke tier runs modern PHPUnit, the
  integration tier uses an isolated PHPUnit 9 toolchain in tests/php/tools/.
- phpunit-integration.{9,11,12}.xml.dist + tests/php/wp-tests-config.php
  (env-driven, wp-env defaults).

Other:
- Makefile: `make test` (smoke) and `make test-integration` (Docker).
- .wp-env.json bumped to PHP 8.3 (drops deprecated testsEnvironment key).
- tests/php/README.md documents the copyable pattern for each tier.
WordPress's WP_UnitTestCase calls PHPUnit\Util\Test::parseTestMethodAnnotations(),
removed in PHPUnit 10+, so the integration tier is capped at PHPUnit 9.6 (verified
against PHPUnit 10.5 and 12.5 — both fatal). Rather than run the smoke tier on
modern PHPUnit and the integration tier on an isolated 9.x toolchain, pin the
whole project to PHPUnit 9.6, matching the version WordPress core tests against.

- composer.json: pin phpunit/phpunit ^9.6; wp-phpunit back in root require-dev.
- Remove tests/php/tools/ (the isolated PHPUnit 9 toolchain) entirely.
- Remove phpunit.{11,12}.xml.dist and phpunit-integration.{11,12}.xml.dist;
  only the .9 configs remain.
- bootstrap-integration.php: drop the WPSC_INTEGRATION_AUTOLOAD indirection —
  both tiers share the root vendor again.
- Makefile: test-integration runs vendor/bin/phpunit directly (no isolated
  install, no platform pin, no env-var plumbing).
- README: note both tiers run on PHPUnit 9.6 and why.

Verified: composer test-php (smoke, PHP 8.5) OK 34/42; make test-integration
(real WP + DB) OK 2/2.
PHPUnit 9.6 (the version the project is now pinned to) does not read the
#[CoversFunction] attribute API (PHPUnit 10+), so the attributes recorded no
coverage attribution. Switch the smoke tests and the README example to the
9.x-native @Covers ::function annotation so coverage runs (composer
test-coverage) attribute coverage to the function under test.
Code-review follow-ups:
- Guard _wpsc_manually_load_procedural_files() with function_exists() so the
  integration bootstrap can't fatal on redeclaration if the plugin is ever
  active in the tests env and loads wp-cache-phase2.php via WPCACHEHOME.
- README: note that the composer test-php / phpunit scripts use pcntl (via
  phpunit-select-config) and how to run PHPUnit directly without it.
npx --yes @wordpress/env re-resolves the package against the npm registry on
every make invocation, which fails behind registry proxies that gate or block
fetches. Pin @wordpress/env as a devDependency and point the Makefile at
node_modules/.bin/wp-env so it resolves locally after a one-time npm install
(make install), with no per-run registry round-trip.
Add a file-target rule for node_modules/.bin/wp-env that exits with a clear
message when the binary is missing, and make every wp-env target depend on it.
Replaces the raw 'No such file or directory' failure when wp-env hasn't been
installed yet.
@donnchawp donnchawp self-assigned this Jun 17, 2026
@donnchawp donnchawp merged commit a47179b into trunk Jun 17, 2026
6 checks passed
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.

Make procedural cache functions unit-testable and seed initial PHPUnit tests

1 participant