From ae1a62883e074eaa7a457fa2f6233f038915aa46 Mon Sep 17 00:00:00 2001 From: Kydoimos Date: Sat, 5 Sep 2026 11:48:38 -0300 Subject: [PATCH] Fix the CI failures in the uninstaller work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both were mine, and both were in code the earlier commit could not run. The four test failures shared one cause: UninstallerTest stubbed get_option with an arrow function, which captures by value, so every read answered from a snapshot of the options taken at setUp — before the test set any and before the run wrote any. Every assertion that depended on reading back what had just been written therefore saw an empty store. The file's other stubs already use by-reference closures; this one now does too. The phpcs error is WordPress.DB.PreparedSQL.NotPrepared on the table drop. The sniff cannot follow $sql across the null guard that PHPStan requires (prepare() is nullable), and unlike the repositories — which call through a typed $this->db property the sniff does not track at all — the uninstaller calls the global $wpdb, so the sniff sees it. Silenced explicitly, with the reason. composer test (996 tests, 2871 assertions), composer lint and composer cs all pass locally on PHP 8.4. Co-Authored-By: Claude Opus 5 --- src/Uninstaller.php | 2 +- tests/Unit/UninstallerTest.php | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Uninstaller.php b/src/Uninstaller.php index ea94628..26400b1 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -182,7 +182,7 @@ class Uninstaller { $sql = $wpdb->prepare( 'DROP TABLE IF EXISTS %i', $wpdb->prefix . $table ); if ( null !== $sql ) { - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- uninstall drops the plugin's own tables; the names come from Schema::TABLES, not from input. + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- $sql is the prepared statement two lines up; the sniff cannot follow it across the null guard, which PHPStan requires because prepare() is nullable. The only interpolated value is a Schema::TABLES constant. $wpdb->query( $sql ); } } diff --git a/tests/Unit/UninstallerTest.php b/tests/Unit/UninstallerTest.php index 1e7cad4..c051d6e 100644 --- a/tests/Unit/UninstallerTest.php +++ b/tests/Unit/UninstallerTest.php @@ -41,8 +41,13 @@ class UninstallerTest extends TestCase $rolesRemoved = &$this->rolesRemoved; $hooksCleared = &$this->hooksCleared; + // A regular closure, not an arrow fn: arrow functions capture by value, + // so every read would answer from a snapshot of the options taken at + // setUp — before the test set any, and before the run wrote any. Functions\when('get_option')->alias( - static fn(string $key, mixed $default = false): mixed => $options[$key] ?? $default + static function (string $key, mixed $default = false) use (&$options): mixed { + return $options[$key] ?? $default; + } ); Functions\when('update_option')->alias( static function (string $key, mixed $value) use (&$options): bool {