packages/sql-faker/tests/Unit/Provider/SqlGeneratorFactoryTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Provider;
6
7use Faker\Factory;
8use PHPUnit\Framework\Attributes\CoversClass;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Plan\GenerationPlan;
12use SqlFaker\Grammar\Model\Grammar;
13use SqlFaker\Grammar\Model\Production;
14use SqlFaker\Grammar\Model\ProductionRule;
15use SqlFaker\Grammar\Model\Terminal;
16use SqlFaker\Provider\SqlGeneratorFactory;
17
18#[CoversClass(SqlGeneratorFactory::class)]
19#[UsesClass(\SqlFaker\Generation\SqlGenerator::class)]
20#[UsesClass(\SqlFaker\Generation\Derivation\Derivation::class)]
21#[UsesClass(GenerationPlan::class)]
22#[UsesClass(\SqlFaker\Generation\Derivation\TerminationAnalyzer::class)]
23#[UsesClass(\SqlFaker\Generation\Derivation\TerminationCost::class)]
24#[UsesClass(Grammar::class)]
25#[UsesClass(\SqlFaker\MySql\Generation\Tokenization\KeywordIndex::class)]
26#[UsesClass(\SqlFaker\PostgreSql\Generation\Tokenization\KeywordIndex::class)]
27#[UsesClass(\SqlFaker\Sqlite\Generation\Tokenization\KeywordIndex::class)]
28#[UsesClass(\SqlFaker\Generation\Value\RandomCharacters::class)]
29#[UsesClass(\SqlFaker\MySql\Generation\Value\LiteralGenerator::class)]
30#[UsesClass(\SqlFaker\PostgreSql\Generation\Value\LiteralGenerator::class)]
31#[UsesClass(\SqlFaker\Sqlite\Generation\Value\LiteralGenerator::class)]
32#[UsesClass(\SqlFaker\Grammar\Model\TerminalInventory::class)]
33#[UsesClass(\SqlFaker\Grammar\Model\NonTerminal::class)]
34#[UsesClass(Production::class)]
35#[UsesClass(ProductionRule::class)]
36#[UsesClass(\SqlFaker\Grammar\Resource\SqlVersionRegistry::class)]
37#[UsesClass(\SqlFaker\Grammar\Resource\SqlVersion::class)]
38#[UsesClass(Terminal::class)]
39#[UsesClass(\SqlFaker\MySql\Generation\GenerationContext::class)]
40#[UsesClass(\SqlFaker\MySql\Grammar\MySqlGrammar::class)]
41#[UsesClass(\SqlFaker\MySql\Generation\LexicalGrammar::class)]
42#[UsesClass(\SqlFaker\MySql\Generation\Tokenization\MySqlTokenizer::class)]
43#[UsesClass(\SqlFaker\MySql\Generation\StartRuleResolver::class)]
44#[UsesClass(\SqlFaker\PostgreSql\Generation\GenerationContext::class)]
45#[UsesClass(\SqlFaker\PostgreSql\Grammar\PgGrammar::class)]
46#[UsesClass(\SqlFaker\PostgreSql\Generation\LexicalGrammar::class)]
47#[UsesClass(\SqlFaker\PostgreSql\Generation\Lookahead\PgLookahead::class)]
48#[UsesClass(\SqlFaker\PostgreSql\Generation\Tokenization\PgTokenizer::class)]
49#[UsesClass(\SqlFaker\Sqlite\Generation\GenerationContext::class)]
50#[UsesClass(\SqlFaker\Sqlite\Generation\GrammarAdaptation::class)]
51#[UsesClass(\SqlFaker\Sqlite\Grammar\SqliteGrammar::class)]
52#[UsesClass(\SqlFaker\Sqlite\Generation\LexicalGrammar::class)]
53#[UsesClass(\SqlFaker\Sqlite\Generation\Tokenization\SqliteTokenizer::class)]
54#[UsesClass(\SqlFaker\Generation\Derivation\CompletionCosts::class)]
55#[UsesClass(\SqlFaker\Generation\Derivation\DerivationTrace::class)]
56#[UsesClass(\SqlFaker\Generation\Candidate\ChoiceLexemeGenerator::class)]
57#[UsesClass(\SqlFaker\Generation\Candidate\FixedLexemeGenerator::class)]
58#[UsesClass(\SqlFaker\Generation\Candidate\IntegerLexemeGenerator::class)]
59#[UsesClass(\SqlFaker\Generation\Lexeme\Lexeme::class)]
60#[UsesClass(\SqlFaker\Generation\Lexeme\LexemeCandidates::class)]
61#[UsesClass(\SqlFaker\Generation\Lexeme\LexemeInput::class)]
62#[UsesClass(\SqlFaker\Generation\Lexeme\LexemeSequence::class)]
63#[UsesClass(\SqlFaker\Generation\Candidate\MatchingLexemeGenerator::class)]
64#[UsesClass(\SqlFaker\Generation\Candidate\ValueLexemeGenerator::class)]
65#[UsesClass(\SqlFaker\Generation\Candidate\RegisteredLexemeGenerator::class)]
66#[UsesClass(\SqlFaker\Generation\Candidate\SequenceLexemeGenerator::class)]
67#[UsesClass(\SqlFaker\Generation\Output\CandidateResolver::class)]
68#[UsesClass(\SqlFaker\Generation\Lexeme\OutputPart::class)]
69#[UsesClass(\SqlFaker\Generation\Lexeme\ResolvedOutput::class)]
70#[UsesClass(\SqlFaker\Generation\Output\ReverseLexemeGenerator::class)]
71#[UsesClass(\SqlFaker\Generation\Output\SqlSerializer::class)]
72#[UsesClass(\SqlFaker\Generation\Output\CombinedSpacingRule::class)]
73#[UsesClass(\SqlFaker\Generation\Lexeme\SpacingConstraint::class)]
74#[UsesClass(\SqlFaker\Generation\Token\ProductionOccurrence::class)]
75#[UsesClass(\SqlFaker\Generation\Token\TerminalOccurrence::class)]
76#[UsesClass(\SqlFaker\Generation\Token\TerminalSequence::class)]
77#[UsesClass(\SqlFaker\Generation\Derivation\TokenGenerator::class)]
78#[UsesClass(\SqlFaker\Generation\Token\TokenRewriter::class)]
79#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Option\UniqueOptionRule::class)]
80#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Option\UniqueOptionRule::class)]
81#[UsesClass(\SqlFaker\Generation\Candidate\VersionCase::class)]
82#[UsesClass(\SqlFaker\Generation\Candidate\VersionedLexemeGenerator::class)]
83#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\DefinitionFactory::class)]
84#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\KeywordLexemeGenerator::class)]
85#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\AlterDatabaseRule::class)]
86#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\ConstraintEnforcementRule::class)]
87#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\FlushExportRule::class)]
88#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\InstanceActionRule::class)]
89#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\IntegerContextRule::class)]
90#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\LoadSourceCountRule::class)]
91#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\RequiredAliasRule::class)]
92#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\RewriteDefinitions::class)]
93#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\RoleGrantRule::class)]
94#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\SetNamesRule::class)]
95#[UsesClass(\SqlFaker\Sqlite\Generation\Lexeme\DefinitionFactory::class)]
96#[UsesClass(\SqlFaker\Sqlite\Generation\Lexeme\JoinLexemeGenerator::class)]
97#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\IdentifierListRule::class)]
98#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\JoinRule::class)]
99#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\RewriteDefinitions::class)]
100#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\StrictTableRule::class)]
101#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\TableOptionRule::class)]
102#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\WindowFrameRule::class)]
103#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\WithoutRowidRule::class)]
104#[UsesClass(\SqlFaker\Generation\Token\TerminalMappingRule::class)]
105#[UsesClass(\SqlFaker\PostgreSql\Generation\Lexeme\DefinitionFactory::class)]
106#[UsesClass(\SqlFaker\PostgreSql\Generation\Lexeme\HashBoundLexemeGenerator::class)]
107#[UsesClass(\SqlFaker\PostgreSql\Generation\Lexeme\KeywordLexemeGenerator::class)]
108#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\CopySourceRule::class)]
109#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\FetchWithTiesRule::class)]
110#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\FunctionNameRule::class)]
111#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\HashPartitionBoundRule::class)]
112#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\LimitOffsetRule::class)]
113#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\LookaheadRule::class)]
114#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\OperatorArgumentsRule::class)]
115#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\OverlapsArgumentsRule::class)]
116#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\PublicationObjectRule::class)]
117#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\RelationNameRule::class)]
118#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\RewriteDefinitions::class)]
119#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\TimeZoneIntervalRule::class)]
120#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\WindowFrameRule::class)]
121#[UsesClass(\SqlFaker\Generation\Plan\ProductionPattern::class)]
122#[UsesClass(\SqlFaker\Generation\Exception\GenerationException::class)]
123#[UsesClass(\SqlFaker\MySql\Generation\Spacing\KeywordPhraseSpacingRule::class)]
124#[UsesClass(\SqlFaker\Generation\Lexeme\LexemeBoundary::class)]
125#[UsesClass(\SqlFaker\Generation\Exception\LexicalException::class)]
126#[UsesClass(\SqlFaker\MySql\Generation\Spacing\CloneAddressSpacingRule::class)]
127#[UsesClass(\SqlFaker\MySql\Generation\Spacing\FunctionSpacingRule::class)]
128#[UsesClass(\SqlFaker\MySql\Generation\Spacing\QualifiedNameSpacingRule::class)]
129#[UsesClass(\SqlFaker\MySql\Generation\Spacing\VariableSpacingRule::class)]
130#[UsesClass(\SqlFaker\Sqlite\Generation\Lexeme\JoinModifiers::class)]
131#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Expression\ExpressionGroupingRule::class)]
132#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Expression\ExpressionGroupingRule::class)]
133#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\Expression\ExpressionGroupingRule::class)]
134#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\AlterEventRule::class)]
135#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\SubqueryContextRule::class)]
136#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\ConstraintAttributesRule::class)]
137#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\AnyRelationNameRule::class)]
138#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\IndirectionStarRule::class)]
139#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\IntoClauseRule::class)]
140#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\GeneratedColumnRule::class)]
141#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\TransactionCompletionRule::class)]
142#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\GeneratedColumnRule::class)]
143#[UsesClass(\SqlFaker\Sqlite\Generation\Lexeme\WindowNameLexemeGenerator::class)]
144#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Alter\OrderByRule::class)]
145#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\BoundedIntegerLexemeGenerator::class)]
146#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\ReplicationTablePatternLexemeGenerator::class)]
147#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\SizeNumberLexemeGenerator::class)]
148#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\CompoundSelectRule::class)]
149#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\UpsertSourceRule::class)]
150#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\FunctionArgumentRule::class)]
151#[UsesClass(\SqlFaker\Sqlite\Generation\Rewrite\GeneratedColumnRule::class)]
152#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Replication\StartRule::class)]
153#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Query\SelectOptionsRule::class)]
154#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\TableFunctionRule::class)]
155#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\TypeModifierRule::class)]
156#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Column\IdentityOptionRule::class)]
157#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Query\IntoClauseRule::class)]
158#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Partition\FieldListRule::class)]
159#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Replication\TablePatternRule::class)]
160#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Expression\QuantifiedComparisonRule::class)]
161#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Expression\TableValueConstructorRule::class)]
162#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Query\QueryContextRule::class)]
163#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Query\JoinGroupingRule::class)]
164#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\WithinGroupRule::class)]
165#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Column\FieldLengthRule::class)]
166#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Routine\ReturnRule::class)]
167#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\ColumnNameRule::class)]
168#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Name\SystemVariableRule::class)]
169#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Column\AutoIncrementRule::class)]
170#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Partition\DefinitionRule::class)]
171#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Partition\ListValueRule::class)]
172#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Routine\LanguageRule::class)]
173#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\FactorLexemeGenerator::class)]
174#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\PrecisionLexemeGenerator::class)]
175#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\AliasRule::class)]
176#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Partition\ValueArityRule::class)]
177#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Partition\ValueShape::class)]
178#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\SubstringRule::class)]
179#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\RangeFunctionOrdinalityRule::class)]
180#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Query\WindowFrameRule::class)]
181#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\JsonOptionsRule::class)]
182#[UsesClass(\SqlFaker\Generation\Value\CharacterDomain::class)]
183#[UsesClass(\SqlFaker\Generation\Value\ChoiceDomain::class)]
184#[UsesClass(\SqlFaker\Generation\Value\IntegerDomain::class)]
185#[UsesClass(\SqlFaker\Generation\Value\SequenceDomain::class)]
186#[UsesClass(\SqlFaker\MySql\Generation\Value\DollarQuotedDomain::class)]
187#[UsesClass(\SqlFaker\PostgreSql\Generation\Value\DollarQuotedDomain::class)]
188#[UsesClass(\SqlFaker\Generation\Output\BoundaryCompletion::class)]
189#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Column\ConstraintCapabilitiesRule::class)]
190#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Column\ForeignKeyActionRule::class)]
191#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Query\SchemaElementsRule::class)]
192#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Query\ParserOptionsRule::class)]
193#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\JsonTablePathRule::class)]
194#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Routine\AggregateArgumentRule::class)]
195#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Expression\ConcatenationRule::class)]
196#[UsesClass(\SqlFaker\Generation\Derivation\CompletionState::class)]
197#[UsesClass(\SqlFaker\Generation\Derivation\CompletionFrontier::class)]
198#[UsesClass(\SqlFaker\Generation\Derivation\ConstrainedCompletion::class)]
199#[UsesClass(\SqlFaker\Generation\Value\ValueChoices::class)]
200#[UsesClass(\SqlFaker\Generation\Derivation\CompletionMemo::class)]
201#[UsesClass(\SqlFaker\Generation\Derivation\CompletionReduction::class)]
202#[UsesClass(\SqlFaker\Generation\Derivation\ConstraintDependencies::class)]
203#[UsesClass(\SqlFaker\Generation\Choice\BytePlanCompiler::class)]
204#[UsesClass(\SqlFaker\MySql\Generation\Rewrite\Name\HostNameRule::class)]
205#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Name\ParserNameRule::class)]
206#[UsesClass(\SqlFaker\PostgreSql\Generation\Rewrite\Column\NumericContextRule::class)]
207#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\CharsetLexemeGenerator::class)]
208#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\CharsetValueLexemeGenerator::class)]
209#[UsesClass(\SqlFaker\MySql\Generation\Value\IdentifierDomain::class)]
210#[UsesClass(\SqlFaker\PostgreSql\Generation\Value\IdentifierDomain::class)]
211#[UsesClass(\SqlFaker\Sqlite\Generation\Value\IdentifierDomain::class)]
212#[UsesClass(\SqlFaker\MySql\Generation\Value\QuotedDomain::class)]
213#[UsesClass(\SqlFaker\PostgreSql\Generation\Value\QuotedDomain::class)]
214#[UsesClass(\SqlFaker\Sqlite\Generation\Value\QuotedDomain::class)]
215#[UsesClass(\SqlFaker\MySql\Generation\Value\RadixDomain::class)]
216#[UsesClass(\SqlFaker\Generation\Value\RepeatDomain::class)]
217#[UsesClass(\SqlFaker\Generation\Value\WordDomain::class)]
218#[UsesClass(\SqlFaker\Generation\Derivation\Completion\PatternProductions::class)]
219#[UsesClass(\SqlFaker\Generation\Derivation\Completion\CompletionWitness::class)]
220#[UsesClass(\SqlFaker\PostgreSql\Generation\Value\OperatorDomain::class)]
221#[UsesClass(\SqlFaker\Generation\Value\Utf8::class)]
222#[UsesClass(\SqlFaker\MySql\Generation\Lexeme\LexicalDefinition::class)]
223#[UsesClass(\SqlFaker\PostgreSql\Generation\Lexeme\LexicalDefinition::class)]
224#[UsesClass(\SqlFaker\Sqlite\Generation\Lexeme\LexicalDefinition::class)]
225final class SqlGeneratorFactoryTest extends TestCase
226{
227 public function testForMySqlPreservesTheGrammarEntryPointAndBindsLexicalDefinitions(): void
228 {
229 $faker = Factory::create();
230 $faker->seed(17);
231 $grammar = new Grammar('entry', [
232 'entry' => new ProductionRule('entry', [new Production([new Terminal('SELECT_SYM')])]),
233 ]);
234 $generator = SqlGeneratorFactory::forMySql($faker, $grammar, 'mysql-8.4.7');
235
236 self::assertMatchesRegularExpression('/SELECT/i', $generator->generate(GenerationPlan::all()));
237 self::assertSame('7', $generator->generate(GenerationPlan::lexical('integer_literal', ['min' => 7, 'max' => 7])));
238 }
239
240 public function testForPostgreSqlPreservesTheGrammarEntryPointAndBindsLexicalDefinitions(): void
241 {
242 $faker = Factory::create();
243 $faker->seed(17);
244 $grammar = new Grammar('entry', [
245 'entry' => new ProductionRule('entry', [new Production([new Terminal('SELECT')])]),
246 ]);
247 $generator = SqlGeneratorFactory::forPostgreSql($faker, $grammar, 'pg-17.2');
248
249 self::assertMatchesRegularExpression('/SELECT/i', $generator->generate(GenerationPlan::all()));
250 self::assertSame('7', $generator->generate(GenerationPlan::lexical('integer_literal', ['min' => 7, 'max' => 7])));
251 }
252
253 public function testForSqlitePreservesTheGrammarEntryPointAndBindsLexicalDefinitions(): void
254 {
255 $faker = Factory::create();
256 $faker->seed(17);
257 $grammar = new Grammar('entry', [
258 'entry' => new ProductionRule('entry', [new Production([new Terminal('SELECT')])]),
259 ]);
260 $generator = SqlGeneratorFactory::forSqlite($faker, $grammar, 'sqlite-3.47.2');
261
262 self::assertMatchesRegularExpression('/SELECT/i', $generator->generate(GenerationPlan::all()));
263 self::assertSame('7', $generator->generate(GenerationPlan::lexical('integer_literal', ['min' => 7, 'max' => 7])));
264 }
265}
266