Passed
Push — master ( e17376...74a3c9 )
by Asmir
01:07 queued 17s
created

DoctrineMigrationsExtensionTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 10
eloc 144
dl 0
loc 269
rs 10
c 3
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
testCanNotSpecifyBothEmAndConnection() 0 14 ?
testCustomSorter() 0 23 ?
testCustomEntityManager() 0 22 ?
A hp$0 ➔ testCanNotSpecifyBothEmAndConnection() 0 14 1
A hp$0 ➔ testCustomMetadataStorage() 0 20 1
A hp$0 ➔ getContainerBuilder() 0 8 1
getContainerBuilder() 0 8 ?
testPrefersEntityManagerOverConnection() 0 16 ?
A hp$0 ➔ compare() 0 2 1
testCustomMetadataStorage() 0 20 ?
A hp$0 ➔ testInvalidService() 0 15 1
A hp$0 ➔ testCustomSorter() 0 23 1
A hp$0 ➔ getContainer() 0 15 1
testCustomConnection() 0 16 ?
A hp$0 ➔ testPrefersEntityManagerOverConnection() 0 16 1
A testXmlConfigs() 0 18 1
A testFullConfig() 0 36 1
A hp$0 ➔ testCustomConnection() 0 16 1
testInvalidService() 0 15 ?
A assertConfigs() 0 23 1
A testNoConfig() 0 12 1
getContainer() 0 15 ?
A hp$0 ➔ testCustomEntityManager() 0 22 1
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\DBAL\Connection;
11
use Doctrine\Migrations\Configuration\Configuration;
12
use Doctrine\Migrations\DependencyFactory;
13
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
14
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
15
use Doctrine\Migrations\Version\Comparator;
16
use Doctrine\Migrations\Version\Version;
17
use Doctrine\ORM\EntityManager;
18
use InvalidArgumentException;
19
use PHPUnit\Framework\TestCase;
20
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
21
use Symfony\Component\Config\FileLocator;
22
use Symfony\Component\DependencyInjection\Alias;
23
use Symfony\Component\DependencyInjection\ContainerBuilder;
24
use Symfony\Component\DependencyInjection\Definition;
25
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
26
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
27
use function assert;
28
use function method_exists;
29
use function sys_get_temp_dir;
30
31
class DoctrineMigrationsExtensionTest extends TestCase
32
{
33
    public function testXmlConfigs() : void
34
    {
35
        $container = $this->getContainerBuilder();
36
37
        $conn = $this->createMock(Connection::class);
38
        $container->set('doctrine.dbal.default_connection', $conn);
39
40
        $container->registerExtension(new DoctrineMigrationsExtension());
41
42
        $container->setAlias('doctrine.migrations.configuration.test', new Alias('doctrine.migrations.configuration', true));
43
44
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Fixtures'));
45
        $loader->load('conf.xml');
46
47
        $container->compile();
48
49
        $config = $container->get('doctrine.migrations.configuration.test');
50
        $this->assertConfigs($config);
51
    }
52
53
    public function testFullConfig() : void
54
    {
55
        $config = [
56
            'name' => 'Doctrine Sandbox Migrations',
57
            'storage' => [
58
                'table_storage' => [
59
                    'table_name'                 => 'doctrine_migration_versions_test',
60
                    'version_column_name'        => 'doctrine_migration_column_test',
61
                    'version_column_length'      => 2000,
62
                    'executed_at_column_name'    => 'doctrine_migration_executed_at_column_test',
63
                    'execution_time_column_name' => 'doctrine_migration_execution_time_column_test',
64
                ],
65
            ],
66
67
            'migrations_paths' => [
68
                'DoctrineMigrationsTest' => 'a',
69
                'DoctrineMigrationsTest2' => 'b',
70
            ],
71
72
            'migrations' => ['Foo', 'Bar'],
73
74
            'organize_migrations' => 'BY_YEAR_AND_MONTH',
75
76
            'all_or_nothing'            => true,
77
            'check_database_platform'   => true,
78
        ];
79
        $container = $this->getContainer($config);
80
81
        $conn = $this->createMock(Connection::class);
82
        $container->set('doctrine.dbal.default_connection', $conn);
83
84
        $container->compile();
85
86
        $config = $container->get('doctrine.migrations.configuration');
87
88
        $this->assertConfigs($config);
89
    }
90
91
    public function testNoConfig() : void
92
    {
93
        $this->expectException(InvalidConfigurationException::class);
94
        $this->expectExceptionMessage('The child node "migrations_paths" at path "doctrine_migrations" must be configured.');
95
96
        $container = $this->getContainer([]);
97
98
        $conn = $this->createMock(Connection::class);
99
        $container->set('doctrine.dbal.default_connection', $conn);
100
        $container->compile();
101
102
        $container->get('doctrine.migrations.configuration');
103
    }
104
105
106
    private function assertConfigs(?object $config) : void
107
    {
108
        self::assertInstanceOf(Configuration::class, $config);
109
        self::assertSame('Doctrine Sandbox Migrations', $config->getName());
0 ignored issues
show
Bug introduced by
The method getName() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
        self::assertSame('Doctrine Sandbox Migrations', $config->/** @scrutinizer ignore-call */ getName());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
110
        self::assertSame([
111
            'DoctrineMigrationsTest' => 'a',
112
            'DoctrineMigrationsTest2' => 'b',
113
114
        ], $config->getMigrationDirectories());
115
116
        self::assertSame(['Foo', 'Bar'], $config->getMigrationClasses());
117
        self::assertTrue($config->isAllOrNothing());
118
        self::assertTrue($config->isDatabasePlatformChecked());
119
        self::assertTrue($config->areMigrationsOrganizedByYearAndMonth());
120
121
        $storage = $config->getMetadataStorageConfiguration();
122
        self::assertInstanceOf(TableMetadataStorageConfiguration::class, $storage);
123
124
        self::assertSame('doctrine_migration_versions_test', $storage->getTableName());
125
        self::assertSame('doctrine_migration_column_test', $storage->getVersionColumnName());
126
        self::assertSame(2000, $storage->getVersionColumnLength());
127
        self::assertSame('doctrine_migration_execution_time_column_test', $storage->getExecutionTimeColumnName());
128
        self::assertSame('doctrine_migration_executed_at_column_test', $storage->getExecutedAtColumnName());
129
    }
130
131
    public function testCustomSorter() : void
132
    {
133
        $config    = [
134
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
135
            'services' => [Comparator::class => 'my_sorter'],
136
        ];
137
        $container = $this->getContainer($config);
138
139
        $conn = $this->createMock(Connection::class);
140
        $container->set('doctrine.dbal.default_connection', $conn);
141
142
        $sorter = new class() implements Comparator{
143
            public function compare(Version $a, Version $b) : int
144
            {
145
            }
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...
146
        };
147
        $container->set('my_sorter', $sorter);
148
149
        $container->compile();
150
151
        $di = $container->get('doctrine.migrations.dependency_factory');
152
        self::assertInstanceOf(DependencyFactory::class, $di);
153
        self::assertSame($sorter, $di->getVersionComparator());
154
    }
155
156
    public function testCustomConnection() : void
157
    {
158
        $config    = [
159
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
160
            'connection' => 'custom',
161
        ];
162
        $container = $this->getContainer($config);
163
164
        $conn = $this->createMock(Connection::class);
165
        $container->set('doctrine.dbal.custom_connection', $conn);
166
167
        $container->compile();
168
169
        $di = $container->get('doctrine.migrations.dependency_factory');
170
        self::assertInstanceOf(DependencyFactory::class, $di);
171
        self::assertSame($conn, $di->getConnection());
172
    }
173
174
175
    public function testPrefersEntityManagerOverConnection() : void
176
    {
177
        $config    = [
178
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
179
        ];
180
        $container = $this->getContainer($config);
181
182
        $em = $this->createMock(EntityManager::class);
183
        $container->set('doctrine.orm.default_entity_manager', $em);
184
185
        $container->compile();
186
187
        $di = $container->get('doctrine.migrations.dependency_factory');
188
189
        self::assertInstanceOf(DependencyFactory::class, $di);
190
        self::assertSame($em, $di->getEntityManager());
191
    }
192
193
    public function testCustomEntityManager() : void
194
    {
195
        $config    = [
196
            'em' => 'custom',
197
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
198
        ];
199
        $container = $this->getContainer($config);
200
201
        $em = new Definition(CustomEntityManager::class);
202
        $container->setDefinition('doctrine.orm.custom_entity_manager', $em);
203
204
        $container->compile();
205
206
        $di = $container->get('doctrine.migrations.dependency_factory');
207
        self::assertInstanceOf(DependencyFactory::class, $di);
208
209
        $em = $di->getEntityManager();
210
        self::assertInstanceOf(CustomEntityManager::class, $em);
211
212
        assert(method_exists($di->getConnection(), 'getEm'));
213
        self::assertInstanceOf(CustomEntityManager::class, $di->getConnection()->getEm());
214
        self::assertSame($em, $di->getConnection()->getEm());
215
    }
216
217
    public function testCustomMetadataStorage() : void
218
    {
219
        $config = [
220
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
221
            'services' => [MetadataStorage::class => 'mock_storage_service'],
222
        ];
223
224
        $container = $this->getContainer($config);
225
226
        $mockStorage = $this->createMock(MetadataStorage::class);
227
        $container->set('mock_storage_service', $mockStorage);
228
229
        $conn = $this->createMock(Connection::class);
230
        $container->set('doctrine.dbal.default_connection', $conn);
231
232
        $container->compile();
233
234
        $di = $container->get('doctrine.migrations.dependency_factory');
235
        self::assertInstanceOf(DependencyFactory::class, $di);
236
        self::assertSame($mockStorage, $di->getMetadataStorage());
237
    }
238
239
    public function testInvalidService() : void
240
    {
241
        $this->expectException(InvalidConfigurationException::class);
242
        $this->expectExceptionMessage('Invalid configuration for path "doctrine_migrations.services": Valid services for the DoctrineMigrationsBundle must be in the "Doctrine\Migrations" namespace.');
243
244
        $config    = [
245
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
246
            'services' => ['foo' => 'mock_storage_service'],
247
        ];
248
        $container = $this->getContainer($config);
249
250
        $conn = $this->createMock(Connection::class);
251
        $container->set('doctrine.dbal.default_connection', $conn);
252
253
        $container->compile();
254
    }
255
256
    public function testCanNotSpecifyBothEmAndConnection() : void
257
    {
258
        $this->expectExceptionMessage('You cannot specify both "connection" and "em" in the DoctrineMigrationsBundle configurations');
259
        $this->expectException(InvalidArgumentException::class);
260
261
        $config = [
262
            'migrations_paths' => ['DoctrineMigrationsTest' => 'a'],
263
            'em' => 'custom',
264
            'connection' => 'custom',
265
        ];
266
267
        $container = $this->getContainer($config);
268
269
        $container->compile();
270
    }
271
272
    /**
273
     * @param mixed[] $config
274
     */
275
    private function getContainer(array $config) : ContainerBuilder
276
    {
277
        $container = $this->getContainerBuilder();
278
279
        $bundle = new DoctrineMigrationsBundle();
280
        $bundle->build($container);
281
282
        $extension = new DoctrineMigrationsExtension();
283
284
        $extension->load(['doctrine_migrations' => $config], $container);
285
286
        $container->getDefinition('doctrine.migrations.dependency_factory')->setPublic(true);
287
        $container->getDefinition('doctrine.migrations.configuration')->setPublic(true);
288
289
        return $container;
290
    }
291
292
    private function getContainerBuilder() : ContainerBuilder
293
    {
294
        return new ContainerBuilder(new ParameterBag([
295
            'kernel.debug' => false,
296
            'kernel.bundles' => [],
297
            'kernel.cache_dir' => sys_get_temp_dir(),
298
            'kernel.environment' => 'test',
299
            'kernel.project_dir' => __DIR__ . '/../',
300
        ]));
301
    }
302
}
303