diff --git a/includes/Helpers/Transient.php b/includes/Helpers/Transient.php index 1124140..b92d2a1 100644 --- a/includes/Helpers/Transient.php +++ b/includes/Helpers/Transient.php @@ -34,18 +34,32 @@ public static function get( string $key ) { } /** - * @var array{value:mixed, expires_at:int} $data The saved value and the Unix time it expires at. + * Implement the filters as used in {@see get_transient()}. + */ + $pre = apply_filters( "pre_transient_{$key}", false, $key ); + if ( false !== $pre ) { + return $pre; + } + + /** + * 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'] ) ) { if ( $data['expires_at'] > time() ) { - return $data['value']; + $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 ); } /** @@ -65,11 +79,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; } /** @@ -86,7 +114,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; } /** @@ -100,7 +147,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 ); } 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 @@ 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( @@ -81,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(); @@ -124,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, ) @@ -134,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 ); @@ -153,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, ) @@ -168,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 ); @@ -205,22 +258,74 @@ 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' ); Transient::set( $test_transient_name, 'value', 999 ); $this->assertConditionsMet(); + } + + /** + * {@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 + */ + 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(); } } diff --git a/tests/phpunit/includes/HiiveConnectionTest.php b/tests/phpunit/includes/HiiveConnectionTest.php index d1bfaa5..5541fa1 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' ); 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()