packages/sql-fixture/tests/Unit/Fixture/GenerationRunTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Fixture;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\Test;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFixture\Fixture\GenerationRun;
12use SqlFixture\Fixture\RowSpec;
13use SqlFixture\Plan\FixturePlan;
14use SqlFixture\Schema\ColumnDefinition;
15use SqlFixture\Schema\TableSchema;
16
17#[CoversClass(GenerationRun::class)]
18#[UsesClass(RowSpec::class)]
19#[UsesClass(FixturePlan::class)]
20#[UsesClass(\SqlFixture\Fixture\FixtureSet::class)]
21#[UsesClass(TableSchema::class)]
22#[UsesClass(ColumnDefinition::class)]
23#[UsesClass(\SqlFixture\Fixture\OverrideRows::class)]
24#[UsesClass(\SqlFixture\Fixture\TableOverrides::class)]
25#[UsesClass(\SqlFixture\Plan\ColumnRef::class)]
26#[UsesClass(\SqlFixture\Plan\PlanParser::class)]
27#[UsesClass(\SqlFixture\Plan\PlanPrinter::class)]
28#[UsesClass(\SqlFixture\Plan\PlanSyntaxException::class)]
29#[UsesClass(\SqlFixture\Plan\Relation::class)]
30#[UsesClass(\SqlFixture\Plan\RelationKind::class)]
31#[UsesClass(\SqlFixture\Plan\RelationSide::class)]
32#[UsesClass(\SqlFixture\Plan\Parsing\PlanStatements::class)]
33#[UsesClass(\SqlFixture\Plan\Parsing\RelationCursor::class)]
34#[UsesClass(\SqlFixture\Plan\Parsing\RelationReader::class)]
35#[UsesClass(\SqlFixture\Plan\PlanStructureException::class)]
36#[UsesClass(\SqlFixture\Plan\Printing\PlanTables::class)]
37#[UsesClass(\SqlFixture\Plan\Printing\RelationGroups::class)]
38#[UsesClass(\SqlFixture\Plan\Printing\StatementPrinter::class)]
39#[UsesClass(\SqlFixture\Plan\Validation\PlanValidation::class)]
40#[UsesClass(\SqlFixture\Plan\Validation\TableName::class)]
41#[UsesClass(\SqlFixture\Plan\Exception\EmptyPlanException::class)]
42#[UsesClass(\SqlFixture\Plan\Exception\EmptyTableNameException::class)]
43#[UsesClass(\SqlFixture\Plan\Exception\MissingEndpointColumnsException::class)]
44#[UsesClass(\SqlFixture\Plan\Exception\InvalidTableNameException::class)]
45#[UsesClass(\SqlFixture\Plan\Exception\UnbalancedBracketsException::class)]
46#[UsesClass(\SqlFixture\Plan\Exception\UnexpectedPlanTokenException::class)]
47#[UsesClass(\SqlFixture\Plan\Exception\UnsupportedManyToManyException::class)]
48#[UsesClass(\SqlFixture\Plan\Exception\CompositeArityMismatchException::class)]
49#[UsesClass(\SqlFixture\Plan\Exception\DuplicateColumnBindingException::class)]
50#[UsesClass(\SqlFixture\Plan\Exception\CyclicDependencyException::class)]
51#[UsesClass(\SqlFixture\Plan\Exception\UnboundedSelfReferenceException::class)]
52final class GenerationRunTest extends TestCase
53{
54 #[Test]
55 public function testClaimingATableStopsASecondWalkStarting(): void
56 {
57 $run = new GenerationRun([]);
58 $run->claim(['order', 'customer']);
59
60 self::assertTrue($run->hasVisited('order'));
61 self::assertTrue($run->hasVisited('customer'));
62 self::assertFalse($run->hasVisited('product'));
63 }
64
65 #[Test]
66 public function testReachedReachingATableAsAListSticks(): void
67 {
68 $run = new GenerationRun([]);
69 $run->claim(['order_detail']);
70 $run->reached('order_detail', true);
71 $run->reached('order_detail', false);
72
73 $plan = FixturePlan::table('order_detail');
74 self::assertSame([], $run->toSet($plan)['order_detail']);
75 }
76
77 #[Test]
78 public function testToSetATableReachedOnlyAsASingleRowReadsBackAsOne(): void
79 {
80 $schema = new TableSchema('order', [
81 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
82 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
83 ], ['id']);
84 $run = new GenerationRun([]);
85 $run->reached('order', false);
86 $run->record($schema, ['status' => 'paid']);
87
88 self::assertSame(
89 ['status' => 'paid'],
90 $run->toSet(FixturePlan::table('order'))['order']
91 );
92 }
93
94 #[Test]
95 public function testAKeyNothingReadsIsLeftToTheDatabase(): void
96 {
97 $schema = new TableSchema('order', [
98 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
99 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
100 ], ['id']);
101 $run = new GenerationRun([]);
102
103 self::assertArrayNotHasKey('id', $run->record($schema, ['status' => 'paid']));
104 }
105
106 #[Test]
107 public function testAKeyARelationReadsIsStoodInFor(): void
108 {
109 $schema = new TableSchema('order', [
110 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
111 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
112 ], ['id']);
113 $run = new GenerationRun([]);
114
115 self::assertSame(1, $run->record($schema, [], ['id'])['id']);
116 self::assertSame(2, $run->record($schema, [], ['id'])['id']);
117 }
118
119 #[Test]
120 public function testRecordKeepsAKeyTheCallerSupplied(): void
121 {
122 $schema = new TableSchema('order', [
123 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
124 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
125 ], ['id']);
126 $run = new GenerationRun([]);
127
128 self::assertSame(100, $run->record($schema, ['id' => 100], ['id'])['id']);
129 }
130
131 #[Test]
132 public function testOnlyAutoIncrementColumnsAreStoodInFor(): void
133 {
134 $schema = new TableSchema('order', [
135 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
136 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
137 ], ['id']);
138 $run = new GenerationRun([]);
139
140 self::assertArrayNotHasKey('status', $run->record($schema, [], ['status']));
141 }
142
143 #[Test]
144 public function testWasAskedForReportsWhatTheCallerMentioned(): void
145 {
146 $run = new GenerationRun(['order' => RowSpec::from('order', 2)]);
147
148 self::assertTrue($run->wasAskedFor('order'));
149 self::assertFalse($run->wasAskedFor('customer'));
150 }
151
152 #[Test]
153 public function testSpecForFallsBackToUnspecified(): void
154 {
155 $run = new GenerationRun(['order' => RowSpec::from('order', 2)]);
156
157 self::assertSame(2, $run->specFor('order')->count);
158 self::assertNull($run->specFor('customer')->count);
159 }
160
161 #[Test]
162 public function testATableThatGeneratedNothingReadsBackAsNull(): void
163 {
164 $run = new GenerationRun([]);
165
166 self::assertNull($run->toSet(FixturePlan::table('order'))['order']);
167 }
168
169 #[Test]
170 public function testClaimingDoesNotUndoWhatTheWalkAlreadyLearnt(): void
171 {
172 $schema = new TableSchema('order', [
173 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
174 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
175 ], ['id']);
176 $run = new GenerationRun([]);
177 $run->reached('order', true);
178 $run->claim(['order']);
179 $run->record($schema, ['status' => 'paid']);
180
181 self::assertSame(
182 [['status' => 'paid']],
183 $run->toSet(FixturePlan::table('order'))['order']
184 );
185 }
186
187 #[Test]
188 public function testAClaimedTableThatWasNeverReachedIsNotAList(): void
189 {
190 $run = new GenerationRun([]);
191 $run->claim(['order']);
192
193 self::assertNull($run->toSet(FixturePlan::table('order'))['order']);
194 }
195
196 #[Test]
197 public function testEveryReferencedColumnIsConsideredNotJustTheFirst(): void
198 {
199 $schema = new TableSchema('order', [
200 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
201 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
202 ], ['id']);
203 $run = new GenerationRun([]);
204
205 $row = $run->record($schema, [], ['status', 'id']);
206
207 self::assertSame(1, $row['id']);
208 }
209
210 #[Test]
211 public function testRecordReturnsTheWholeRow(): void
212 {
213 $schema = new TableSchema('order', [
214 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
215 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
216 ], ['id']);
217 $run = new GenerationRun([]);
218
219 self::assertSame(
220 ['status' => 'paid', 'id' => 1],
221 $run->record($schema, ['status' => 'paid'], ['id'])
222 );
223 }
224 public function testLastRowReturnsTheMostRecentRecordedValues(): void
225 {
226 $schema = new TableSchema('order', [
227 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
228 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
229 ], ['id']);
230 $run = new GenerationRun([]);
231 $run->record($schema, ['status' => 'new']);
232 $run->record($schema, ['status' => 'paid']);
233 self::assertSame(['status' => 'paid'], $run->lastRow('order'));
234 self::assertSame([], $run->lastRow('unknown'));
235 }
236 public function testHasVisitedDistinguishesNewAndClaimedTables(): void
237 {
238 $run = new GenerationRun([]);
239 self::assertFalse($run->hasVisited('order'));
240 $run->claim(['order']);
241 self::assertTrue($run->hasVisited('order'));
242 }
243}
244