From 2ee601813aa625f6f203b4c374b6b62dd4d51633 Mon Sep 17 00:00:00 2001
From: Pascal Birchler <pascalb@google.com>
Date: Fri, 24 Jan 2025 17:31:47 +0100
Subject: [PATCH 01/10] 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 aa53ee36..dd805ea8 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 a727e8c7..48f432ed 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 00000000..8c9a822e
--- /dev/null
+++ b/utils/maybe-generate-wp-cli-coverage.php
@@ -0,0 +1,42 @@
+<?php
+
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Driver\Selector;
+use SebastianBergmann\CodeCoverage\Filter;
+use SebastianBergmann\CodeCoverage\Report\Clover;
+
+$root_folder = realpath( dirname( __DIR__, 3 ) );
+
+if ( ! class_exists( 'SebastianBergmann\CodeCoverage\Filter' ) ) {
+	require "{$root_folder}/vendor/autoload.php";
+}
+
+$filter = new Filter();
+$filter->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 <pascalb@google.com>
Date: Sat, 25 Jan 2025 00:16:45 +0100
Subject: [PATCH 02/10] 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 62a1a672..938e6fdc 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -73,4 +73,13 @@
 	<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
 		<exclude-pattern>*/utils/polyfills\.php$</exclude-pattern>
 	</rule>
+
+	<!-- This is a procedural stand-alone file that is never loaded in a WordPress context,
+		 so this file does not have to comply with WP naming conventions. -->
+	<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
+		<exclude-pattern>*/maybe-generate-wp-cli-coverage\.php$</exclude-pattern>
+	</rule>
+	<rule ref="WordPress.WP.GlobalVariablesOverride">
+		<exclude-pattern>*/maybe-generate-wp-cli-coverage\.php$</exclude-pattern>
+	</rule>
 </ruleset>
diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php
index dd805ea8..34a3ef7a 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 <pascalb@google.com>
Date: Sat, 25 Jan 2025 00:19:10 +0100
Subject: [PATCH 03/10] 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 8c9a822e..66dbcf09 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 <pascalb@google.com>
Date: Sat, 25 Jan 2025 18:50:06 +0100
Subject: [PATCH 04/10] 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 48f432ed..382dc9df 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 <pascalb@google.com>
Date: Sat, 25 Jan 2025 18:55:49 +0100
Subject: [PATCH 05/10] 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 34a3ef7a..93e565b8 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 66dbcf09..d7926326 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 <pascalb@google.com>
Date: Tue, 28 Jan 2025 17:26:21 +0100
Subject: [PATCH 06/10] 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 d7926326..7ba98675 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 <pascalb@google.com>
Date: Tue, 28 Jan 2025 18:21:18 +0100
Subject: [PATCH 07/10] 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 7ba98675..73f5127c 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 <pascalb@google.com>
Date: Thu, 20 Feb 2025 15:09:37 +0100
Subject: [PATCH 08/10] 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 382dc9df..cf1eb36f 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 73f5127c..67c55433 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 <pascalb@google.com>
Date: Thu, 20 Feb 2025 15:15:13 +0100
Subject: [PATCH 09/10] 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 cf1eb36f..8aa758e8 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 <pascalb@google.com>
Date: Thu, 20 Feb 2025 15:17:52 +0100
Subject: [PATCH 10/10] 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 938e6fdc..79a149e2 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -77,9 +77,9 @@
 	<!-- This is a procedural stand-alone file that is never loaded in a WordPress context,
 		 so this file does not have to comply with WP naming conventions. -->
 	<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
-		<exclude-pattern>*/maybe-generate-wp-cli-coverage\.php$</exclude-pattern>
+		<exclude-pattern>*/generate-coverage\.php$</exclude-pattern>
 	</rule>
 	<rule ref="WordPress.WP.GlobalVariablesOverride">
-		<exclude-pattern>*/maybe-generate-wp-cli-coverage\.php$</exclude-pattern>
+		<exclude-pattern>*/generate-coverage\.php$</exclude-pattern>
 	</rule>
 </ruleset>