Skip to content

Commit 89ca8a3

Browse files
committed
Lint a few items in PHPDBG and Xdebug. More work in CodeCoverage to add path and branch coverage
1 parent 13fc27f commit 89ca8a3

File tree

3 files changed

+241
-54
lines changed

3 files changed

+241
-54
lines changed

src/CodeCoverage.php

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

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

369363
foreach ($fileData['functions'] as $function => $functionCoverage) {
370364
foreach ($functionCoverage['branches'] as $branch => $branchCoverage) {
371-
if ($branchCoverage['hit'] === 1) {
372-
$this->data[$file]['branches'][$function][$branch]['hit'] = 1;
373-
if (!\in_array($id, $this->data[$file]['branches'][$function][$branch]['tests'], true)) {
374-
$this->data[$file]['branches'][$function][$branch]['tests'][] = $id;
375-
}
365+
if (($branchCoverage['hit'] ?? 0) === 1) {
366+
$this->addCoverageBranchHit($file, $function, $branch, $branchCoverage['hit'] ?? 0);
367+
$this->addCoverageBranchTest($file, $function, $branch, $id);
376368
}
377369
}
370+
378371
foreach ($functionCoverage['paths'] as $path => $pathCoverage) {
379-
if ($pathCoverage['hit'] === 1 && $this->data[$file]['paths'][$function][$path]['hit'] === 0) {
380-
$this->data[$file]['paths'][$function][$path]['hit'] = 1;
381-
}
372+
$this->addCoveragePathHit($file, $function, $path, $pathCoverage['hit'] ?? 0);
382373
}
383374
}
384375
}
@@ -397,11 +388,13 @@ public function merge(self $that): void
397388
\array_merge($this->filter->getWhitelistedFiles(), $that->filter()->getWhitelistedFiles())
398389
);
399390

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

407400
continue;
@@ -410,30 +403,30 @@ public function merge(self $that): void
410403
// we should compare the lines if any of two contains data
411404
$compareLineNumbers = \array_unique(
412405
\array_merge(
413-
\array_keys($this->data[$file]['lines']),
414-
\array_keys($that->data[$file]['lines']) // can this be $fileData?
406+
\array_keys($thisData[$file]['lines']),
407+
\array_keys($thatData[$file]['lines']) // can this be $fileData?
415408
)
416409
);
417410

418411
foreach ($compareLineNumbers as $line) {
419-
$thatPriority = $this->getLinePriority($that->data[$file]['lines'], $line);
420-
$thisPriority = $this->getLinePriority($this->data[$file]['lines'], $line);
412+
$thatPriority = $this->getLinePriority($thatData[$file]['lines'], $line);
413+
$thisPriority = $this->getLinePriority($thisData[$file]['lines'], $line);
421414

422415
if ($thatPriority > $thisPriority) {
423-
$this->data[$file]['lines'][$line] = $that->data[$file]['lines'][$line];
424-
} elseif ($thatPriority === $thisPriority && \is_array($this->data[$file]['lines'][$line])) {
416+
$thisData[$file]['lines'][$line] = $thatData[$file]['lines'][$line];
417+
} elseif ($thatPriority === $thisPriority && \is_array($thisData[$file]['lines'][$line])) {
425418
if ($line['pathCovered'] === true) {
426-
$this->data[$file]['lines']['line']['pathCovered'] = $line['pathCovered'];
419+
$thisData[$file]['lines'][$line]['pathCovered'] = $line['pathCovered'];
427420
}
428-
$this->data[$file]['lines'][$line] = \array_unique(
429-
\array_merge($this->data[$file]['lines'][$line], $that->data[$file]['lines'][$line])
421+
$thisData[$file]['lines'][$line] = \array_unique(
422+
\array_merge($thisData[$file]['lines'][$line], $thatData[$file]['lines'][$line])
430423
);
431424
}
432425
}
433426
}
434427

435-
$this->tests = \array_merge($this->tests, $that->getTests());
436-
$this->report = null;
428+
$this->tests = \array_merge($this->tests, $that->getTests());
429+
$this->setData($thisData);
437430
}
438431

439432
public function setCacheTokens(bool $flag): void
@@ -518,12 +511,9 @@ public function setDetermineBranchCoverage(bool $flag): void
518511
*
519512
* During a merge, a higher number is better.
520513
*
521-
* @param array $data
522-
* @param int $line
523-
*
524514
* @return int
525515
*/
526-
private function getLinePriority($data, $line)
516+
private function getLinePriority(array $data, int $line)
527517
{
528518
if (!\array_key_exists($line, $data)) {
529519
return 1;
@@ -558,7 +548,10 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
558548
throw new MissingCoversAnnotationException;
559549
}
560550

561-
$data = [];
551+
$data = [
552+
'lines' => [],
553+
'functions' => [],
554+
];
562555

563556
return;
564557
}
@@ -569,7 +562,7 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
569562

570563
if ($this->checkForUnintentionallyCoveredCode &&
571564
(!$this->currentId instanceof TestCase ||
572-
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
565+
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
573566
$this->performUnintentionallyCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
574567
}
575568

@@ -581,7 +574,11 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
581574

582575
foreach (\array_keys($data) as $filename) {
583576
$_linesToBeCovered = \array_flip($linesToBeCovered[$filename]);
584-
$data[$filename] = \array_intersect_key($data[$filename], $_linesToBeCovered);
577+
578+
$data[$filename]['lines'] = \array_intersect_key(
579+
$data[$filename],
580+
$_linesToBeCovered
581+
);
585582
}
586583
}
587584

@@ -605,24 +602,210 @@ private function applyIgnoredLinesFilter(array &$data): void
605602
}
606603

607604
foreach ($this->getLinesToBeIgnored($filename) as $line) {
608-
unset($data[$filename][$line]);
605+
unset($data[$filename]['lines'][$line]);
609606
}
610607
}
611608
}
612609

613610
private function initializeFilesThatAreSeenTheFirstTime(array $data): void
614611
{
615-
foreach ($data as $file => $lines) {
616-
if (!isset($this->data[$file]) && $this->filter->isFile($file)) {
617-
$this->data[$file] = [];
612+
foreach ($data as $file => $fileData) {
613+
if (isset($this->data[$file]) || !$this->filter->isFile($file)) {
614+
continue;
615+
}
616+
$this->initializeFileCoverageData($file);
617+
618+
// If this particular line is identified as not covered, mark it as null
619+
foreach ($fileData['lines'] as $lineNumber => $flag) {
620+
if ($flag === Driver::LINE_NOT_EXECUTABLE) {
621+
$this->data[$file]['lines'][$lineNumber] = null;
622+
}
623+
}
618624

619-
foreach ($lines as $k => $v) {
620-
$this->data[$file][$k] = $v === -2 ? null : [];
625+
foreach ($fileData['functions'] as $functionName => $functionData) {
626+
// @todo - should this have a helper to merge covered paths?
627+
$this->data[$file]['paths'][$functionName] = $functionData['paths'];
628+
629+
foreach ($functionData['branches'] as $branchIndex => $branchData) {
630+
$this->addCoverageBranchHit($file, $functionName, $branchIndex, $branchData['hit']);
631+
$this->addCoverageBranchLineStart($file, $functionName, $branchIndex, $branchData['line_start']);
632+
$this->addCoverageBranchLineEnd($file, $functionName, $branchIndex, $branchData['line_end']);
633+
634+
for ($curLine = $branchData['line_start']; $curLine < $branchData['line_end']; $curLine++) {
635+
if (isset($this->data[$file]['lines'][$curLine])) {
636+
$this->addCoverageLinePathCovered($file, $curLine, (bool) $branchData['hit']);
637+
}
638+
}
621639
}
622640
}
623641
}
624642
}
625643

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

647-
$data[$uncoveredFile] = [];
830+
$data[$uncoveredFile] = [
831+
'lines' => [],
832+
'functions' => [],
833+
];
648834

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

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

@@ -842,10 +1028,10 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
8421028

8431029
$unintentionallyCoveredUnits = [];
8441030

845-
foreach ($data as $file => $_data) {
846-
foreach ($_data as $line => $flag) {
847-
if ($flag === 1 && !isset($allowedLines[$file][$line])) {
848-
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $line);
1031+
foreach ($data as $file => $fileData) {
1032+
foreach ($fileData['lines'] as $lineNumber => $flag) {
1033+
if ($flag === 1 && !isset($allowedLines[$file][$lineNumber])) {
1034+
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $lineNumber);
8491035
}
8501036
}
8511037
}

0 commit comments

Comments
 (0)