From 2ee601813aa625f6f203b4c374b6b62dd4d51633 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 24 Jan 2025 17:31:47 +0100 Subject: [PATCH 01/18] Begin adding code coverage support --- src/Context/FeatureContext.php | 109 +++++++++++++++++------ src/Context/WhenStepDefinitions.php | 5 ++ utils/maybe-generate-wp-cli-coverage.php | 42 +++++++++ 3 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 utils/maybe-generate-wp-cli-coverage.php diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index aa53ee367..dd805ea8a 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -7,6 +7,8 @@ use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behat\Testwork\Hook\Scope\AfterSuiteScope; use Behat\Testwork\Hook\Scope\BeforeSuiteScope; +use Behat\Behat\Hook\Scope\AfterFeatureScope; +use Behat\Behat\Hook\Scope\BeforeFeatureScope; use RuntimeException; use WP_CLI\Process; use WP_CLI\Utils; @@ -107,6 +109,48 @@ class FeatureContext implements SnippetAcceptingContext { private static $scenario_count = 0; // Scenario count, incremented on `@AfterScenario`. private static $proc_method_run_times = []; // Array of run time info for proc methods, keyed by method name and arg, each a 2-element array containing run time and run count. + /** + * The current feature. + * + * @var \Behat\Gherkin\Node\FeatureNode|null + */ + private static $feature; + + /** + * The current scenario. + * + * @var \Behat\Gherkin\Node\ScenarioInterface|null + */ + private $scenario; + + /** + * @BeforeFeature + */ + public static function store_feature( BeforeFeatureScope $scope ) { + self::$feature = $scope->getFeature(); + } + + /** + * @BeforeScenario + */ + public function store_scenario( BeforeScenarioScope $scope ) { + $this->scenario = $scope->getScenario(); + } + + /** + * @AfterScenario + */ + public function forget_scenario( AfterScenarioScope $scope ) { + $this->scenario = null; + } + + /** + * @AfterFeature + */ + public static function forget_feature( AfterFeatureScope $scope ) { + self::$feature = null; + } + /** * Get the path to the Composer vendor folder. * @@ -330,9 +374,9 @@ private static function get_behat_internal_variables() { } /** - * Download and extract a single copy of the sqlite-database-integration plugin - * for use in subsequent WordPress copies - */ + * Download and extract a single copy of the sqlite-database-integration plugin + * for use in subsequent WordPress copies + */ private static function download_sqlite_plugin( $dir ) { $download_url = 'https://downloads.wordpress.org/plugin/sqlite-database-integration.zip'; $download_location = $dir . '/sqlite-database-integration.zip'; @@ -367,9 +411,9 @@ private static function download_sqlite_plugin( $dir ) { } /** - * Given a WordPress installation with the sqlite-database-integration plugin, - * configure it to use SQLite as the database by placing the db.php dropin file - */ + * Given a WordPress installation with the sqlite-database-integration plugin, + * configure it to use SQLite as the database by placing the db.php dropin file + */ private static function configure_sqlite( $dir ) { $db_copy = $dir . '/wp-content/mu-plugins/sqlite-database-integration/db.copy'; $db_dropin = $dir . '/wp-content/db.php'; @@ -806,8 +850,8 @@ public function download_phar( $version = 'same' ) { ); $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' - . uniqid( 'wp-cli-download-', true ) - . '.phar'; + . uniqid( 'wp-cli-download-', true ) + . '.phar'; Process::create( Utils\esc_cmd( @@ -879,6 +923,19 @@ public function proc( $command, $assoc_args = [], $path = '' ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } + if ( isset( $this->variables['PROJECT_DIR'] ) ) { + $env['BEHAT_PROJECT_DIR'] = $this->variables['PROJECT_DIR']; + } + + if ( self::$feature ) { + $env['BEHAT_FEATURE_TITLE'] = self::$feature->getTitle(); + + } + if ( $this->scenario ) { + $env['BEHAT_SCENARIO_TITLE'] = $this->scenario->getTitle(); + + } + if ( isset( $this->variables['RUN_DIR'] ) ) { $cwd = "{$this->variables['RUN_DIR']}/{$path}"; } else { @@ -1240,8 +1297,8 @@ private static function dir_diff_copy( $upd_dir, $src_dir, $cop_dir ) { } self::copy_dir( $upd_file, $cop_file ); } elseif ( ! copy( $upd_file, $cop_file ) ) { - $error = error_get_last(); - throw new RuntimeException( sprintf( "Failed to copy '%s' to '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_file, $cop_file, $error['message'] ) ); + $error = error_get_last(); + throw new RuntimeException( sprintf( "Failed to copy '%s' to '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_file, $cop_file, $error['message'] ) ); } } elseif ( is_dir( $upd_file ) ) { self::dir_diff_copy( $upd_file, $src_file, $cop_file ); @@ -1324,14 +1381,14 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) { $log .= PHP_EOL . 'Top ' . self::$num_top_processes . " process run times for '$suite'"; $log .= PHP_EOL . implode( - PHP_EOL, - array_map( - $runtime_callback, - array_keys( $tops ), - $tops, - array_keys( array_keys( $tops ) ) - ) - ) . PHP_EOL; + PHP_EOL, + array_map( + $runtime_callback, + array_keys( $tops ), + $tops, + array_keys( array_keys( $tops ) ) + ) + ) . PHP_EOL; // Scenario run times. arsort( self::$scenario_run_times ); @@ -1345,14 +1402,14 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) { $log .= PHP_EOL . 'Top ' . self::$num_top_scenarios . ' (of ' . self::$scenario_count . ") scenario run times for '$suite'"; $log .= PHP_EOL . implode( - PHP_EOL, - array_map( - $scenario_runtime_callback, - array_keys( $tops ), - $tops, - array_keys( array_keys( $tops ) ) - ) - ) . PHP_EOL; + PHP_EOL, + array_map( + $scenario_runtime_callback, + array_keys( $tops ), + $tops, + array_keys( array_keys( $tops ) ) + ) + ) . PHP_EOL; $log .= PHP_EOL . str_repeat( ')', 80 ); diff --git a/src/Context/WhenStepDefinitions.php b/src/Context/WhenStepDefinitions.php index a727e8c7f..48f432ed7 100644 --- a/src/Context/WhenStepDefinitions.php +++ b/src/Context/WhenStepDefinitions.php @@ -35,6 +35,11 @@ public function when_i_launch_in_the_background( $cmd ) { * @When /^I (run|try) `([^`]+)`$/ */ public function when_i_run( $mode, $cmd ) { + $with_code_coverage = (string) getenv( 'BEHAT_CODE_COVERAGE' ); + if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) { + $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={PROJECT_DIR}/vendor/wp-cli/wp-cli-tests/utils/maybe-generate-wp-cli-coverage.php ', $cmd ); + } + $cmd = $this->replace_variables( $cmd ); $this->result = $this->wpcli_tests_invoke_proc( $this->proc( $cmd ), $mode ); list( $this->result->stdout, $this->email_sends ) = $this->wpcli_tests_capture_email_sends( $this->result->stdout ); diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/maybe-generate-wp-cli-coverage.php new file mode 100644 index 000000000..8c9a822ee --- /dev/null +++ b/utils/maybe-generate-wp-cli-coverage.php @@ -0,0 +1,42 @@ +includeDirectory( "{$root_folder}/includes" ); +$filter->includeFiles( array( "{$root_folder}/plugin.php" ) ); + +$coverage = new CodeCoverage( + ( new Selector() )->forLineCoverage( $filter ), + $filter +); + +$feature = getenv( 'BEHAT_FEATURE_TITLE' ); +$scenario = getenv( 'BEHAT_SCENARIO_TITLE' ); +$name = "{$feature} - {$scenario}"; + +$coverage->start( $name ); + +register_shutdown_function( + static function () use ( $coverage, $feature, $scenario, $name ) { + $coverage->stop(); + + $project_dir = (string) getenv( 'BEHAT_PROJECT_DIR' ); + + $feature_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $feature ) ); + $scenario_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $scenario ) ); + $filename = "clover-behat/{$feature_suffix}-{$scenario_suffix}.xml"; + $destination = "{$project_dir}/build/logs/{$filename}"; + + ( new Clover() )->process( $coverage, $destination, $name ); + } +); From 43f58f0b22639a4cd71b4346af23745d2b551b6e Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sat, 25 Jan 2025 00:16:45 +0100 Subject: [PATCH 02/18] Lint fixes --- phpcs.xml.dist | 9 +++++++++ src/Context/FeatureContext.php | 36 +++++++++++++++++----------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 62a1a672c..938e6fdcc 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -73,4 +73,13 @@ */utils/polyfills\.php$ + + + + */maybe-generate-wp-cli-coverage\.php$ + + + */maybe-generate-wp-cli-coverage\.php$ + diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index dd805ea8a..34a3ef7ac 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -850,8 +850,8 @@ public function download_phar( $version = 'same' ) { ); $this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' - . uniqid( 'wp-cli-download-', true ) - . '.phar'; + . uniqid( 'wp-cli-download-', true ) + . '.phar'; Process::create( Utils\esc_cmd( @@ -1381,14 +1381,14 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) { $log .= PHP_EOL . 'Top ' . self::$num_top_processes . " process run times for '$suite'"; $log .= PHP_EOL . implode( - PHP_EOL, - array_map( - $runtime_callback, - array_keys( $tops ), - $tops, - array_keys( array_keys( $tops ) ) - ) - ) . PHP_EOL; + PHP_EOL, + array_map( + $runtime_callback, + array_keys( $tops ), + $tops, + array_keys( array_keys( $tops ) ) + ) + ) . PHP_EOL; // Scenario run times. arsort( self::$scenario_run_times ); @@ -1402,14 +1402,14 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) { $log .= PHP_EOL . 'Top ' . self::$num_top_scenarios . ' (of ' . self::$scenario_count . ") scenario run times for '$suite'"; $log .= PHP_EOL . implode( - PHP_EOL, - array_map( - $scenario_runtime_callback, - array_keys( $tops ), - $tops, - array_keys( array_keys( $tops ) ) - ) - ) . PHP_EOL; + PHP_EOL, + array_map( + $scenario_runtime_callback, + array_keys( $tops ), + $tops, + array_keys( array_keys( $tops ) ) + ) + ) . PHP_EOL; $log .= PHP_EOL . str_repeat( ')', 80 ); From 5708fb7d428b646525f983e5a0b053cbad341001 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sat, 25 Jan 2025 00:19:10 +0100 Subject: [PATCH 03/18] Don't use levels for dirname --- utils/maybe-generate-wp-cli-coverage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/maybe-generate-wp-cli-coverage.php index 8c9a822ee..66dbcf09a 100644 --- a/utils/maybe-generate-wp-cli-coverage.php +++ b/utils/maybe-generate-wp-cli-coverage.php @@ -5,7 +5,7 @@ use SebastianBergmann\CodeCoverage\Filter; use SebastianBergmann\CodeCoverage\Report\Clover; -$root_folder = realpath( dirname( __DIR__, 3 ) ); +$root_folder = realpath( dirname( dirname( dirname( __DIR__ ) ) ) ); if ( ! class_exists( 'SebastianBergmann\CodeCoverage\Filter' ) ) { require "{$root_folder}/vendor/autoload.php"; From 98a69afa44305499195c59517e8e5f2fe723d5d8 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sat, 25 Jan 2025 18:50:06 +0100 Subject: [PATCH 04/18] Rename env var --- src/Context/WhenStepDefinitions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Context/WhenStepDefinitions.php b/src/Context/WhenStepDefinitions.php index 48f432ed7..382dc9df2 100644 --- a/src/Context/WhenStepDefinitions.php +++ b/src/Context/WhenStepDefinitions.php @@ -35,7 +35,7 @@ public function when_i_launch_in_the_background( $cmd ) { * @When /^I (run|try) `([^`]+)`$/ */ public function when_i_run( $mode, $cmd ) { - $with_code_coverage = (string) getenv( 'BEHAT_CODE_COVERAGE' ); + $with_code_coverage = (string) getenv( 'WP_CLI_TEST_COVERAGE' ); if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) { $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={PROJECT_DIR}/vendor/wp-cli/wp-cli-tests/utils/maybe-generate-wp-cli-coverage.php ', $cmd ); } From ecbf4ffe24f58be38a285869096e87ae4565a6d7 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sat, 25 Jan 2025 18:55:49 +0100 Subject: [PATCH 05/18] Add db type as suffix --- src/Context/FeatureContext.php | 6 ++++-- utils/maybe-generate-wp-cli-coverage.php | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index 34a3ef7ac..93e565b8d 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -919,6 +919,7 @@ public function proc( $command, $assoc_args = [], $path = '' ) { } $env = self::get_process_env_variables(); + if ( isset( $this->variables['SUITE_CACHE_DIR'] ) ) { $env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR']; } @@ -929,13 +930,14 @@ public function proc( $command, $assoc_args = [], $path = '' ) { if ( self::$feature ) { $env['BEHAT_FEATURE_TITLE'] = self::$feature->getTitle(); - } + if ( $this->scenario ) { $env['BEHAT_SCENARIO_TITLE'] = $this->scenario->getTitle(); - } + $env['WP_CLI_TEST_DBTYPE'] = self::$db_type; + if ( isset( $this->variables['RUN_DIR'] ) ) { $cwd = "{$this->variables['RUN_DIR']}/{$path}"; } else { diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/maybe-generate-wp-cli-coverage.php index 66dbcf09a..d7926326e 100644 --- a/utils/maybe-generate-wp-cli-coverage.php +++ b/utils/maybe-generate-wp-cli-coverage.php @@ -34,8 +34,9 @@ static function () use ( $coverage, $feature, $scenario, $name ) { $feature_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $feature ) ); $scenario_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $scenario ) ); - $filename = "clover-behat/{$feature_suffix}-{$scenario_suffix}.xml"; - $destination = "{$project_dir}/build/logs/{$filename}"; + $db_type = strtolower( getenv( 'WP_CLI_TEST_DBTYPE' ) ); + $filename = "clover-behat/$feature_suffix-$scenario_suffix-$db_type.xml"; + $destination = "$project_dir/build/logs/{$filename}"; ( new Clover() )->process( $coverage, $destination, $name ); } From 766ef2c72e797578eeab71e572aade023d32fce4 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 28 Jan 2025 17:26:21 +0100 Subject: [PATCH 06/18] Change destination for coverage files --- utils/maybe-generate-wp-cli-coverage.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/maybe-generate-wp-cli-coverage.php index d7926326e..7ba986750 100644 --- a/utils/maybe-generate-wp-cli-coverage.php +++ b/utils/maybe-generate-wp-cli-coverage.php @@ -35,8 +35,7 @@ static function () use ( $coverage, $feature, $scenario, $name ) { $feature_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $feature ) ); $scenario_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $scenario ) ); $db_type = strtolower( getenv( 'WP_CLI_TEST_DBTYPE' ) ); - $filename = "clover-behat/$feature_suffix-$scenario_suffix-$db_type.xml"; - $destination = "$project_dir/build/logs/{$filename}"; + $destination = "$project_dir/build/logs/$feature_suffix-$scenario_suffix-$db_type.xml"; ( new Clover() )->process( $coverage, $destination, $name ); } From 50f20e662e54b9e3f0c47d8ce77a1dddfe9b0c26 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 28 Jan 2025 18:21:18 +0100 Subject: [PATCH 07/18] Create directory if missing --- utils/maybe-generate-wp-cli-coverage.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/maybe-generate-wp-cli-coverage.php index 7ba986750..73f5127c7 100644 --- a/utils/maybe-generate-wp-cli-coverage.php +++ b/utils/maybe-generate-wp-cli-coverage.php @@ -37,6 +37,11 @@ static function () use ( $coverage, $feature, $scenario, $name ) { $db_type = strtolower( getenv( 'WP_CLI_TEST_DBTYPE' ) ); $destination = "$project_dir/build/logs/$feature_suffix-$scenario_suffix-$db_type.xml"; + $dir = dirname( $destination ); + if ( ! file_exists( $dir ) ) { + mkdir( $dir, 0777, true /*recursive*/ ); + } + ( new Clover() )->process( $coverage, $destination, $name ); } ); From a952f8577ebdf432f5ca2d83c021ccf4d0df0a80 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 20 Feb 2025 15:09:37 +0100 Subject: [PATCH 08/18] Use `SRC_DIR` variable instead --- src/Context/WhenStepDefinitions.php | 2 +- utils/maybe-generate-wp-cli-coverage.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Context/WhenStepDefinitions.php b/src/Context/WhenStepDefinitions.php index 382dc9df2..cf1eb36f6 100644 --- a/src/Context/WhenStepDefinitions.php +++ b/src/Context/WhenStepDefinitions.php @@ -37,7 +37,7 @@ public function when_i_launch_in_the_background( $cmd ) { public function when_i_run( $mode, $cmd ) { $with_code_coverage = (string) getenv( 'WP_CLI_TEST_COVERAGE' ); if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) { - $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={PROJECT_DIR}/vendor/wp-cli/wp-cli-tests/utils/maybe-generate-wp-cli-coverage.php ', $cmd ); + $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={SRC_DIR}/utils/maybe-generate-wp-cli-coverage.php ', $cmd ); } $cmd = $this->replace_variables( $cmd ); diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/maybe-generate-wp-cli-coverage.php index 73f5127c7..67c55433b 100644 --- a/utils/maybe-generate-wp-cli-coverage.php +++ b/utils/maybe-generate-wp-cli-coverage.php @@ -5,7 +5,7 @@ use SebastianBergmann\CodeCoverage\Filter; use SebastianBergmann\CodeCoverage\Report\Clover; -$root_folder = realpath( dirname( dirname( dirname( __DIR__ ) ) ) ); +$root_folder = realpath( dirname( __DIR__ ) ); if ( ! class_exists( 'SebastianBergmann\CodeCoverage\Filter' ) ) { require "{$root_folder}/vendor/autoload.php"; From bfaccf451436c2f3115fd56e5f01e48e6b1e3b6f Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 20 Feb 2025 15:15:13 +0100 Subject: [PATCH 09/18] Rename file --- src/Context/WhenStepDefinitions.php | 2 +- ...maybe-generate-wp-cli-coverage.php => generate-coverage.php} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename utils/{maybe-generate-wp-cli-coverage.php => generate-coverage.php} (100%) diff --git a/src/Context/WhenStepDefinitions.php b/src/Context/WhenStepDefinitions.php index cf1eb36f6..8aa758e88 100644 --- a/src/Context/WhenStepDefinitions.php +++ b/src/Context/WhenStepDefinitions.php @@ -37,7 +37,7 @@ public function when_i_launch_in_the_background( $cmd ) { public function when_i_run( $mode, $cmd ) { $with_code_coverage = (string) getenv( 'WP_CLI_TEST_COVERAGE' ); if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) { - $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={SRC_DIR}/utils/maybe-generate-wp-cli-coverage.php ', $cmd ); + $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={SRC_DIR}/utils/generate-coverage.php ', $cmd ); } $cmd = $this->replace_variables( $cmd ); diff --git a/utils/maybe-generate-wp-cli-coverage.php b/utils/generate-coverage.php similarity index 100% rename from utils/maybe-generate-wp-cli-coverage.php rename to utils/generate-coverage.php From da6c27debba5e7409ad3490dae40f7473b528db9 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 20 Feb 2025 15:17:52 +0100 Subject: [PATCH 10/18] Update phpcs config --- phpcs.xml.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 938e6fdcc..79a149e27 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -77,9 +77,9 @@ - */maybe-generate-wp-cli-coverage\.php$ + */generate-coverage\.php$ - */maybe-generate-wp-cli-coverage\.php$ + */generate-coverage\.php$ From 74745d4963f498af573f4f5a978c66a4ebfae583 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 6 Mar 2025 11:09:25 +0100 Subject: [PATCH 11/18] Apply suggestions from code review Co-authored-by: Alain Schlesser --- utils/generate-coverage.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/utils/generate-coverage.php b/utils/generate-coverage.php index 67c55433b..6a19e806e 100644 --- a/utils/generate-coverage.php +++ b/utils/generate-coverage.php @@ -1,5 +1,11 @@ Date: Wed, 5 Mar 2025 10:50:29 +0100 Subject: [PATCH 12/18] Fix HTTP mocking test The expected output changed because there are new table columns. Figured just changing it to CSV output makes the test more stable --- features/http-mocking.feature | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/features/http-mocking.feature b/features/http-mocking.feature index ac5a42c91..e8891a802 100644 --- a/features/http-mocking.feature +++ b/features/http-mocking.feature @@ -77,10 +77,11 @@ Feature: HTTP request mocking ] """ - When I run `wp cli check-update` - Then STDOUT should be a table containing rows: - | version | update_type | package_url | - | 999.9.9 | major | https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar | + When I try `wp cli check-update --format=csv` + Then STDOUT should contain: + """ + 999.9.9,major,https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar,available + """ Scenario: Mock HTTP request in WordPress Given a WP install From 0ebd313035974055845ba2623ec5c403c5bcb032 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 5 Mar 2025 11:04:46 +0100 Subject: [PATCH 13/18] Support Requests v1 for request mocking --- src/Context/GivenStepDefinitions.php | 72 ++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index b8e49c068..60a13d28d 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -113,12 +113,11 @@ public function given_a_request_to_a_url_respond_with_file( $url_or_pattern, PyS $mock_file_contents = <<request( \$url, \$headers, \$data, \$options ); + if ( class_exists( 'Requests_Transport_cURL' ) ) { + return ( new Requests_Transport_cURL() )->request( \$url, \$headers, \$data, \$options ); + } + + return ( new WpOrg\Requests\Transport\Curl() )->request( \$url, \$headers, \$data, \$options ); } public function request_multiple( \$requests, \$options ) { @@ -145,6 +148,16 @@ public static function test( \$capabilities = array() ) { } } +if ( interface_exists( 'Requests_Transport' ) ) { + class WP_CLI_Tests_Mock_Requests_Transport implements Requests_Transport { + use WP_CLI_Tests_Mock_Requests_Trait; + } +} else { + class WP_CLI_Tests_Mock_Requests_Transport implements WpOrg\Requests\Transport { + use WP_CLI_Tests_Mock_Requests_Trait; + } +} + WP_CLI::add_hook( 'http_request_options', static function( \$options ) { @@ -165,20 +178,39 @@ static function( \$pre, \$parsed_args, \$url ) { if ( false !== \$pos ) { \$response = substr( \$response, 0, \$pos ) . "\r\n\r\n" . substr( \$response, \$pos + 2 ); } - Requests::parse_multiple( - \$response, - array( - 'url' => \$url, - 'headers' => array(), - 'data' => array(), - 'options' => array_merge( - Requests::OPTION_DEFAULTS, - array( - 'hooks' => new Hooks(), - ) - ), - ) - ); + + if ( class_exists( '\Requests' ) ) { + \Requests::parse_multiple( + \$response, + array( + 'url' => \$url, + 'headers' => array(), + 'data' => array(), + 'options' => array_merge( + Requests::OPTION_DEFAULTS, + array( + 'hooks' => new Requests_Hooks(), + ) + ), + ) + ); + } else { + WpOrg\Requests\Requests::parse_multiple( + \$response, + array( + 'url' => \$url, + 'headers' => array(), + 'data' => array(), + 'options' => array_merge( + Requests::OPTION_DEFAULTS, + array( + 'hooks' => new WpOrg\Requests\Hooks(), + ) + ), + ) + ); + } + return array( 'headers' => \$response->headers->getAll(), From ff03cf01eb13e9f0938f08db47ff4595c3a02365 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 5 Mar 2025 11:11:08 +0100 Subject: [PATCH 14/18] Swap around --- src/Context/GivenStepDefinitions.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 60a13d28d..6699ec60c 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -132,11 +132,11 @@ public function request( \$url, \$headers = array(), \$data = array(), \$options } } - if ( class_exists( 'Requests_Transport_cURL' ) ) { - return ( new Requests_Transport_cURL() )->request( \$url, \$headers, \$data, \$options ); + if ( class_exists( '\WpOrg\Requests\Transport\Curl' ) ) { + return ( new WpOrg\Requests\Transport\Curl() )->request( \$url, \$headers, \$data, \$options ); } - return ( new WpOrg\Requests\Transport\Curl() )->request( \$url, \$headers, \$data, \$options ); + return ( new Requests_Transport_cURL() )->request( \$url, \$headers, \$data, \$options ); } public function request_multiple( \$requests, \$options ) { @@ -148,12 +148,12 @@ public static function test( \$capabilities = array() ) { } } -if ( interface_exists( 'Requests_Transport' ) ) { - class WP_CLI_Tests_Mock_Requests_Transport implements Requests_Transport { +if ( interface_exists( '\WpOrg\Requests\Transport' ) ) { + class WP_CLI_Tests_Mock_Requests_Transport implements WpOrg\Requests\Transport { use WP_CLI_Tests_Mock_Requests_Trait; } } else { - class WP_CLI_Tests_Mock_Requests_Transport implements WpOrg\Requests\Transport { + class WP_CLI_Tests_Mock_Requests_Transport implements Requests_Transport { use WP_CLI_Tests_Mock_Requests_Trait; } } @@ -179,8 +179,8 @@ static function( \$pre, \$parsed_args, \$url ) { \$response = substr( \$response, 0, \$pos ) . "\r\n\r\n" . substr( \$response, \$pos + 2 ); } - if ( class_exists( '\Requests' ) ) { - \Requests::parse_multiple( + if ( class_exists( '\WpOrg\Requests\Requests' ) ) { + WpOrg\Requests\Requests::parse_multiple( \$response, array( 'url' => \$url, @@ -189,13 +189,13 @@ static function( \$pre, \$parsed_args, \$url ) { 'options' => array_merge( Requests::OPTION_DEFAULTS, array( - 'hooks' => new Requests_Hooks(), + 'hooks' => new WpOrg\Requests\Hooks(), ) ), ) ); } else { - WpOrg\Requests\Requests::parse_multiple( + \Requests::parse_multiple( \$response, array( 'url' => \$url, @@ -204,14 +204,13 @@ static function( \$pre, \$parsed_args, \$url ) { 'options' => array_merge( Requests::OPTION_DEFAULTS, array( - 'hooks' => new WpOrg\Requests\Hooks(), + 'hooks' => new Requests_Hooks(), ) ), ) ); } - return array( 'headers' => \$response->headers->getAll(), 'body' => \$response->body, From 2b71a7dbbefa73d2145cd33ce0cb8907f0b359a5 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 5 Mar 2025 11:15:43 +0100 Subject: [PATCH 15/18] Full namespace --- src/Context/GivenStepDefinitions.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 6699ec60c..3a23a565d 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -133,10 +133,10 @@ public function request( \$url, \$headers = array(), \$data = array(), \$options } if ( class_exists( '\WpOrg\Requests\Transport\Curl' ) ) { - return ( new WpOrg\Requests\Transport\Curl() )->request( \$url, \$headers, \$data, \$options ); + return ( new \WpOrg\Requests\Transport\Curl() )->request( \$url, \$headers, \$data, \$options ); } - return ( new Requests_Transport_cURL() )->request( \$url, \$headers, \$data, \$options ); + return ( new \Requests_Transport_cURL() )->request( \$url, \$headers, \$data, \$options ); } public function request_multiple( \$requests, \$options ) { @@ -149,11 +149,11 @@ public static function test( \$capabilities = array() ) { } if ( interface_exists( '\WpOrg\Requests\Transport' ) ) { - class WP_CLI_Tests_Mock_Requests_Transport implements WpOrg\Requests\Transport { + class WP_CLI_Tests_Mock_Requests_Transport implements \WpOrg\Requests\Transport { use WP_CLI_Tests_Mock_Requests_Trait; } } else { - class WP_CLI_Tests_Mock_Requests_Transport implements Requests_Transport { + class WP_CLI_Tests_Mock_Requests_Transport implements \Requests_Transport { use WP_CLI_Tests_Mock_Requests_Trait; } } @@ -187,7 +187,7 @@ static function( \$pre, \$parsed_args, \$url ) { 'headers' => array(), 'data' => array(), 'options' => array_merge( - Requests::OPTION_DEFAULTS, + WpOrg\Requests\Requests::OPTION_DEFAULTS, array( 'hooks' => new WpOrg\Requests\Hooks(), ) From 973fcd7579f3db75c0efef5e4d24b67bf50dbe3c Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 5 Mar 2025 11:19:51 +0100 Subject: [PATCH 16/18] Remove non-existent constant --- src/Context/GivenStepDefinitions.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 3a23a565d..61fc114f1 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -201,11 +201,8 @@ static function( \$pre, \$parsed_args, \$url ) { 'url' => \$url, 'headers' => array(), 'data' => array(), - 'options' => array_merge( - Requests::OPTION_DEFAULTS, - array( - 'hooks' => new Requests_Hooks(), - ) + 'options' => array( + 'hooks' => new Requests_Hooks(), ), ) ); From aa2ce7ec38015c2bfbc65b3817521e43428beab4 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Wed, 5 Mar 2025 11:25:00 +0100 Subject: [PATCH 17/18] Manually add defaults --- src/Context/GivenStepDefinitions.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 61fc114f1..615999b7b 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -202,7 +202,12 @@ static function( \$pre, \$parsed_args, \$url ) { 'headers' => array(), 'data' => array(), 'options' => array( - 'hooks' => new Requests_Hooks(), + 'blocking' => true, + 'filename' => false, + 'follow_redirects' => true, + 'redirected' => 0, + 'redirects' => 10, + 'hooks' => new Requests_Hooks(), ), ) ); From ab81bedf2f79edc9c7ec5b778bb2bd7997f39997 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 6 Mar 2025 11:19:11 +0100 Subject: [PATCH 18/18] Add to `when_i_run_from_a_subfolder` --- src/Context/FeatureContext.php | 17 +++++++++++++++++ src/Context/WhenStepDefinitions.php | 7 ++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index b51354d9e..2eb061db7 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -683,6 +683,23 @@ public function __construct() { $this->set_cache_dir(); } + /** + * Enhances a `wp ` string with an additional `--require` for code coverage collection. + * + * Only applies if `WP_CLI_TEST_COVERAGE` is set. + * + * @param string $cmd Command string. + * @return string Possibly enhanced command string. + */ + public function get_command_with_coverage( $cmd ) { + $with_code_coverage = (string) getenv( 'WP_CLI_TEST_COVERAGE' ); + if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) { + return preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={SRC_DIR}/utils/generate-coverage.php ', $cmd ); + } + + return $cmd; + } + /** * Replace standard {VARIABLE_NAME} variables and the special {INVOKE_WP_CLI_WITH_PHP_ARGS-args} and {WP_VERSION-version-latest} variables. * Note that standard variable names can only contain uppercase letters, digits and underscores and cannot begin with a digit. diff --git a/src/Context/WhenStepDefinitions.php b/src/Context/WhenStepDefinitions.php index 8aa758e88..3fac6b75e 100644 --- a/src/Context/WhenStepDefinitions.php +++ b/src/Context/WhenStepDefinitions.php @@ -35,11 +35,7 @@ public function when_i_launch_in_the_background( $cmd ) { * @When /^I (run|try) `([^`]+)`$/ */ public function when_i_run( $mode, $cmd ) { - $with_code_coverage = (string) getenv( 'WP_CLI_TEST_COVERAGE' ); - if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) { - $cmd = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3--require={SRC_DIR}/utils/generate-coverage.php ', $cmd ); - } - + $cmd = $this->get_command_with_coverage( $cmd ); $cmd = $this->replace_variables( $cmd ); $this->result = $this->wpcli_tests_invoke_proc( $this->proc( $cmd ), $mode ); list( $this->result->stdout, $this->email_sends ) = $this->wpcli_tests_capture_email_sends( $this->result->stdout ); @@ -49,6 +45,7 @@ public function when_i_run( $mode, $cmd ) { * @When /^I (run|try) `([^`]+)` from '([^\s]+)'$/ */ public function when_i_run_from_a_subfolder( $mode, $cmd, $subdir ) { + $cmd = $this->get_command_with_coverage( $cmd ); $cmd = $this->replace_variables( $cmd ); $this->result = $this->wpcli_tests_invoke_proc( $this->proc( $cmd, array(), $subdir ), $mode ); list( $this->result->stdout, $this->email_sends ) = $this->wpcli_tests_capture_email_sends( $this->result->stdout );