Skip to content
Permalink
Browse files

PhpInterpreter: list code coverage engines and let others to choose o…

…ne (#400)
  • Loading branch information...
milo authored and dg committed Feb 20, 2019
1 parent 359ddb1 commit 5787f670f8f32b36d7008fbe70bcafcc1a279138
@@ -15,13 +15,26 @@
*/
class Collector
{
public const
ENGINE_PHPDBG = 'PHPDBG',
ENGINE_XDEBUG = 'Xdebug';
/** @var resource */
private static $file;
/** @var string */
private static $collector;
public static function detectEngines(): array
{
return array_filter([
defined('PHPDBG_VERSION') ? self::ENGINE_PHPDBG : null,
extension_loaded('xdebug') ? self::ENGINE_XDEBUG : null,
]);
}
public static function isStarted(): bool
{
return self::$file !== null;
@@ -32,23 +45,26 @@ public static function isStarted(): bool
* Starts gathering the information for code coverage.
* @throws \LogicException
*/
public static function start(string $file): void
public static function start(string $file, string $engine): void
{
if (self::isStarted()) {
throw new \LogicException('Code coverage collector has been already started.');
}
self::$file = fopen($file, 'c+');
if (defined('PHPDBG_VERSION')) {
phpdbg_start_oplog();
self::$collector = 'collectPhpDbg';
switch ($engine) {
case self::ENGINE_PHPDBG:
phpdbg_start_oplog();
self::$collector = 'collectPhpDbg';
break;
} elseif (extension_loaded('xdebug')) {
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
self::$collector = 'collectXdebug';
case self::ENGINE_XDEBUG:
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
self::$collector = 'collectXdebug';
break;
} else {
throw new \LogicException('Code coverage functionality requires Xdebug extension or phpdbg SAPI.');
default:
throw new \LogicException("Code coverage engine '$engine' is not supported.");
}
register_shutdown_function(function (): void {
@@ -21,6 +21,9 @@ class Environment
/** Test is run by Runner */
public const RUNNER = 'NETTE_TESTER_RUNNER';
/** Code coverage engine */
public const COVERAGE_ENGINE = 'NETTE_TESTER_COVERAGE_ENGINE';
/** Code coverage file */
public const COVERAGE = 'NETTE_TESTER_COVERAGE';
@@ -53,8 +56,8 @@ class_exists('Tester\Assert');
$annotations = self::getTestAnnotations();
self::$checkAssertions = !isset($annotations['outputmatch']) && !isset($annotations['outputmatchfile']);
if (getenv(self::COVERAGE)) {
CodeCoverage\Collector::start(getenv(self::COVERAGE));
if (getenv(self::COVERAGE) && getenv(self::COVERAGE_ENGINE)) {
CodeCoverage\Collector::start(getenv(self::COVERAGE), getenv(self::COVERAGE_ENGINE));
}
}
@@ -58,15 +58,12 @@ public function run(): ?int
return null;
}
if ($this->options['--coverage']) {
$coverageFile = $this->prepareCodeCoverage();
}
$runner = $this->createRunner();
$runner->setEnvironmentVariable(Environment::RUNNER, '1');
$runner->setEnvironmentVariable(Environment::COLORS, (string) (int) Environment::$useColors);
if (isset($coverageFile)) {
$runner->setEnvironmentVariable(Environment::COVERAGE, $coverageFile);
if ($this->options['--coverage']) {
$coverageFile = $this->prepareCodeCoverage($runner);
}
if ($this->options['-o'] !== null) {
@@ -228,14 +225,20 @@ private function createRunner(): Runner
}
private function prepareCodeCoverage(): string
private function prepareCodeCoverage(Runner $runner): string
{
if (!$this->interpreter->canMeasureCodeCoverage()) {
$engines = $this->interpreter->getCodeCoverageEngines();
if (count($engines) < 1) {
throw new \Exception("Code coverage functionality requires Xdebug extension or phpdbg SAPI (used {$this->interpreter->getCommandLine()})");
}
file_put_contents($this->options['--coverage'], '');
$file = realpath($this->options['--coverage']);
echo "Code coverage: {$file}\n";
$runner->setEnvironmentVariable(Environment::COVERAGE, $file);
$runner->setEnvironmentVariable(Environment::COVERAGE_ENGINE, $engine = reset($engines));
echo "Code coverage by $engine: $file\n";
return $file;
}
@@ -107,9 +107,9 @@ public function getVersion(): string
}
public function canMeasureCodeCoverage(): bool
public function getCodeCoverageEngines(): array
{
return $this->info->canMeasureCodeCoverage;
return $this->info->codeCoverageEngines;
}
@@ -6,6 +6,8 @@
declare(strict_types=1);
require __DIR__ . '/../CodeCoverage/Collector.php';
$isPhpDbg = defined('PHPDBG_VERSION');
$extensions = get_loaded_extensions();
natcasesort($extensions);
@@ -21,7 +23,7 @@
),
'extensions' => $extensions,
'tempDir' => sys_get_temp_dir(),
'canMeasureCodeCoverage' => $isPhpDbg || in_array('xdebug', $extensions, true),
'codeCoverageEngines' => Tester\CodeCoverage\Collector::detectEngines(),
];
if (isset($_SERVER['argv'][1])) {
@@ -34,6 +36,7 @@
'PHP version' . ($isPhpDbg ? '; PHPDBG version' : '')
=> "$info->version ($info->sapi)" . ($isPhpDbg ? "; $info->phpDbgVersion" : ''),
'Loaded php.ini files' => count($info->iniFiles) ? implode(', ', $info->iniFiles) : '(none)',
'Code coverage engines' => count($info->codeCoverageEngines) ? implode(', ', $info->codeCoverageEngines) : '(not available)',
'PHP temporary directory' => $info->tempDir == '' ? '(empty)' : $info->tempDir,
'Loaded extensions' => count($info->extensions) ? implode(', ', $info->extensions) : '(none)',
] as $title => $value) {
@@ -9,9 +9,11 @@ use Tester\FileMock;
require __DIR__ . '/../bootstrap.php';
if (!extension_loaded('xdebug') && (!defined('PHPDBG_VERSION'))) {
$engines = CodeCoverage\Collector::detectEngines();
if (count($engines) < 1) {
Tester\Environment::skip('Requires Xdebug or phpdbg SAPI.');
}
$engine = reset($engines);
if (CodeCoverage\Collector::isStarted()) {
Tester\Environment::skip('Requires running without --coverage.');
@@ -20,11 +22,11 @@ if (CodeCoverage\Collector::isStarted()) {
$outputFile = FileMock::create('');
Assert::false(CodeCoverage\Collector::isStarted());
CodeCoverage\Collector::start($outputFile);
CodeCoverage\Collector::start($outputFile, $engine);
Assert::true(CodeCoverage\Collector::isStarted());
Assert::exception(function () use ($outputFile) {
CodeCoverage\Collector::start($outputFile);
Assert::exception(function () use ($outputFile, $engine) {
CodeCoverage\Collector::start($outputFile, $engine);
}, LogicException::class, 'Code coverage collector has been already started.');
$content = file_get_contents($outputFile);

This file was deleted.

Oops, something went wrong.
@@ -10,3 +10,19 @@ $interpreter = createInterpreter();
Assert::true($interpreter->hasExtension('DaTe'));
Assert::false($interpreter->hasExtension('foo-bar'));
Assert::contains(PHP_BINARY, $interpreter->getCommandLine());
Assert::same(PHP_VERSION, $interpreter->getVersion());
Assert::same(strpos(PHP_SAPI, 'cgi') !== false, $interpreter->isCgi());
$count = 0;
$engines = $interpreter->getCodeCoverageEngines();
if (defined('PHPDBG_VERSION')) {
Assert::contains(Tester\CodeCoverage\Collector::ENGINE_PHPDBG, $engines);
$count++;
}
if (extension_loaded('xdebug')) {
Assert::contains(Tester\CodeCoverage\Collector::ENGINE_XDEBUG, $engines);
$count++;
}
Assert::count($count, $engines);

0 comments on commit 5787f67

Please sign in to comment.
You can’t perform that action at this time.