diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index 2eb061db7..2e3fe67b1 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -38,6 +38,11 @@ class FeatureContext implements SnippetAcceptingContext { */ private static $run_dir; + /** + * The Directory that 'composer behat' is run from, assumed to always be the top level project folder + */ + private static $behat_run_dir; + /** * Where WordPress core is downloaded to for caching, and which is copied to RUN_DIR during a "Given a WP installation" step. Lives until manually deleted. */ @@ -286,9 +291,10 @@ private static function get_process_env_variables() { $path_separator = Utils\is_windows() ? ';' : ':'; $env = [ - 'PATH' => $bin_path . $path_separator . getenv( 'PATH' ), - 'BEHAT_RUN' => 1, - 'HOME' => sys_get_temp_dir() . '/wp-cli-home', + 'PATH' => $bin_path . $path_separator . getenv( 'PATH' ), + 'BEHAT_RUN' => 1, + 'HOME' => sys_get_temp_dir() . '/wp-cli-home', + 'TEST_RUN_DIR' => self::$behat_run_dir, ]; $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); @@ -371,6 +377,7 @@ private static function get_behat_internal_variables() { 'FRAMEWORK_ROOT' => realpath( $framework_root ), 'SRC_DIR' => realpath( dirname( dirname( __DIR__ ) ) ), 'PROJECT_DIR' => realpath( dirname( dirname( dirname( dirname( dirname( __DIR__ ) ) ) ) ) ), + 'TEST_RUN_DIR' => self::$behat_run_dir, ]; return $variables; @@ -475,6 +482,7 @@ public static function prepare( BeforeSuiteScope $scope ) { if ( false !== self::$log_run_times ) { self::log_run_times_before_suite( $scope ); } + self::$behat_run_dir = getcwd(); $result = Process::create( 'wp cli info', null, self::get_process_env_variables() )->run_check(); echo "{$result->stdout}\n"; @@ -521,7 +529,6 @@ public function beforeScenario( BeforeScenarioScope $scope ) { if ( self::$log_run_times ) { self::log_run_times_before_scenario( $scope ); } - $this->variables = array_merge( $this->variables, self::get_behat_internal_variables() @@ -693,8 +700,31 @@ public function __construct() { */ 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 ); + + $modify_command = function ( $part ) { + if ( preg_match( '/(^wp )|( wp )|(\/wp )/', $part ) ) { + $part = preg_replace( '/(^wp )|( wp )|(\/wp )/', '$1$2$3', $part ); + + $require_path = '{TEST_RUN_DIR}/vendor/wp-cli/wp-cli-tests/utils/generate-coverage.php'; + if ( ! file_exists( $this->variables['TEST_RUN_DIR'] . '/vendor/wp-cli/wp-cli-tests/utils/generate-coverage.php' ) ) { + // This file is not vendored inside the wp-cli-tests project + $require_path = '{TEST_RUN_DIR}/utils/generate-coverage.php'; + } + $part .= " --require={$require_path}"; + + } + return $part; + }; + + if ( strpos( $cmd, '|' ) !== false ) { + $parts = explode( '|', $cmd ); + $parts = array_map( $modify_command, $parts ); + $cmd = implode( '|', $parts ); + } else { + $cmd = $modify_command( $cmd ); + } } return $cmd; diff --git a/utils/generate-coverage.php b/utils/generate-coverage.php index 6a19e806e..d324fe757 100644 --- a/utils/generate-coverage.php +++ b/utils/generate-coverage.php @@ -11,15 +11,54 @@ use SebastianBergmann\CodeCoverage\Filter; use SebastianBergmann\CodeCoverage\Report\Clover; -$root_folder = realpath( dirname( __DIR__ ) ); + +$project_dir = (string) getenv( 'TEST_RUN_DIR' ); if ( ! class_exists( 'SebastianBergmann\CodeCoverage\Filter' ) ) { - require "{$root_folder}/vendor/autoload.php"; + if ( ! file_exists( $project_dir . '/vendor/autoload.php' ) ) { + die( 'Could not load dependencies for generating code coverage' ); + } + require "{$project_dir}/vendor/autoload.php"; +} + +$filtered_items = new CallbackFilterIterator( + new DirectoryIterator( $project_dir ), + function ( $file ) { + // Allow directories named "php" or "src" + if ( $file->isDir() && in_array( $file->getFilename(), [ 'php', 'src' ], true ) ) { + return true; + } + + // Allow top-level files ending in "-command.php" + if ( $file->isFile() && false !== strpos( $file->getFilename(), '-command.php' ) ) { + return true; + } + + return false; + } +); + +$files = []; + +foreach ( $filtered_items as $item ) { + if ( $item->isDir() ) { + foreach ( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $item->getPathname(), RecursiveDirectoryIterator::SKIP_DOTS ) + ) as $file + ) { + if ( $file->isFile() && $file->getExtension() === 'php' ) { + $files[] = $file->getPathname(); + } + } + } else { + $files[] = $item->getPathname(); + } } $filter = new Filter(); -$filter->includeDirectory( "{$root_folder}/includes" ); -$filter->includeFiles( array( "{$root_folder}/plugin.php" ) ); + +$filter->includeFiles( $files ); $coverage = new CodeCoverage( ( new Selector() )->forLineCoverage( $filter ), @@ -37,11 +76,9 @@ $coverage->start( $name ); register_shutdown_function( - static function () use ( $coverage, $feature, $scenario, $name ) { + static function () use ( $coverage, $feature, $scenario, $name, $project_dir ) { $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 ) ); $db_type = strtolower( getenv( 'WP_CLI_TEST_DBTYPE' ) );