From 056d99f22d02ee04a664f8a8e346596c0cdc839f Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Tue, 14 Feb 2023 14:39:20 +0000 Subject: [PATCH 1/4] add AJAX_Runner and tests --- includes/Checker/AJAX_Runner.php | 88 +++++++++++++++++ tests/Checker/AJAX_Runner_Tests.php | 145 ++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 includes/Checker/AJAX_Runner.php create mode 100644 tests/Checker/AJAX_Runner_Tests.php diff --git a/includes/Checker/AJAX_Runner.php b/includes/Checker/AJAX_Runner.php new file mode 100644 index 000000000..12222c116 --- /dev/null +++ b/includes/Checker/AJAX_Runner.php @@ -0,0 +1,88 @@ +checks ) ) { + // Get the plugin name from the AJAX request. + $plugin_slug = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : ''; + $plugin_file = Plugin_Request_Utility::get_plugin_basename_from_input( $plugin_slug ); + + $this->checks = new Checks( WP_PLUGIN_DIR . '/' . $plugin_file ); + } + + return $this->checks; + } + + /** + * Returns an array of Check instances to run. + * + * @since n.e.x.t + * + * @return array An array of Check instances to run. + */ + protected function get_check_slugs_to_run() { + $checks = array(); + + if ( isset( $_REQUEST['checks'] ) ) { + // Checks are passed as a comma separated string. + $checks = explode( ',', $_REQUEST['checks'] ); + } + + return $checks; + } +} diff --git a/tests/Checker/AJAX_Runner_Tests.php b/tests/Checker/AJAX_Runner_Tests.php new file mode 100644 index 000000000..4682be237 --- /dev/null +++ b/tests/Checker/AJAX_Runner_Tests.php @@ -0,0 +1,145 @@ +assertTrue( $runner->is_plugin_check() ); + } + + public function test_is_plugin_check_returns_false() { + $runner = new AJAX_Runner(); + + $this->assertFalse( $runner->is_plugin_check() ); + } + + public function test_prepare_with_runtime_check() { + $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'runtime_check'; + + add_filter( + 'wp_plugin_check_checks', + function( $checks ) { + return array( + 'runtime_check' => new WordPress\Plugin_Check\Test_Data\Runtime_Check(), + ); + } + ); + + $runner = new AJAX_Runner(); + $cleanup = $runner->prepare(); + + $this->assertIsCallable( $cleanup ); + + // Assert the Universal_Runtume_Preparation was run. + $this->assertTrue( has_filter( 'option_active_plugins' ) ); + $this->assertTrue( has_filter( 'default_option_active_plugins' ) ); + $this->assertTrue( has_filter( 'stylesheet' ) ); + $this->assertTrue( has_filter( 'template' ) ); + $this->assertTrue( has_filter( 'pre_option_template' ) ); + $this->assertTrue( has_filter( 'pre_option_stylesheet' ) ); + $this->assertTrue( has_filter( 'pre_option_current_theme' ) ); + $this->assertTrue( has_filter( 'pre_option_template_root' ) ); + $this->assertTrue( has_filter( 'pre_option_stylesheet_root' ) ); + } + + public function test_prepare_with_static_check() { + $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'empty_check'; + + add_filter( + 'wp_plugin_check_checks', + function( $checks ) { + return array( + 'empty_check' => new WordPress\Plugin_Check\Test_Data\Empty_Check(), + ); + } + ); + + $runner = new AJAX_Runner(); + $cleanup = $runner->prepare(); + + $this->assertIsCallable( $cleanup ); + + // Assert the Universal_Runtume_Preparation was not run. + $this->assertFalse( has_filter( 'option_active_plugins' ) ); + $this->assertFalse( has_filter( 'default_option_active_plugins' ) ); + $this->assertFalse( has_filter( 'stylesheet' ) ); + $this->assertFalse( has_filter( 'template' ) ); + $this->assertFalse( has_filter( 'pre_option_template' ) ); + $this->assertFalse( has_filter( 'pre_option_stylesheet' ) ); + $this->assertFalse( has_filter( 'pre_option_current_theme' ) ); + $this->assertFalse( has_filter( 'pre_option_template_root' ) ); + $this->assertFalse( has_filter( 'pre_option_stylesheet_root' ) ); + } + + public function test_run() { + $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'empty_check'; + + add_filter( + 'wp_plugin_check_checks', + function( $checks ) { + return array( + 'empty_check' => new WordPress\Plugin_Check\Test_Data\Empty_Check(), + ); + } + ); + + $runner = new AJAX_Runner(); + $runner->prepare(); + $results = $runner->run(); + + $this->assertInstanceOf( Check_Result::class, $results ); + $this->assertEmpty( $results->get_warnings() ); + $this->assertEmpty( $results->get_errors() ); + } + + public function test_run_with_errors() { + $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'error_check'; + + add_filter( + 'wp_plugin_check_checks', + function( $checks ) { + return array( + 'error_check' => new WordPress\Plugin_Check\Test_Data\Error_Check(), + ); + } + ); + + $runner = new AJAX_Runner(); + $runner->prepare(); + $results = $runner->run(); + + $this->assertInstanceOf( Check_Result::class, $results ); + $this->assertEmpty( $results->get_warnings() ); + $this->assertNotEmpty( $results->get_errors() ); + } +} From 66b5ac3f4f71b8377fbde5cccc09151cb23bf6ca Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Wed, 15 Feb 2023 13:06:03 +0000 Subject: [PATCH 2/4] use wp ajax functions with AJAX_Runner class --- includes/Checker/AJAX_Runner.php | 24 +++++++-------- includes/Checker/CLI_Runner.php | 8 ++--- tests/Checker/AJAX_Runner_Tests.php | 45 ++++++++++++++--------------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/includes/Checker/AJAX_Runner.php b/includes/Checker/AJAX_Runner.php index 12222c116..d83d51278 100644 --- a/includes/Checker/AJAX_Runner.php +++ b/includes/Checker/AJAX_Runner.php @@ -7,6 +7,7 @@ namespace WordPress\Plugin_Check\Checker; +use Exception; use WordPress\Plugin_Check\Utilities\Plugin_Request_Utility; /** @@ -29,10 +30,10 @@ class AJAX_Runner extends Abstract_Check_Runner { * * @since n.e.x.t * - * @return bool + * @return bool Returns true if is an AJAX request for the plugin check else false. */ public function is_plugin_check() { - if ( 0 !== strpos( $_SERVER['REQUEST_URI'], '/admin-ajax.php' ) ) { + if ( ! wp_doing_ajax() ) { return false; } @@ -40,10 +41,6 @@ public function is_plugin_check() { return false; } - if ( ! check_ajax_referer( 'plugin_check_run_checks' ) ) { - return false; - } - return true; } @@ -52,15 +49,18 @@ public function is_plugin_check() { * * @since n.e.x.t * - * @return Checks + * @return Checks An instances of the Checks class. * * @throws Exception Thrown if the plugin main file cannot be found based on the AJAX input. */ protected function get_checks_instance() { if ( ! isset( $this->checks ) ) { + if ( ! isset( $_REQUEST['plugin'] ) ) { + throw new Exception( 'Invalid plugin slug: Plugin slug must not be empty.' ); + } + // Get the plugin name from the AJAX request. - $plugin_slug = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : ''; - $plugin_file = Plugin_Request_Utility::get_plugin_basename_from_input( $plugin_slug ); + $plugin_file = Plugin_Request_Utility::get_plugin_basename_from_input( $_REQUEST['plugin'] ); $this->checks = new Checks( WP_PLUGIN_DIR . '/' . $plugin_file ); } @@ -69,18 +69,18 @@ protected function get_checks_instance() { } /** - * Returns an array of Check instances to run. + * Returns an array of Check slugs to run. * * @since n.e.x.t * - * @return array An array of Check instances to run. + * @return array An array of Check slugs to run. */ protected function get_check_slugs_to_run() { $checks = array(); if ( isset( $_REQUEST['checks'] ) ) { // Checks are passed as a comma separated string. - $checks = explode( ',', $_REQUEST['checks'] ); + $checks = wp_parse_list( $_REQUEST['checks'] ); } return $checks; diff --git a/includes/Checker/CLI_Runner.php b/includes/Checker/CLI_Runner.php index d240ebf2c..12828eabf 100644 --- a/includes/Checker/CLI_Runner.php +++ b/includes/Checker/CLI_Runner.php @@ -29,7 +29,7 @@ class CLI_Runner extends Abstract_Check_Runner { * * @since n.e.x.t * - * @return bool + * @return bool Returns true if is an CLI request for the plugin check else false. */ public function is_plugin_check() { if ( empty( $_SERVER['argv'] ) || 3 > count( $_SERVER['argv'] ) ) { @@ -52,7 +52,7 @@ public function is_plugin_check() { * * @since n.e.x.t * - * @return Checks + * @return Checks An instances of the Checks class. * * @throws Exception Thrown if the plugin main file cannot be found based on the CLI input. */ @@ -69,11 +69,11 @@ protected function get_checks_instance() { } /** - * Returns an array of Check instances to run. + * Returns an array of Check slugs to run. * * @since n.e.x.t * - * @return array An array of Check instances to run. + * @return array An array of Check slugs to run. */ protected function get_check_slugs_to_run() { $checks = array(); diff --git a/tests/Checker/AJAX_Runner_Tests.php b/tests/Checker/AJAX_Runner_Tests.php index 4682be237..f9b35afdf 100644 --- a/tests/Checker/AJAX_Runner_Tests.php +++ b/tests/Checker/AJAX_Runner_Tests.php @@ -12,9 +12,8 @@ class AJAX_Runner_Tests extends WP_UnitTestCase { public function test_is_plugin_check_returns_true() { // Mock the AJAX request. - $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; - $_REQUEST['action'] = 'plugin_check_run_checks'; - $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'plugin_check_run_checks'; $runner = new AJAX_Runner(); @@ -22,17 +21,20 @@ public function test_is_plugin_check_returns_true() { } public function test_is_plugin_check_returns_false() { + // Mock the AJAX request. + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'a_different_ajax_request'; + $runner = new AJAX_Runner(); $this->assertFalse( $runner->is_plugin_check() ); } public function test_prepare_with_runtime_check() { - $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; - $_REQUEST['action'] = 'plugin_check_run_checks'; - $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); - $_REQUEST['plugin'] = 'plugin-check'; - $_REQUEST['checks'] = 'runtime_check'; + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'runtime_check'; add_filter( 'wp_plugin_check_checks', @@ -61,11 +63,10 @@ function( $checks ) { } public function test_prepare_with_static_check() { - $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; - $_REQUEST['action'] = 'plugin_check_run_checks'; - $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); - $_REQUEST['plugin'] = 'plugin-check'; - $_REQUEST['checks'] = 'empty_check'; + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'empty_check'; add_filter( 'wp_plugin_check_checks', @@ -94,11 +95,10 @@ function( $checks ) { } public function test_run() { - $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; - $_REQUEST['action'] = 'plugin_check_run_checks'; - $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); - $_REQUEST['plugin'] = 'plugin-check'; - $_REQUEST['checks'] = 'empty_check'; + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'empty_check'; add_filter( 'wp_plugin_check_checks', @@ -119,11 +119,10 @@ function( $checks ) { } public function test_run_with_errors() { - $_SERVER['REQUEST_URI'] = '/admin-ajax.php?action=plugin_check_run_checks'; - $_REQUEST['action'] = 'plugin_check_run_checks'; - $_REQUEST['_wpnonce'] = wp_create_nonce( 'plugin_check_run_checks' ); - $_REQUEST['plugin'] = 'plugin-check'; - $_REQUEST['checks'] = 'error_check'; + add_filter( 'wp_doing_ajax', '__return_true' ); + $_REQUEST['action'] = 'plugin_check_run_checks'; + $_REQUEST['plugin'] = 'plugin-check'; + $_REQUEST['checks'] = 'error_check'; add_filter( 'wp_plugin_check_checks', From 68eafd561be41af7af861f8ce88e6e79277d65e7 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Wed, 15 Feb 2023 10:18:10 -0800 Subject: [PATCH 3/4] Minor doc fixes. --- includes/Checker/AJAX_Runner.php | 8 ++++---- includes/Checker/Abstract_Check_Runner.php | 2 +- includes/Checker/CLI_Runner.php | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/includes/Checker/AJAX_Runner.php b/includes/Checker/AJAX_Runner.php index d83d51278..eb46bc0df 100644 --- a/includes/Checker/AJAX_Runner.php +++ b/includes/Checker/AJAX_Runner.php @@ -18,7 +18,7 @@ class AJAX_Runner extends Abstract_Check_Runner { /** - * An instances of the Checks class. + * An instance of the Checks class. * * @since n.e.x.t * @var Checks @@ -45,11 +45,11 @@ public function is_plugin_check() { } /** - * Retruns an instance of the Checks class. + * Creates and returns an instance of the Checks class based on the request. * * @since n.e.x.t * - * @return Checks An instances of the Checks class. + * @return Checks An instance of the Checks class. * * @throws Exception Thrown if the plugin main file cannot be found based on the AJAX input. */ @@ -69,7 +69,7 @@ protected function get_checks_instance() { } /** - * Returns an array of Check slugs to run. + * Returns an array of Check slugs to run based on the request. * * @since n.e.x.t * diff --git a/includes/Checker/Abstract_Check_Runner.php b/includes/Checker/Abstract_Check_Runner.php index d3d44c6ce..b1762344a 100644 --- a/includes/Checker/Abstract_Check_Runner.php +++ b/includes/Checker/Abstract_Check_Runner.php @@ -30,7 +30,7 @@ abstract public function is_plugin_check(); * * @since n.e.x.t * - * @return Checks An instances of the Checks class. + * @return Checks An instance of the Checks class. */ abstract protected function get_checks_instance(); diff --git a/includes/Checker/CLI_Runner.php b/includes/Checker/CLI_Runner.php index 12828eabf..a084b61ae 100644 --- a/includes/Checker/CLI_Runner.php +++ b/includes/Checker/CLI_Runner.php @@ -17,7 +17,7 @@ class CLI_Runner extends Abstract_Check_Runner { /** - * An instances of the Checks class. + * An instance of the Checks class. * * @since n.e.x.t * @var Checks @@ -48,11 +48,11 @@ public function is_plugin_check() { } /** - * Retruns an instance of the Checks class. + * Creates and returns an instance of the Checks class based on the request. * * @since n.e.x.t * - * @return Checks An instances of the Checks class. + * @return Checks An instance of the Checks class. * * @throws Exception Thrown if the plugin main file cannot be found based on the CLI input. */ @@ -69,7 +69,7 @@ protected function get_checks_instance() { } /** - * Returns an array of Check slugs to run. + * Returns an array of Check slugs to run based on the request. * * @since n.e.x.t * From 6d9b1b687b9d369ef0f91ad503e083730ccd7689 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Thu, 16 Feb 2023 12:26:45 +0000 Subject: [PATCH 4/4] add non ajax test --- tests/Checker/AJAX_Runner_Tests.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Checker/AJAX_Runner_Tests.php b/tests/Checker/AJAX_Runner_Tests.php index f9b35afdf..52a4160c3 100644 --- a/tests/Checker/AJAX_Runner_Tests.php +++ b/tests/Checker/AJAX_Runner_Tests.php @@ -30,6 +30,15 @@ public function test_is_plugin_check_returns_false() { $this->assertFalse( $runner->is_plugin_check() ); } + public function test_is_plugin_check_returns_false_not_ajax() { + // Mock the AJAX request. + add_filter( 'wp_doing_ajax', '__return_false' ); + + $runner = new AJAX_Runner(); + + $this->assertFalse( $runner->is_plugin_check() ); + } + public function test_prepare_with_runtime_check() { add_filter( 'wp_doing_ajax', '__return_true' ); $_REQUEST['action'] = 'plugin_check_run_checks';