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