packages/sql-fixture/tests/Unit/Plan/ColumnRefTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Plan;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\Test;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFixture\Plan\ColumnRef;
12use SqlFixture\Plan\PlanSyntaxException;
13
14#[CoversClass(ColumnRef::class)]
15#[UsesClass(PlanSyntaxException::class)]
16#[UsesClass(\SqlFixture\Plan\FixturePlan::class)]
17#[UsesClass(\SqlFixture\Plan\PlanParser::class)]
18#[UsesClass(\SqlFixture\Plan\PlanPrinter::class)]
19#[UsesClass(\SqlFixture\Plan\Relation::class)]
20#[UsesClass(\SqlFixture\Plan\RelationKind::class)]
21#[UsesClass(\SqlFixture\Plan\RelationSide::class)]
22#[UsesClass(\SqlFixture\Plan\Parsing\PlanStatements::class)]
23#[UsesClass(\SqlFixture\Plan\Parsing\RelationCursor::class)]
24#[UsesClass(\SqlFixture\Plan\Parsing\RelationReader::class)]
25#[UsesClass(\SqlFixture\Plan\PlanStructureException::class)]
26#[UsesClass(\SqlFixture\Plan\Printing\PlanTables::class)]
27#[UsesClass(\SqlFixture\Plan\Printing\RelationGroups::class)]
28#[UsesClass(\SqlFixture\Plan\Printing\StatementPrinter::class)]
29#[UsesClass(\SqlFixture\Plan\Validation\PlanValidation::class)]
30#[UsesClass(\SqlFixture\Plan\Validation\TableName::class)]
31#[UsesClass(\SqlFixture\Plan\Exception\EmptyPlanException::class)]
32#[UsesClass(\SqlFixture\Plan\Exception\EmptyTableNameException::class)]
33#[UsesClass(\SqlFixture\Plan\Exception\MissingEndpointColumnsException::class)]
34#[UsesClass(\SqlFixture\Plan\Exception\InvalidTableNameException::class)]
35#[UsesClass(\SqlFixture\Plan\Exception\UnbalancedBracketsException::class)]
36#[UsesClass(\SqlFixture\Plan\Exception\UnexpectedPlanTokenException::class)]
37#[UsesClass(\SqlFixture\Plan\Exception\UnsupportedManyToManyException::class)]
38#[UsesClass(\SqlFixture\Plan\Exception\CompositeArityMismatchException::class)]
39#[UsesClass(\SqlFixture\Plan\Exception\DuplicateColumnBindingException::class)]
40#[UsesClass(\SqlFixture\Plan\Exception\CyclicDependencyException::class)]
41#[UsesClass(\SqlFixture\Plan\Exception\UnboundedSelfReferenceException::class)]
42#[UsesClass(\SqlFixture\Plan\Choice\ChoiceValidation::class)]
43#[UsesClass(\SqlFixture\Plan\Choice\PlanContents::class)]
44final class ColumnRefTest extends TestCase
45{
46    #[Test]
47    public function testNamesATableAndItsColumns(): void
48    {
49        $ref = new ColumnRef('order', ['id']);
50
51        self::assertSame('order', $ref->table);
52        self::assertSame(['id'], $ref->columns);
53    }
54
55    #[Test]
56    public function testOfBuildsFromVariadicColumns(): void
57    {
58        $ref = ColumnRef::of('order', 'shop_id', 'no');
59
60        self::assertSame(['shop_id', 'no'], $ref->columns);
61    }
62
63    #[Test]
64    public function testIsCompositeASingleColumnIsNotComposite(): void
65    {
66        self::assertFalse(ColumnRef::of('order', 'id')->isComposite());
67    }
68
69    #[Test]
70    public function testSeveralColumnsAreComposite(): void
71    {
72        self::assertTrue(ColumnRef::of('order', 'shop_id', 'no')->isComposite());
73    }
74
75    #[Test]
76    public function testToStringPrintsASingleColumnWithADot(): void
77    {
78        self::assertSame('order.id', ColumnRef::of('order', 'id')->toString());
79    }
80
81    #[Test]
82    public function testPrintsCompositeColumnsInParentheses(): void
83    {
84        self::assertSame('order.(shop_id, no)', ColumnRef::of('order', 'shop_id', 'no')->toString());
85    }
86
87    #[Test]
88    public function testCastsToItsWrittenForm(): void
89    {
90        self::assertSame('order.id', (string) ColumnRef::of('order', 'id'));
91    }
92
93    #[Test]
94    public function testEqualsComparesTableAndColumns(): void
95    {
96        self::assertTrue(ColumnRef::of('order', 'id')->equals(ColumnRef::of('order', 'id')));
97        self::assertFalse(ColumnRef::of('order', 'id')->equals(ColumnRef::of('order', 'no')));
98        self::assertFalse(ColumnRef::of('order', 'id')->equals(ColumnRef::of('shipment', 'id')));
99    }
100
101    #[Test]
102    public function testFromReadsASingleColumnEndpoint(): void
103    {
104        $ref = ColumnRef::from('order.id');
105
106        self::assertSame('order', $ref->table);
107        self::assertSame(['id'], $ref->columns);
108    }
109
110    #[Test]
111    public function testFromReadsACompositeEndpoint(): void
112    {
113        $ref = ColumnRef::from('order.(shop_id, no)');
114
115        self::assertSame(['shop_id', 'no'], $ref->columns);
116    }
117
118    #[Test]
119    public function testFromStripsQuoting(): void
120    {
121        self::assertSame('order.id', ColumnRef::from('`order`."id"')->toString());
122    }
123
124    #[Test]
125    public function testFromIgnoresSpaceAroundACompositeList(): void
126    {
127        self::assertSame(['shop_id', 'no'], ColumnRef::from('order. (shop_id, no) ')->columns);
128    }
129
130    #[Test]
131    public function testFromDropsEmptyEntriesWithoutLeavingGapsInTheList(): void
132    {
133        self::assertSame(['a', 'b'], ColumnRef::from('order.(a, , b)')->columns);
134    }
135
136    #[Test]
137    public function testOfKeepsColumnsInTheOrderGiven(): void
138    {
139        self::assertSame(['shop_id', 'no'], ColumnRef::of('order', 'shop_id', 'no')->columns);
140    }
141
142    #[Test]
143    public function testOfReindexesColumnsSpreadFromAKeyedArray(): void
144    {
145        self::assertSame(['shop_id', 'no'], ColumnRef::of('order', ...['a' => 'shop_id', 'b' => 'no'])->columns);
146    }
147}
148