packages/sql-catalog/tests/Unit/Core/Php/SourceParserTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Core\Php;
6
7use PhpParser\Node\Stmt\Class_;
8use PhpParser\Node\Stmt\Namespace_;
9use PhpParser\Node\Stmt\Nop;
10use PHPUnit\Framework\Attributes\CoversClass;
11use PHPUnit\Framework\Attributes\UsesClass;
12use PHPUnit\Framework\TestCase;
13use SqlCatalog\Core\Php\ParsedFile;
14use SqlCatalog\Core\Php\SourceParser;
15use SqlCatalog\Core\Php\SyntaxException;
16
17#[CoversClass(SourceParser::class)]
18#[UsesClass(ParsedFile::class)]
19#[UsesClass(SyntaxException::class)]
20final class SourceParserTest extends TestCase
21{
22 public function testParseReturnsTheStatementsOfTheFile(): void
23 {
24 $file = (new SourceParser())->parse('a.php', '<?php $a = 1;');
25 self::assertSame('a.php', $file->path);
26 self::assertCount(1, $file->statements);
27 }
28
29 public function testParseResolvesNamesToTheirFullyQualifiedForm(): void
30 {
31 $file = (new SourceParser())->parse('a.php', '<?php namespace App; class User {}');
32 $namespace = $file->statements[0];
33 self::assertInstanceOf(Namespace_::class, $namespace);
34 $class = $namespace->stmts[0];
35 self::assertInstanceOf(Class_::class, $class);
36 self::assertSame('App\\User', $class->namespacedName?->toString());
37 }
38
39 public function testParseReportsTheFileASyntaxErrorCameFrom(): void
40 {
41 $this->expectException(SyntaxException::class);
42 $this->expectExceptionMessage('Cannot parse "broken.php"');
43 (new SourceParser())->parse('broken.php', '<?php function {');
44 }
45
46 public function testResolveNamesKeepsOnlyStatements(): void
47 {
48 self::assertCount(1, (new SourceParser())->resolveNames([new Nop()]));
49 }
50
51 public function testResolveNamesConnectsFileScopeSiblingsForWriteAnalysis(): void
52 {
53 $file = (new SourceParser())->parse('a.php', '<?php $a =& $b; $b = 1;');
54 self::assertSame($file->statements, $file->statements[1]->getAttribute('fileStatements'));
55 }
56
57}
58