Failed Conditions
Pull Request — master (#318)
by Asmir
04:58 queued 01:55
created

testBundleRelativePathResolution()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
c 0
b 0
f 0
dl 0
loc 23
rs 9.7998
cc 1
nc 1
nop 0
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 InvalidArgumentException;
20
use PHPUnit\Framework\TestCase;
21
use ReflectionClass;
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 function assert;
30
use function dirname;
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 testNoConfig() : void
94
    {
95
        $this->expectException(InvalidConfigurationException::class);
96
        $this->expectExceptionMessage('The child node "migrations_paths" at path "doctrine_migrations" must be configured.');
97
98
        $container = $this->getContainer([]);
99
100
        $conn = $this->createMock(Connection::class);
101
        $container->set('doctrine.dbal.default_connection', $conn);
102
        $container->compile();
103
104
        $container->get('doctrine.migrations.configuration');
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
122
        self::assertInstanceOf(Configuration::class, $config);
123
124
        $ref = new ReflectionClass(TestBundle::class);
125
        self::assertSame([
126
            'DoctrineMigrationsTest' => dirname($ref->getFileName()),
127
            'DoctrineMigrationsTestAnother' => dirname($ref->getFileName()) . '/another-path',
128
129
        ], $config->getMigrationDirectories());
130
    }
131
132
    private function assertConfigs(?object $config) : void
133
    {
134
        self::assertInstanceOf(Configuration::class, $config);
135
        self::assertSame([
136
            'DoctrineMigrationsTest' => 'a',
137
            'DoctrineMigrationsTest2' => 'b',
138
139
        ], $config->getMigrationDirectories());
140
141
        self::assertSame(['Foo', 'Bar'], $config->getMigrationClasses());
142
        self::assertTrue($config->isAllOrNothing());
143
        self::assertTrue($config->isDatabasePlatformChecked());
144
        self::assertTrue($config->areMigrationsOrganizedByYearAndMonth());
145
146
        $storage = $config->getMetadataStorageConfiguration();
147
        self::assertInstanceOf(TableMetadataStorageConfiguration::class, $storage);
148
149
        self::assertSame('doctrine_migration_versions_test', $storage->getTableName());
150
        self::assertSame('doctrine_migration_column_test', $storage->getVersionColumnName());
151
        self::assertSame(2000, $storage->getVersionColumnLength());
152
        self::assertSame('doctrine_migration_execution_time_column_test', $storage->getExecutionTimeColumnName());
153
        self::assertSame('doctrine_migration_executed_at_column_test', $storage->getExecutedAtColumnName());
154
    }
155
156
    public function testCustomSorter() : void
157
    {
158
        $config    = [
159
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
160
            'services' => [Comparator::class => 'my_sorter'],
161
        ];
162
        $container = $this->getContainer($config);
163
164
        $conn = $this->createMock(Connection::class);
165
        $container->set('doctrine.dbal.default_connection', $conn);
166
167
        $sorter = new class() implements Comparator{
168
            public function compare(Version $a, Version $b) : int
169
            {
170
            }
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...
171
        };
172
        $container->set('my_sorter', $sorter);
173
174
        $container->compile();
175
176
        $di = $container->get('doctrine.migrations.dependency_factory');
177
        self::assertInstanceOf(DependencyFactory::class, $di);
178
        self::assertSame($sorter, $di->getVersionComparator());
179
    }
180
181
    public function testCustomConnection() : void
182
    {
183
        $config    = [
184
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
185
            'connection' => 'custom',
186
        ];
187
        $container = $this->getContainer($config);
188
189
        $conn = $this->createMock(Connection::class);
190
        $container->set('doctrine.dbal.custom_connection', $conn);
191
192
        $container->compile();
193
194
        $di = $container->get('doctrine.migrations.dependency_factory');
195
        self::assertInstanceOf(DependencyFactory::class, $di);
196
        self::assertSame($conn, $di->getConnection());
197
    }
198
199
200
    public function testPrefersEntityManagerOverConnection() : void
201
    {
202
        $config    = [
203
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
204
        ];
205
        $container = $this->getContainer($config);
206
207
        $em = $this->createMock(EntityManager::class);
208
        $container->set('doctrine.orm.default_entity_manager', $em);
209
210
        $container->compile();
211
212
        $di = $container->get('doctrine.migrations.dependency_factory');
213
214
        self::assertInstanceOf(DependencyFactory::class, $di);
215
        self::assertSame($em, $di->getEntityManager());
216
    }
217
218
    public function testCustomEntityManager() : void
219
    {
220
        $config    = [
221
            'em' => 'custom',
222
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
223
        ];
224
        $container = $this->getContainer($config);
225
226
        $em = new Definition(CustomEntityManager::class);
227
        $container->setDefinition('doctrine.orm.custom_entity_manager', $em);
228
229
        $container->compile();
230
231
        $di = $container->get('doctrine.migrations.dependency_factory');
232
        self::assertInstanceOf(DependencyFactory::class, $di);
233
234
        $em = $di->getEntityManager();
235
        self::assertInstanceOf(CustomEntityManager::class, $em);
236
237
        assert(method_exists($di->getConnection(), 'getEm'));
238
        self::assertInstanceOf(CustomEntityManager::class, $di->getConnection()->getEm());
239
        self::assertSame($em, $di->getConnection()->getEm());
240
    }
241
242
    public function testCustomMetadataStorage() : void
243
    {
244
        $config = [
245
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
246
            'services' => [MetadataStorage::class => 'mock_storage_service'],
247
        ];
248
249
        $container = $this->getContainer($config);
250
251
        $mockStorage = $this->createMock(MetadataStorage::class);
252
        $container->set('mock_storage_service', $mockStorage);
253
254
        $conn = $this->createMock(Connection::class);
255
        $container->set('doctrine.dbal.default_connection', $conn);
256
257
        $container->compile();
258
259
        $di = $container->get('doctrine.migrations.dependency_factory');
260
        self::assertInstanceOf(DependencyFactory::class, $di);
261
        self::assertSame($mockStorage, $di->getMetadataStorage());
262
    }
263
264
    public function testInvalidService() : void
265
    {
266
        $this->expectException(InvalidConfigurationException::class);
267
        $this->expectExceptionMessage('Invalid configuration for path "doctrine_migrations.services": Valid services for the DoctrineMigrationsBundle must be in the "Doctrine\Migrations" namespace.');
268
269
        $config    = [
270
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
271
            'services' => ['foo' => 'mock_storage_service'],
272
        ];
273
        $container = $this->getContainer($config);
274
275
        $conn = $this->createMock(Connection::class);
276
        $container->set('doctrine.dbal.default_connection', $conn);
277
278
        $container->compile();
279
    }
280
281
    public function testCanNotSpecifyBothEmAndConnection() : void
282
    {
283
        $this->expectExceptionMessage('You cannot specify both "connection" and "em" in the DoctrineMigrationsBundle configurations');
284
        $this->expectException(InvalidArgumentException::class);
285
286
        $config = [
287
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
288
            'em' => 'custom',
289
            'connection' => 'custom',
290
        ];
291
292
        $container = $this->getContainer($config);
293
294
        $container->compile();
295
    }
296
297
    /**
298
     * @param mixed[] $config
299
     */
300
    private function getContainer(array $config) : ContainerBuilder
301
    {
302
        $container = $this->getContainerBuilder();
303
304
        $bundle = new DoctrineMigrationsBundle();
305
        $bundle->build($container);
306
307
        $extension = new DoctrineMigrationsExtension();
308
309
        $extension->load(['doctrine_migrations' => $config], $container);
310
311
        $container->getDefinition('doctrine.migrations.dependency_factory')->setPublic(true);
312
        $container->getDefinition('doctrine.migrations.configuration')->setPublic(true);
313
314
        return $container;
315
    }
316
317
    private function getContainerBuilder() : ContainerBuilder
318
    {
319
        return new ContainerBuilder(new ParameterBag([
320
            'kernel.debug' => false,
321
            'kernel.bundles' => ['TestBundle' => TestBundle::class],
322
            'kernel.cache_dir' => sys_get_temp_dir(),
323
            'kernel.environment' => 'test',
324
            'kernel.project_dir' => __DIR__ . '/../',
325
        ]));
326
    }
327
}
328