packages/sql-faker/tests/Unit/Compiler/Lemon/LemonPreprocessorTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Compiler\Lemon;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\Small;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use RuntimeException;
12use SqlFaker\Compiler\Lemon\LemonCondition;
13use SqlFaker\Compiler\Lemon\LemonPreprocessor;
14
15#[CoversClass(LemonPreprocessor::class)]
16#[UsesClass(LemonCondition::class)]
17#[Small]
18final class LemonPreprocessorTest extends TestCase
19{
20    public function testProcessSelectsNestedSourceBranchesAndPreservesLineCount(): void
21    {
22        $input = <<<'LEMON'
23%ifdef EXTENSION
24extension ::= ENABLED.
25%ifndef OMIT_FEATURE
26feature ::= KEPT.
27%endif OMIT_FEATURE
28%else
29extension ::= DISABLED.
30%ifdef NOT_ENABLED
31omitted ::= NEVER.
32%else
33fallback ::= DEFAULT.
34%endif
35%endif
36root ::= END.
37LEMON;
38        $enabled = (new LemonPreprocessor(new LemonCondition(['EXTENSION'])))->process($input);
39        self::assertStringContainsString('extension ::= ENABLED.', $enabled);
40        self::assertStringContainsString('feature ::= KEPT.', $enabled);
41        self::assertStringNotContainsString('DISABLED', $enabled);
42        self::assertStringNotContainsString('DEFAULT', $enabled);
43        self::assertSame(substr_count($input, "\n"), substr_count($enabled, "\n"));
44        $disabled = (new LemonPreprocessor())->process($input);
45        self::assertStringContainsString('extension ::= DISABLED.', $disabled);
46        self::assertStringContainsString('fallback ::= DEFAULT.', $disabled);
47        self::assertStringNotContainsString('NEVER', $disabled);
48    }
49
50    public function testProcessHandlesSqliteUpdateDeleteLimitCondition(): void
51    {
52        $input = "%if LIMIT || CAPABLE\ncmd ::= DELETE ORDER BY.\n%else\ncmd ::= DELETE.\n%endif\n";
53        self::assertSame("\n\n\ncmd ::= DELETE.\n\n", (new LemonPreprocessor())->process($input));
54        self::assertSame("\ncmd ::= DELETE ORDER BY.\n\n\n\n", (new LemonPreprocessor(new LemonCondition(['CAPABLE'])))->process($input));
55    }
56
57    public function testProcessRejectsUnmatchedElse(): void
58    {
59        $this->expectException(RuntimeException::class);
60        (new LemonPreprocessor())->process("%else\n");
61    }
62
63    public function testProcessRejectsRepeatedElse(): void
64    {
65        $this->expectException(RuntimeException::class);
66        (new LemonPreprocessor())->process("%ifdef YES\n%else\n%else\n%endif\n");
67    }
68
69    public function testProcessRejectsUnterminatedConditionalsEvenWhenActive(): void
70    {
71        $this->expectException(RuntimeException::class);
72        (new LemonPreprocessor())->process("%ifndef NO\ncmd ::= YES.\n");
73    }
74}
75