packages/sql-fixture/tests/Unit/Plan/Choice/ChoiceLiteralTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Plan\Choice;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFixture\Fixture\Choice\ChoiceValueException;
12use SqlFixture\Fixture\GenerationRun;
13use SqlFixture\Fixture\RowSpec;
14use SqlFixture\Plan\Choice\ChoiceCase;
15use SqlFixture\Plan\Choice\ChoiceDefinitionException;
16use SqlFixture\Plan\Choice\ChoiceLiteral as Subject;
17use SqlFixture\Plan\ColumnRef;
18use SqlFixture\Plan\FixturePlan;
19use SqlFixture\Plan\Parsing\RelationCursor;
20use SqlFixture\Plan\Relation;
21use SqlFixture\Plan\RelationChoice;
22
23#[CoversClass(Subject::class)]
24#[UsesClass(\SqlFixture\Fixture\Choice\CaseSelection::class)]
25#[UsesClass(\SqlFixture\Fixture\Choice\ChoiceBindings::class)]
26#[UsesClass(ChoiceValueException::class)]
27#[UsesClass(\SqlFixture\Fixture\Choice\InverseRelations::class)]
28#[UsesClass(\SqlFixture\Fixture\Choice\ResolvedRow::class)]
29#[UsesClass(\SqlFixture\Fixture\Choice\RowChoices::class)]
30#[UsesClass(GenerationRun::class)]
31#[UsesClass(\SqlFixture\Fixture\OverrideRows::class)]
32#[UsesClass(RowSpec::class)]
33#[UsesClass(\SqlFixture\Fixture\TableOverrides::class)]
34#[UsesClass(ChoiceCase::class)]
35#[UsesClass(ChoiceDefinitionException::class)]
36#[UsesClass(\SqlFixture\Plan\Choice\ChoiceSyntax::class)]
37#[UsesClass(\SqlFixture\Plan\Choice\ChoiceValidation::class)]
38#[UsesClass(\SqlFixture\Plan\Choice\PlanContents::class)]
39#[UsesClass(ColumnRef::class)]
40#[UsesClass(\SqlFixture\Plan\Exception\CompositeArityMismatchException::class)]
41#[UsesClass(\SqlFixture\Plan\Exception\CyclicDependencyException::class)]
42#[UsesClass(\SqlFixture\Plan\Exception\DuplicateColumnBindingException::class)]
43#[UsesClass(\SqlFixture\Plan\Exception\EmptyPlanException::class)]
44#[UsesClass(\SqlFixture\Plan\Exception\EmptyTableNameException::class)]
45#[UsesClass(\SqlFixture\Plan\Exception\InvalidTableNameException::class)]
46#[UsesClass(\SqlFixture\Plan\Exception\MissingEndpointColumnsException::class)]
47#[UsesClass(\SqlFixture\Plan\Exception\UnbalancedBracketsException::class)]
48#[UsesClass(\SqlFixture\Plan\Exception\UnboundedSelfReferenceException::class)]
49#[UsesClass(\SqlFixture\Plan\Exception\UnexpectedPlanTokenException::class)]
50#[UsesClass(\SqlFixture\Plan\Exception\UnsupportedManyToManyException::class)]
51#[UsesClass(FixturePlan::class)]
52#[UsesClass(\SqlFixture\Plan\Parsing\PlanStatements::class)]
53#[UsesClass(RelationCursor::class)]
54#[UsesClass(\SqlFixture\Plan\Parsing\RelationReader::class)]
55#[UsesClass(\SqlFixture\Plan\PlanParser::class)]
56#[UsesClass(\SqlFixture\Plan\PlanPrinter::class)]
57#[UsesClass(\SqlFixture\Plan\PlanStructureException::class)]
58#[UsesClass(\SqlFixture\Plan\PlanSyntaxException::class)]
59#[UsesClass(\SqlFixture\Plan\Printing\PlanTables::class)]
60#[UsesClass(\SqlFixture\Plan\Printing\RelationGroups::class)]
61#[UsesClass(\SqlFixture\Plan\Printing\StatementPrinter::class)]
62#[UsesClass(Relation::class)]
63#[UsesClass(RelationChoice::class)]
64#[UsesClass(\SqlFixture\Plan\RelationKind::class)]
65#[UsesClass(\SqlFixture\Plan\RelationSide::class)]
66#[UsesClass(\SqlFixture\Plan\Validation\PlanValidation::class)]
67#[UsesClass(\SqlFixture\Plan\Validation\TableName::class)]
68final class ChoiceLiteralTest extends TestCase
69{
70    /**
71     * @return list<array{string, string|int|bool|null}>
72     */
73    public static function providerLiterals(): array
74    {
75        return [["'a,b;{c}''d'", "a,b;{c}'d"], ["'1'", '1'], ['1', 1], ['-12', -12], ['0', 0], ['true', true], ['false', false], ['null', null], ["''", '']];
76    }
77
78    #[DataProvider('providerLiterals')]
79    public function testReadPreservesTypeAndAdvancesTheCursor(string $literal, string|int|bool|null $expected): void
80    {
81        $cursor = new RelationCursor($literal . ' {}');
82        self::assertSame($expected, (new Subject())->read($cursor));
83        self::assertSame(strlen($literal), $cursor->offset);
84    }
85
86    #[DataProvider('providerLiterals')]
87    public function testPrintRoundTripsTypedValues(string $literal, string|int|bool|null $value): void
88    {
89        self::assertSame($literal, (new Subject())->print($value));
90    }
91
92    public function testIntegerAcceptsNegativeValues(): void
93    {
94        self::assertSame(-23, (new Subject())->integer('-23', new RelationCursor('-23 {}')));
95    }
96
97
98    #[DataProvider('providerLiterals')]
99    public function testReadStartsAtTheSuppliedOffset(string $literal, string|int|bool|null $expected): void
100    {
101        $cursor = new RelationCursor('prefix ' . $literal . ' {}', 7);
102        self::assertSame($expected, (new Subject())->read($cursor));
103        self::assertSame(7 + strlen($literal), $cursor->offset);
104    }
105}
106