packages/sql-faker/tests/Unit/MySql/Generation/Spacing/CloneAddressSpacingRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Spacing;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Lexeme\Lexeme;
12use SqlFaker\Generation\Lexeme\LexemeBoundary;
13use SqlFaker\Generation\Lexeme\LexemeInput;
14use SqlFaker\Generation\Lexeme\ResolvedOutput;
15use SqlFaker\Generation\Lexeme\SpacingConstraint;
16use SqlFaker\Generation\Lexeme\SpacingRule;
17use SqlFaker\Generation\Token\TerminalOccurrence;
18use SqlFaker\Generation\Token\TerminalSequence;
19use SqlFaker\MySql\Generation\Spacing\CloneAddressSpacingRule;
20
21#[CoversClass(CloneAddressSpacingRule::class)]
22#[UsesClass(Lexeme::class)]
23#[UsesClass(LexemeBoundary::class)]
24#[UsesClass(LexemeInput::class)]
25#[UsesClass(ResolvedOutput::class)]
26#[UsesClass(SpacingConstraint::class)]
27#[UsesClass(SpacingRule::class)]
28#[UsesClass(TerminalOccurrence::class)]
29#[UsesClass(TerminalSequence::class)]
30#[UsesClass(\SqlFaker\Generation\Lexeme\LexemeSequence::class)]
31#[UsesClass(\SqlFaker\Generation\Token\ProductionOccurrence::class)]
32final class CloneAddressSpacingRuleTest extends TestCase
33{
34    public function testApplyConstrainsOnlyItsSourceDefinedBoundary(): void
35    {
36        $origin = new TerminalOccurrence('TOKEN', 1, [0], ['clone_stmt']);
37        $input = new LexemeInput(new TerminalSequence([$origin]), 0, new ResolvedOutput());
38        $left = new Lexeme('host', 'identifier', $origin, 'source');
39        $right = new Lexeme(':', 'symbol', $origin, 'source');
40        $rule = new CloneAddressSpacingRule();
41        self::assertSame(SpacingConstraint::JOIN, $rule->apply(new LexemeBoundary($left, $right), $input)?->allowed);
42        $plain = new Lexeme('word', 'keyword', new TerminalOccurrence('OTHER', 2), 'other');
43        self::assertNull($rule->apply(new LexemeBoundary($plain, $plain), $input));
44    }
45
46    #[DataProvider('providerColonSides')]
47    public function testApplyRecognizesAFlatStatementAndBothSidesOfTheAddressColon(bool $left): void
48    {
49        $sequence = TerminalSequence::fromNames(['CLONE_SYM', 'INSTANCE_SYM', 'FROM', 'HOST', ':', 'PORT']);
50        $input = new LexemeInput($sequence, 3, new ResolvedOutput());
51        $host = new Lexeme('host', 'string', $sequence->terminals[3], 'host');
52        $colon = new Lexeme(':', 'symbol', $sequence->terminals[4], 'colon');
53        $port = new Lexeme('3306', 'number', $sequence->terminals[5], 'port');
54        $rule = new CloneAddressSpacingRule();
55        $boundary = $left ? new LexemeBoundary($colon, $port) : new LexemeBoundary($host, $colon);
56        $constraint = $rule->apply($boundary, $input);
57        self::assertNotNull($constraint);
58        self::assertSame(SpacingConstraint::JOIN, $constraint->allowed);
59        self::assertSame(['mysql.clone-address'], $constraint->rules);
60        self::assertNull($rule->apply($boundary, new LexemeInput(TerminalSequence::fromNames(['OTHER']), 0, new ResolvedOutput())));
61    }
62    /**
63     * @return iterable<array{bool}>
64     */
65    public static function providerColonSides(): iterable
66    {
67        yield [false];
68        yield [true];
69    }
70}
71