From 76141a65984719dbbdb4fb49f1a648d83db135f4 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 14 Nov 2024 10:19:03 -0800 Subject: [PATCH 01/10] Add `set_transient()` filters and actions --- includes/Helpers/Transient.php | 29 ++++++++++- tests/phpunit/bootstrap.php | 7 --- .../includes/Helpers/TransientTest.php | 50 +++++++++++++++++++ 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/includes/Helpers/Transient.php b/includes/Helpers/Transient.php index 1124140..43fcc90 100644 --- a/includes/Helpers/Transient.php +++ b/includes/Helpers/Transient.php @@ -33,13 +33,24 @@ public static function get( string $key ) { return \get_transient( $key ); } + /** + * Implement the filters as used in {@see get_transient()}. + */ + $pre = apply_filters( "pre_transient_{$key}", false, $key ); + if ( false !== $pre ) { + return $pre; + } + /** * @var array{value:mixed, expires_at:int} $data The saved value and the Unix time it expires at. */ $data = \get_option( $key ); if ( is_array( $data ) && isset( $data['expires_at'], $data['value'] ) ) { if ( $data['expires_at'] > time() ) { - return $data['value']; + /** + * Implement the filters as used in {@see get_transient()}. + */ + return apply_filters( "transient_{$key}", $data['value'], $key ); } else { \delete_option( $key ); } @@ -65,11 +76,25 @@ public static function set( string $key, $value, int $expires_in = 3600 ): bool return \set_transient( $key, $value, $expires_in ); } + /** + * Implement the filters as used in {@see set_transient()}. + */ + $value = apply_filters( "pre_set_transient_{$key}", $value, $expires_in, $key ); + $expires_in = apply_filters( "expiration_of_transient_{$key}", $expires_in, $value, $key ); + $data = array( 'value' => $value, 'expires_at' => $expires_in + time(), ); - return \update_option( $key, $data, false ); + + $result = \update_option( $key, $data, false ); + + if ( $result ) { + do_action( "set_transient_{$key}", $value, $expires_in, $key ); + do_action( 'setted_transient', $key, $value, $expires_in ); + } + + return $result; } /** diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php index f39969f..a47486e 100644 --- a/tests/phpunit/bootstrap.php +++ b/tests/phpunit/bootstrap.php @@ -1,12 +1,5 @@ assertConditionsMet(); + } + + /** + * {@see WP_Mock::expectFilter()} and {WP_Mock::expectAction()} are not working for me. I have created some dummy + * + * @covers ::set + */ + public function test_set_transient_filters_are_called(): void { + + $test_transient_name = uniqid( __FUNCTION__ ); + + \WP_Mock::userFunction( 'get_dropins' ) + ->once() + ->andReturn( array( 'object-cache.php' => array() ) ); + + WP_Mock::expectFilter( + "pre_set_transient_{$test_transient_name}", + 'value', + 999, + $test_transient_name + ); + + WP_Mock::expectFilter( + "expiration_of_transient_{$test_transient_name}", + 999, + 'value', + $test_transient_name, + ); + \WP_Mock::userFunction( 'update_option' ) + ->once() + ->andReturn( true ); + + WP_Mock::expectAction( + "set_transient_{$test_transient_name}", + 'value', + 999, + $test_transient_name + ); + + WP_Mock::expectAction( + 'setted_transient', + $test_transient_name, + 'value', + 999 + ); + + Transient::set( $test_transient_name, 'value', 999 ); + + $this->assertConditionsMet(); } } From 77aa5b1be0df391719ca991c6508c69c98d29db9 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 14 Nov 2024 10:19:14 -0800 Subject: [PATCH 02/10] lint --- tests/phpunit/includes/Helpers/TransientTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/phpunit/includes/Helpers/TransientTest.php b/tests/phpunit/includes/Helpers/TransientTest.php index 58ca470..cb91f51 100644 --- a/tests/phpunit/includes/Helpers/TransientTest.php +++ b/tests/phpunit/includes/Helpers/TransientTest.php @@ -206,16 +206,16 @@ public function test_should_use_transients_bluehost_cloud(): void { $test_transient_name = uniqid( __FUNCTION__ ); \WP_Mock::userFunction( 'get_dropins' ) - ->once() - ->andReturn( array( 'object-cache.php' => array() ) ); + ->once() + ->andReturn( array( 'object-cache.php' => array() ) ); \WP_Mock::userFunction( 'set_transient' ) - ->once() - ->with( $test_transient_name, 'value', 999 ) - ->andReturnTrue(); + ->once() + ->with( $test_transient_name, 'value', 999 ) + ->andReturnTrue(); \WP_Mock::userFunction( 'update_option' ) - ->never(); + ->never(); \NewfoldLabs\WP\Context\setContext( 'platform', 'atomic' ); From b231937673389c0152673f107827428ae3cdb296 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 14 Nov 2024 10:44:38 -0800 Subject: [PATCH 03/10] Update existing tests to work with newly added filters --- .../includes/Helpers/TransientTest.php | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/includes/Helpers/TransientTest.php b/tests/phpunit/includes/Helpers/TransientTest.php index cb91f51..f23cecc 100644 --- a/tests/phpunit/includes/Helpers/TransientTest.php +++ b/tests/phpunit/includes/Helpers/TransientTest.php @@ -73,6 +73,20 @@ public function test_set_transient_use_options(): void { \WP_Mock::userFunction( 'set_transient' ) ->never(); + WP_Mock::expectFilter( + "pre_set_transient_{$test_transient_name}", + 'value', + 999, + $test_transient_name + ); + + WP_Mock::expectFilter( + "expiration_of_transient_{$test_transient_name}", + 999, + 'value', + $test_transient_name, + ); + \WP_Mock::userFunction( 'update_option' ) ->once() ->with( @@ -82,6 +96,20 @@ public function test_set_transient_use_options(): void { ) ->andReturnTrue(); + WP_Mock::expectAction( + "set_transient_{$test_transient_name}", + 'value', + 999, + $test_transient_name + ); + + WP_Mock::expectAction( + 'setted_transient', + $test_transient_name, + 'value', + 999 + ); + Transient::set( $test_transient_name, 'value', 999 ); $this->assertConditionsMet(); @@ -125,6 +153,12 @@ public function test_get_transient_use_options(): void { \WP_Mock::userFunction( 'get_transient' ) ->never(); + WP_Mock::expectFilter( + "pre_transient_{$test_transient_name}", + false, + $test_transient_name + ); + \WP_Mock::userFunction( 'get_option' ) ->once() ->with( $test_transient_name, ) @@ -135,6 +169,12 @@ public function test_get_transient_use_options(): void { ) ); + WP_Mock::expectFilter( + "transient_{$test_transient_name}", + 'value', + $test_transient_name + ); + $result = Transient::get( $test_transient_name ); $this->assertEquals( 'value', $result ); @@ -154,6 +194,12 @@ public function test_get_transient_use_options_expired(): void { \WP_Mock::userFunction( 'get_transient' ) ->never(); + WP_Mock::expectFilter( + "pre_transient_{$test_transient_name}", + false, + $test_transient_name + ); + \WP_Mock::userFunction( 'get_option' ) ->once() ->with( $test_transient_name, ) @@ -225,7 +271,10 @@ public function test_should_use_transients_bluehost_cloud(): void { } /** - * {@see WP_Mock::expectFilter()} and {WP_Mock::expectAction()} are not working for me. I have created some dummy + * {@see \WP_Mock\Functions::$wp_mocked_fuctions} array is not being reset between tests. The code seems to + * have been refactored in WP_Mock's newer versions but we are stuck using PHP 7.3 for now. + * + * @runInSeparateProcess * * @covers ::set */ @@ -233,7 +282,7 @@ public function test_set_transient_filters_are_called(): void { $test_transient_name = uniqid( __FUNCTION__ ); - \WP_Mock::userFunction( 'get_dropins' ) + WP_Mock::userFunction( 'get_dropins' ) ->once() ->andReturn( array( 'object-cache.php' => array() ) ); From db3c377a7fa47b159a63598dfaf930ac26a59840 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 14 Nov 2024 11:07:50 -0800 Subject: [PATCH 04/10] Update tests re `WP_Mock::expectAction()` and `WP_Mock::expectFilter()` --- .../phpunit/includes/HiiveConnectionTest.php | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/tests/phpunit/includes/HiiveConnectionTest.php b/tests/phpunit/includes/HiiveConnectionTest.php index 4c0265f..db4373c 100644 --- a/tests/phpunit/includes/HiiveConnectionTest.php +++ b/tests/phpunit/includes/HiiveConnectionTest.php @@ -3,6 +3,7 @@ namespace NewfoldLabs\WP\Module\Data; use Mockery; +use NewfoldLabs\Container\Container; use NewfoldLabs\WP\Module\Data\Listeners\Plugin; use WP_Mock; use WP_Mock\Tools\TestCase; @@ -16,6 +17,8 @@ class HiiveConnectionTest extends TestCase { public function setUp(): void { parent::setUp(); + forceWpMockStrictModeOn(); + WP_Mock::passthruFunction( '__' ); WP_Mock::passthruFunction( 'sanitize_title' ); @@ -39,7 +42,11 @@ function () { * @covers ::get_core_data */ public function test_plugin_sends_boxname_to_hiive(): void { - // WP_Mock::expectAction('newfold_container_set'); + /** + * Unable to get this working. + */ + forceWpMockStrictModeOff(); + // WP_Mock::expectAction( 'newfold_container_set', \WP_Mock\Functions::type( Container::class ) ); $plugin = Mockery::mock( Plugin::class ); $plugin->brand = 'bluehost'; @@ -48,11 +55,11 @@ public function test_plugin_sends_boxname_to_hiive(): void { container()->set( 'plugin', $plugin ); WP_Mock::userFunction( 'get_option' )->once()->with( 'newfold_cache_level', 2 )->andReturn( 2 ); - WP_Mock::userFunction( 'get_option' )->once()->with( 'newfold_cloudflare_enabled', false )->andReturn( false ); + WP_Mock::userFunction( 'get_option' )->once()->with( 'newfold_cloudflare_enabled', false )->andReturnFalse(); WP_Mock::userFunction( 'get_option' )->once()->with( 'admin_email' )->andReturn( 'admin@example.com' ); WP_Mock::userFunction( 'get_site_url' )->once()->withNoArgs()->andReturn( 'http://example.com' ); - // WP_Mock::expectFilter('newfold_wp_data_module_core_data_filter'); + // WP_Mock::expectFilter( 'newfold_wp_data_module_core_data_filter', \WP_Mock\Functions::type( 'array' ) ); global $wpdb; $wpdb = Mockery::mock(); @@ -64,11 +71,16 @@ public function test_plugin_sends_boxname_to_hiive(): void { self::assertArrayHasKey( 'hostname', $result ); } + /** * @covers ::get_core_data */ public function test_plugin_sends_server_path_to_hiive(): void { - // WP_Mock::expectAction('newfold_container_set'); + /** + * Unable to get this working. + */ + forceWpMockStrictModeOff(); + // WP_Mock::expectAction( 'newfold_container_set', \WP_Mock\Functions::type( Container::class ) ); $plugin = Mockery::mock( Plugin::class ); $plugin->brand = 'bluehost'; @@ -81,7 +93,7 @@ public function test_plugin_sends_server_path_to_hiive(): void { WP_Mock::userFunction( 'get_option' )->once()->with( 'admin_email' )->andReturn( 'admin@example.com' ); WP_Mock::userFunction( 'get_site_url' )->once()->withNoArgs()->andReturn( 'http://example.com' ); - // WP_Mock::expectFilter('newfold_wp_data_module_core_data_filter'); + // WP_Mock::expectFilter( 'newfold_wp_data_module_core_data_filter', \WP_Mock\Functions::type( 'array' ) ); global $wpdb; $wpdb = Mockery::mock(); @@ -118,6 +130,12 @@ public function test_hiive_request_returns_wperror_when_no_auth_token(): void { ->once() ->andReturnNull(); + /** + * Unable to get this working. + */ + forceWpMockStrictModeOff(); + // WP_Mock::expectAction('wp_error_added', \WP_Mock\Functions::type( 'string' ),\WP_Mock\Functions::type( 'string' ),\WP_Mock\Functions::type( 'string' ), \WP_Mock\Functions::type( 'WP_Error' ) ); + $result = $sut->hiive_request( '/sites/v2/events' ); self::assertInstanceOf( \WP_Error::class, $result ); @@ -347,6 +365,12 @@ function ( string $constant_name ) use ( $temp_dir ) { ->twice() ->with( 'http_headers_useragent', array( $sut, 'add_plugin_name_version_to_user_agent' ) ); + /** + * Unable to get this working. + */ + forceWpMockStrictModeOff(); + // WP_Mock::expectAction('wp_error_added', \WP_Mock\Functions::type( 'string' ),\WP_Mock\Functions::type( 'string' ),\WP_Mock\Functions::type( 'string' ), \WP_Mock\Functions::type( 'WP_Error' ) ); + $sut->notify( array( $event ) ); $this->assertConditionsMet(); @@ -358,6 +382,7 @@ function ( string $constant_name ) use ( $temp_dir ) { * @covers ::get_auth_token */ public function test_fails_to_reconnect() { + $sut = Mockery::mock( HiiveConnection::class )->makePartial(); WP_Mock::expectFilterAdded( 'http_headers_useragent', array( $sut, 'add_plugin_name_version_to_user_agent' ), 10, 2 ); @@ -386,6 +411,12 @@ public function test_fails_to_reconnect() { ->once() ->andReturnFalse(); + /** + * Unable to get this working. + */ + forceWpMockStrictModeOff(); + // WP_Mock::expectAction('wp_error_added', 'hiive_connection', 'This site is not connected to the hiive.', '', \WP_Mock\Functions::type( 'WP_Error' ) ); + $sut->expects( 'reconnect' )->once()->andReturnFalse(); $result = $sut->hiive_request( 'sites/v2/events' ); From 3f42d76e2b28090e5b59141ce07e64716d31e82c Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 14 Nov 2024 11:09:37 -0800 Subject: [PATCH 05/10] Update tests re `WP_Mock::expectFilter()` --- tests/phpunit/includes/Listeners/CronTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/includes/Listeners/CronTest.php b/tests/phpunit/includes/Listeners/CronTest.php index 30cf2ef..b720dc2 100644 --- a/tests/phpunit/includes/Listeners/CronTest.php +++ b/tests/phpunit/includes/Listeners/CronTest.php @@ -85,7 +85,7 @@ public function test_cron_job_main_function(): void { WP_Mock::userFunction('get_mu_plugins') ->once()->andReturn(array()); - // WP_Mock::expectFilter('newfold_wp_data_module_cron_data_filter'); + WP_Mock::expectFilter( 'newfold_wp_data_module_cron_data_filter', array( 'plugins' => array() ) ); $sut->shouldReceive('push') ->once() From 6be0969b840213805a5143bd65ca762e7fb10eaf Mon Sep 17 00:00:00 2001 From: Giuseppe Arcifa Date: Fri, 15 Nov 2024 15:42:48 +0100 Subject: [PATCH 06/10] Fixed PHPCS errors --- includes/Helpers/Transient.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/includes/Helpers/Transient.php b/includes/Helpers/Transient.php index 43fcc90..a9be71a 100644 --- a/includes/Helpers/Transient.php +++ b/includes/Helpers/Transient.php @@ -42,7 +42,9 @@ public static function get( string $key ) { } /** - * @var array{value:mixed, expires_at:int} $data The saved value and the Unix time it expires at. + * The saved value and the Unix time it expires at. + * + * @var array{value:mixed, expires_at:int} $data */ $data = \get_option( $key ); if ( is_array( $data ) && isset( $data['expires_at'], $data['value'] ) ) { @@ -125,7 +127,7 @@ public static function delete( $key ): bool { */ public function __call( $name, $arguments ) { if ( ! method_exists( __CLASS__, $name ) ) { - throw new \BadMethodCallException( "Method $name does not exist" ); + throw new \BadMethodCallException( "Method " . esc_html( $name ) . " does not exist" ); } return self::$name( ...$arguments ); } From c5de37c972b6ea6ea0b147ff6581bc34556722f9 Mon Sep 17 00:00:00 2001 From: Giuseppe Arcifa Date: Fri, 15 Nov 2024 15:46:00 +0100 Subject: [PATCH 07/10] Fixed PHPCS double quotes errors --- includes/Helpers/Transient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Helpers/Transient.php b/includes/Helpers/Transient.php index a9be71a..bcedfe2 100644 --- a/includes/Helpers/Transient.php +++ b/includes/Helpers/Transient.php @@ -127,7 +127,7 @@ public static function delete( $key ): bool { */ public function __call( $name, $arguments ) { if ( ! method_exists( __CLASS__, $name ) ) { - throw new \BadMethodCallException( "Method " . esc_html( $name ) . " does not exist" ); + throw new \BadMethodCallException( 'Method ' . esc_html( $name ) . ' does not exist' ); } return self::$name( ...$arguments ); } From 0ec2a6fc6b4a8cc832365ec056ccc6ffeca6e657 Mon Sep 17 00:00:00 2001 From: Giuseppe Arcifa Date: Wed, 4 Dec 2024 10:29:38 +0100 Subject: [PATCH 08/10] Add WP filters and actions in method --- includes/Helpers/Transient.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/includes/Helpers/Transient.php b/includes/Helpers/Transient.php index bcedfe2..196d611 100644 --- a/includes/Helpers/Transient.php +++ b/includes/Helpers/Transient.php @@ -113,7 +113,26 @@ public static function delete( $key ): bool { return \delete_transient( $key ); } - return \delete_option( $key ); + /** + * Implement the filters as used in {@see set_transient()}. + * + * @param string $key Transient name. + */ + do_action( "delete_transient_{$key}", $key ); + + $result = \delete_option( $key ); + + if ( $result ) { + + /** + * Implement the filters as used in {@see set_transient()}. + * + * @param string $transient Deleted transient name. + */ + do_action( 'deleted_transient', $key ); + } + + return $result; } /** From 914bcf91c4cc2e00d2a05fff8442ee37512145e1 Mon Sep 17 00:00:00 2001 From: Giuseppe Arcifa Date: Wed, 4 Dec 2024 10:37:58 +0100 Subject: [PATCH 09/10] Refactored `Transient::get()` method to reproduce the same WP filters behaviour --- includes/Helpers/Transient.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/includes/Helpers/Transient.php b/includes/Helpers/Transient.php index 196d611..b92d2a1 100644 --- a/includes/Helpers/Transient.php +++ b/includes/Helpers/Transient.php @@ -49,16 +49,17 @@ public static function get( string $key ) { $data = \get_option( $key ); if ( is_array( $data ) && isset( $data['expires_at'], $data['value'] ) ) { if ( $data['expires_at'] > time() ) { - /** - * Implement the filters as used in {@see get_transient()}. - */ - return apply_filters( "transient_{$key}", $data['value'], $key ); + $value = $data['value']; } else { \delete_option( $key ); + $value = false; } } - return false; + /** + * Implement the filters as used in {@see get_transient()}. + */ + return apply_filters( "transient_{$key}", $value, $key ); } /** From 5785af658ff96daa50c0ee58345c57112131bd57 Mon Sep 17 00:00:00 2001 From: Giuseppe Arcifa Date: Wed, 4 Dec 2024 11:41:19 +0100 Subject: [PATCH 10/10] Updated `TransientTest::test_get_transient_use_options_expired()` method to match the expected filters when testing an expired transient --- tests/phpunit/includes/Helpers/TransientTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/phpunit/includes/Helpers/TransientTest.php b/tests/phpunit/includes/Helpers/TransientTest.php index f23cecc..9049bbf 100644 --- a/tests/phpunit/includes/Helpers/TransientTest.php +++ b/tests/phpunit/includes/Helpers/TransientTest.php @@ -215,6 +215,12 @@ public function test_get_transient_use_options_expired(): void { ->with( $test_transient_name ) ->andReturnTrue(); + WP_Mock::expectFilter( + "transient_{$test_transient_name}", + false, + $test_transient_name + ); + $result = Transient::get( $test_transient_name ); $this->assertFalse( $result );