packages/requirements/tests/Unit/Console/CoverageTableTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Console;
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\Console\CoverageTable;
13use Requirements\Console\Text;
14use Requirements\Input\Fields;
15use Requirements\Input\InvalidInputException;
16use Symfony\Component\Console\Input\ArrayInput;
17use Symfony\Component\Console\Output\BufferedOutput;
18use Symfony\Component\Console\Style\SymfonyStyle;
19
20#[CoversClass(CoverageTable::class)]
21#[UsesClass(Text::class)]
22#[UsesClass(Fields::class)]
23#[Small]
24final class CoverageTableTest extends TestCase
25{
26    public function testRenderShowsOverallSourceAndChangedUnitRows(): void
27    {
28        $output = new BufferedOutput();
29        (new CoverageTable())->render(new SymfonyStyle(new ArrayInput([]), $output), [
30            'overall' => ['total' => 3, 'accounted' => 1, 'supported' => 1, 'unsupported' => 0, 'uncovered' => 2, 'percentage' => 33.333333],
31            'sources' => ['manual' => ['total' => 3, 'accounted' => 1, 'supported' => 1, 'unsupported' => 0, 'uncovered' => 2, 'percentage' => 66.666666]],
32            'diff' => ['total' => 0, 'accounted' => 0, 'supported' => 0, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => null],
33        ]);
34        $text = preg_replace('/ +$/m', '', $output->fetch());
35        self::assertIsString($text);
36        self::assertStringStartsWith(<<<'TABLE'
37 --------------- ------- ----------- ----------- ------------- ----------- ----------
38  Scope           Units   Accounted   Supported   Unsupported   Uncovered   Coverage
39 --------------- ------- ----------- ----------- ------------- ----------- ----------
40  Overall         3       1           1           0             2           33.33%
41  manual          3       1           1           0             2           66.67%
42  Changed units   0       0           0           0             0           n/a
43 --------------- ------- ----------- ----------- ------------- ----------- ----------
44
45TABLE, $text);
46        self::assertStringContainsString('[NOTE] Coverage applies only to the declared source scopes.', $text);
47    }
48
49    public function testRenderOmitsChangedUnitsWithoutASnapshotComparison(): void
50    {
51        $output = new BufferedOutput();
52        (new CoverageTable())->render(new SymfonyStyle(new ArrayInput([]), $output), [
53            'overall' => ['total' => 4, 'accounted' => 2, 'supported' => 1, 'unsupported' => 1, 'uncovered' => 2, 'percentage' => 50],
54            'sources' => ['<info>x</info>' => ['total' => 4, 'accounted' => 2, 'supported' => 1, 'unsupported' => 1, 'uncovered' => 2, 'percentage' => '50'], 'empty' => ['total' => 0, 'accounted' => 0, 'supported' => 0, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => null]],
55            'diff' => null,
56        ]);
57        $text = preg_replace('/ +$/m', '', $output->fetch());
58        self::assertIsString($text);
59        self::assertStringStartsWith(<<<'TABLE'
60 ---------------- ------- ----------- ----------- ------------- ----------- ----------
61  Scope            Units   Accounted   Supported   Unsupported   Uncovered   Coverage
62 ---------------- ------- ----------- ----------- ------------- ----------- ----------
63  Overall          4       2           1           1             2           50.00%
64  <info>x</info>   4       2           1           1             2           n/a
65  empty            0       0           0           0             0           n/a
66 ---------------- ------- ----------- ----------- ------------- ----------- ----------
67
68TABLE, $text);
69        self::assertStringNotContainsString('Changed units', $text);
70        self::assertStringContainsString('Unsupported units', $text);
71    }
72
73    /**
74     * @param array<string, mixed> $report
75     */
76    #[DataProvider('providerRenderRejected')]
77    public function testRenderRejectsScopesThatAreNotMappings(array $report, string $message): void
78    {
79        $this->expectException(InvalidInputException::class);
80        $this->expectExceptionMessage($message);
81        (new CoverageTable())->render(new SymfonyStyle(new ArrayInput([]), new BufferedOutput()), $report);
82    }
83
84    /**
85     * @return array<string, array{array<string, mixed>, string}>
86     */
87    public static function providerRenderRejected(): array
88    {
89        $scope = ['total' => 0, 'accounted' => 0, 'supported' => 0, 'unsupported' => 0, 'uncovered' => 0, 'percentage' => null];
90        return [
91            'sources list' => [['overall' => $scope, 'sources' => 'manual', 'diff' => null], 'sources must be a mapping.'],
92            'overall' => [['overall' => 'all', 'sources' => [], 'diff' => null], 'coverage must be a mapping.'],
93            'source' => [['overall' => $scope, 'sources' => ['manual' => 3], 'diff' => null], 'coverage must be a mapping.'],
94            'diff' => [['overall' => $scope, 'sources' => [], 'diff' => 'none'], 'coverage must be a mapping.'],
95        ];
96    }
97}
98