Skip to content

Commit 02adea8

Browse files
Implement CodeCoverage::validate(TargetCollection)
1 parent 873416b commit 02adea8

File tree

6 files changed

+199
-0
lines changed

6 files changed

+199
-0
lines changed

src/CodeCoverage.php

+23
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
use SebastianBergmann\CodeCoverage\StaticAnalysis\CachingFileAnalyser;
3030
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
3131
use SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingFileAnalyser;
32+
use SebastianBergmann\CodeCoverage\Test\Target\MapBuilder;
33+
use SebastianBergmann\CodeCoverage\Test\Target\Mapper;
34+
use SebastianBergmann\CodeCoverage\Test\Target\TargetCollection;
35+
use SebastianBergmann\CodeCoverage\Test\Target\ValidationResult;
3236
use SebastianBergmann\CodeCoverage\Test\TestSize\TestSize;
3337
use SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus;
3438
use SebastianBergmann\CodeUnitReverseLookup\Wizard;
@@ -47,6 +51,7 @@ final class CodeCoverage
4751
private readonly Driver $driver;
4852
private readonly Filter $filter;
4953
private readonly Wizard $wizard;
54+
private ?Mapper $targetMapper = null;
5055
private bool $checkForUnintentionallyCoveredCode = false;
5156
private bool $ignoreDeprecatedCode = false;
5257
private ?string $currentId = null;
@@ -348,6 +353,11 @@ public function detectsDeadCode(): bool
348353
return $this->driver->detectsDeadCode();
349354
}
350355

356+
public function validate(TargetCollection $targets): ValidationResult
357+
{
358+
return $targets->validate($this->targetMapper());
359+
}
360+
351361
/**
352362
* @throws ReflectionException
353363
* @throws UnintentionallyCoveredCodeException
@@ -566,6 +576,19 @@ private function processUnintentionallyCoveredUnits(array $unintentionallyCovere
566576
return $processed;
567577
}
568578

579+
private function targetMapper(): Mapper
580+
{
581+
if ($this->targetMapper !== null) {
582+
return $this->targetMapper;
583+
}
584+
585+
$this->targetMapper = new Mapper(
586+
(new MapBuilder)->build($this->filter, $this->analyser()),
587+
);
588+
589+
return $this->targetMapper;
590+
}
591+
569592
private function analyser(): FileAnalyser
570593
{
571594
if ($this->analyser !== null) {

src/Target/TargetCollection.php

+20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace SebastianBergmann\CodeCoverage\Test\Target;
1111

1212
use function count;
13+
use function implode;
1314
use Countable;
1415
use IteratorAggregate;
1516

@@ -67,4 +68,23 @@ public function getIterator(): TargetCollectionIterator
6768
{
6869
return new TargetCollectionIterator($this);
6970
}
71+
72+
public function validate(Mapper $mapper): ValidationResult
73+
{
74+
$errors = [];
75+
76+
foreach ($this->targets as $target) {
77+
try {
78+
$mapper->mapTarget($target);
79+
} catch (InvalidCodeCoverageTargetException $e) {
80+
$errors[] = $e->getMessage();
81+
}
82+
}
83+
84+
if ($errors === []) {
85+
return ValidationResult::success();
86+
}
87+
88+
return ValidationResult::failure(implode("\n", $errors));
89+
}
7090
}

src/Target/ValidationFailure.php

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of phpunit/php-code-coverage.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\CodeCoverage\Test\Target;
11+
12+
/**
13+
* @immutable
14+
*
15+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
16+
*/
17+
final readonly class ValidationFailure extends ValidationResult
18+
{
19+
/**
20+
* @var non-empty-string
21+
*/
22+
private string $message;
23+
24+
/**
25+
* @param non-empty-string $message
26+
*
27+
* @noinspection PhpMissingParentConstructorInspection
28+
*/
29+
protected function __construct(string $message)
30+
{
31+
$this->message = $message;
32+
}
33+
34+
public function isFailure(): true
35+
{
36+
return true;
37+
}
38+
39+
/**
40+
* @return non-empty-string
41+
*/
42+
public function message(): string
43+
{
44+
return $this->message;
45+
}
46+
}

src/Target/ValidationResult.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of phpunit/php-code-coverage.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\CodeCoverage\Test\Target;
11+
12+
/**
13+
* @immutable
14+
*
15+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
16+
*/
17+
abstract readonly class ValidationResult
18+
{
19+
public static function success(): ValidationSuccess
20+
{
21+
return new ValidationSuccess;
22+
}
23+
24+
/**
25+
* @param non-empty-string $message
26+
*/
27+
public static function failure(string $message): ValidationFailure
28+
{
29+
return new ValidationFailure($message);
30+
}
31+
32+
protected function __construct()
33+
{
34+
}
35+
36+
/**
37+
* @phpstan-assert-if-true ValidationSuccess $this
38+
*/
39+
public function isSuccess(): bool
40+
{
41+
return false;
42+
}
43+
44+
/**
45+
* @phpstan-assert-if-true ValidationFailure $this
46+
*/
47+
public function isFailure(): bool
48+
{
49+
return false;
50+
}
51+
}

src/Target/ValidationSuccess.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of phpunit/php-code-coverage.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\CodeCoverage\Test\Target;
11+
12+
/**
13+
* @immutable
14+
*
15+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
16+
*/
17+
final readonly class ValidationSuccess extends ValidationResult
18+
{
19+
public function isSuccess(): true
20+
{
21+
return true;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of phpunit/php-code-coverage.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\CodeCoverage\Test\Target;
11+
12+
use PHPUnit\Framework\Attributes\CoversClass;
13+
use PHPUnit\Framework\Attributes\Small;
14+
use PHPUnit\Framework\TestCase;
15+
16+
#[CoversClass(ValidationResult::class)]
17+
#[CoversClass(ValidationSuccess::class)]
18+
#[CoversClass(ValidationFailure::class)]
19+
#[Small]
20+
final class ValidationResultTest extends TestCase
21+
{
22+
public function testCanBeSuccess(): void
23+
{
24+
$this->assertTrue(ValidationResult::success()->isSuccess());
25+
$this->assertFalse(ValidationResult::success()->isFailure());
26+
}
27+
28+
public function testCanBeFailure(): void
29+
{
30+
$message = 'message';
31+
32+
$this->assertTrue(ValidationResult::failure($message)->isFailure());
33+
$this->assertFalse(ValidationResult::failure($message)->isSuccess());
34+
$this->assertSame($message, ValidationResult::failure($message)->message());
35+
}
36+
}

0 commit comments

Comments
 (0)