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