packages/sql-fixture/tests/Unit/Plan/Validation/PlanValidationTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Plan\Validation;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\TestCase;
9use SqlFixture\Plan\Relation;
10use SqlFixture\Plan\Validation\PlanValidation as Subject;
11
12#[CoversClass(Subject::class)]
13#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\ColumnRef::class)]
14#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\FixturePlan::class)]
15#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\PlanParser::class)]
16#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\PlanPrinter::class)]
17#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\PlanStructureException::class)]
18#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\PlanSyntaxException::class)]
19#[\PHPUnit\Framework\Attributes\UsesClass(Relation::class)]
20#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\RelationKind::class)]
21#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\RelationSide::class)]
22#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Parsing\PlanStatements::class)]
23#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Parsing\RelationCursor::class)]
24#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Parsing\RelationReader::class)]
25#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Printing\PlanTables::class)]
26#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Printing\RelationGroups::class)]
27#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Printing\StatementPrinter::class)]
28#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Validation\TableName::class)]
29#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\EmptyPlanException::class)]
30#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\EmptyTableNameException::class)]
31#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\MissingEndpointColumnsException::class)]
32#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\InvalidTableNameException::class)]
33#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\UnbalancedBracketsException::class)]
34#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\UnexpectedPlanTokenException::class)]
35#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\UnsupportedManyToManyException::class)]
36#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\CompositeArityMismatchException::class)]
37#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\DuplicateColumnBindingException::class)]
38#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\CyclicDependencyException::class)]
39#[\PHPUnit\Framework\Attributes\UsesClass(\SqlFixture\Plan\Exception\UnboundedSelfReferenceException::class)]
40final class PlanValidationTest extends TestCase
41{
42    public function testRejectColumnsBoundTwiceAcceptsDistinctForeignKeys(): void
43    {
44        $relations = [Relation::oneToMany('a.id', 'b.a_id'), Relation::oneToMany('a.id', 'b.other_id')];
45        (new Subject())->rejectColumnsBoundTwice($relations);
46        self::assertSame(['a', 'b'], (new Subject())->sortByDependency(['b', 'a'], $relations));
47    }
48
49    public function testRejectUnboundedSelfReferencesAcceptsOptionalChildren(): void
50    {
51        $relations = [Relation::oneToMany('node.id', 'node.parent_id', true)];
52        (new Subject())->rejectUnboundedSelfReferences($relations);
53        self::assertSame(['node'], (new Subject())->sortByDependency(['node'], $relations));
54    }
55
56    public function testSortByDependencyPreservesIndependentOrder(): void
57    {
58        $relations = [Relation::oneToMany('a.id', 'b.a_id')];
59        self::assertSame(['c', 'a', 'b'], (new Subject())->sortByDependency(['b', 'c', 'a'], $relations));
60    }
61
62    public function testWaitsForAnyChecksOnlyPendingParents(): void
63    {
64        $relations = [Relation::oneToMany('a.id', 'b.a_id')];
65        self::assertTrue((new Subject())->waitsForAny('b', $relations, ['a']));
66        self::assertFalse((new Subject())->waitsForAny('b', $relations, ['b']));
67    }
68}
69