Skip to content

Commit 2ee6018

Browse files
committed
Begin adding code coverage support
1 parent 083a54e commit 2ee6018

File tree

3 files changed

+130
-26
lines changed

3 files changed

+130
-26
lines changed

src/Context/FeatureContext.php

Lines changed: 83 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
88
use Behat\Testwork\Hook\Scope\AfterSuiteScope;
99
use Behat\Testwork\Hook\Scope\BeforeSuiteScope;
10+
use Behat\Behat\Hook\Scope\AfterFeatureScope;
11+
use Behat\Behat\Hook\Scope\BeforeFeatureScope;
1012
use RuntimeException;
1113
use WP_CLI\Process;
1214
use WP_CLI\Utils;
@@ -107,6 +109,48 @@ class FeatureContext implements SnippetAcceptingContext {
107109
private static $scenario_count = 0; // Scenario count, incremented on `@AfterScenario`.
108110
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.
109111

112+
/**
113+
* The current feature.
114+
*
115+
* @var \Behat\Gherkin\Node\FeatureNode|null
116+
*/
117+
private static $feature;
118+
119+
/**
120+
* The current scenario.
121+
*
122+
* @var \Behat\Gherkin\Node\ScenarioInterface|null
123+
*/
124+
private $scenario;
125+
126+
/**
127+
* @BeforeFeature
128+
*/
129+
public static function store_feature( BeforeFeatureScope $scope ) {
130+
self::$feature = $scope->getFeature();
131+
}
132+
133+
/**
134+
* @BeforeScenario
135+
*/
136+
public function store_scenario( BeforeScenarioScope $scope ) {
137+
$this->scenario = $scope->getScenario();
138+
}
139+
140+
/**
141+
* @AfterScenario
142+
*/
143+
public function forget_scenario( AfterScenarioScope $scope ) {
144+
$this->scenario = null;
145+
}
146+
147+
/**
148+
* @AfterFeature
149+
*/
150+
public static function forget_feature( AfterFeatureScope $scope ) {
151+
self::$feature = null;
152+
}
153+
110154
/**
111155
* Get the path to the Composer vendor folder.
112156
*
@@ -330,9 +374,9 @@ private static function get_behat_internal_variables() {
330374
}
331375

332376
/**
333-
* Download and extract a single copy of the sqlite-database-integration plugin
334-
* for use in subsequent WordPress copies
335-
*/
377+
* Download and extract a single copy of the sqlite-database-integration plugin
378+
* for use in subsequent WordPress copies
379+
*/
336380
private static function download_sqlite_plugin( $dir ) {
337381
$download_url = 'https://downloads.wordpress.org/plugin/sqlite-database-integration.zip';
338382
$download_location = $dir . '/sqlite-database-integration.zip';
@@ -367,9 +411,9 @@ private static function download_sqlite_plugin( $dir ) {
367411
}
368412

369413
/**
370-
* Given a WordPress installation with the sqlite-database-integration plugin,
371-
* configure it to use SQLite as the database by placing the db.php dropin file
372-
*/
414+
* Given a WordPress installation with the sqlite-database-integration plugin,
415+
* configure it to use SQLite as the database by placing the db.php dropin file
416+
*/
373417
private static function configure_sqlite( $dir ) {
374418
$db_copy = $dir . '/wp-content/mu-plugins/sqlite-database-integration/db.copy';
375419
$db_dropin = $dir . '/wp-content/db.php';
@@ -806,8 +850,8 @@ public function download_phar( $version = 'same' ) {
806850
);
807851

808852
$this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/'
809-
. uniqid( 'wp-cli-download-', true )
810-
. '.phar';
853+
. uniqid( 'wp-cli-download-', true )
854+
. '.phar';
811855

812856
Process::create(
813857
Utils\esc_cmd(
@@ -879,6 +923,19 @@ public function proc( $command, $assoc_args = [], $path = '' ) {
879923
$env['WP_CLI_CACHE_DIR'] = $this->variables['SUITE_CACHE_DIR'];
880924
}
881925

926+
if ( isset( $this->variables['PROJECT_DIR'] ) ) {
927+
$env['BEHAT_PROJECT_DIR'] = $this->variables['PROJECT_DIR'];
928+
}
929+
930+
if ( self::$feature ) {
931+
$env['BEHAT_FEATURE_TITLE'] = self::$feature->getTitle();
932+
933+
}
934+
if ( $this->scenario ) {
935+
$env['BEHAT_SCENARIO_TITLE'] = $this->scenario->getTitle();
936+
937+
}
938+
882939
if ( isset( $this->variables['RUN_DIR'] ) ) {
883940
$cwd = "{$this->variables['RUN_DIR']}/{$path}";
884941
} else {
@@ -1240,8 +1297,8 @@ private static function dir_diff_copy( $upd_dir, $src_dir, $cop_dir ) {
12401297
}
12411298
self::copy_dir( $upd_file, $cop_file );
12421299
} elseif ( ! copy( $upd_file, $cop_file ) ) {
1243-
$error = error_get_last();
1244-
throw new RuntimeException( sprintf( "Failed to copy '%s' to '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_file, $cop_file, $error['message'] ) );
1300+
$error = error_get_last();
1301+
throw new RuntimeException( sprintf( "Failed to copy '%s' to '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_file, $cop_file, $error['message'] ) );
12451302
}
12461303
} elseif ( is_dir( $upd_file ) ) {
12471304
self::dir_diff_copy( $upd_file, $src_file, $cop_file );
@@ -1324,14 +1381,14 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) {
13241381

13251382
$log .= PHP_EOL . 'Top ' . self::$num_top_processes . " process run times for '$suite'";
13261383
$log .= PHP_EOL . implode(
1327-
PHP_EOL,
1328-
array_map(
1329-
$runtime_callback,
1330-
array_keys( $tops ),
1331-
$tops,
1332-
array_keys( array_keys( $tops ) )
1333-
)
1334-
) . PHP_EOL;
1384+
PHP_EOL,
1385+
array_map(
1386+
$runtime_callback,
1387+
array_keys( $tops ),
1388+
$tops,
1389+
array_keys( array_keys( $tops ) )
1390+
)
1391+
) . PHP_EOL;
13351392

13361393
// Scenario run times.
13371394
arsort( self::$scenario_run_times );
@@ -1345,14 +1402,14 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) {
13451402
$log .= PHP_EOL . 'Top ' . self::$num_top_scenarios . ' (of ' . self::$scenario_count . ") scenario run times for '$suite'";
13461403

13471404
$log .= PHP_EOL . implode(
1348-
PHP_EOL,
1349-
array_map(
1350-
$scenario_runtime_callback,
1351-
array_keys( $tops ),
1352-
$tops,
1353-
array_keys( array_keys( $tops ) )
1354-
)
1355-
) . PHP_EOL;
1405+
PHP_EOL,
1406+
array_map(
1407+
$scenario_runtime_callback,
1408+
array_keys( $tops ),
1409+
$tops,
1410+
array_keys( array_keys( $tops ) )
1411+
)
1412+
) . PHP_EOL;
13561413

13571414
$log .= PHP_EOL . str_repeat( ')', 80 );
13581415

src/Context/WhenStepDefinitions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public function when_i_launch_in_the_background( $cmd ) {
3535
* @When /^I (run|try) `([^`]+)`$/
3636
*/
3737
public function when_i_run( $mode, $cmd ) {
38+
$with_code_coverage = (string) getenv( 'BEHAT_CODE_COVERAGE' );
39+
if ( \in_array( $with_code_coverage, [ 'true', '1' ], true ) ) {
40+
$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 );
41+
}
42+
3843
$cmd = $this->replace_variables( $cmd );
3944
$this->result = $this->wpcli_tests_invoke_proc( $this->proc( $cmd ), $mode );
4045
list( $this->result->stdout, $this->email_sends ) = $this->wpcli_tests_capture_email_sends( $this->result->stdout );
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
use SebastianBergmann\CodeCoverage\CodeCoverage;
4+
use SebastianBergmann\CodeCoverage\Driver\Selector;
5+
use SebastianBergmann\CodeCoverage\Filter;
6+
use SebastianBergmann\CodeCoverage\Report\Clover;
7+
8+
$root_folder = realpath( dirname( __DIR__, 3 ) );
9+
10+
if ( ! class_exists( 'SebastianBergmann\CodeCoverage\Filter' ) ) {
11+
require "{$root_folder}/vendor/autoload.php";
12+
}
13+
14+
$filter = new Filter();
15+
$filter->includeDirectory( "{$root_folder}/includes" );
16+
$filter->includeFiles( array( "{$root_folder}/plugin.php" ) );
17+
18+
$coverage = new CodeCoverage(
19+
( new Selector() )->forLineCoverage( $filter ),
20+
$filter
21+
);
22+
23+
$feature = getenv( 'BEHAT_FEATURE_TITLE' );
24+
$scenario = getenv( 'BEHAT_SCENARIO_TITLE' );
25+
$name = "{$feature} - {$scenario}";
26+
27+
$coverage->start( $name );
28+
29+
register_shutdown_function(
30+
static function () use ( $coverage, $feature, $scenario, $name ) {
31+
$coverage->stop();
32+
33+
$project_dir = (string) getenv( 'BEHAT_PROJECT_DIR' );
34+
35+
$feature_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $feature ) );
36+
$scenario_suffix = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $scenario ) );
37+
$filename = "clover-behat/{$feature_suffix}-{$scenario_suffix}.xml";
38+
$destination = "{$project_dir}/build/logs/{$filename}";
39+
40+
( new Clover() )->process( $coverage, $destination, $name );
41+
}
42+
);

0 commit comments

Comments
 (0)