packages/sql-faker/tests/Unit/Generation/Candidate/ChoiceLexemeGeneratorTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Generation\Candidate;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Generation\Candidate\ChoiceLexemeGenerator;
11use SqlFaker\Generation\Candidate\FixedLexemeGenerator;
12use SqlFaker\Generation\Candidate\MatchingLexemeGenerator;
13use SqlFaker\Generation\Lexeme\LexemeCandidates;
14use SqlFaker\Generation\Lexeme\LexemeGenerator;
15use SqlFaker\Generation\Lexeme\LexemeInput;
16use SqlFaker\Generation\Lexeme\ResolvedOutput;
17use SqlFaker\Generation\Token\TerminalSequence;
18
19#[CoversClass(ChoiceLexemeGenerator::class)]
20#[UsesClass(LexemeCandidates::class)]
21#[UsesClass(LexemeInput::class)]
22#[UsesClass(ResolvedOutput::class)]
23#[UsesClass(\SqlFaker\Generation\Token\TerminalOccurrence::class)]
24#[UsesClass(TerminalSequence::class)]
25#[UsesClass(FixedLexemeGenerator::class)]
26#[UsesClass(\SqlFaker\Generation\Lexeme\Lexeme::class)]
27#[UsesClass(\SqlFaker\Generation\Lexeme\LexemeSequence::class)]
28#[UsesClass(MatchingLexemeGenerator::class)]
29#[UsesClass(\SqlFaker\Generation\Lexeme\SpacingConstraint::class)]
30#[UsesClass(\SqlFaker\Generation\Token\ProductionOccurrence::class)]
31final class ChoiceLexemeGeneratorTest extends TestCase
32{
33 public function testGenerateAllMatchingChildrenContributeInDeclarationOrder(): void
34 {
35 $choice = new ChoiceLexemeGenerator(
36 new MatchingLexemeGenerator('OTHER', new FixedLexemeGenerator('unused', 'keyword', 'other')),
37 new FixedLexemeGenerator('CURRENT_TIMESTAMP', 'keyword', 'now-keyword'),
38 new FixedLexemeGenerator('NOW', 'function', 'now-function'),
39 );
40 $input = new LexemeInput(TerminalSequence::fromNames(['NOW_SYM']), 0, new ResolvedOutput());
41 $result = $choice->generate($input);
42 self::assertNotNull($result);
43 self::assertSame(['CURRENT_TIMESTAMP', 'NOW'], array_map(
44 static fn ($candidate): string => $candidate->lexemes[0]->text,
45 [...$result->sequences()],
46 ));
47 }
48
49 public function testAnApplicableEmptyStreamDiffersFromNoApplicableChild(): void
50 {
51 $input = new LexemeInput(TerminalSequence::fromNames(['X']), 0, new ResolvedOutput());
52 self::assertNull((new ChoiceLexemeGenerator())->generate($input));
53 $empty = $this->createMock(LexemeGenerator::class);
54 $empty->method('generate')->willReturn(LexemeCandidates::of());
55 $result = (new ChoiceLexemeGenerator($empty))->generate($input);
56 self::assertNotNull($result);
57 self::assertSame([], [...$result->sequences()]);
58 }
59
60 public function testSourcesIncludesEveryEquivalentCandidateAndExcludesDifferentOutputs(): void
61 {
62 $input = new LexemeInput(TerminalSequence::fromNames(['WORD']), 0, new ResolvedOutput());
63 $a = (new FixedLexemeGenerator('word', 'keyword', 'source:a'))->generate($input);
64 $b = (new FixedLexemeGenerator('word', 'keyword', 'source:b'))->generate($input);
65 $other = (new FixedLexemeGenerator('other', 'keyword', 'source:c'))->generate($input);
66 $key = [...$a->sequences()][0]->key();
67 self::assertSame(['source:a:word', 'source:b:word'], [...(new ChoiceLexemeGenerator())->sources([$a, $b, $other], $key)]);
68 }
69
70}
71