Skip to content

Instantly share code, notes, and snippets.

@christeredvartsen
Created April 4, 2018 13:52
Show Gist options
  • Save christeredvartsen/de3123c0c5cba1519ab57cd3e3e5a665 to your computer and use it in GitHub Desktop.
Save christeredvartsen/de3123c0c5cba1519ab57cd3e3e5a665 to your computer and use it in GitHub Desktop.
Collect code coverage with imbo/behat-api-extension
imports:
- behat.yml
default:
suites:
default:
codeCoverage:
enabled: true
output: '%paths.base%/build/behat-coverage'
whitelist:
files:
- '%paths.base%/some-file.php'
directories:
- '%paths.base%/some-dir'
default:
suites:
default:
contexts: [FeatureContext]
codeCoverage:
enabled: false
extensions:
Imbo\BehatApiExtension:
apiClient:
base_uri: http://localhost:8080
<?php
use Imbo\BehatApiExtension\Context\ApiContext;
use Behat\Testwork\Hook\Scope\BeforeSuiteScope;
use Behat\Testwork\Hook\Scope\AfterSuiteScope;
use SebastianBergmann\CodeCoverage;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
class FeatureContext extends ApiContext {
private static $codeCoverageSessionId;
private static $codeCoverageCollectionUri;
/**
* @BeforeSuite
*/
public static function setUp(BeforeSuiteScope $scope) {
if (!$scope->getSuite()->getSettings()['codeCoverage']['enabled']) {
return;
}
self::$codeCoverageSessionId = uniqid('', true);
}
/**
* @AfterSuite
*/
public static function tearDown(AfterSuiteScope $scope) {
$suite = $scope->getSuite();
$settings = $suite->getSettings()['codeCoverage'];
if (!$settings['enabled'] || empty(self::$codeCoverageCollectionUri)) {
return;
}
$context = stream_context_create([
'http' => [
'header' => implode("\r\n", [
sprintf('X-Code-Coverage-Session-Id: %s', self::$codeCoverageSessionId),
'X-Collect-Code-Coverage: 1',
]),
]
]);
$response = file_get_contents(self::$codeCoverageCollectionUri, false, $context);
$data = unserialize($response);
$filter = new CodeCoverage\Filter();
foreach ($settings['whitelist']['files'] as $file) {
$filter->addFileToWhitelist($file);
}
foreach ($settings['whitelist']['directories'] as $dir) {
$filter->addDirectoryToWhitelist($dir);
}
$coverage = new CodeCoverage\CodeCoverage(null, $filter);
$coverage->append($data, 'behat-suite');
$report = new CodeCoverage\Report\Html\Facade();
$report->process($coverage, sprintf('%s/%s', $settings['output'], $suite->getName()));
}
public function setClient(ClientInterface $client) {
$stack = $client->getConfig('handler');
if (!empty(self::$codeCoverageSessionId)) {
self::$codeCoverageCollectionUri = (string) $client->getConfig()['base_uri'];
$stack->push(Middleware::mapRequest(function(RequestInterface $request) {
return $request
->withHeader('X-Code-Coverage-Session-Id', self::$codeCoverageSessionId)
->withHeader('X-Enable-Code-Coverage', 1);
}));
}
return parent::setClient($client);
}
}
<?php
$codeCoverageDir = defined('CODE_COVERAGE_DIR')
? CODE_COVERAGE_DIR
: sys_get_temp_dir() . '/behat-api-extension-code-coverage';
if (isset($_SERVER['HTTP_X_COLLECT_CODE_COVERAGE']) && isset($_SERVER['HTTP_X_CODE_COVERAGE_SESSION_ID'])) {
if (!is_dir($codeCoverageDir)) {
mkdir($codeCoverageDir);
}
$files = new FilesystemIterator(
$codeCoverageDir,
FilesystemIterator::CURRENT_AS_PATHNAME | FilesystemIterator::SKIP_DOTS
);
$data = [];
$suffix = $_SERVER['HTTP_X_CODE_COVERAGE_SESSION_ID'] . '.cov';
foreach ($files as $filename) {
if (!preg_match('/' . preg_quote($suffix, '/') . '$/', $filename)) {
continue;
}
$content = unserialize(file_get_contents($filename));
unlink($filename);
foreach ($content as $file => $lines) {
if (is_file($file)) {
if (!isset($data[$file])) {
$data[$file] = $lines;
} else {
foreach ($lines as $line => $flag) {
if (!isset($data[$file][$line]) || $flag > $data[$file][$line]) {
$data[$file][$line] = $flag;
}
}
}
}
}
}
echo serialize($data);
return true;
}
if (isset($_SERVER['HTTP_X_ENABLE_CODE_COVERAGE']) && isset($_SERVER['HTTP_X_CODE_COVERAGE_SESSION_ID']) && extension_loaded('xdebug')) {
register_shutdown_function(function() use ($codeCoverageDir) {
$data = xdebug_get_code_coverage();
xdebug_stop_code_coverage();
if (is_dir($codeCoverageDir) || mkdir($codeCoverageDir, 0775, true)) {
$filename = sprintf(
'%s/%s.%s.cov',
$codeCoverageDir,
md5(uniqid('', true)),
$_SERVER['HTTP_X_CODE_COVERAGE_SESSION_ID']
);
file_put_contents($filename, serialize($data));
}
});
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
}
return false;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment