@@ -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);
@@ -765,8 +751,8 @@ function pg_plugin_real_path(string $relative_path, string $kind): ?string {
765751 return $real;
766752}
767753
768- function pg_project_bootstrap_from_config(string $xml_path): string {
769- if (!is_readable($xml_path) && basename($xml_path) === 'phpunit.xml.dist') {
754+ function pg_project_bootstrap_from_config(string & $xml_path, bool $xml_is_default ): string {
755+ if ($xml_is_default && !is_readable($xml_path) && basename($xml_path) === 'phpunit.xml.dist') {
770756 $alternate = dirname($xml_path) . '/phpunit.xml';
771757 if (is_readable($alternate)) {
772758 $xml_path = $alternate;
@@ -838,9 +824,10 @@ function pg_run_project_bootstrap_stage(array $cfg): void {
838824 try {
839825 $bootstrap = trim((string) ($cfg['project_bootstrap'] ?? ''));
840826 $phpunit_xml = (string) ($cfg['phpunit_xml'] ?? '');
827+ $phpunit_xml_is_default = !empty($cfg['phpunit_xml_is_default']);
841828 $from_config = false;
842829 if ($bootstrap === '') {
843- $bootstrap = pg_project_bootstrap_from_config($phpunit_xml);
830+ $bootstrap = pg_project_bootstrap_from_config($phpunit_xml, $phpunit_xml_is_default );
844831 $from_config = $bootstrap !== '';
845832 }
846833 $bootstrap_real = pg_project_bootstrap_real_path($bootstrap, $phpunit_xml, $from_config);
@@ -1038,7 +1025,6 @@ ${phpunitChangedTestFilterPhp({
10381025 logFunction : "pg_log" ,
10391026 rootParameterName : "plugin_path" ,
10401027 testsPathFallback : true ,
1041- emptyWantedNotice : true ,
10421028 } ) }
10431029
10441030pg_install_diagnostics_handlers();
@@ -1089,7 +1075,7 @@ $config_path = pg_run_boot_stage(array('extra_defines' => $wp_config_defines, 't
10891075if ($bootstrap_mode === 'project') {
10901076 pg_prepare_project_bootstrap_environment($config_path);
10911077 pg_skip_project_bootstrap_shell_install();
1092- pg_run_project_bootstrap_stage(array('project_bootstrap' => $project_bootstrap, 'phpunit_xml' => ${ JSON . stringify ( options . phpunitXml ) } ));
1078+ pg_run_project_bootstrap_stage(array('project_bootstrap' => $project_bootstrap, 'phpunit_xml' => ${ JSON . stringify ( options . phpunitXml ) } , 'phpunit_xml_is_default' => ${ JSON . stringify ( options . phpunitXmlIsDefault ) } ));
10931079 pg_run_project_autoload_stage($project_autoload_file !== '' ? $project_autoload_file : $legacy_project_autoload_file);
10941080} else {
10951081 if ($bootstrap_mode !== 'managed') {
@@ -1216,11 +1202,8 @@ try {
12161202${ phpunitConfigDiscoveryPhp ( {
12171203 functionName : "wp_codebox_phpunit_parse_config" ,
12181204 logFunction : "pg_log" ,
1219- missingConfigMessage : "NOTICE:phpunit.xml.dist not readable at " ,
1220- parseFailureMessage : "NOTICE:phpunit.xml.dist parse failed (" ,
1221- includeParseFailureDetail : true ,
12221205 loadedConfigMessage : "NOTICE:phpunit.xml.dist loaded from " ,
1223- fallbackXmlDist : true ,
1206+ fallbackXmlDist : options . phpunitXmlIsDefault ,
12241207 restrictDirectoriesToTests : ! options . testRoot ,
12251208 basePathExpression : "dirname($xml_path)" ,
12261209 uniqueReturnValues : false ,
@@ -1233,10 +1216,7 @@ pg_stage_begin('discover_tests');
12331216try {
12341217 $test_dir = $test_root;
12351218 if (!is_dir($test_dir)) {
1236- pg_log('NO_TEST_FILES');
1237- pg_log('NOTICE:tests directory not found at ' . $test_dir);
1238- pg_stage_ok('discover_tests');
1239- exit(0);
1219+ throw new RuntimeException('configured PHPUnit test root is not a readable directory: ' . $test_dir);
12401220 }
12411221 list($directories, $suffixes, $prefixes, $excludes, $configured_files) = wp_codebox_phpunit_parse_config(${ JSON . stringify ( options . phpunitXml ) } , $test_dir);
12421222 $test_files = wp_codebox_phpunit_discover($directories, $suffixes, $prefixes, $excludes, $configured_files);
@@ -1258,10 +1238,9 @@ try {
12581238 $test_files = array($selected_abs);
12591239 }
12601240 pg_log('DISCOVERY: dirs=' . implode(',', $directories) . ' files=' . count($configured_files) . ' suffixes=' . implode(',', $suffixes) . ' prefixes=' . implode(',', $prefixes) . ' excludes=' . count($excludes) . ' found=' . count($test_files));
1261- if (empty($test_files)) {
1241+ if (empty($test_files) && !$changed_test_scope ) {
12621242 pg_log('NO_TEST_FILES');
1263- pg_stage_ok('discover_tests');
1264- exit(0);
1243+ throw new RuntimeException('PHPUnit discovery found no test files');
12651244 }
12661245 pg_stage_ok('discover_tests');
12671246} catch (Throwable $e) {
@@ -1347,6 +1326,7 @@ $tests_dir = rtrim(${JSON.stringify(options.testsDir)}, '/');
13471326$phpunit_xml = ${ JSON . stringify ( options . phpunitXml ) } ;
13481327$selected_test_file = ${ JSON . stringify ( options . selectedTestFile ) } ;
13491328$changed_test_files_raw = ${ JSON . stringify ( JSON . stringify ( options . changedTestFiles ) ) } ;
1329+ $changed_test_scope = ${ JSON . stringify ( options . changedTestFiles . length > 0 ) } ;
13501330$autoload_file = ${ JSON . stringify ( options . autoloadFile ) } ;
13511331$wp_config_defines = json_decode(${ JSON . stringify ( JSON . stringify ( options . wpConfigDefines ) ) } , true);
13521332$multisite = ${ JSON . stringify ( options . multisite ) } ;
@@ -1482,11 +1462,8 @@ function core_pg_write_tests_config(string $core_root, array $extra_defines): st
14821462${ phpunitConfigDiscoveryPhp ( {
14831463 functionName : "core_pg_parse_phpunit_config" ,
14841464 logFunction : "core_pg_log" ,
1485- missingConfigMessage : "NOTICE:phpunit config not readable at " ,
1486- parseFailureMessage : "NOTICE:phpunit config parse failed; using defaults" ,
1487- includeParseFailureDetail : false ,
14881465 loadedConfigMessage : "NOTICE:phpunit config loaded from " ,
1489- fallbackXmlDist : false ,
1466+ fallbackXmlDist : options . phpunitXmlIsDefault ,
14901467 restrictDirectoriesToTests : false ,
14911468 basePathExpression : "dirname($xml_path)" ,
14921469 uniqueReturnValues : true ,
@@ -1501,7 +1478,6 @@ ${phpunitChangedTestFilterPhp({
15011478 logFunction : "core_pg_log" ,
15021479 rootParameterName : "core_root" ,
15031480 testsPathFallback : false ,
1504- emptyWantedNotice : false ,
15051481 } ) }
15061482
15071483${ phpunitArgsPhp ( "core_pg_phpunit_args" , "core_pg_log" ) }
@@ -1584,10 +1560,9 @@ try {
15841560 $test_files = array($selected_abs);
15851561 }
15861562 core_pg_log('DISCOVERY: dirs=' . implode(',', $directories) . ' files=' . count($configured_files) . ' suffixes=' . implode(',', $suffixes) . ' prefixes=' . implode(',', $prefixes) . ' excludes=' . count($excludes) . ' found=' . count($test_files));
1587- if (empty($test_files)) {
1563+ if (empty($test_files) && !$changed_test_scope ) {
15881564 core_pg_log('NO_TEST_FILES');
1589- core_pg_stage_ok('discover_tests');
1590- exit(0);
1565+ throw new RuntimeException('PHPUnit discovery found no test files');
15911566 }
15921567 core_pg_stage_ok('discover_tests');
15931568} catch (Throwable $e) {
0 commit comments