packages/sql-catalog/tests/Unit/Extension/Laravel/CallModelTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Extension\Laravel;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlCatalog\Extension\Laravel\CallModel;
11
12#[CoversClass(CallModel::class)]
13#[UsesClass(\SqlCatalog\Facade\AnalysisOptions::class)]
14#[UsesClass(\SqlCatalog\Core\Analysis\BuiltinCallModel::class)]
15#[UsesClass(\SqlCatalog\Core\Analysis\CallEvaluator::class)]
16#[UsesClass(\SqlCatalog\Core\Analysis\ConstantReader::class)]
17#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Binding::class)]
18#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\CalleeReturns::class)]
19#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\CallerIndex::class)]
20#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Callers::class)]
21#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Deriver::class)]
22#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\EntryBinder::class)]
23#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\FreeNames::class)]
24#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\ModifiedNames::class)]
25#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Objects\CallbackEffects::class)]
26#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Objects\ObjectEffects::class)]
27#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\PropertyWrites::class)]
28#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\SliceExecutor::class)]
29#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Slice\Arrival::class)]
30#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Slice\AssignmentSteps::class)]
31#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::class)]
32#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses::class)]
33#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Slice\Pending::class)]
34#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\Solution::class)]
35#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\SourceTree::class)]
36#[UsesClass(\SqlCatalog\Core\Analysis\EntryFactory::class)]
37#[UsesClass(\SqlCatalog\Core\Analysis\EvaluationBudget::class)]
38#[UsesClass(\SqlCatalog\Core\Analysis\ExpressionEvaluator::class)]
39#[UsesClass(\SqlCatalog\Core\Analysis\ExternalInput::class)]
40#[UsesClass(\SqlCatalog\Core\Analysis\FunctionScope::class)]
41#[UsesClass(\SqlCatalog\Core\Analysis\Interpreter::class)]
42#[UsesClass(\SqlCatalog\Core\Analysis\Model\ModelQueries::class)]
43#[UsesClass(\SqlCatalog\Core\Analysis\QueryRecord::class)]
44#[UsesClass(\SqlCatalog\Core\Analysis\ReferenceEvaluator::class)]
45#[UsesClass(\SqlCatalog\Core\Analysis\SinkFinder::class)]
46#[UsesClass(\SqlCatalog\Core\Analysis\SinkMatcher::class)]
47#[UsesClass(\SqlCatalog\Core\Analysis\StatementRecorder::class)]
48#[UsesClass(\SqlCatalog\Core\Analysis\ValueBinder::class)]
49#[UsesClass(\SqlCatalog\Facade\Analyzer::class)]
50#[UsesClass(\SqlCatalog\Core\Catalog\CallSite::class)]
51#[UsesClass(\SqlCatalog\Core\Catalog\Catalog::class)]
52#[UsesClass(\SqlCatalog\Core\Catalog\CatalogEntry::class)]
53#[UsesClass(\SqlCatalog\Core\Catalog\EntryIdentity::class)]
54#[UsesClass(\SqlCatalog\Core\Catalog\Placeholder::class)]
55#[UsesClass(\SqlCatalog\Core\Catalog\Resolution::class)]
56#[UsesClass(\SqlCatalog\Core\Catalog\ValueDomain::class)]
57#[UsesClass(\SqlCatalog\Core\Evaluation\ArrayEntry::class)]
58#[UsesClass(\SqlCatalog\Core\Evaluation\ArrayTerm::class)]
59#[UsesClass(\SqlCatalog\Core\Evaluation\CallResults::class)]
60#[UsesClass(\SqlCatalog\Core\Evaluation\Domain::class)]
61#[UsesClass(\SqlCatalog\Core\Evaluation\Environment::class)]
62#[UsesClass(\SqlCatalog\Core\Evaluation\LiteralTerm::class)]
63#[UsesClass(\SqlCatalog\Core\Evaluation\ObjectMemory::class)]
64#[UsesClass(\SqlCatalog\Core\Evaluation\ObjectTerm::class)]
65#[UsesClass(\SqlCatalog\Extension\Doctrine\DoctrineExtension::class)]
66#[UsesClass(\SqlCatalog\Core\Extension\ExtensionRegistry::class)]
67#[UsesClass(\SqlCatalog\Extension\Laravel\LaravelExtension::class)]
68#[UsesClass(\SqlCatalog\Extension\Laravel\BuilderCalls::class)]
69#[UsesClass(\SqlCatalog\Extension\Laravel\BuilderQueries::class)]
70#[UsesClass(\SqlCatalog\Extension\Laravel\CallbackModel::class)]
71#[UsesClass(\SqlCatalog\Extension\Laravel\Clauses::class)]
72#[UsesClass(\SqlCatalog\Extension\Laravel\Grammar::class)]
73#[UsesClass(\SqlCatalog\Extension\Laravel\Predicates::class)]
74#[UsesClass(\SqlCatalog\Extension\Laravel\QueryState::class)]
75#[UsesClass(\SqlCatalog\Extension\Laravel\SelectCompiler::class)]
76#[UsesClass(\SqlCatalog\Core\Extension\Model\CallContext::class)]
77#[UsesClass(\SqlCatalog\Core\Extension\Model\ModelContext::class)]
78#[UsesClass(\SqlCatalog\Core\Extension\Model\ModelSet::class)]
79#[UsesClass(\SqlCatalog\Core\Extension\Model\QueryOutput::class)]
80#[UsesClass(\SqlCatalog\Extension\Mysqli\MysqliExtension::class)]
81#[UsesClass(\SqlCatalog\Extension\Pdo\PdoExtension::class)]
82#[UsesClass(\SqlCatalog\Core\Extension\SinkSpec::class)]
83#[UsesClass(\SqlCatalog\Extension\WordPress\WordPressExtension::class)]
84#[UsesClass(\SqlCatalog\Core\Php\DeclaredGlobals::class)]
85#[UsesClass(\SqlCatalog\Core\Php\FunctionShape::class)]
86#[UsesClass(\SqlCatalog\Core\Php\NodeText::class)]
87#[UsesClass(\SqlCatalog\Core\Php\ParsedFile::class)]
88#[UsesClass(\SqlCatalog\Core\Php\ProgramIndex::class)]
89#[UsesClass(\SqlCatalog\Core\Php\ProgramIndexBuilder::class)]
90#[UsesClass(\SqlCatalog\Core\Php\SourceParser::class)]
91#[UsesClass(\SqlCatalog\Core\Php\TypeReader::class)]
92#[UsesClass(\SqlCatalog\Core\Source\SourceFile::class)]
93#[UsesClass(\SqlCatalog\Core\Sql\PlaceholderRef::class)]
94#[UsesClass(\SqlCatalog\Core\Sql\PlaceholderScanner::class)]
95#[UsesClass(\SqlCatalog\Core\Sql\SqlLexer::class)]
96#[UsesClass(\SqlCatalog\Core\Sql\SqlToken::class)]
97#[UsesClass(\SqlCatalog\Core\Sql\StatementKindReader::class)]
98#[UsesClass(\SqlCatalog\Core\Sql\TableReader::class)]
99#[UsesClass(\SqlCatalog\Core\Text\LiteralText::class)]
100#[UsesClass(\SqlCatalog\Core\Text\TextPattern::class)]
101#[UsesClass(\SqlCatalog\Core\Type\TypeShape::class)]
102#[UsesClass(\SqlCatalog\Core\Analysis\Derivation\CallerSet::class)]
103#[UsesClass(\SqlCatalog\Core\Evaluation\OpaqueTerm::class)]
104#[UsesClass(\SqlCatalog\Core\Php\ParameterShape::class)]
105#[UsesClass(\SqlCatalog\Core\Analysis\Effect\ReferenceEffects::class)]
106#[UsesClass(\SqlCatalog\Core\Analysis\Effect\WriteEffects::class)]
107#[UsesClass(\SqlCatalog\Core\Analysis\FunctionModel\Registry::class)]
108final class CallModelTest extends TestCase
109{
110    public function testEvaluateModelsFactoriesMutationsAndLeavesOtherCallsAlone(): void
111    {
112        $catalog = (new \SqlCatalog\Facade\Analyzer())->analyzeSource(['query.php' => '<?php use Illuminate\\Support\\Facades\\DB; function name() { return "users"; } DB::table(name())->where("id", 7)->get();'], new \SqlCatalog\Facade\AnalysisOptions(['laravel'], dialect: 'sqlite'));
113        self::assertSame('select * from "users" where "id" = ?', $catalog->entries()[0]->sql());
114        self::assertTrue($catalog->entries()[0]->searchClosed());
115    }
116
117    public function testMatchesClassRecognizesConcreteFrameworkTypesOnlyWhenEnabled(): void
118    {
119        $catalog = (new \SqlCatalog\Facade\Analyzer())->analyzeSource(['query.php' => '<?php function run(\\Illuminate\\Database\\MySqlConnection $db) { $db->table("users")->get(); }'], new \SqlCatalog\Facade\AnalysisOptions(['laravel']));
120        self::assertSame('select * from `users`', $catalog->entries()[0]->sql());
121    }
122}
123