packages/sql-fixture/tests/Unit/DatabaseFixtureProviderTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit;
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\DatabaseFixtureProvider;
14use SqlFixture\FixtureGenerator;
15use SqlFixture\Platform\PlatformFactory;
16use SqlFixture\Platform\Sqlite\SqliteSchemaFetcher;
17use SqlFixture\Platform\Sqlite\SqliteSchemaParser;
18use SqlFixture\Platform\Sqlite\SqliteTypeMapper;
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\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)]
107final class DatabaseFixtureProviderTest extends TestCase
108{
109    #[Test]
110    public function testFixtureGeneratesArrayFromSqliteTable(): void
111    {
112        $pdo = new PDO('sqlite::memory:');
113        $pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT)');
114
115        $faker = Factory::create();
116        $provider = new DatabaseFixtureProvider($faker, $pdo);
117
118        $result = $provider->fixture('users');
119        self::assertArrayHasKey('name', $result);
120    }
121
122    #[Test]
123    public function testClearCacheAllowsRefetch(): void
124    {
125        $pdo = new PDO('sqlite::memory:');
126        $pdo->exec('CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT)');
127
128        $faker = Factory::create();
129        $provider = new DatabaseFixtureProvider($faker, $pdo);
130
131        $provider->fixture('items');
132        $provider->clearCache();
133        $result = $provider->fixture('items');
134        self::assertArrayHasKey('title', $result);
135    }
136
137    #[Test]
138    public function testGetDriverReturnsSqlite(): void
139    {
140        $pdo = new PDO('sqlite::memory:');
141        $faker = Factory::create();
142        $provider = new DatabaseFixtureProvider($faker, $pdo);
143
144        self::assertSame('sqlite', $provider->getDriver());
145    }
146
147    #[Test]
148    public function testGetFixtureGeneratorReturnsInstance(): void
149    {
150        $pdo = new PDO('sqlite::memory:');
151        $faker = Factory::create();
152        $provider = new DatabaseFixtureProvider($faker, $pdo);
153
154        self::assertSame(['id' => 7], $provider->getFixtureGenerator()->generate(new TableSchema('sample', ['id' => new ColumnDefinition('id', 'INT')]), ['id' => 7]));
155    }
156
157    #[Test]
158    public function testFixtureWithCustomTypeMapper(): void
159    {
160        $pdo = new PDO('sqlite::memory:');
161        $pdo->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
162
163        $faker = Factory::create();
164        $typeMapper = new SqliteTypeMapper();
165        $provider = new DatabaseFixtureProvider($faker, $pdo, typeMapper: $typeMapper);
166
167        $data = $provider->fixture('test');
168        self::assertArrayHasKey('name', $data);
169    }
170
171    #[Test]
172    public function testFixtureWithCustomSchemaFetcher(): void
173    {
174        $pdo = new PDO('sqlite::memory:');
175        $pdo->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
176
177        $faker = Factory::create();
178        $fetcher = new SqliteSchemaFetcher();
179        $provider = new DatabaseFixtureProvider($faker, $pdo, schemaFetcher: $fetcher);
180
181        $data = $provider->fixture('test');
182        self::assertArrayHasKey('name', $data);
183    }
184
185    #[Test]
186    public function testSchemaCacheWorksOnSecondCall(): void
187    {
188        $pdo = new PDO('sqlite::memory:');
189        $pdo->exec('CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT NOT NULL)');
190
191        $faker = Factory::create();
192        $provider = new DatabaseFixtureProvider($faker, $pdo);
193
194        $data1 = $provider->fixture('items');
195        $data2 = $provider->fixture('items');
196
197        self::assertArrayHasKey('val', $data1);
198        self::assertArrayHasKey('val', $data2);
199    }
200
201    #[Test]
202    public function testFixtureNormalizesQuotedTableNames(): void
203    {
204        $pdo = new PDO('sqlite::memory:');
205        $pdo->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
206
207        $faker = Factory::create();
208        $provider = new DatabaseFixtureProvider($faker, $pdo);
209
210        $data = $provider->fixture('products');
211        self::assertArrayHasKey('name', $data);
212    }
213
214    #[Test]
215    public function testFixtureWithOverrides(): void
216    {
217        $pdo = new PDO('sqlite::memory:');
218        $pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
219
220        $faker = Factory::create();
221        $provider = new DatabaseFixtureProvider($faker, $pdo);
222
223        $data = $provider->fixture('users', ['name' => 'Override']);
224        self::assertSame('Override', $data['name']);
225    }
226
227}
228