From a73c9be4fd7ac3934db56e4bb36200b111e3b37f Mon Sep 17 00:00:00 2001 From: Tony Hegyes Date: Sun, 1 Nov 2026 11:13:22 +0100 Subject: [PATCH 1/2] Test Internal Comments' underscore include skip with a written include The boot row asserted that includes/_disabled-example.php never loads, but no such file exists, so the row passed even with the loader's underscore check removed. The row writes an underscore-prefixed include defining a constant and checks in a fresh request, which must exit cleanly, that the plugin booted and the constant stayed undefined; it fails once the loader's check is removed. The fresh request comes from RunsRequestsTrait in tests/Support, which PartialDeployTest's helper moves to. Assisted-by: Claude Code:claude-opus-5-5 --- .../tests/Integration/PartialDeployTest.php | 17 +++-------------- .../tests/Integration/PluginBootTest.php | 13 ++++++++++++- .../tests/Support/RunsRequestsTrait.php | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 plugins/internal-comments/tests/Support/RunsRequestsTrait.php diff --git a/plugins/internal-comments/tests/Integration/PartialDeployTest.php b/plugins/internal-comments/tests/Integration/PartialDeployTest.php index c3739ca..ec28df5 100644 --- a/plugins/internal-comments/tests/Integration/PartialDeployTest.php +++ b/plugins/internal-comments/tests/Integration/PartialDeployTest.php @@ -3,12 +3,15 @@ namespace DeepWebSolutions\InternalComments\Tests\Integration; use DeepWebSolutions\InternalComments\Scoped\DeepWebSolutions\Framework\Core\Uninstall\Uninstaller; +use DeepWebSolutions\InternalComments\Tests\Support\RunsRequestsTrait; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\RunInSeparateProcess; use PHPUnit\Framework\TestCase; #[CoversNothing] final class PartialDeployTest extends TestCase { + use RunsRequestsTrait; + public function test_a_missing_built_asset_shows_the_build_notice_and_loads_nothing_built(): void { $manifest = \dirname( DWS_IC_FILE ) . '/assets/build/meta-box.asset.php'; \rename( $manifest, "$manifest.hidden" ); @@ -83,18 +86,4 @@ static function ( string $class_name ): void { \unlink( $log ); update_option( DWS_IC_OPTION_PLUGIN, DWS_IC_SETTING_DEFAULTS[ DWS_IC_OPTION_PLUGIN ] ); } - - /** - * @return array{status: int, output: string, last: string} - */ - protected static function request( string $php ): array { - \exec( 'wp --path=' . \escapeshellarg( ABSPATH ) . ' eval ' . \escapeshellarg( $php ) . ' 2>&1', $output, $status ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec -- Each row needs a fresh request that loads the plugin. - $output = \array_values( \array_filter( $output, static fn ( string $line ): bool => '' !== \trim( $line ) ) ); - - return array( - 'status' => $status, - 'output' => \implode( "\n", $output ), - 'last' => (string) \end( $output ), - ); - } } diff --git a/plugins/internal-comments/tests/Integration/PluginBootTest.php b/plugins/internal-comments/tests/Integration/PluginBootTest.php index 324f8fc..624c5ee 100644 --- a/plugins/internal-comments/tests/Integration/PluginBootTest.php +++ b/plugins/internal-comments/tests/Integration/PluginBootTest.php @@ -13,11 +13,14 @@ use DeepWebSolutions\InternalComments\Scoped\DeepWebSolutions\Framework\Core\Permission\CapabilityGrants; use DeepWebSolutions\InternalComments\Scoped\DeepWebSolutions\Framework\Core\Scheduling\Scheduler; use DeepWebSolutions\InternalComments\Settings; +use DeepWebSolutions\InternalComments\Tests\Support\RunsRequestsTrait; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\TestCase; #[CoversNothing] final class PluginBootTest extends TestCase { + use RunsRequestsTrait; + public function test_the_plugin_boots_every_component(): void { $plugin = dws_ic_plugin(); @@ -31,7 +34,15 @@ public function test_the_entry_loads_every_include_but_those_whose_names_start_w self::assertContains( $includes . 'safeguards.php', \get_included_files() ); self::assertContains( $includes . 'index.php', \get_included_files() ); - self::assertNotContains( $includes . '_disabled-example.php', \get_included_files() ); + self::assertIsInt( \file_put_contents( $includes . '_ic-skipped.php', "&1', $output, $status ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec -- Each row needs a fresh request that loads the plugin. + $output = \array_values( \array_filter( $output, static fn ( string $line ): bool => '' !== \trim( $line ) ) ); + + return array( + 'status' => $status, + 'output' => \implode( "\n", $output ), + 'last' => (string) \end( $output ), + ); + } +} From 9af859eb642276630917ff5dd2a6a0f58777cb2f Mon Sep 17 00:00:00 2001 From: Tony Hegyes Date: Sun, 1 Nov 2026 11:13:23 +0100 Subject: [PATCH 2/2] Check that Linked Orders booted in its underscore include row The row read "skipped" from a fresh request whenever the constant the underscore include defines stayed undefined, which also happens when the plugin never loads or boots in that request or the include was never written, so the row could pass without testing the loader. The row checks the write and prints "not booted" unless the plugin's boot succeeded, through RunsRequestsTrait in tests/Support, which PartialDeployTest's helper moves to; the request's exit status is still checked. Assisted-by: Claude Code:claude-opus-5-5 --- .../tests/Integration/PartialDeployTest.php | 17 +++-------------- .../tests/Integration/PluginBootTest.php | 11 +++++++---- .../tests/Support/RunsRequestsTrait.php | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 plugins/linked-orders-for-woocommerce/tests/Support/RunsRequestsTrait.php diff --git a/plugins/linked-orders-for-woocommerce/tests/Integration/PartialDeployTest.php b/plugins/linked-orders-for-woocommerce/tests/Integration/PartialDeployTest.php index 68baf64..5bc6c56 100644 --- a/plugins/linked-orders-for-woocommerce/tests/Integration/PartialDeployTest.php +++ b/plugins/linked-orders-for-woocommerce/tests/Integration/PartialDeployTest.php @@ -3,12 +3,15 @@ namespace DeepWebSolutions\LinkedOrders\Tests\Integration; use DeepWebSolutions\LinkedOrders\Scoped\DeepWebSolutions\Framework\Core\Uninstall\Uninstaller; +use DeepWebSolutions\LinkedOrders\Tests\Support\RunsRequestsTrait; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\RunInSeparateProcess; use PHPUnit\Framework\TestCase; #[CoversNothing] final class PartialDeployTest extends TestCase { + use RunsRequestsTrait; + public function test_a_missing_built_asset_shows_the_build_notice_and_loads_nothing_built(): void { $manifest = \dirname( DWS_LOWC_FILE ) . '/assets/build/orders-list-table.asset.php'; \rename( $manifest, "$manifest.hidden" ); @@ -83,18 +86,4 @@ static function ( string $class_name ): void { \unlink( $log ); update_option( DWS_LOWC_OPTION_DELETE_DATA, 'no' ); } - - /** - * @return array{status: int, output: string, last: string} - */ - protected static function request( string $php ): array { - \exec( 'wp --path=' . \escapeshellarg( ABSPATH ) . ' eval ' . \escapeshellarg( $php ) . ' 2>&1', $output, $status ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec -- Each row needs a fresh request that loads the plugin. - $output = \array_values( \array_filter( $output, static fn ( string $line ): bool => '' !== \trim( $line ) ) ); - - return array( - 'status' => $status, - 'output' => \implode( "\n", $output ), - 'last' => (string) \end( $output ), - ); - } } diff --git a/plugins/linked-orders-for-woocommerce/tests/Integration/PluginBootTest.php b/plugins/linked-orders-for-woocommerce/tests/Integration/PluginBootTest.php index 45ed05b..4171d66 100644 --- a/plugins/linked-orders-for-woocommerce/tests/Integration/PluginBootTest.php +++ b/plugins/linked-orders-for-woocommerce/tests/Integration/PluginBootTest.php @@ -13,11 +13,14 @@ use DeepWebSolutions\LinkedOrders\Scoped\DeepWebSolutions\Framework\Core\Permission\CapabilityGrants; use DeepWebSolutions\LinkedOrders\Scoped\DeepWebSolutions\Framework\Core\Scheduling\Scheduler; use DeepWebSolutions\LinkedOrders\Settings; +use DeepWebSolutions\LinkedOrders\Tests\Support\RunsRequestsTrait; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\TestCase; #[CoversNothing] final class PluginBootTest extends TestCase { + use RunsRequestsTrait; + public function test_the_plugin_boots_every_component_but_the_integration_with_an_absent_plugin(): void { $plugin = dws_lowc_plugin(); @@ -31,15 +34,15 @@ public function test_the_entry_loads_every_include_but_those_whose_names_start_w self::assertContains( $includes . 'safeguards.php', \get_included_files() ); self::assertContains( $includes . 'index.php', \get_included_files() ); - \file_put_contents( $includes . '_lowc-skipped.php', "&1', $output, $status ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec -- The loader runs only in a fresh request. + $request = self::request( 'echo 0 < did_action( "dws_lowc/boot/succeeded" ) ? ( defined( "DWS_LOWC_SKIPPED_INCLUDE" ) ? "loaded" : "skipped" ) : "not booted";' ); } finally { \unlink( $includes . '_lowc-skipped.php' ); } - self::assertSame( 0, $status, \implode( "\n", $output ) ); - self::assertSame( 'skipped', (string) \end( $output ) ); + self::assertSame( 0, $request['status'], $request['output'] ); + self::assertSame( 'skipped', $request['last'], $request['output'] ); } public function test_the_stored_data_is_at_the_revision_of_the_code(): void { diff --git a/plugins/linked-orders-for-woocommerce/tests/Support/RunsRequestsTrait.php b/plugins/linked-orders-for-woocommerce/tests/Support/RunsRequestsTrait.php new file mode 100644 index 0000000..25bbd72 --- /dev/null +++ b/plugins/linked-orders-for-woocommerce/tests/Support/RunsRequestsTrait.php @@ -0,0 +1,19 @@ +&1', $output, $status ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec -- Each row needs a fresh request that loads the plugin. + $output = \array_values( \array_filter( $output, static fn ( string $line ): bool => '' !== \trim( $line ) ) ); + + return array( + 'status' => $status, + 'output' => \implode( "\n", $output ), + 'last' => (string) \end( $output ), + ); + } +}