Skip to content

Commit 12baaf6

Browse files
committed
Lint a few items in PHPDBG and Xdebug. More work in CodeCoverage to add path and branch coverage
1 parent bcbe25b commit 12baaf6

File tree

2 files changed

+238
-51
lines changed

2 files changed

+238
-51
lines changed

src/CodeCoverage.php

Lines changed: 237 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -354,30 +354,21 @@ public function append(array $data, $id = null, bool $append = true, $linesToBeC
354354

355355
foreach ($fileData['lines'] as $line => $lineCoverage) {
356356
if ($lineCoverage === Driver::LINE_EXECUTED) {
357-
if ($this->data[$file]['lines'][$line] === null) {
358-
$this->data[$file]['lines'][$line] = [
359-
'pathCovered' => false,
360-
'tests' => [$id],
361-
];
362-
} elseif (!\in_array($id, $this->data[$file]['lines'][$line]['tests'], true)) {
363-
$this->data[$file]['lines'][$line]['tests'][] = [$id];
364-
}
357+
$this->addCoverageLinePathCovered($file, $line, false);
358+
$this->addCoverageLineTest($file, $line, $id);
365359
}
366360
}
367361

368362
foreach ($fileData['functions'] as $function => $functionCoverage) {
369363
foreach ($functionCoverage['branches'] as $branch => $branchCoverage) {
370-
if ($branchCoverage['hit'] === 1) {
371-
$this->data[$file]['branches'][$function][$branch]['hit'] = 1;
372-
if (!\in_array($id, $this->data[$file]['branches'][$function][$branch]['tests'], true)) {
373-
$this->data[$file]['branches'][$function][$branch]['tests'][] = $id;
374-
}
364+
if (($branchCoverage['hit'] ?? 0) === 1) {
365+
$this->addCoverageBranchHit($file, $function, $branch, $branchCoverage['hit'] ?? 0);
366+
$this->addCoverageBranchTest($file, $function, $branch, $id);
375367
}
376368
}
369+
377370
foreach ($functionCoverage['paths'] as $path => $pathCoverage) {
378-
if ($pathCoverage['hit'] === 1 && $this->data[$file]['paths'][$function][$path]['hit'] === 0) {
379-
$this->data[$file]['paths'][$function][$path]['hit'] = 1;
380-
}
371+
$this->addCoveragePathHit($file, $function, $path, $pathCoverage['hit'] ?? 0);
381372
}
382373
}
383374
}
@@ -396,11 +387,13 @@ public function merge(self $that): void
396387
\array_merge($this->filter->getWhitelistedFiles(), $that->filter()->getWhitelistedFiles())
397388
);
398389

399-
// I don't know how / why this works, but it should be refactored to ->getData()
400-
foreach ($that->getData() as $file => $fileData) {
401-
if (!isset($this->data[$file])) {
390+
$thisData = $this->getData();
391+
$thatData = $that->getData();
392+
393+
foreach ($thatData as $file => $fileData) {
394+
if (!isset($thisData[$file])) {
402395
if (!$this->filter->isFiltered($file)) {
403-
$this->data[$file] = $fileData;
396+
$thisData[$file] = $fileData;
404397
}
405398

406399
continue;
@@ -409,30 +402,30 @@ public function merge(self $that): void
409402
// we should compare the lines if any of two contains data
410403
$compareLineNumbers = \array_unique(
411404
\array_merge(
412-
\array_keys($this->data[$file]['lines']),
413-
\array_keys($that->data[$file]['lines']) // can this be $fileData?
405+
\array_keys($thisData[$file]['lines']),
406+
\array_keys($thatData[$file]['lines']) // can this be $fileData?
414407
)
415408
);
416409

417410
foreach ($compareLineNumbers as $line) {
418-
$thatPriority = $this->getLinePriority($that->data[$file]['lines'], $line);
419-
$thisPriority = $this->getLinePriority($this->data[$file]['lines'], $line);
411+
$thatPriority = $this->getLinePriority($thatData[$file]['lines'], $line);
412+
$thisPriority = $this->getLinePriority($thisData[$file]['lines'], $line);
420413

421414
if ($thatPriority > $thisPriority) {
422-
$this->data[$file]['lines'][$line] = $that->data[$file]['lines'][$line];
423-
} elseif ($thatPriority === $thisPriority && \is_array($this->data[$file]['lines'][$line])) {
415+
$thisData[$file]['lines'][$line] = $thatData[$file]['lines'][$line];
416+
} elseif ($thatPriority === $thisPriority && \is_array($thisData[$file]['lines'][$line])) {
424417
if ($line['pathCovered'] === true) {
425-
$this->data[$file]['lines']['line']['pathCovered'] = $line['pathCovered'];
418+
$thisData[$file]['lines'][$line]['pathCovered'] = $line['pathCovered'];
426419
}
427-
$this->data[$file]['lines'][$line] = \array_unique(
428-
\array_merge($this->data[$file]['lines'][$line], $that->data[$file]['lines'][$line])
420+
$thisData[$file]['lines'][$line] = \array_unique(
421+
\array_merge($thisData[$file]['lines'][$line], $thatData[$file]['lines'][$line])
429422
);
430423
}
431424
}
432425
}
433426

434-
$this->tests = \array_merge($this->tests, $that->getTests());
435-
$this->report = null;
427+
$this->tests = \array_merge($this->tests, $that->getTests());
428+
$this->setData($thisData);
436429
}
437430

438431
public function setCacheTokens(bool $flag): void
@@ -517,12 +510,9 @@ public function setDetermineBranchCoverage(bool $flag): void
517510
*
518511
* During a merge, a higher number is better.
519512
*
520-
* @param array $data
521-
* @param int $line
522-
*
523513
* @return int
524514
*/
525-
private function getLinePriority($data, $line)
515+
private function getLinePriority(array $data, int $line)
526516
{
527517
if (!\array_key_exists($line, $data)) {
528518
return 1;
@@ -557,7 +547,10 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
557547
throw new MissingCoversAnnotationException;
558548
}
559549

560-
$data = [];
550+
$data = [
551+
'lines' => [],
552+
'functions' => [],
553+
];
561554

562555
return;
563556
}
@@ -568,7 +561,7 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
568561

569562
if ($this->checkForUnintentionallyCoveredCode &&
570563
(!$this->currentId instanceof TestCase ||
571-
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
564+
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
572565
$this->performUnintentionallyCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
573566
}
574567

@@ -580,7 +573,11 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
580573

581574
foreach (\array_keys($data) as $filename) {
582575
$_linesToBeCovered = \array_flip($linesToBeCovered[$filename]);
583-
$data[$filename] = \array_intersect_key($data[$filename], $_linesToBeCovered);
576+
577+
$data[$filename]['lines'] = \array_intersect_key(
578+
$data[$filename],
579+
$_linesToBeCovered
580+
);
584581
}
585582
}
586583

@@ -604,24 +601,210 @@ private function applyIgnoredLinesFilter(array &$data): void
604601
}
605602

606603
foreach ($this->getLinesToBeIgnored($filename) as $line) {
607-
unset($data[$filename][$line]);
604+
unset($data[$filename]['lines'][$line]);
608605
}
609606
}
610607
}
611608

612609
private function initializeFilesThatAreSeenTheFirstTime(array $data): void
613610
{
614-
foreach ($data as $file => $lines) {
615-
if (!isset($this->data[$file]) && $this->filter->isFile($file)) {
616-
$this->data[$file] = [];
611+
foreach ($data as $file => $fileData) {
612+
if (isset($this->data[$file]) || !$this->filter->isFile($file)) {
613+
continue;
614+
}
615+
$this->initializeFileCoverageData($file);
617616

618-
foreach ($lines as $k => $v) {
619-
$this->data[$file][$k] = $v === -2 ? null : [];
617+
// If this particular line is identified as not covered, mark it as null
618+
foreach ($fileData['lines'] as $lineNumber => $flag) {
619+
if ($flag === Driver::LINE_NOT_EXECUTABLE) {
620+
$this->data[$file]['lines'][$lineNumber] = null;
621+
}
622+
}
623+
624+
foreach ($fileData['functions'] as $functionName => $functionData) {
625+
// @todo - should this have a helper to merge covered paths?
626+
$this->data[$file]['paths'][$functionName] = $functionData['paths'];
627+
628+
foreach ($functionData['branches'] as $branchIndex => $branchData) {
629+
$this->addCoverageBranchHit($file, $functionName, $branchIndex, $branchData['hit']);
630+
$this->addCoverageBranchLineStart($file, $functionName, $branchIndex, $branchData['line_start']);
631+
$this->addCoverageBranchLineEnd($file, $functionName, $branchIndex, $branchData['line_end']);
632+
633+
for ($curLine = $branchData['line_start']; $curLine < $branchData['line_end']; $curLine++) {
634+
if (isset($this->data[$file]['lines'][$curLine])) {
635+
$this->addCoverageLinePathCovered($file, $curLine, (bool) $branchData['hit']);
636+
}
637+
}
620638
}
621639
}
622640
}
623641
}
624642

643+
private function initializeFileCoverageData(string $file): void
644+
{
645+
if (!isset($this->data[$file]) && $this->filter->isFile($file)) {
646+
$this->data[$file] = [
647+
'lines' => [],
648+
'branches' => [],
649+
'paths' => [],
650+
];
651+
}
652+
}
653+
654+
private function addCoverageLinePathCovered(string $file, int $lineNumber, bool $isCovered): void
655+
{
656+
$this->initializeFileCoverageData($file);
657+
658+
// Initialize the data coverage array for this line
659+
if (!isset($this->data[$file]['lines'][$lineNumber])) {
660+
$this->data[$file]['lines'][$lineNumber] = [
661+
'pathCovered' => false,
662+
'tests' => [],
663+
];
664+
}
665+
666+
$this->data[$file]['lines'][$lineNumber]['pathCovered'] = $isCovered;
667+
}
668+
669+
private function addCoverageLineTest(string $file, int $lineNumber, string $testId): void
670+
{
671+
$this->initializeFileCoverageData($file);
672+
673+
// Initialize the data coverage array for this line
674+
if (!isset($this->data[$file]['lines'][$lineNumber])) {
675+
$this->data[$file]['lines'][$lineNumber] = [
676+
'pathCovered' => false,
677+
'tests' => [],
678+
];
679+
}
680+
681+
if (!\in_array($testId, $this->data[$file]['lines'][$lineNumber]['tests'], true)) {
682+
$this->data[$file]['lines'][$lineNumber]['tests'][] = $testId;
683+
}
684+
}
685+
686+
private function addCoverageBranchHit(string $file, string $functionName, int $branchIndex, int $hit): void
687+
{
688+
$this->initializeFileCoverageData($file);
689+
690+
if (!\array_key_exists($functionName, $this->data[$file]['branches'])) {
691+
$this->data[$file]['branches'][$functionName] = [];
692+
}
693+
694+
if (!\array_key_exists($branchIndex, $this->data[$file]['branches'][$functionName])) {
695+
$this->data[$file]['branches'][$functionName][$branchIndex] = [
696+
'hit' => 0,
697+
'line_start' => 0,
698+
'line_end' => 0,
699+
'tests' => [],
700+
];
701+
}
702+
703+
$this->data[$file]['branches'][$functionName][$branchIndex]['hit'] = \max(
704+
$this->data[$file]['branches'][$functionName][$branchIndex]['hit'],
705+
$hit
706+
);
707+
}
708+
709+
private function addCoverageBranchLineStart(
710+
string $file,
711+
string $functionName,
712+
int $branchIndex,
713+
int $lineStart
714+
): void {
715+
$this->initializeFileCoverageData($file);
716+
717+
if (!\array_key_exists($functionName, $this->data[$file]['branches'])) {
718+
$this->data[$file]['branches'][$functionName] = [];
719+
}
720+
721+
if (!\array_key_exists($branchIndex, $this->data[$file]['branches'][$functionName])) {
722+
$this->data[$file]['branches'][$functionName][$branchIndex] = [
723+
'hit' => 0,
724+
'line_start' => 0,
725+
'line_end' => 0,
726+
'tests' => [],
727+
];
728+
}
729+
730+
$this->data[$file]['branches'][$functionName][$branchIndex]['line_start'] = $lineStart;
731+
}
732+
733+
private function addCoverageBranchLineEnd(
734+
string $file,
735+
string $functionName,
736+
int $branchIndex,
737+
int $lineEnd
738+
): void {
739+
$this->initializeFileCoverageData($file);
740+
741+
if (!\array_key_exists($functionName, $this->data[$file]['branches'])) {
742+
$this->data[$file]['branches'][$functionName] = [];
743+
}
744+
745+
if (!\array_key_exists($branchIndex, $this->data[$file]['branches'][$functionName])) {
746+
$this->data[$file]['branches'][$functionName][$branchIndex] = [
747+
'hit' => 0,
748+
'line_start' => 0,
749+
'line_end' => 0,
750+
'tests' => [],
751+
];
752+
}
753+
754+
$this->data[$file]['branches'][$functionName][$branchIndex]['line_end'] = $lineEnd;
755+
}
756+
757+
private function addCoverageBranchTest(
758+
string $file,
759+
string $functionName,
760+
int $branchIndex,
761+
string $testId
762+
): void {
763+
$this->initializeFileCoverageData($file);
764+
765+
if (!\array_key_exists($functionName, $this->data[$file]['branches'])) {
766+
$this->data[$file]['branches'][$functionName] = [];
767+
}
768+
769+
if (!\array_key_exists($branchIndex, $this->data[$file]['branches'][$functionName])) {
770+
$this->data[$file]['branches'][$functionName][$branchIndex] = [
771+
'hit' => 0,
772+
'line_start' => 0,
773+
'line_end' => 0,
774+
'tests' => [],
775+
];
776+
}
777+
778+
if (!\in_array($testId, $this->data[$file]['branches'][$functionName][$branchIndex]['tests'], true)) {
779+
$this->data[$file]['branches'][$functionName][$branchIndex]['tests'][] = $testId;
780+
}
781+
}
782+
783+
private function addCoveragePathHit(
784+
string $file,
785+
string $functionName,
786+
int $pathId,
787+
int $hit
788+
): void {
789+
$this->initializeFileCoverageData($file);
790+
791+
if (!\array_key_exists($functionName, $this->data[$file]['paths'])) {
792+
$this->data[$file]['paths'][$functionName] = [];
793+
}
794+
795+
if (!\array_key_exists($pathId, $this->data[$file]['paths'][$functionName])) {
796+
$this->data[$file]['paths'][$functionName][$pathId] = [
797+
'hit' => 0,
798+
'path' => [],
799+
];
800+
}
801+
802+
$this->data[$file]['paths'][$functionName][$pathId]['hit'] = \max(
803+
$this->data[$file]['paths'][$functionName][$pathId]['hit'],
804+
$hit
805+
);
806+
}
807+
625808
/**
626809
* @throws CoveredCodeNotExecutedException
627810
* @throws InvalidArgumentException
@@ -643,12 +826,15 @@ private function addUncoveredFilesFromWhitelist(): void
643826
continue;
644827
}
645828

646-
$data[$uncoveredFile] = [];
829+
$data[$uncoveredFile] = [
830+
'lines' => [],
831+
'functions' => [],
832+
];
647833

648834
$lines = \count(\file($uncoveredFile));
649835

650-
for ($i = 1; $i <= $lines; $i++) {
651-
$data[$uncoveredFile][$i] = Driver::LINE_NOT_EXECUTED;
836+
for ($line = 1; $line <= $lines; $line++) {
837+
$data[$uncoveredFile]['lines'][$line] = Driver::LINE_NOT_EXECUTED;
652838
}
653839
}
654840

@@ -852,10 +1038,10 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
8521038

8531039
$unintentionallyCoveredUnits = [];
8541040

855-
foreach ($data as $file => $_data) {
856-
foreach ($_data as $line => $flag) {
857-
if ($flag === 1 && !isset($allowedLines[$file][$line])) {
858-
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $line);
1041+
foreach ($data as $file => $fileData) {
1042+
foreach ($fileData['lines'] as $lineNumber => $flag) {
1043+
if ($flag === 1 && !isset($allowedLines[$file][$lineNumber])) {
1044+
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $lineNumber);
8591045
}
8601046
}
8611047
}

0 commit comments

Comments
 (0)