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