packages/requirements/tests/Unit/Report/AnalysisTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Report;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\Small;
10use PHPUnit\Framework\Attributes\UsesClass;
11use PHPUnit\Framework\TestCase;
12use Requirements\Model\Item;
13use Requirements\Model\Source;
14use Requirements\Report\Analysis;
15use Requirements\Report\SourceUnit;
16use Requirements\Source\Unit;
17
18#[CoversClass(Analysis::class)]
19#[UsesClass(SourceUnit::class)]
20#[UsesClass(Item::class)]
21#[UsesClass(Source::class)]
22#[UsesClass(Unit::class)]
23#[Small]
24final class AnalysisTest extends TestCase
25{
26 /**
27 * @param list<string>|null $keys
28 * @param array{total: int, accounted: int, supported: int, unsupported: int, uncovered: int, percentage: float|null} $expected
29 */
30 #[DataProvider('providerSummaryKeys')]
31 public function testSummaryCountsTheGivenUnits(?array $keys, array $expected): void
32 {
33 $source = new Source('manual', 'source.html', 'html', 'main p');
34 $supported = new Item('SPEC-001', 'specification', 'The parser shall read names.', 'supported', $source, [], [], [], [], [], '', 'sourced', '', 'definition.yaml', []);
35 $unsupported = new Item('SPEC-002', 'specification', 'The parser shall read digits.', 'unsupported', $source, [], [], [], [], [], '', 'sourced', 'Out of scope.', 'definition.yaml', []);
36 $a = new SourceUnit($source, new Unit('p:1', 'First.'));
37 $a->claims = ['SPEC-001' => $supported];
38 $b = new SourceUnit($source, new Unit('p:2', 'Second.'));
39 $b->claims = ['SPEC-002' => $unsupported];
40 $c = new SourceUnit($source, new Unit('p:3', 'Third.'));
41 $d = new SourceUnit($source, new Unit('p:4', 'Fourth.'));
42 $d->claims = ['SPEC-002' => $unsupported, 'SPEC-001' => $supported];
43 $analysis = new Analysis(['a' => $a, 'b' => $b, 'c' => $c, 'd' => $d], ['manual' => ['a', 'b', 'c', 'd']], [], []);
44 self::assertSame($expected, $analysis->summary($keys));
45 }
46
47 /**
48 * @return array<string, array{list<string>|null, array{total: int, accounted: int, supported: int, unsupported: int, uncovered: int, percentage: float|null}}>
49 */
50 public static function providerSummaryKeys(): array
51 {
52 return [
53 'every unit' => [null, ['total' => 4, 'accounted' => 3, 'supported' => 2, 'unsupported' => 1, 'uncovered' => 1, 'percentage' => 75.0]],
54 'supported' => [['a'], ['total' => 1, 'accounted' => 1, 'supported' => 1, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => 100.0]],
55 'unsupported' => [['b'], ['total' => 1, 'accounted' => 1, 'supported' => 0, 'unsupported' => 1, 'uncovered' => 0, 'percentage' => 100.0]],
56 'uncovered' => [['c'], ['total' => 1, 'accounted' => 0, 'supported' => 0, 'unsupported' => 0, 'uncovered' => 1, 'percentage' => 0.0]],
57 'mixed claims count as supported once' => [['d'], ['total' => 1, 'accounted' => 1, 'supported' => 1, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => 100.0]],
58 'three of four' => [['a', 'b', 'c'], ['total' => 3, 'accounted' => 2, 'supported' => 1, 'unsupported' => 1, 'uncovered' => 1, 'percentage' => 200.0 / 3]],
59 'no keys' => [[], ['total' => 0, 'accounted' => 0, 'supported' => 0, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => null]],
60 ];
61 }
62
63 public function testSummaryHasNoPercentageWithoutUnits(): void
64 {
65 $analysis = new Analysis([], [], ['manual: Scope selected no source units.'], []);
66 self::assertSame(['total' => 0, 'accounted' => 0, 'supported' => 0, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => null], $analysis->summary());
67 }
68}
69