@@ -9,8 +9,9 @@ export interface PhpunitRunCodeOptions {
99 testsDir : string
1010 testRoot ?: string
1111 phpunitXml : string
12+ phpunitXmlIsDefault : boolean
1213 selectedTestFile : string
13- changedTestFiles : unknown [ ]
14+ changedTestFiles : string [ ]
1415 phpunitArgs : string [ ]
1516 env : Record < string , unknown >
1617 wpConfigDefines : Record < string , unknown >
@@ -32,8 +33,9 @@ export interface CorePhpunitRunCodeOptions {
3233 coreRoot : string
3334 testsDir : string
3435 phpunitXml : string
36+ phpunitXmlIsDefault : boolean
3537 selectedTestFile : string
36- changedTestFiles : unknown [ ]
38+ changedTestFiles : string [ ]
3739 autoloadFile : string
3840 wpConfigDefines : Record < string , unknown >
3941 multisite : boolean
@@ -51,9 +53,6 @@ export const PLUGIN_PHPUNIT_RESULT_FILE = "/tmp/wp-codebox-phpunit-result.txt"
5153interface PhpunitConfigDiscoveryPhpOptions {
5254 functionName : string
5355 logFunction : string
54- missingConfigMessage : string
55- parseFailureMessage : string
56- includeParseFailureDetail : boolean
5756 loadedConfigMessage : string
5857 fallbackXmlDist : boolean
5958 restrictDirectoriesToTests : boolean
@@ -68,7 +67,6 @@ interface PhpunitChangedTestFilterPhpOptions {
6867 logFunction : string
6968 rootParameterName : string
7069 testsPathFallback : boolean
71- emptyWantedNotice : boolean
7270}
7371
7472function phpunitConfigDiscoveryPhp ( options : PhpunitConfigDiscoveryPhpOptions ) : string {
@@ -90,9 +88,6 @@ function phpunitConfigDiscoveryPhp(options: PhpunitConfigDiscoveryPhpOptions): s
9088 const returnValues = options . uniqueReturnValues
9189 ? "array(array_values(array_unique($directories)), array_values(array_unique($suffixes)), array_values(array_unique($prefixes)), $excludes, array_values(array_unique($files)))"
9290 : "array($directories, $suffixes, $prefixes, $excludes, $files)"
93- const parseFailureLog = options . includeParseFailureDetail
94- ? `${ options . logFunction } ('${ options . parseFailureMessage } ' . $first . '); using defaults');`
95- : `${ options . logFunction } ('${ options . parseFailureMessage } ');`
9691 const suffixAssignment = options . replaceDefaultMatchers ? "$suffixes = $config_suffixes;" : "$suffixes = array_merge($suffixes, $config_suffixes);"
9792 const prefixAssignment = options . replaceDefaultMatchers ? "$prefixes = $config_prefixes;" : "$prefixes = array_merge($prefixes, $config_prefixes);"
9893
@@ -106,8 +101,7 @@ function phpunitConfigDiscoveryPhp(options: PhpunitConfigDiscoveryPhpOptions): s
106101 return ${ returnValues } ;
107102 };${ fallbackXmlDist }
108103 if (!is_readable($xml_path)) {
109- ${ options . logFunction } ('${ options . missingConfigMessage } ' . $xml_path . '; using defaults');
110- return $return_values();
104+ throw new RuntimeException('PHPUnit config is not readable: ' . $xml_path);
111105 }
112106 $prev = libxml_use_internal_errors(true);
113107 $xml = @simplexml_load_file($xml_path);
@@ -116,8 +110,7 @@ function phpunitConfigDiscoveryPhp(options: PhpunitConfigDiscoveryPhpOptions): s
116110 libxml_use_internal_errors($prev);
117111 if ($xml === false) {
118112 $first = $errors ? trim($errors[0]->message) : 'unknown';
119- ${ parseFailureLog }
120- return $return_values();
113+ throw new RuntimeException('PHPUnit config could not be parsed at ' . $xml_path . ': ' . $first);
121114 }
122115 $base = ${ options . basePathExpression } ;
123116 $config_dirs = array();
@@ -170,11 +163,10 @@ function phpunitDiscoveryPhp(functionName: string, logFunction: string): string
170163 $found = array();
171164 foreach ($files as $file) {
172165 if (!is_string($file) || $file === '') {
173- continue ;
166+ throw new RuntimeException('configured PHPUnit test file is invalid') ;
174167 }
175- if (!is_file($file) || pathinfo($file, PATHINFO_EXTENSION) !== 'php') {
176- ${ logFunction } ('NOTICE:test file does not exist: ' . $file);
177- continue;
168+ if (!is_file($file) || !is_readable($file) || pathinfo($file, PATHINFO_EXTENSION) !== 'php') {
169+ throw new RuntimeException('configured PHPUnit test file is not a readable PHP file: ' . $file);
178170 }
179171 foreach ($excludes as $exclude) {
180172 if (strpos($file, $exclude) === 0) {
@@ -184,9 +176,8 @@ function phpunitDiscoveryPhp(functionName: string, logFunction: string): string
184176 $found[] = $file;
185177 }
186178 foreach ($directories as $dir) {
187- if (!is_dir($dir)) {
188- ${ logFunction } ('NOTICE:test directory does not exist: ' . $dir);
189- continue;
179+ if (!is_dir($dir) || !is_readable($dir)) {
180+ throw new RuntimeException('configured PHPUnit test directory is not a readable directory: ' . $dir);
190181 }
191182 $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::LEAVES_ONLY);
192183 foreach ($iterator as $file) {
@@ -229,12 +220,6 @@ function phpunitChangedTestFilterPhp(options: PhpunitChangedTestFilterPhpOptions
229220 const testsPathFallback = options . testsPathFallback ? ` elseif (strpos($path, '/tests/') !== false) {
230221 $path = substr($path, strpos($path, '/tests/') + 1);
231222 }` : ""
232- const emptyWantedNotice = options . emptyWantedNotice ? `
233- if (empty($wanted)) {
234- ${ options . logFunction } ('NOTICE:changed tests did not contain usable test paths');
235- return array();
236- }` : ""
237-
238223 return `function ${ options . filterFunctionName } (array $test_files, string $changed_files_json, string $${ options . rootParameterName } ): array {
239224 $decoded = json_decode($changed_files_json, true);
240225 if (!is_array($decoded) || empty($decoded)) {
@@ -249,7 +234,7 @@ function phpunitChangedTestFilterPhp(options: PhpunitChangedTestFilterPhpOptions
249234 if ($normalized !== '') {
250235 $wanted[$normalized] = true;
251236 }
252- }${ emptyWantedNotice }
237+ }
253238 $filtered = array();
254239 foreach ($test_files as $file) {
255240 if (isset($wanted[${ options . relativeFunctionName } ((string) $file, $${ options . rootParameterName } )])) {
@@ -360,6 +345,7 @@ $tests_dir = ${JSON.stringify(options.testsDir)};
360345$test_root = ${ JSON . stringify ( options . testRoot || `/wordpress/wp-content/plugins/${ options . pluginSlug } /tests` ) } ;
361346$selected_test_file = ${ JSON . stringify ( options . selectedTestFile ) } ;
362347$changed_test_files_raw = ${ JSON . stringify ( JSON . stringify ( options . changedTestFiles ) ) } ;
348+ $changed_test_scope = ${ JSON . stringify ( options . changedTestFiles . length > 0 ) } ;
363349$phpunit_args_raw = json_decode(${ JSON . stringify ( JSON . stringify ( options . phpunitArgs ) ) } , true);
364350$bench_env = json_decode(${ JSON . stringify ( JSON . stringify ( options . env ) ) } , true);
365351$wp_config_defines = json_decode(${ JSON . stringify ( JSON . stringify ( options . wpConfigDefines ) ) } , true);
@@ -763,8 +749,8 @@ function pg_plugin_real_path(string $relative_path, string $kind): ?string {
763749 return $real;
764750}
765751
766- function pg_project_bootstrap_from_config(string $xml_path): string {
767- if (!is_readable($xml_path) && basename($xml_path) === 'phpunit.xml.dist') {
752+ function pg_project_bootstrap_from_config(string & $xml_path, bool $xml_is_default ): string {
753+ if ($xml_is_default && !is_readable($xml_path) && basename($xml_path) === 'phpunit.xml.dist') {
768754 $alternate = dirname($xml_path) . '/phpunit.xml';
769755 if (is_readable($alternate)) {
770756 $xml_path = $alternate;
@@ -836,9 +822,10 @@ function pg_run_project_bootstrap_stage(array $cfg): void {
836822 try {
837823 $bootstrap = trim((string) ($cfg['project_bootstrap'] ?? ''));
838824 $phpunit_xml = (string) ($cfg['phpunit_xml'] ?? '');
825+ $phpunit_xml_is_default = !empty($cfg['phpunit_xml_is_default']);
839826 $from_config = false;
840827 if ($bootstrap === '') {
841- $bootstrap = pg_project_bootstrap_from_config($phpunit_xml);
828+ $bootstrap = pg_project_bootstrap_from_config($phpunit_xml, $phpunit_xml_is_default );
842829 $from_config = $bootstrap !== '';
843830 }
844831 $bootstrap_real = pg_project_bootstrap_real_path($bootstrap, $phpunit_xml, $from_config);
@@ -1036,7 +1023,6 @@ ${phpunitChangedTestFilterPhp({
10361023 logFunction : "pg_log" ,
10371024 rootParameterName : "plugin_path" ,
10381025 testsPathFallback : true ,
1039- emptyWantedNotice : true ,
10401026 } ) }
10411027
10421028pg_install_diagnostics_handlers();
@@ -1087,7 +1073,7 @@ $config_path = pg_run_boot_stage(array('extra_defines' => $wp_config_defines, 't
10871073if ($bootstrap_mode === 'project') {
10881074 pg_prepare_project_bootstrap_environment($config_path);
10891075 pg_skip_project_bootstrap_shell_install();
1090- pg_run_project_bootstrap_stage(array('project_bootstrap' => $project_bootstrap, 'phpunit_xml' => ${ JSON . stringify ( options . phpunitXml ) } ));
1076+ pg_run_project_bootstrap_stage(array('project_bootstrap' => $project_bootstrap, 'phpunit_xml' => ${ JSON . stringify ( options . phpunitXml ) } , 'phpunit_xml_is_default' => ${ JSON . stringify ( options . phpunitXmlIsDefault ) } ));
10911077 pg_run_project_autoload_stage($project_autoload_file !== '' ? $project_autoload_file : $legacy_project_autoload_file);
10921078} else {
10931079 if ($bootstrap_mode !== 'managed') {
@@ -1214,11 +1200,8 @@ try {
12141200${ phpunitConfigDiscoveryPhp ( {
12151201 functionName : "wp_codebox_phpunit_parse_config" ,
12161202 logFunction : "pg_log" ,
1217- missingConfigMessage : "NOTICE:phpunit.xml.dist not readable at " ,
1218- parseFailureMessage : "NOTICE:phpunit.xml.dist parse failed (" ,
1219- includeParseFailureDetail : true ,
12201203 loadedConfigMessage : "NOTICE:phpunit.xml.dist loaded from " ,
1221- fallbackXmlDist : true ,
1204+ fallbackXmlDist : options . phpunitXmlIsDefault ,
12221205 restrictDirectoriesToTests : ! options . testRoot ,
12231206 basePathExpression : "dirname($xml_path)" ,
12241207 uniqueReturnValues : false ,
@@ -1231,10 +1214,7 @@ pg_stage_begin('discover_tests');
12311214try {
12321215 $test_dir = $test_root;
12331216 if (!is_dir($test_dir)) {
1234- pg_log('NO_TEST_FILES');
1235- pg_log('NOTICE:tests directory not found at ' . $test_dir);
1236- pg_stage_ok('discover_tests');
1237- exit(0);
1217+ throw new RuntimeException('configured PHPUnit test root is not a readable directory: ' . $test_dir);
12381218 }
12391219 list($directories, $suffixes, $prefixes, $excludes, $configured_files) = wp_codebox_phpunit_parse_config(${ JSON . stringify ( options . phpunitXml ) } , $test_dir);
12401220 $test_files = wp_codebox_phpunit_discover($directories, $suffixes, $prefixes, $excludes, $configured_files);
@@ -1256,10 +1236,9 @@ try {
12561236 $test_files = array($selected_abs);
12571237 }
12581238 pg_log('DISCOVERY: dirs=' . implode(',', $directories) . ' files=' . count($configured_files) . ' suffixes=' . implode(',', $suffixes) . ' prefixes=' . implode(',', $prefixes) . ' excludes=' . count($excludes) . ' found=' . count($test_files));
1259- if (empty($test_files)) {
1239+ if (empty($test_files) && !$changed_test_scope ) {
12601240 pg_log('NO_TEST_FILES');
1261- pg_stage_ok('discover_tests');
1262- exit(0);
1241+ throw new RuntimeException('PHPUnit discovery found no test files');
12631242 }
12641243 pg_stage_ok('discover_tests');
12651244} catch (Throwable $e) {
@@ -1345,6 +1324,7 @@ $tests_dir = rtrim(${JSON.stringify(options.testsDir)}, '/');
13451324$phpunit_xml = ${ JSON . stringify ( options . phpunitXml ) } ;
13461325$selected_test_file = ${ JSON . stringify ( options . selectedTestFile ) } ;
13471326$changed_test_files_raw = ${ JSON . stringify ( JSON . stringify ( options . changedTestFiles ) ) } ;
1327+ $changed_test_scope = ${ JSON . stringify ( options . changedTestFiles . length > 0 ) } ;
13481328$autoload_file = ${ JSON . stringify ( options . autoloadFile ) } ;
13491329$wp_config_defines = json_decode(${ JSON . stringify ( JSON . stringify ( options . wpConfigDefines ) ) } , true);
13501330$multisite = ${ JSON . stringify ( options . multisite ) } ;
@@ -1480,11 +1460,8 @@ function core_pg_write_tests_config(string $core_root, array $extra_defines): st
14801460${ phpunitConfigDiscoveryPhp ( {
14811461 functionName : "core_pg_parse_phpunit_config" ,
14821462 logFunction : "core_pg_log" ,
1483- missingConfigMessage : "NOTICE:phpunit config not readable at " ,
1484- parseFailureMessage : "NOTICE:phpunit config parse failed; using defaults" ,
1485- includeParseFailureDetail : false ,
14861463 loadedConfigMessage : "NOTICE:phpunit config loaded from " ,
1487- fallbackXmlDist : false ,
1464+ fallbackXmlDist : options . phpunitXmlIsDefault ,
14881465 restrictDirectoriesToTests : false ,
14891466 basePathExpression : "dirname($xml_path)" ,
14901467 uniqueReturnValues : true ,
@@ -1499,7 +1476,6 @@ ${phpunitChangedTestFilterPhp({
14991476 logFunction : "core_pg_log" ,
15001477 rootParameterName : "core_root" ,
15011478 testsPathFallback : false ,
1502- emptyWantedNotice : false ,
15031479 } ) }
15041480
15051481${ phpunitArgsPhp ( "core_pg_phpunit_args" , "core_pg_log" ) }
@@ -1582,10 +1558,9 @@ try {
15821558 $test_files = array($selected_abs);
15831559 }
15841560 core_pg_log('DISCOVERY: dirs=' . implode(',', $directories) . ' files=' . count($configured_files) . ' suffixes=' . implode(',', $suffixes) . ' prefixes=' . implode(',', $prefixes) . ' excludes=' . count($excludes) . ' found=' . count($test_files));
1585- if (empty($test_files)) {
1561+ if (empty($test_files) && !$changed_test_scope ) {
15861562 core_pg_log('NO_TEST_FILES');
1587- core_pg_stage_ok('discover_tests');
1588- exit(0);
1563+ throw new RuntimeException('PHPUnit discovery found no test files');
15891564 }
15901565 core_pg_stage_ok('discover_tests');
15911566} catch (Throwable $e) {
0 commit comments