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)]
52#[UsesClass(\SqlFixture\Plan\Choice\ChoiceValidation::class)]
53#[UsesClass(\SqlFixture\Plan\Choice\PlanContents::class)]
54final class GenerationRunTest extends TestCase
55{
56 #[Test]
57 public function testClaimingATableStopsASecondWalkStarting(): void
58 {
59 $run = new GenerationRun([]);
60 $run->claim(['order', 'customer']);
61
62 self::assertTrue($run->hasVisited('order'));
63 self::assertTrue($run->hasVisited('customer'));
64 self::assertFalse($run->hasVisited('product'));
65 }
66
67 #[Test]
68 public function testReachedReachingATableAsAListSticks(): void
69 {
70 $run = new GenerationRun([]);
71 $run->claim(['order_detail']);
72 $run->reached('order_detail', true);
73 $run->reached('order_detail', false);
74
75 $plan = FixturePlan::table('order_detail');
76 self::assertSame([], $run->toSet($plan)['order_detail']);
77 }
78
79 #[Test]
80 public function testToSetATableReachedOnlyAsASingleRowReadsBackAsOne(): void
81 {
82 $schema = new TableSchema('order', [
83 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
84 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
85 ], ['id']);
86 $run = new GenerationRun([]);
87 $run->reached('order', false);
88 $run->record($schema, ['status' => 'paid']);
89
90 self::assertSame(
91 ['status' => 'paid'],
92 $run->toSet(FixturePlan::table('order'))['order']
93 );
94 }
95
96 #[Test]
97 public function testAKeyNothingReadsIsLeftToTheDatabase(): void
98 {
99 $schema = new TableSchema('order', [
100 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
101 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
102 ], ['id']);
103 $run = new GenerationRun([]);
104
105 self::assertArrayNotHasKey('id', $run->record($schema, ['status' => 'paid']));
106 }
107
108 #[Test]
109 public function testAKeyARelationReadsIsStoodInFor(): void
110 {
111 $schema = new TableSchema('order', [
112 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
113 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
114 ], ['id']);
115 $run = new GenerationRun([]);
116
117 self::assertSame(1, $run->record($schema, [], ['id'])['id']);
118 self::assertSame(2, $run->record($schema, [], ['id'])['id']);
119 }
120
121 #[Test]
122 public function testRecordKeepsAKeyTheCallerSupplied(): void
123 {
124 $schema = new TableSchema('order', [
125 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
126 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
127 ], ['id']);
128 $run = new GenerationRun([]);
129
130 self::assertSame(100, $run->record($schema, ['id' => 100], ['id'])['id']);
131 }
132
133 #[Test]
134 public function testOnlyAutoIncrementColumnsAreStoodInFor(): void
135 {
136 $schema = new TableSchema('order', [
137 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
138 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
139 ], ['id']);
140 $run = new GenerationRun([]);
141
142 self::assertArrayNotHasKey('status', $run->record($schema, [], ['status']));
143 }
144
145 #[Test]
146 public function testWasAskedForReportsWhatTheCallerMentioned(): void
147 {
148 $run = new GenerationRun(['order' => RowSpec::from('order', 2)]);
149
150 self::assertTrue($run->wasAskedFor('order'));
151 self::assertFalse($run->wasAskedFor('customer'));
152 }
153
154 #[Test]
155 public function testSpecForFallsBackToUnspecified(): void
156 {
157 $run = new GenerationRun(['order' => RowSpec::from('order', 2)]);
158
159 self::assertSame(2, $run->specFor('order')->count);
160 self::assertNull($run->specFor('customer')->count);
161 }
162
163 #[Test]
164 public function testATableThatGeneratedNothingReadsBackAsNull(): void
165 {
166 $run = new GenerationRun([]);
167
168 self::assertNull($run->toSet(FixturePlan::table('order'))['order']);
169 }
170
171 #[Test]
172 public function testClaimingDoesNotUndoWhatTheWalkAlreadyLearnt(): void
173 {
174 $schema = new TableSchema('order', [
175 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
176 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
177 ], ['id']);
178 $run = new GenerationRun([]);
179 $run->reached('order', true);
180 $run->claim(['order']);
181 $run->record($schema, ['status' => 'paid']);
182
183 self::assertSame(
184 [['status' => 'paid']],
185 $run->toSet(FixturePlan::table('order'))['order']
186 );
187 }
188
189 #[Test]
190 public function testAClaimedTableThatWasNeverReachedIsNotAList(): void
191 {
192 $run = new GenerationRun([]);
193 $run->claim(['order']);
194
195 self::assertNull($run->toSet(FixturePlan::table('order'))['order']);
196 }
197
198 #[Test]
199 public function testEveryReferencedColumnIsConsideredNotJustTheFirst(): void
200 {
201 $schema = new TableSchema('order', [
202 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
203 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
204 ], ['id']);
205 $run = new GenerationRun([]);
206
207 $row = $run->record($schema, [], ['status', 'id']);
208
209 self::assertSame(1, $row['id']);
210 }
211
212 #[Test]
213 public function testRecordReturnsTheWholeRow(): void
214 {
215 $schema = new TableSchema('order', [
216 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
217 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
218 ], ['id']);
219 $run = new GenerationRun([]);
220
221 self::assertSame(
222 ['status' => 'paid', 'id' => 1],
223 $run->record($schema, ['status' => 'paid'], ['id'])
224 );
225 }
226 public function testLastRowReturnsTheMostRecentRecordedValues(): void
227 {
228 $schema = new TableSchema('order', [
229 'id' => new ColumnDefinition('id', 'INT', autoIncrement: true),
230 'status' => new ColumnDefinition('status', 'VARCHAR', length: 20),
231 ], ['id']);
232 $run = new GenerationRun([]);
233 $run->record($schema, ['status' => 'new']);
234 $run->record($schema, ['status' => 'paid']);
235 self::assertSame(['status' => 'paid'], $run->lastRow('order'));
236 self::assertSame([], $run->lastRow('unknown'));
237 }
238 public function testHasVisitedDistinguishesNewAndClaimedTables(): void
239 {
240 $run = new GenerationRun([]);
241 self::assertFalse($run->hasVisited('order'));
242 $run->claim(['order']);
243 self::assertTrue($run->hasVisited('order'));
244 }
245}
246