1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace Atk4\Ui\Behat;
6:
7: use PHPUnit\Framework\TestCase;
8: use SebastianBergmann\CodeCoverage\CodeCoverage;
9: use SebastianBergmann\CodeCoverage\Driver\Selector as DriverSelector;
10: use SebastianBergmann\CodeCoverage\Filter;
11: use SebastianBergmann\CodeCoverage\Report;
12:
13: class CoverageUtil
14: {
15: private static ?CodeCoverage $coverage = null;
16:
17: private function __construct()
18: {
19: // zeroton
20: }
21:
22: public static function start(Filter $filter): void
23: {
24: if (self::$coverage !== null) {
25: throw new \Error('Coverage already started');
26: }
27:
28: self::$coverage = new CodeCoverage((new DriverSelector())->forLineCoverage($filter), $filter);
29: self::$coverage->cacheStaticAnalysis(sys_get_temp_dir() . '/phpunit-coverage.' . md5(__DIR__) . '.cache');
30: self::$coverage->start(self::class);
31: }
32:
33: public static function startFromPhpunitConfig(string $phpunitConfigDir): void
34: {
35: $filter = new Filter();
36:
37: $phpunitCoverageConfig = simplexml_load_file($phpunitConfigDir . '/phpunit.xml.dist')->source;
38: foreach ($phpunitCoverageConfig->include->directory ?? [] as $path) {
39: $filter->includeDirectory($phpunitConfigDir . '/' . $path); // @phpstan-ignore-line
40: }
41: foreach ($phpunitCoverageConfig->include->file ?? [] as $path) {
42: $filter->includeFile($phpunitConfigDir . '/' . $path);
43: }
44: foreach ($phpunitCoverageConfig->exclude->directory ?? [] as $path) {
45: $filter->excludeDirectory($phpunitConfigDir . '/' . $path); // @phpstan-ignore-line
46: }
47: foreach ($phpunitCoverageConfig->exclude->file ?? [] as $path) {
48: $filter->excludeFile($phpunitConfigDir . '/' . $path); // @phpstan-ignore-line
49: }
50:
51: static::start($filter);
52:
53: // fix https://github.com/sebastianbergmann/php-code-coverage/issues/942
54: // https://github.com/sebastianbergmann/php-code-coverage/pull/939
55: foreach ($filter->files() as $path) {
56: opcache_compile_file($path);
57: }
58: }
59:
60: public static function saveData(string $outputDir): void
61: {
62: $outputFile = $outputDir . '/' . basename($_SERVER['SCRIPT_NAME'] ?? 'unknown', '.php') . '-' . hash('sha256', microtime(true) . random_bytes(64)) . '.cov';
63:
64: self::$coverage->stop();
65: $writer = new Report\PHP();
66: $writer->process(self::$coverage, $outputFile);
67: self::$coverage = null;
68: }
69:
70: public static function isCalledFromPhpunit(): bool
71: {
72: foreach (debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
73: if (is_a($frame['class'] ?? null, TestCase::class, true)) {
74: return true;
75: }
76: }
77:
78: return false;
79: }
80: }
81: