class Builder
Same name in this branch
- 11.1.x vendor/phpunit/phpunit/src/TextUI/Configuration/Builder.php \PHPUnit\TextUI\Configuration\Builder
- 11.1.x vendor/phpunit/phpunit/src/TextUI/Configuration/Cli/Builder.php \PHPUnit\TextUI\CliArguments\Builder
@internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@psalm-import-type TestType from \SebastianBergmann\CodeCoverage\CodeCoverage
Hierarchy
- class \SebastianBergmann\CodeCoverage\Node\Builder
Expanded class hierarchy of Builder
1 file declares its use of Builder
- CodeCoverage.php in vendor/
phpunit/ php-code-coverage/ src/ CodeCoverage.php
File
-
vendor/
phpunit/ php-code-coverage/ src/ Node/ Builder.php, line 33
Namespace
SebastianBergmann\CodeCoverage\NodeView source
final class Builder {
private readonly FileAnalyser $analyser;
public function __construct(FileAnalyser $analyser) {
$this->analyser = $analyser;
}
public function build(CodeCoverage $coverage) : Directory {
$data = clone $coverage->getData();
// clone because path munging is destructive to the original data
$commonPath = $this->reducePaths($data);
$root = new Directory($commonPath, null);
$this->addItems($root, $this->buildDirectoryStructure($data), $coverage->getTests());
return $root;
}
/**
* @psalm-param array<string, TestType> $tests
*/
private function addItems(Directory $root, array $items, array $tests) : void {
foreach ($items as $key => $value) {
$key = (string) $key;
if (str_ends_with($key, '/f')) {
$key = substr($key, 0, -2);
$filename = $root->pathAsString() . DIRECTORY_SEPARATOR . $key;
if (is_file($filename)) {
$root->addFile(new File($key, $root, $value['lineCoverage'], $value['functionCoverage'], $tests, $this->analyser
->classesIn($filename), $this->analyser
->traitsIn($filename), $this->analyser
->functionsIn($filename), $this->analyser
->linesOfCodeFor($filename)));
}
}
else {
$child = $root->addDirectory($key);
$this->addItems($child, $value, $tests);
}
}
}
/**
* Builds an array representation of the directory structure.
*
* For instance,
*
* <code>
* Array
* (
* [Money.php] => Array
* (
* ...
* )
*
* [MoneyBag.php] => Array
* (
* ...
* )
* )
* </code>
*
* is transformed into
*
* <code>
* Array
* (
* [.] => Array
* (
* [Money.php] => Array
* (
* ...
* )
*
* [MoneyBag.php] => Array
* (
* ...
* )
* )
* )
* </code>
*
* @psalm-return array<string, array<string, array{lineCoverage: array<int, int>, functionCoverage: array<string, array<int, int>>}>>
*/
private function buildDirectoryStructure(ProcessedCodeCoverageData $data) : array {
$result = [];
foreach ($data->coveredFiles() as $originalPath) {
$path = explode(DIRECTORY_SEPARATOR, $originalPath);
$pointer =& $result;
$max = count($path);
for ($i = 0; $i < $max; $i++) {
$type = '';
if ($i === $max - 1) {
$type = '/f';
}
$pointer =& $pointer[$path[$i] . $type];
}
$pointer = [
'lineCoverage' => $data->lineCoverage()[$originalPath] ?? [],
'functionCoverage' => $data->functionCoverage()[$originalPath] ?? [],
];
}
return $result;
}
/**
* Reduces the paths by cutting the longest common start path.
*
* For instance,
*
* <code>
* Array
* (
* [/home/sb/Money/Money.php] => Array
* (
* ...
* )
*
* [/home/sb/Money/MoneyBag.php] => Array
* (
* ...
* )
* )
* </code>
*
* is reduced to
*
* <code>
* Array
* (
* [Money.php] => Array
* (
* ...
* )
*
* [MoneyBag.php] => Array
* (
* ...
* )
* )
* </code>
*/
private function reducePaths(ProcessedCodeCoverageData $coverage) : string {
if (empty($coverage->coveredFiles())) {
return '.';
}
$commonPath = '';
$paths = $coverage->coveredFiles();
if (count($paths) === 1) {
$commonPath = dirname($paths[0]) . DIRECTORY_SEPARATOR;
$coverage->renameFile($paths[0], basename($paths[0]));
return $commonPath;
}
$max = count($paths);
for ($i = 0; $i < $max; $i++) {
// strip phar:// prefixes
if (str_starts_with($paths[$i], 'phar://')) {
$paths[$i] = substr($paths[$i], 7);
$paths[$i] = str_replace('/', DIRECTORY_SEPARATOR, $paths[$i]);
}
$paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]);
if (empty($paths[$i][0])) {
$paths[$i][0] = DIRECTORY_SEPARATOR;
}
}
$done = false;
$max = count($paths);
while (!$done) {
for ($i = 0; $i < $max - 1; $i++) {
if (!isset($paths[$i][0]) || !isset($paths[$i + 1][0]) || $paths[$i][0] !== $paths[$i + 1][0]) {
$done = true;
break;
}
}
if (!$done) {
$commonPath .= $paths[0][0];
if ($paths[0][0] !== DIRECTORY_SEPARATOR) {
$commonPath .= DIRECTORY_SEPARATOR;
}
for ($i = 0; $i < $max; $i++) {
array_shift($paths[$i]);
}
}
}
$original = $coverage->coveredFiles();
$max = count($original);
for ($i = 0; $i < $max; $i++) {
$coverage->renameFile($original[$i], implode(DIRECTORY_SEPARATOR, $paths[$i]));
}
return substr($commonPath, 0, -1);
}
}
Members
Title Sort descending | Modifiers | Object type | Summary |
---|---|---|---|
Builder::$analyser | private | property | |
Builder::addItems | private | function | @psalm-param array<string, TestType> $tests |
Builder::build | public | function | |
Builder::buildDirectoryStructure | private | function | Builds an array representation of the directory structure. |
Builder::reducePaths | private | function | Reduces the paths by cutting the longest common start path. |
Builder::__construct | public | function |