Passed
Pull Request — master (#2)
by Alex
02:59
created

testSetAndGetEntityManagers()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
c 1
b 0
f 0
dl 0
loc 33
rs 9.584
cc 3
nc 3
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\LaminasDoctrine\Service\EntityManager;
6
7
use Arp\LaminasDoctrine\Config\DoctrineConfig;
8
use Arp\LaminasDoctrine\Factory\Service\EntityManagerFactory;
9
use Arp\LaminasDoctrine\Service\EntityManager\ContainerInterface;
10
use Arp\LaminasDoctrine\Service\EntityManager\EntityManagerProvider;
11
use Arp\LaminasDoctrine\Service\EntityManager\EntityManagerProviderInterface;
12
use Arp\LaminasDoctrine\Service\EntityManager\Exception\EntityManagerProviderException;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
15
use PHPUnit\Framework\MockObject\MockObject;
16
use PHPUnit\Framework\TestCase;
17
18
/**
19
 * @covers  \Arp\LaminasDoctrine\Service\EntityManager\EntityManagerProvider
20
 *
21
 * @author  Alex Patterson <[email protected]>
22
 * @package ArpTest\LaminasDoctrine\Service\EntityManager
23
 */
24
final class EntityManagerProviderTest extends TestCase
25
{
26
    /**
27
     * @var DoctrineConfig&MockObject
28
     */
29
    private $config;
30
31
    /**
32
     * @var ContainerInterface&MockObject
33
     */
34
    private $container;
35
36
    /**
37
     * Prepare the test case dependencies
38
     */
39
    public function setUp(): void
40
    {
41
        $this->config = $this->createMock(DoctrineConfig::class);
42
43
        $this->container = $this->createMock(ContainerInterface::class);
44
    }
45
46
    /**
47
     * Assert the class is an instance of the EntityManagerProviderInterface
48
     *
49
     * @throws EntityManagerProviderException
50
     */
51
    public function testImplementsEntityManagerProviderInterface(): void
52
    {
53
        $provider = new EntityManagerProvider($this->config, $this->container);
54
55
        $this->assertInstanceOf(EntityManagerProviderInterface::class, $provider);
56
    }
57
58
    /**
59
     * Assert has() will return the expected boolean result
60
     *
61
     * @param bool $expected
62
     * @param bool $hasContainer
63
     * @param bool $hasConfig
64
     *
65
     * @dataProvider getHasData
66
     *
67
     * @throws EntityManagerProviderException
68
     */
69
    public function testHas(bool $expected, bool $hasContainer, bool $hasConfig): void
70
    {
71
        $name = 'FooServiceName';
72
        if ($hasContainer) {
73
            $this->container->expects($this->once())
74
                ->method('has')
75
                ->with($name)
76
                ->willReturn($hasContainer);
77
        }
78
79
        if (!$hasContainer) {
80
            $this->config->expects($this->once())
81
                ->method('hasEntityManagerConfig')
82
                ->with($name)
83
                ->willReturn($hasConfig);
84
        }
85
86
        $provider = new EntityManagerProvider($this->config, $this->container);
87
88
        $this->assertSame($expected, $provider->hasEntityManager($name));
89
    }
90
91
    /**
92
     * @return array<mixed>
93
     */
94
    public function getHasData(): array
95
    {
96
        return [
97
            [true, true, true],
98
            [true, true, false],
99
            [true, false, true],
100
            [false, false, false],
101
        ];
102
    }
103
104
    /**
105
     * Assert that getCollection() will return a matching connection by name
106
     *
107
     * @throws EntityManagerProviderException
108
     */
109
    public function testGetEntityManagerWillReturnEntityManagerByName(): void
110
    {
111
        $provider = new EntityManagerProvider($this->config, $this->container);
112
113
        /** @var EntityManagerInterface|MockObject $entityManager */
114
        $entityManager = $this->createMock(EntityManagerInterface::class);
115
        $name = 'FooEntityManager';
116
117
        $this->container->expects($this->exactly(2))
118
            ->method('has')
119
            ->withConsecutive([$name], [$name])
120
            ->willReturn(true, true);
121
122
        $this->container->expects($this->once())
123
            ->method('get')
124
            ->with($name)
125
            ->willReturn($entityManager);
126
127
        $this->assertSame($entityManager, $provider->getEntityManager($name));
128
    }
129
130
    /**
131
     * Assert that a single entity manager can be set and then returned by its $name
132
     *
133
     * @throws EntityManagerProviderException
134
     */
135
    public function testSetAndGetEntityManager(): void
136
    {
137
        $provider = new EntityManagerProvider($this->config, $this->container);
138
139
        /** @var EntityManagerInterface&MockObject $entityManager */
140
        $entityManager = $this->createMock(EntityManagerInterface::class);
141
        $name = 'FooEntityManager';
142
143
        $this->container->expects($this->once())
144
            ->method('setService')
145
            ->with($name, $entityManager);
146
147
        $provider->setEntityManager($name, $entityManager);
148
149
        $this->container->expects($this->exactly(2))
150
            ->method('has')
151
            ->withConsecutive([$name], [$name])
152
            ->willReturnOnConsecutiveCalls(true, true);
153
154
        $this->container->expects($this->once())
155
            ->method('get')
156
            ->with($name)
157
            ->willReturn($entityManager);
158
159
        $this->assertSame($entityManager, $provider->getEntityManager($name));
160
    }
161
162
    /**
163
     * Assert that a multiple entity manager can be set and then returned by their names
164
     *
165
     * @throws EntityManagerProviderException
166
     */
167
    public function testSetAndGetEntityManagers(): void
168
    {
169
        /** @var array<EntityManagerInterface&MockObject>|array[] $configs */
170
        $configs = [
171
            'foo' => $this->createMock(EntityManagerInterface::class),
172
            'bar' => $this->createMock(EntityManagerInterface::class),
173
            'test' => [
174
                'name' => 'hello',
175
                'test' => 'data',
176
                'active' => true,
177
            ],
178
        ];
179
180
        $provider = new EntityManagerProvider($this->config, $this->container);
181
182
        $setArgs = $configsArgs = [];
183
        foreach ($configs as $name => $config) {
184
            if (is_array($config)) {
185
                $configsArgs[] = [$name, $config];
186
            } else {
187
                $setArgs[] = [$name, $config];
188
            }
189
        }
190
191
        $this->container->expects($this->exactly(count($setArgs)))
192
            ->method('setService')
193
            ->withConsecutive(...$setArgs);
194
195
        $this->config->expects($this->exactly(count($configsArgs)))
196
            ->method('setEntityManagerConfig')
197
            ->withConsecutive(...$configsArgs);
198
199
        $provider->setEntityManagers($configs);
200
    }
201
202
    /**
203
     * Assert that getCollection() will return a connection by lazy loading the configuration
204
     *
205
     * @throws EntityManagerProviderException
206
     */
207
    public function testGetEntityManagerWillReturnLazyLoadedEntityManagerByName(): void
208
    {
209
        $provider = new EntityManagerProvider($this->config, $this->container);
210
211
        /** @var EntityManagerInterface&MockObject $entityManager */
212
        $entityManager = $this->createMock(EntityManagerInterface::class);
213
        $name = 'FooEntityManager';
214
        $config = [
215
            'foo' => 'bar',
216
        ];
217
218
        $this->container->expects($this->exactly(3))
219
            ->method('has')
220
            ->withConsecutive([$name], [$name], [$name])
221
            ->willReturn(false, false, true);
222
223
        $this->config->expects($this->once())
224
            ->method('hasEntityManagerConfig')
225
            ->with($name)
226
            ->willReturn(true);
227
228
        $this->config->expects($this->once())
229
            ->method('getEntityManagerConfig')
230
            ->with($name)
231
            ->willReturn($config);
232
233
        $this->container->expects($this->once())
234
            ->method('setFactory')
235
            ->with($name, EntityManagerFactory::class);
236
237
        $this->container->expects($this->once())
238
            ->method('build')
239
            ->with($name, $config)
240
            ->willReturn($entityManager);
241
242
        $this->container->expects($this->once())
243
            ->method('get')
244
            ->with($name)
245
            ->willReturn($entityManager);
246
247
        $this->assertSame($entityManager, $provider->getEntityManager($name));
248
    }
249
250
    /**
251
     * Assert a EntityManagerProviderException is thrown from getEntityManager() if the provided $name can not be
252
     * resolved to a valid entity manager instance
253
     *
254
     * @throws EntityManagerProviderException
255
     */
256
    public function testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotFound(): void
257
    {
258
        $provider = new EntityManagerProvider($this->config, $this->container);
259
260
        $name = 'EntityManagerTest';
261
262
        $this->container->expects($this->exactly(2))
263
            ->method('has')
264
            ->withConsecutive([$name], [$name])
265
            ->willReturnOnConsecutiveCalls(false, false);
266
267
        $this->config->expects($this->once())
268
            ->method('hasEntityManagerConfig')
269
            ->with($name)
270
            ->willReturn(false);
271
272
        $this->expectException(EntityManagerProviderException::class);
273
        $this->expectExceptionMessage(sprintf('Unable to find entity manager \'%s\'', $name));
274
275
        $provider->refresh($name);
276
    }
277
278
    /**
279
     * Assert a EntityManagerProviderException is thrown from getEntityManager() if the lazy loaded entity manager
280
     * cannot be created
281
     *
282
     * @throws EntityManagerProviderException
283
     */
284
    public function testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotCreated(): void
285
    {
286
        $provider = new EntityManagerProvider($this->config, $this->container);
287
288
        $name = 'EntityManagerTest';
289
        $config = [
290
            'foo' => 123,
291
            'bar' => 'Hello World!',
292
        ];
293
294
        $this->container->expects($this->exactly(2))
295
            ->method('has')
296
            ->withConsecutive([$name], [$name])
297
            ->willReturnOnConsecutiveCalls(false, false);
298
299
        $this->config->expects($this->once())
300
            ->method('hasEntityManagerConfig')
301
            ->with($name)
302
            ->willReturn(true);
303
304
        $this->config->expects($this->once())
305
            ->method('getEntityManagerConfig')
306
            ->with($name)
307
            ->willReturn($config);
308
309
        $this->container->expects($this->once())
310
            ->method('setFactory')
311
            ->with($name, EntityManagerFactory::class);
312
313
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
314
        $exceptionCode = 12345;
315
        $exception = new ServiceNotCreatedException($exceptionMessage, $exceptionCode);
316
317
        $this->container->expects($this->once())
318
            ->method('build')
319
            ->with($name, $config)
320
            ->willThrowException($exception);
321
322
        $this->expectException(EntityManagerProviderException::class);
323
        $this->expectExceptionCode($exceptionCode);
324
        $this->expectExceptionMessage(
325
            sprintf('Failed to create entity manager \'%s\' from configuration: %s', $name, $exceptionMessage)
326
        );
327
328
        $provider->getEntityManager($name);
329
    }
330
331
    /**
332
     * Assert a EntityManagerProviderException is thrown from getEntityManager() if the lazy loaded entity manager
333
     * cannot be returned from the container
334
     *
335
     * @throws EntityManagerProviderException
336
     */
337
    public function testGetEntityManagerWillThrowEntityManagerProviderExceptionIfNotRetrieved(): void
338
    {
339
        $provider = new EntityManagerProvider($this->config, $this->container);
340
341
        $name = 'EntityManagerTest';
342
343
        $this->container->expects($this->exactly(2))
344
            ->method('has')
345
            ->withConsecutive([$name], [$name])
346
            ->willReturnOnConsecutiveCalls(true, true);
347
348
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
349
        $exceptionCode = 54321;
350
        $exception = new ServiceNotCreatedException($exceptionMessage, $exceptionCode);
351
352
        $this->container->expects($this->once())
353
            ->method('get')
354
            ->with($name)
355
            ->willThrowException($exception);
356
357
        $this->expectException(EntityManagerProviderException::class);
358
        $this->expectExceptionCode($exceptionCode);
359
        $this->expectExceptionMessage(
360
            sprintf('Failed retrieve entity manager \'%s\': %s', $name, $exceptionMessage),
361
        );
362
363
        $provider->getEntityManager($name);
364
    }
365
366
    /**
367
     * Assert an EntityManager instance can be refreshed by closing the existing connection and creating a new
368
     * instance based on the configuration
369
     *
370
     * @throws EntityManagerProviderException
371
     */
372
    public function testRefresh(): void
373
    {
374
        $provider = new EntityManagerProvider($this->config, $this->container);
375
376
        $name = 'FooEntityManager';
377
378
        /** @var EntityManagerInterface&MockObject $entityManager */
379
        $entityManager = $this->createMock(EntityManagerInterface::class);
380
381
        /** @var EntityManagerInterface&MockObject $newInstance */
382
        $newInstance = $this->createMock(EntityManagerInterface::class);
383
384
        $config = [
385
            'foo' => 123,
386
            'bar' => 'test',
387
        ];
388
389
        $this->container->expects($this->exactly(4))
390
            ->method('has')
391
            ->withConsecutive([$name], [$name], [$name], [$name])
392
            ->willReturnOnConsecutiveCalls(true, true, true, true);
393
394
        $this->container->expects($this->once())
395
            ->method('get')
396
            ->with($name)
397
            ->willReturn($entityManager);
398
399
        $entityManager->expects($this->once())
400
            ->method('isOpen')
401
            ->willReturn(true);
402
403
        $entityManager->expects($this->once())
404
            ->method('close');
405
406
        $this->config->expects($this->once())
407
            ->method('getEntityManagerConfig')
408
            ->with($name)
409
            ->willReturn($config);
410
411
        $this->container->expects($this->once())
412
            ->method('build')
413
            ->with($name, $config)
414
            ->willReturn($newInstance);
415
416
        $this->assertSame($newInstance, $provider->refresh($name));
417
    }
418
}
419