@@ -97,6 +97,68 @@ echo json_encode($cases);
9797 } )
9898}
9999
100+ function assertProjectBootstrapHarnessGuard ( source : string ) : void {
101+ const tempDir = mkdtempSync ( join ( tmpdir ( ) , "wp-codebox-phpunit-harness-guard-" ) )
102+ const stubFile = join ( tempDir , "phpunit-testsuite-stub.php" )
103+ const scriptPath = join ( tempDir , "assert-harness-guard.php" )
104+
105+ writeFileSync ( stubFile , `<?php
106+ namespace PHPUnit\\Framework;
107+ class TestSuite {}
108+ ` )
109+
110+ const ensureFn = extractPhpFunction ( source , "pg_ensure_phpunit_harness_loaded" )
111+
112+ writeFileSync ( scriptPath , `<?php
113+ function pg_log($msg) {}
114+ function pg_stage_begin($stage) {}
115+ function pg_stage_ok($stage) {}
116+ function pg_stage_fail($stage, Throwable $e) {}
117+ ${ ensureFn }
118+
119+ if (class_exists('PHPUnit\\Framework\\TestSuite', false)) {
120+ throw new RuntimeException('precondition failed: PHPUnit\\Framework\\TestSuite must not be preloaded in the test environment');
121+ }
122+
123+ $reached_testsuite = false;
124+ $boundary_message = '';
125+ try {
126+ pg_ensure_phpunit_harness_loaded();
127+ $reached_testsuite = true;
128+ } catch (RuntimeException $e) {
129+ $boundary_message = $e->getMessage();
130+ } catch (Throwable $e) {
131+ throw new RuntimeException('REGRESSION: guard threw non-RuntimeException: ' . get_class($e) . ': ' . $e->getMessage());
132+ }
133+
134+ if ($reached_testsuite) {
135+ throw new RuntimeException('REGRESSION: harness guard did not fail when PHPUnit was unavailable; TestSuite construction would be reached');
136+ }
137+ foreach (array('PHPUnit\\Framework\\TestSuite', 'bootstrap-mode=project', 'project-autoload-file', 'autoload-file=/wp-codebox-vendor/autoload.php') as $needle) {
138+ if (strpos($boundary_message, $needle) === false) {
139+ throw new RuntimeException('REGRESSION: boundary error missing actionable hint: ' . $needle . '; message=' . $boundary_message);
140+ }
141+ }
142+
143+ spl_autoload_register(function ($class) {
144+ if ($class !== 'PHPUnit\\Framework\\TestSuite') {
145+ return;
146+ }
147+ require_once ${ phpString ( realpathSync ( stubFile ) ) } ;
148+ });
149+
150+ try {
151+ pg_ensure_phpunit_harness_loaded();
152+ } catch (Throwable $e) {
153+ throw new RuntimeException('REGRESSION: harness guard failed even though a project autoloader provides PHPUnit: ' . $e->getMessage());
154+ }
155+
156+ echo "BOUNDARY_OK\n";
157+ ` )
158+
159+ assert . equal ( execFileSync ( "php" , [ scriptPath ] , { encoding : "utf8" } ) , "BOUNDARY_OK\n" )
160+ }
161+
100162const recipe = buildWordPressPhpunitRecipe ( {
101163 pluginSlug : "woocommerce" ,
102164 extra_plugins : [ {
@@ -191,6 +253,15 @@ assert.equal(projectModeCode.match(/return \$return_values\(\);/g)?.length, 3)
191253assertPhpunitParseConfigFallbacksReturnFiveTuple ( projectModeCode , "wp_codebox_phpunit_parse_config" , "pg_log" )
192254assertSelectedTestFileResolution ( projectModeCode )
193255
256+ assert . ok ( projectModeCode . includes ( "function pg_ensure_phpunit_harness_loaded(): void" ) )
257+ assert . ok ( projectModeCode . includes ( "PHPUnit harness is not initialized" ) )
258+ assert . ok ( projectModeCode . includes ( "pg_stage_begin('verify_harness')" ) )
259+ const verifyHarnessIndex = projectModeCode . indexOf ( "pg_stage_begin('verify_harness')" )
260+ const projectModeTestsuiteIndex = projectModeCode . indexOf ( "$suite = new PHPUnit\\Framework\\TestSuite(" )
261+ assert . ok ( verifyHarnessIndex > 0 , "verify_harness stage must be present" )
262+ assert . ok ( projectModeTestsuiteIndex > verifyHarnessIndex , "harness verification must precede TestSuite construction" )
263+ assertProjectBootstrapHarnessGuard ( projectModeCode )
264+
194265let capturedDefaultProjectCode = ""
195266await runPhpunitCommand ( {
196267 artifactRoot : mkdtempSync ( join ( tmpdir ( ) , "wp-codebox-phpunit-artifacts-" ) ) ,
0 commit comments