packages/sql-catalog/tests/Unit/Reporter/Html/ReportSiteTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Reporter\Html;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlCatalog\Core\Catalog\CallSite;
12use SqlCatalog\Core\Catalog\Catalog;
13use SqlCatalog\Core\Catalog\CatalogEntry;
14use SqlCatalog\Core\Sql\StatementKind;
15use SqlCatalog\Core\Text\LiteralText;
16use SqlCatalog\Core\Text\TextPattern;
17use SqlCatalog\Reporter\Html\CatalogIndex;
18use SqlCatalog\Reporter\Html\CatalogStatistics;
19use SqlCatalog\Reporter\Html\HtmlText;
20use SqlCatalog\Reporter\Html\ReportSite;
21use SqlCatalog\Reporter\Html\Scope;
22
23#[CoversClass(ReportSite::class)]
24#[UsesClass(CallSite::class)]
25#[UsesClass(Catalog::class)]
26#[UsesClass(CatalogEntry::class)]
27#[UsesClass(CatalogIndex::class)]
28#[UsesClass(CatalogStatistics::class)]
29#[UsesClass(HtmlText::class)]
30#[UsesClass(Scope::class)]
31#[UsesClass(StatementKind::class)]
32#[UsesClass(LiteralText::class)]
33#[UsesClass(TextPattern::class)]
34final class ReportSiteTest extends TestCase
35{
36    public function testCatalogIsHeldInReportingOrder(): void
37    {
38        $catalog = new Catalog([
39            new CatalogEntry('b', StatementKind::Select, TextPattern::fromText('SELECT 2'), [], [], new CallSite('b.php', 1, 'f', 'pdo.query'), []),
40            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('a.php', 1, 'f', 'pdo.query'), []),
41        ]);
42
43        self::assertSame(['a', 'b'], array_column((new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->catalog()->entries(), 'id'));
44    }
45
46    public function testIndexGroupsTheCatalog(): void
47    {
48        $catalog = new Catalog([
49            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), ['users'], [], new CallSite('a.php', 1, 'f', 'pdo.query'), []),
50        ]);
51
52        self::assertSame(['users'], array_keys((new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->index()->byTable()));
53    }
54
55    public function testStatisticsCountTheCatalog(): void
56    {
57        $catalog = new Catalog([
58            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('a.php', 1, 'f', 'pdo.query'), []),
59        ]);
60
61        self::assertSame(1, (new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->statistics()->statements());
62    }
63
64    public function testPagesForKeepsNamesApartWhenTheySlugAlike(): void
65    {
66        self::assertSame(
67            ['wp_posts' => 'tables/wp-posts.html', 'wp-posts' => 'tables/wp-posts-2.html', '' => 'tables/unnamed.html'],
68            (new ReportSite(new Catalog(), formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->pagesFor(['wp_posts', 'wp-posts', ''], 'tables/'),
69        );
70    }
71
72    public function testStatementPageIsNamedAfterTheIdentifier(): void
73    {
74        self::assertSame('statements/abc123.html', (new ReportSite(new Catalog(), formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->statementPage('abc123'));
75    }
76
77    public function testTablePageFallsBackToTheListingForAnUnknownTable(): void
78    {
79        $catalog = new Catalog([
80            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), ['app.users'], [], new CallSite('a.php', 1, 'f', 'pdo.query'), []),
81        ]);
82        $site = new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter());
83
84        self::assertSame('tables/app-users.html', $site->tablePage('app.users'));
85        self::assertSame('tables.html', $site->tablePage('none'));
86    }
87
88    public function testClassPageFallsBackToTheListingForAnUnknownClass(): void
89    {
90        $catalog = new Catalog([
91            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('a.php', 1, 'App\\Users::find', 'pdo.query'), []),
92        ]);
93        $site = new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter());
94
95        self::assertSame('classes/app-users.html', $site->classPage('App\\Users'));
96        self::assertSame('namespaces.html', $site->classPage('None'));
97    }
98
99    public function testFilePageFallsBackToTheListingForAnUnknownFile(): void
100    {
101        $catalog = new Catalog([
102            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('src/a.php', 1, 'f', 'pdo.query'), []),
103        ]);
104        $site = new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter());
105
106        self::assertSame('files/src-a-php.html', $site->filePage('src/a.php'));
107        self::assertSame('files.html', $site->filePage('none.php'));
108    }
109
110    public function testFunctionAnchorIsWhatAFunctionsStatementsAreGroupedUnder(): void
111    {
112        self::assertSame('fn-app-users-find', (new ReportSite(new Catalog(), formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->functionAnchor('\\App\\Users::find'));
113    }
114
115    public function testFunctionUrlLeadsToTheClassPageForAMethodAndTheFilePageOtherwise(): void
116    {
117        $method = new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('src/a.php', 1, 'App\\Users::find', 'pdo.query'), []);
118        $function = new CatalogEntry('b', StatementKind::Select, TextPattern::fromText('SELECT 2'), [], [], new CallSite('src/b.php', 1, 'helper', 'pdo.query'), []);
119        $site = new ReportSite(new Catalog([$method, $function]), formatter: \SqlCatalog\Facade\Builtins::sqlFormatter());
120
121        self::assertSame('classes/app-users.html#fn-app-users-find', $site->functionUrl($method));
122        self::assertSame('files/src-b-php.html#fn-helper', $site->functionUrl($function));
123    }
124
125    public function testTablesAreMostNamedFirst(): void
126    {
127        $catalog = new Catalog([
128            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), ['users', 'posts'], [], new CallSite('a.php', 1, 'f', 'pdo.query'), []),
129            new CatalogEntry('b', StatementKind::Select, TextPattern::fromText('SELECT 2'), ['posts'], [], new CallSite('a.php', 2, 'f', 'pdo.query'), []),
130        ]);
131
132        self::assertSame(['posts', 'users'], (new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->tables());
133    }
134
135    public function testClassesAreInNameOrder(): void
136    {
137        $catalog = new Catalog([
138            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('a.php', 1, 'B::f', 'pdo.query'), []),
139            new CatalogEntry('b', StatementKind::Select, TextPattern::fromText('SELECT 2'), [], [], new CallSite('a.php', 2, 'A::f', 'pdo.query'), []),
140        ]);
141
142        self::assertSame(['A', 'B'], (new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->classes());
143    }
144
145    public function testFilesAreInPathOrder(): void
146    {
147        $catalog = new Catalog([
148            new CatalogEntry('a', StatementKind::Select, TextPattern::fromText('SELECT 1'), [], [], new CallSite('b.php', 1, 'f', 'pdo.query'), []),
149            new CatalogEntry('b', StatementKind::Select, TextPattern::fromText('SELECT 2'), [], [], new CallSite('a.php', 1, 'f', 'pdo.query'), []),
150        ]);
151
152        self::assertSame(['a.php', 'b.php'], (new ReportSite($catalog, formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->files());
153    }
154
155    /**
156     * @return list<array{string, string}>
157     */
158    public static function providerPrefixOf(): array
159    {
160        return [['index.html', ''], ['tables/users.html', '../']];
161    }
162
163    #[DataProvider('providerPrefixOf')]
164    public function testPrefixOfIsWhatALinkFromThatPageGoesThrough(string $page, string $expected): void
165    {
166        self::assertSame($expected, (new ReportSite(new Catalog(), formatter: \SqlCatalog\Facade\Builtins::sqlFormatter()))->prefixOf($page));
167    }
168}
169