packages/sql-fixture/tests/Unit/Provider/DatabaseFixtureProviderTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Provider;
6
7use Faker\Factory;
8use PDO;
9use PHPUnit\Framework\Attributes\CoversClass;
10use PHPUnit\Framework\Attributes\Test;
11use PHPUnit\Framework\Attributes\UsesClass;
12use PHPUnit\Framework\TestCase;
13use SqlFixture\Platform\Sqlite\SqliteSchemaFetcher;
14use SqlFixture\Platform\Sqlite\SqliteSchemaParser;
15use SqlFixture\Platform\Sqlite\SqliteTypeMapper;
16use SqlFixture\Provider\DatabaseFixtureProvider;
17use SqlFixture\Provider\FixtureGenerator;
18use SqlFixture\Provider\PlatformFactory;
19use SqlFixture\Schema\ColumnDefinition;
20use SqlFixture\Schema\TableSchema;
21
22#[CoversClass(DatabaseFixtureProvider::class)]
23#[UsesClass(FixtureGenerator::class)]
24#[UsesClass(PlatformFactory::class)]
25#[UsesClass(SqliteSchemaFetcher::class)]
26#[UsesClass(SqliteSchemaParser::class)]
27#[UsesClass(SqliteTypeMapper::class)]
28#[UsesClass(ColumnDefinition::class)]
29#[UsesClass(TableSchema::class)]
30#[CoversClass(\SqlFixture\Provider\DatabaseSchemaCache::class)]
31#[UsesClass(\SqlFixture\Hydrator\HydrationException::class)]
32#[UsesClass(\SqlFixture\Hydrator\HydratorInterface::class)]
33#[UsesClass(\SqlFixture\Hydrator\ReflectionHydrator::class)]
34#[UsesClass(\SqlFixture\Platform\MySql\MySqlSchemaFetcher::class)]
35#[UsesClass(\SqlFixture\Platform\MySql\MySqlSchemaParser::class)]
36#[UsesClass(\SqlFixture\Platform\MySql\MySqlTypeMapper::class)]
37#[UsesClass(\SqlFixture\Platform\PostgreSql\PostgreSqlSchemaFetcher::class)]
38#[UsesClass(\SqlFixture\Platform\PostgreSql\PostgreSqlSchemaParser::class)]
39#[UsesClass(\SqlFixture\Platform\PostgreSql\PostgreSqlTypeMapper::class)]
40#[UsesClass(\SqlFixture\Schema\SchemaFetcherInterface::class)]
41#[UsesClass(\SqlFixture\Schema\SchemaParseException::class)]
42#[UsesClass(\SqlFixture\Schema\SchemaParserInterface::class)]
43#[UsesClass(\SqlFixture\TypeMapper\TypeMapperInterface::class)]
44#[UsesClass(\SqlFixture\Fixture\RowGeneration::class)]
45#[UsesClass(\SqlFixture\Fixture\Validation\OverrideValidator::class)]
46#[UsesClass(\SqlFixture\Hydrator\Reflection\ConstructorHydration::class)]
47#[UsesClass(\SqlFixture\Hydrator\Reflection\PropertyHydration::class)]
48#[UsesClass(\SqlFixture\Hydrator\Reflection\PropertyNames::class)]
49#[UsesClass(\SqlFixture\Hydrator\Reflection\ValueConversion::class)]
50#[UsesClass(\SqlFixture\Fixture\Exception\InvalidOverrideException::class)]
51#[UsesClass(\SqlFixture\Platform\MySql\Schema\ColumnParser::class)]
52#[UsesClass(\SqlFixture\Platform\MySql\Schema\CreateTableQuery::class)]
53#[UsesClass(\SqlFixture\Platform\MySql\Schema\DefaultExpression::class)]
54#[UsesClass(\SqlFixture\Platform\MySql\Schema\DefinitionIntegrity::class)]
55#[UsesClass(\SqlFixture\Platform\MySql\Schema\IdentifierQuoter::class)]
56#[UsesClass(\SqlFixture\Platform\MySql\Schema\TableDefinition::class)]
57#[UsesClass(\SqlFixture\Platform\MySql\Schema\TypeParameters::class)]
58#[UsesClass(\SqlFixture\Platform\MySql\Value\ColumnGenerator::class)]
59#[UsesClass(\SqlFixture\Platform\MySql\Value\DecimalGenerator::class)]
60#[UsesClass(\SqlFixture\Platform\MySql\Value\GeometryGenerator::class)]
61#[UsesClass(\SqlFixture\Platform\MySql\Value\IntegerGenerator::class)]
62#[UsesClass(\SqlFixture\Platform\MySql\Value\NumericGenerator::class)]
63#[UsesClass(\SqlFixture\Platform\MySql\Value\SpatialGenerator::class)]
64#[UsesClass(\SqlFixture\Platform\MySql\Value\StringGenerator::class)]
65#[UsesClass(\SqlFixture\Platform\MySql\Value\TextGenerator::class)]
66#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\CatalogColumn::class)]
67#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\CatalogDdl::class)]
68#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\CatalogQuery::class)]
69#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\CatalogSchema::class)]
70#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\ColumnParser::class)]
71#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\DefaultExpression::class)]
72#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\DefinitionList::class)]
73#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\TableSyntax::class)]
74#[UsesClass(\SqlFixture\Platform\PostgreSql\Schema\TypeDeclaration::class)]
75#[UsesClass(\SqlFixture\Platform\PostgreSql\Value\ColumnGenerator::class)]
76#[UsesClass(\SqlFixture\Platform\PostgreSql\Value\DecimalGenerator::class)]
77#[UsesClass(\SqlFixture\Platform\PostgreSql\Value\NumericGenerator::class)]
78#[UsesClass(\SqlFixture\Platform\PostgreSql\Value\StringGenerator::class)]
79#[UsesClass(\SqlFixture\Platform\PostgreSql\Value\StructuredGenerator::class)]
80#[UsesClass(\SqlFixture\Platform\PostgreSql\Value\TemporalGenerator::class)]
81#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\ColumnParser::class)]
82#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\CreateTableQuery::class)]
83#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\DefaultExpression::class)]
84#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\DefinitionList::class)]
85#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\PragmaColumn::class)]
86#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\PragmaSchema::class)]
87#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\TableSyntax::class)]
88#[UsesClass(\SqlFixture\Platform\Sqlite\Schema\TypeDeclaration::class)]
89#[UsesClass(\SqlFixture\Platform\Sqlite\Value\ColumnGenerator::class)]
90#[UsesClass(\SqlFixture\Platform\Sqlite\Value\TypeAffinity::class)]
91#[UsesClass(\SqlFixture\Schema\DefinitionSegments::class)]
92#[UsesClass(\SqlFixture\Schema\TypeShape::class)]
93#[UsesClass(\SqlFixture\TypeMapper\ParagraphGenerator::class)]
94#[UsesClass(\SqlFixture\Platform\MySql\Schema\TableDefinitionInput::class)]
95#[UsesClass(\SqlFixture\Hydrator\Exception\ClassNotFoundException::class)]
96#[UsesClass(\SqlFixture\Hydrator\Exception\MissingConstructorArgumentException::class)]
97#[UsesClass(\SqlFixture\Fixture\Exception\UnknownOverrideColumnException::class)]
98#[UsesClass(\SqlFixture\Fixture\Exception\NullOverrideException::class)]
99#[UsesClass(\SqlFixture\Fixture\Exception\GeneratedColumnOverrideException::class)]
100#[UsesClass(\SqlFixture\Schema\Exception\InvalidSqlException::class)]
101#[UsesClass(\SqlFixture\Schema\Exception\ExpectedCreateTableException::class)]
102#[UsesClass(\SqlFixture\Schema\Exception\MissingColumnDefinitionsException::class)]
103#[UsesClass(\SqlFixture\TypeMapper\IntegerRange::class)]
104#[UsesClass(\SqlFixture\TypeMapper\IntegerWidth::class)]
105#[UsesClass(\SqlFixture\TypeMapper\DecimalRange::class)]
106#[UsesClass(\SqlFixture\Hydrator\Reflection\ConversionTarget::class)]
107#[UsesClass(\SqlFixture\Fixture\RowGenerator::class)]
108#[UsesClass(\SqlFixture\Version\ServerVersion::class)]
109#[UsesClass(\SqlFixture\Version\Releases::class)]
110#[UsesClass(\SqlFixture\Version\ReleaseNumber::class)]
111#[UsesClass(\SqlFixture\Version\UnsupportedVersionException::class)]
112final class DatabaseFixtureProviderTest extends TestCase
113{
114 #[Test]
115 public function testFixtureGeneratesArrayFromSqliteTable(): void
116 {
117 $pdo = new PDO('sqlite::memory:');
118 $pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT)');
119
120 $faker = Factory::create();
121 $provider = new DatabaseFixtureProvider($faker, $pdo);
122
123 $result = $provider->fixture('users');
124 self::assertArrayHasKey('name', $result);
125 }
126
127 #[Test]
128 public function testClearCacheAllowsRefetch(): void
129 {
130 $pdo = new PDO('sqlite::memory:');
131 $pdo->exec('CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT)');
132
133 $faker = Factory::create();
134 $provider = new DatabaseFixtureProvider($faker, $pdo);
135
136 $provider->fixture('items');
137 $provider->clearCache();
138 $result = $provider->fixture('items');
139 self::assertArrayHasKey('title', $result);
140 }
141
142 #[Test]
143 public function testGetDriverReturnsSqlite(): void
144 {
145 $pdo = new PDO('sqlite::memory:');
146 $faker = Factory::create();
147 $provider = new DatabaseFixtureProvider($faker, $pdo);
148
149 self::assertSame('sqlite', $provider->getDriver());
150 }
151
152 #[Test]
153 public function testGetFixtureGeneratorReturnsInstance(): void
154 {
155 $pdo = new PDO('sqlite::memory:');
156 $faker = Factory::create();
157 $provider = new DatabaseFixtureProvider($faker, $pdo);
158
159 self::assertSame(['id' => 7], $provider->getFixtureGenerator()->generate(new TableSchema('sample', ['id' => new ColumnDefinition('id', 'INT')]), ['id' => 7]));
160 }
161
162 #[Test]
163 public function testFixtureWithCustomTypeMapper(): void
164 {
165 $pdo = new PDO('sqlite::memory:');
166 $pdo->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
167
168 $faker = Factory::create();
169 $typeMapper = new SqliteTypeMapper();
170 $provider = new DatabaseFixtureProvider($faker, $pdo, typeMapper: $typeMapper);
171
172 $data = $provider->fixture('test');
173 self::assertArrayHasKey('name', $data);
174 }
175
176 #[Test]
177 public function testFixtureWithCustomSchemaFetcher(): void
178 {
179 $pdo = new PDO('sqlite::memory:');
180 $pdo->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
181
182 $faker = Factory::create();
183 $fetcher = new SqliteSchemaFetcher();
184 $provider = new DatabaseFixtureProvider($faker, $pdo, schemaFetcher: $fetcher);
185
186 $data = $provider->fixture('test');
187 self::assertArrayHasKey('name', $data);
188 }
189
190 #[Test]
191 public function testSchemaCacheWorksOnSecondCall(): void
192 {
193 $pdo = new PDO('sqlite::memory:');
194 $pdo->exec('CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT NOT NULL)');
195
196 $faker = Factory::create();
197 $provider = new DatabaseFixtureProvider($faker, $pdo);
198
199 $data1 = $provider->fixture('items');
200 $data2 = $provider->fixture('items');
201
202 self::assertArrayHasKey('val', $data1);
203 self::assertArrayHasKey('val', $data2);
204 }
205
206 #[Test]
207 public function testFixtureNormalizesQuotedTableNames(): void
208 {
209 $pdo = new PDO('sqlite::memory:');
210 $pdo->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
211
212 $faker = Factory::create();
213 $provider = new DatabaseFixtureProvider($faker, $pdo);
214
215 $data = $provider->fixture('products');
216 self::assertArrayHasKey('name', $data);
217 }
218
219 #[Test]
220 public function testFixtureWithOverrides(): void
221 {
222 $pdo = new PDO('sqlite::memory:');
223 $pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
224
225 $faker = Factory::create();
226 $provider = new DatabaseFixtureProvider($faker, $pdo);
227
228 $data = $provider->fixture('users', ['name' => 'Override']);
229 self::assertSame('Override', $data['name']);
230 }
231
232 #[Test]
233 public function testGetVersionMatchesTheLinkedSqlite(): void
234 {
235 $provider = new DatabaseFixtureProvider(Factory::create(), new PDO('sqlite::memory:'));
236
237 self::assertSame('sqlite-3.47.2', $provider->getVersion());
238 }
239
240 #[Test]
241 public function testGetVersionKeepsAnExplicitTag(): void
242 {
243 $provider = new DatabaseFixtureProvider(Factory::create(), new PDO('sqlite::memory:'), version: 'sqlite-3.47.2');
244
245 self::assertSame('sqlite-3.47.2', $provider->getVersion());
246
247 $this->expectException(\SqlFixture\Version\UnsupportedVersionException::class);
248 new DatabaseFixtureProvider(Factory::create(), new PDO('sqlite::memory:'), version: 'mysql-8.4.7');
249 }
250}
251