Passed
Push — master ( 0e1800...6c1629 )
by Asmir
41s queued 10s
created

sionTest.php$2   A

Complexity

Total Complexity 2

Size/Duplication

Total Lines 12
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 2
c 1
b 0
f 1
dl 0
loc 12
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Bundle\MigrationsBundle\Tests\DependencyInjection;
6
7
use Doctrine\Bundle\MigrationsBundle\DependencyInjection\DoctrineMigrationsExtension;
8
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
9
use Doctrine\Bundle\MigrationsBundle\Tests\Fixtures\CustomEntityManager;
10
use Doctrine\Bundle\MigrationsBundle\Tests\Fixtures\TestBundle\TestBundle;
11
use Doctrine\DBAL\Connection;
12
use Doctrine\Migrations\Configuration\Configuration;
13
use Doctrine\Migrations\DependencyFactory;
14
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
15
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
16
use Doctrine\Migrations\Version\Comparator;
17
use Doctrine\Migrations\Version\Version;
18
use Doctrine\ORM\EntityManager;
19
use Exception;
20
use InvalidArgumentException;
21
use PHPUnit\Framework\TestCase;
22
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
23
use Symfony\Component\Config\FileLocator;
24
use Symfony\Component\DependencyInjection\Alias;
25
use Symfony\Component\DependencyInjection\ContainerBuilder;
26
use Symfony\Component\DependencyInjection\Definition;
27
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
28
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
29
use Symfony\Component\DependencyInjection\Reference;
30
use function assert;
31
use function method_exists;
32
use function sys_get_temp_dir;
33
34
class DoctrineMigrationsExtensionTest extends TestCase
35
{
36
    public function testXmlConfigs() : void
37
    {
38
        $container = $this->getContainerBuilder();
39
40
        $conn = $this->createMock(Connection::class);
41
        $container->set('doctrine.dbal.default_connection', $conn);
42
43
        $container->registerExtension(new DoctrineMigrationsExtension());
44
45
        $container->setAlias('doctrine.migrations.configuration.test', new Alias('doctrine.migrations.configuration', true));
46
47
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Fixtures'));
48
        $loader->load('conf.xml');
49
50
        $container->compile();
51
52
        $config = $container->get('doctrine.migrations.configuration.test');
53
        $this->assertConfigs($config);
54
    }
55
56
    public function testFullConfig() : void
57
    {
58
        $config = [
59
            'storage' => [
60
                'table_storage' => [
61
                    'table_name'                 => 'doctrine_migration_versions_test',
62
                    'version_column_name'        => 'doctrine_migration_column_test',
63
                    'version_column_length'      => 2000,
64
                    'executed_at_column_name'    => 'doctrine_migration_executed_at_column_test',
65
                    'execution_time_column_name' => 'doctrine_migration_execution_time_column_test',
66
                ],
67
            ],
68
69
            'migrations_paths' => [
70
                'DoctrineMigrationsTest' => 'a',
71
                'DoctrineMigrationsTest2' => 'b',
72
            ],
73
74
            'migrations' => ['Foo', 'Bar'],
75
76
            'organize_migrations' => 'BY_YEAR_AND_MONTH',
77
78
            'all_or_nothing'            => true,
79
            'check_database_platform'   => true,
80
        ];
81
        $container = $this->getContainer($config);
82
83
        $conn = $this->createMock(Connection::class);
84
        $container->set('doctrine.dbal.default_connection', $conn);
85
86
        $container->compile();
87
88
        $config = $container->get('doctrine.migrations.configuration');
89
90
        $this->assertConfigs($config);
91
    }
92
93
    public function testNoConfigsAreNeeded() : void
94
    {
95
        $container = $this->getContainer([]);
96
97
        $conn = $this->createMock(Connection::class);
98
        $container->set('doctrine.dbal.default_connection', $conn);
99
        $container->compile();
100
101
        $config = $container->get('doctrine.migrations.configuration');
102
103
        self::assertInstanceOf(Configuration::class, $config);
104
        self::assertSame([], $config->getMigrationDirectories());
105
    }
106
107
    public function testBundleRelativePathResolution() : void
108
    {
109
        $container = $this->getContainer([
110
            'migrations_paths' => [
111
                'DoctrineMigrationsTest' => '@TestBundle',
112
                'DoctrineMigrationsTestAnother' => '@TestBundle/another-path',
113
            ],
114
        ]);
115
116
        $conn = $this->createMock(Connection::class);
117
        $container->set('doctrine.dbal.default_connection', $conn);
118
        $container->compile();
119
120
        $config = $container->get('doctrine.migrations.configuration');
121
        $bundle = new TestBundle();
122
123
        self::assertInstanceOf(Configuration::class, $config);
124
        self::assertSame([
125
            'DoctrineMigrationsTest' => $bundle->getPath(),
126
            'DoctrineMigrationsTestAnother' => $bundle->getPath() . '/another-path',
127
128
        ], $config->getMigrationDirectories());
129
    }
130
131
    private function assertConfigs(?object $config) : void
132
    {
133
        self::assertInstanceOf(Configuration::class, $config);
134
        self::assertSame([
135
            'DoctrineMigrationsTest' => 'a',
136
            'DoctrineMigrationsTest2' => 'b',
137
138
        ], $config->getMigrationDirectories());
139
140
        self::assertSame(['Foo', 'Bar'], $config->getMigrationClasses());
141
        self::assertTrue($config->isAllOrNothing());
142
        self::assertTrue($config->isDatabasePlatformChecked());
143
        self::assertTrue($config->areMigrationsOrganizedByYearAndMonth());
144
145
        $storage = $config->getMetadataStorageConfiguration();
146
        self::assertInstanceOf(TableMetadataStorageConfiguration::class, $storage);
147
148
        self::assertSame('doctrine_migration_versions_test', $storage->getTableName());
149
        self::assertSame('doctrine_migration_column_test', $storage->getVersionColumnName());
150
        self::assertSame(2000, $storage->getVersionColumnLength());
151
        self::assertSame('doctrine_migration_execution_time_column_test', $storage->getExecutionTimeColumnName());
152
        self::assertSame('doctrine_migration_executed_at_column_test', $storage->getExecutedAtColumnName());
153
    }
154
155
    public function testCustomSorter() : void
156
    {
157
        $config    = [
158
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
159
            'services' => [Comparator::class => 'my_sorter'],
160
        ];
161
        $container = $this->getContainer($config);
162
163
        $conn = $this->createMock(Connection::class);
164
        $container->set('doctrine.dbal.default_connection', $conn);
165
166
        $sorter = new class() implements Comparator{
167
            public function compare(Version $a, Version $b) : int
168
            {
169
            }
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return integer. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
170
        };
171
        $container->set('my_sorter', $sorter);
172
173
        $container->compile();
174
175
        $di = $container->get('doctrine.migrations.dependency_factory');
176
        self::assertInstanceOf(DependencyFactory::class, $di);
177
        self::assertSame($sorter, $di->getVersionComparator());
178
    }
179
180
    public function testServicesAreLazy() : void
181
    {
182
        $config    = [
183
            'services' => [Comparator::class => 'my_sorter'],
184
        ];
185
        $container = $this->getContainer($config);
186
187
        $conn = $this->createMock(Connection::class);
188
        $container->set('doctrine.dbal.default_connection', $conn);
189
190
        $sorterFactory = new class() {
191
            public function __invoke() : void
192
            {
193
                throw new Exception('This method should not be invoked.');
194
            }
195
        };
196
        $container->set('my_sorter_factory', $sorterFactory);
197
198
        $sorterDefinition = new Definition(Comparator::class);
199
        $sorterDefinition->setFactory(new Reference('my_sorter_factory'));
200
        $container->setDefinition('my_sorter', $sorterDefinition);
201
202
        $container->compile();
203
204
        $di = $container->get('doctrine.migrations.dependency_factory');
205
        self::assertInstanceOf(DependencyFactory::class, $di);
206
    }
207
208
    public function testServiceFactory() : void
209
    {
210
        $mockComparator = $this->createMock(Comparator::class);
211
        $config         = [
212
            'factories' => [Comparator::class => 'my_sorter'],
213
        ];
214
215
        $container = $this->getContainer($config);
216
217
        $conn = $this->createMock(Connection::class);
218
        $container->set('doctrine.dbal.default_connection', $conn);
219
220
        $sorterFactory = new class($mockComparator) {
221
            /** @var Comparator */
222
            private $comparator;
223
224
            public function __construct(Comparator $comparator)
225
            {
226
                $this->comparator = $comparator;
227
            }
228
229
            public function __invoke(DependencyFactory $di) : Comparator
230
            {
231
                return $this->comparator;
232
            }
233
        };
234
        $container->set('my_sorter', $sorterFactory);
235
236
        $container->compile();
237
238
        $di = $container->get('doctrine.migrations.dependency_factory');
239
        self::assertInstanceOf(DependencyFactory::class, $di);
240
        self::assertSame($mockComparator, $di->getVersionComparator());
241
    }
242
243
    public function testCustomConnection() : void
244
    {
245
        $config    = [
246
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
247
            'connection' => 'custom',
248
        ];
249
        $container = $this->getContainer($config);
250
251
        $conn = $this->createMock(Connection::class);
252
        $container->set('doctrine.dbal.custom_connection', $conn);
253
254
        $container->compile();
255
256
        $di = $container->get('doctrine.migrations.dependency_factory');
257
        self::assertInstanceOf(DependencyFactory::class, $di);
258
        self::assertSame($conn, $di->getConnection());
259
    }
260
261
262
    public function testPrefersEntityManagerOverConnection() : void
263
    {
264
        $config    = [
265
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
266
        ];
267
        $container = $this->getContainer($config);
268
269
        $em = $this->createMock(EntityManager::class);
270
        $container->set('doctrine.orm.default_entity_manager', $em);
271
272
        $container->compile();
273
274
        $di = $container->get('doctrine.migrations.dependency_factory');
275
276
        self::assertInstanceOf(DependencyFactory::class, $di);
277
        self::assertSame($em, $di->getEntityManager());
278
    }
279
280
    public function testCustomEntityManager() : void
281
    {
282
        $config    = [
283
            'em' => 'custom',
284
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
285
        ];
286
        $container = $this->getContainer($config);
287
288
        $em = new Definition(CustomEntityManager::class);
289
        $container->setDefinition('doctrine.orm.custom_entity_manager', $em);
290
291
        $container->compile();
292
293
        $di = $container->get('doctrine.migrations.dependency_factory');
294
        self::assertInstanceOf(DependencyFactory::class, $di);
295
296
        $em = $di->getEntityManager();
297
        self::assertInstanceOf(CustomEntityManager::class, $em);
298
299
        assert(method_exists($di->getConnection(), 'getEm'));
300
        self::assertInstanceOf(CustomEntityManager::class, $di->getConnection()->getEm());
301
        self::assertSame($em, $di->getConnection()->getEm());
302
    }
303
304
    public function testCustomMetadataStorage() : void
305
    {
306
        $config = [
307
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
308
            'services' => [MetadataStorage::class => 'mock_storage_service'],
309
        ];
310
311
        $container = $this->getContainer($config);
312
313
        $mockStorage = $this->createMock(MetadataStorage::class);
314
        $container->set('mock_storage_service', $mockStorage);
315
316
        $conn = $this->createMock(Connection::class);
317
        $container->set('doctrine.dbal.default_connection', $conn);
318
319
        $container->compile();
320
321
        $di = $container->get('doctrine.migrations.dependency_factory');
322
        self::assertInstanceOf(DependencyFactory::class, $di);
323
        self::assertSame($mockStorage, $di->getMetadataStorage());
324
    }
325
326
    public function testInvalidService() : void
327
    {
328
        $this->expectException(InvalidConfigurationException::class);
329
        $this->expectExceptionMessage('Invalid configuration for path "doctrine_migrations.services": Valid services for the DoctrineMigrationsBundle must be in the "Doctrine\Migrations" namespace.');
330
331
        $config    = [
332
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
333
            'services' => ['foo' => 'mock_storage_service'],
334
        ];
335
        $container = $this->getContainer($config);
336
337
        $conn = $this->createMock(Connection::class);
338
        $container->set('doctrine.dbal.default_connection', $conn);
339
340
        $container->compile();
341
    }
342
343
    public function testCanNotSpecifyBothEmAndConnection() : void
344
    {
345
        $this->expectExceptionMessage('You cannot specify both "connection" and "em" in the DoctrineMigrationsBundle configurations');
346
        $this->expectException(InvalidArgumentException::class);
347
348
        $config = [
349
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
350
            'em' => 'custom',
351
            'connection' => 'custom',
352
        ];
353
354
        $container = $this->getContainer($config);
355
356
        $container->compile();
357
    }
358
359
    /**
360
     * @param mixed[] $config
361
     */
362
    private function getContainer(array $config) : ContainerBuilder
363
    {
364
        $container = $this->getContainerBuilder();
365
366
        $bundle = new DoctrineMigrationsBundle();
367
        $bundle->build($container);
368
369
        $extension = new DoctrineMigrationsExtension();
370
371
        $extension->load(['doctrine_migrations' => $config], $container);
372
373
        $container->getDefinition('doctrine.migrations.dependency_factory')->setPublic(true);
374
        $container->getDefinition('doctrine.migrations.configuration')->setPublic(true);
375
376
        return $container;
377
    }
378
379
    private function getContainerBuilder() : ContainerBuilder
380
    {
381
        $bundle = new TestBundle();
382
        return new ContainerBuilder(new ParameterBag([
383
            'kernel.debug' => false,
384
            'kernel.bundles' => [$bundle->getName() => TestBundle::class],
385
            'kernel.bundles_metadata' => [
386
                $bundle->getName() => [
387
                    'path' => $bundle->getPath(),
388
                    'namespace' => $bundle->getNamespace(),
389
                ],
390
            ],
391
            'kernel.cache_dir' => sys_get_temp_dir(),
392
            'kernel.environment' => 'test',
393
            'kernel.project_dir' => __DIR__ . '/../',
394
        ]));
395
    }
396
}
397