Test Failed
Pull Request — master (#8)
by Alex
04:30
created

PersistServiceTest   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 835
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 9
eloc 398
dl 0
loc 835
rs 10
c 5
b 1
f 0

36 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 9 1
testRefreshError() 0 32 ?
A testPersistWillThrowPersistenceExceptionIfTheEntityCannotBePersisted() 0 36 1
A hp$1 ➔ testRefreshWillThrowPersistenceExceptionForInvalidEntity() 0 34 1
A testClear() 0 12 1
A testFlushExceptionsAreLoggedAndRethrownAsPersistenceException() 0 32 1
A testGetEntityNameWillReturnFQCNOfEntity() 0 10 1
testRollbackTransactionError() 0 22 ?
A hp$1 ➔ testBeginTransactionError() 0 22 1
A testSaveWillUpdateAndReturnEntityWithId() 0 39 1
testRefresh() 0 17 ?
A testSaveWillInsertAndReturnEntityWithNoId() 0 39 1
A getSaveWillUpdateAndReturnEntityWithIdData() 0 12 1
A testSaveExceptionWillBeCaughtLoggedAndTheDispatchErrorEventTriggeredWhenEntityIdIsNull() 0 31 1
A testPersist() 0 17 1
A hp$1 ➔ testRefresh() 0 17 1
A testPersistWillThrowPersistenceExceptionIfProvidedEntityIsAnInvalidType() 0 30 1
testRefreshWillThrowPersistenceExceptionForInvalidEntity() 0 34 ?
A testImplementsPersistServiceInterface() 0 10 1
A hp$1 ➔ testRollbackTransaction() 0 12 1
A hp$1 ➔ testCommitTransactionError() 0 22 1
testBeginTransactionError() 0 22 ?
A hp$1 ➔ testCommitTransaction() 0 12 1
A testSaveExceptionWillBeCaughtLoggedAndZeroReturnedIfTheEntityIdIsNotNull() 0 31 1
A testDeleteWillDispatchDeleteEventAndReturnTrue() 0 32 1
A getSaveWillInsertAndReturnEntityWithNoIdData() 0 4 1
A testDeleteWillTriggerDeleteErrorEventOnError() 0 47 1
testCommitTransactionError() 0 22 ?
A hp$1 ➔ testRollbackTransactionError() 0 22 1
testCommitTransaction() 0 12 ?
A testFlush() 0 12 1
A hp$1 ➔ testBeginTransaction() 0 12 1
A testClearExceptionsAreLoggedAndRethrownAsPersistenceException() 0 32 1
testBeginTransaction() 0 12 ?
A hp$1 ➔ testRefreshError() 0 32 1
testRollbackTransaction() 0 12 ?
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\DoctrineEntityRepository\Persistence;
6
7
use Arp\DoctrineEntityRepository\Constant\EntityEventName;
8
use Arp\DoctrineEntityRepository\Constant\PersistServiceOption;
9
use Arp\DoctrineEntityRepository\Persistence\Event\EntityErrorEvent;
10
use Arp\DoctrineEntityRepository\Persistence\Event\EntityEvent;
11
use Arp\DoctrineEntityRepository\Persistence\Exception\PersistenceException;
12
use Arp\DoctrineEntityRepository\Persistence\PersistService;
13
use Arp\DoctrineEntityRepository\Persistence\PersistServiceInterface;
14
use Arp\Entity\EntityInterface;
15
use Arp\Entity\EntityTrait;
16
use Arp\EventDispatcher\Listener\Exception\EventListenerException;
17
use Doctrine\ORM\EntityManagerInterface;
18
use PHPUnit\Framework\MockObject\MockObject;
19
use PHPUnit\Framework\TestCase;
20
use Psr\EventDispatcher\EventDispatcherInterface;
21
use Psr\Log\LoggerInterface;
22
23
/**
24
 * @covers  \Arp\DoctrineEntityRepository\Persistence\PersistService
25
 *
26
 * @author  Alex Patterson <[email protected]>
27
 * @package ArpTest\DoctrineEntityRepository\Persistence
28
 */
29
final class PersistServiceTest extends TestCase
30
{
31
    /**
32
     * @var string
33
     */
34
    private string $entityName;
35
36
    /**
37
     * @var EntityManagerInterface&MockObject
38
     */
39
    private $entityManager;
40
41
    /**
42
     * @var EventDispatcherInterface&MockObject
43
     */
44
    private $eventDispatcher;
45
46
    /**
47
     * @var LoggerInterface&MockObject
48
     */
49
    private $logger;
50
51
    /**
52
     * Set up the test case dependencies.
53
     */
54
    public function setUp(): void
55
    {
56
        $this->entityName = EntityInterface::class;
57
58
        $this->entityManager = $this->createMock(EntityManagerInterface::class);
59
60
        $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
61
62
        $this->logger = $this->createMock(LoggerInterface::class);
63
    }
64
65
    /**
66
     * Assert that the class implements PersistServiceInterface
67
     */
68
    public function testImplementsPersistServiceInterface(): void
69
    {
70
        $persistService = new PersistService(
71
            $this->entityName,
72
            $this->entityManager,
73
            $this->eventDispatcher,
74
            $this->logger
75
        );
76
77
        $this->assertInstanceOf(PersistServiceInterface::class, $persistService);
78
    }
79
80
    /**
81
     * Assert that getEntityName() will return the fully qualified class name of the managed entity
82
     */
83
    public function testGetEntityNameWillReturnFQCNOfEntity(): void
84
    {
85
        $persistService = new PersistService(
86
            $this->entityName,
87
            $this->entityManager,
88
            $this->eventDispatcher,
89
            $this->logger
90
        );
91
92
        $this->assertSame($this->entityName, $persistService->getEntityName());
93
    }
94
95
    /**
96
     * If an exception is raised when calling save(), and our entity has an ID value, then the
97
     * EntityEventName::UPDATE_ERROR event should be triggered and a new exception thrown.
98
     *
99
     * @throws PersistenceException
100
     */
101
    public function testSaveExceptionWillBeCaughtLoggedAndZeroReturnedIfTheEntityIdIsNotNull(): void
102
    {
103
        $persistService = new PersistService(
104
            $this->entityName,
105
            $this->entityManager,
106
            $this->eventDispatcher,
107
            $this->logger
108
        );
109
110
        /** @var EntityInterface&MockObject $entity */
111
        $entity = $this->createMock(EntityInterface::class);
112
113
        $entity->expects($this->once())
114
            ->method('hasId')
115
            ->willReturn(true);
116
117
        $exceptionMessage = 'Test exception message for save() and update()';
118
        $exceptionCode = 123;
119
        $exception = new \Exception($exceptionMessage, $exceptionCode);
120
121
        $this->eventDispatcher->expects($this->exactly(2))
122
            ->method('dispatch')
123
            ->withConsecutive(
124
                [$this->isInstanceOf(EntityEvent::class)],
125
                [$this->isInstanceOf(EntityErrorEvent::class)],
126
            )->willReturnOnConsecutiveCalls(
127
                $this->throwException($exception),
128
                $this->returnArgument(0)
129
            );
130
131
        $this->assertSame($entity, $persistService->save($entity));
132
    }
133
134
    /**
135
     * Assert that if we pass an entity with an id to save() that the entity will be updated and returned.
136
     *
137
     * @param array<mixed> $options Optional save options that should be passed to the updated method.
138
     *
139
     * @dataProvider getSaveWillUpdateAndReturnEntityWithIdData
140
     *
141
     * @throws PersistenceException
142
     */
143
    public function testSaveWillUpdateAndReturnEntityWithId(array $options = []): void
144
    {
145
        /** @var PersistService&MockObject $persistService */
146
        $persistService = $this->getMockBuilder(PersistService::class)
147
            ->setConstructorArgs(
148
                [
149
                    $this->entityName,
150
                    $this->entityManager,
151
                    $this->eventDispatcher,
152
                    $this->logger,
153
                ]
154
            )->onlyMethods(['createEvent'])
155
            ->getMock();
156
157
        /** @var EntityInterface&MockObject $entity */
158
        $entity = $this->createMock(EntityInterface::class);
159
160
        $entity->expects($this->once())
161
            ->method('hasId')
162
            ->willReturn(true);
163
164
        /** @var EntityEvent&MockObject $event */
165
        $event = $this->createMock(EntityEvent::class);
166
167
        $persistService->expects($this->once())
168
            ->method('createEvent')
169
            ->with(EntityEventName::UPDATE, $entity, $options)
170
            ->willReturn($event);
171
172
        $this->eventDispatcher->expects($this->once())
173
            ->method('dispatch')
174
            ->with($event)
175
            ->willReturn($event);
176
177
        $event->expects($this->once())
178
            ->method('getEntity')
179
            ->willReturn($entity);
180
181
        $this->assertSame($entity, $persistService->save($entity, $options));
182
    }
183
184
    /**
185
     * @return array<mixed>
186
     */
187
    public function getSaveWillUpdateAndReturnEntityWithIdData(): array
188
    {
189
        return [
190
            [
191
                [
192
                    // empty options
193
                ],
194
                [
195
                    PersistServiceOption::FLUSH => true,
196
                ],
197
                [
198
                    PersistServiceOption::FLUSH => false,
199
                ],
200
            ],
201
        ];
202
    }
203
204
    /**
205
     * If an exception is raised when calling save(), and our entity does NOT have an ID value, then the
206
     * EntityEventName::CREATE_ERROR event should be triggered and a new exception thrown
207
     *
208
     * @throws PersistenceException
209
     */
210
    public function testSaveExceptionWillBeCaughtLoggedAndTheDispatchErrorEventTriggeredWhenEntityIdIsNull(): void
211
    {
212
        $persistService = new PersistService(
213
            $this->entityName,
214
            $this->entityManager,
215
            $this->eventDispatcher,
216
            $this->logger
217
        );
218
219
        /** @var EntityInterface&MockObject $entity */
220
        $entity = $this->createMock(EntityInterface::class);
221
222
        $entity->expects($this->once())
223
            ->method('hasId')
224
            ->willReturn(false);
225
226
        $exceptionMessage = 'Test exception message for ' . __FUNCTION__;
227
        $exceptionCode = 456;
228
        $exception = new \Error($exceptionMessage, $exceptionCode);
229
230
        $this->eventDispatcher->expects($this->exactly(2))
231
            ->method('dispatch')
232
            ->withConsecutive(
233
                [$this->isInstanceOf(EntityEvent::class)],
234
                [$this->isInstanceOf(EntityErrorEvent::class)],
235
            )->willReturnOnConsecutiveCalls(
236
                $this->throwException($exception),
237
                $this->returnArgument(0)
238
            );
239
240
        $this->assertSame($entity, $persistService->save($entity));
241
    }
242
243
    /**
244
     * Assert that an entity provided to save() that does not have an identity will be proxies to insert()
245
     *
246
     * @param array<mixed> $options
247
     *
248
     * @dataProvider getSaveWillInsertAndReturnEntityWithNoIdData
249
     *
250
     * @throws PersistenceException
251
     */
252
    public function testSaveWillInsertAndReturnEntityWithNoId(array $options = []): void
253
    {
254
        /** @var PersistService&MockObject $persistService */
255
        $persistService = $this->getMockBuilder(PersistService::class)
256
            ->setConstructorArgs(
257
                [
258
                    $this->entityName,
259
                    $this->entityManager,
260
                    $this->eventDispatcher,
261
                    $this->logger,
262
                ]
263
            )->onlyMethods(['createEvent'])
264
            ->getMock();
265
266
        /** @var EntityInterface&MockObject $entity */
267
        $entity = $this->createMock(EntityInterface::class);
268
269
        $entity->expects($this->once())
270
            ->method('hasId')
271
            ->willReturn(false);
272
273
        /** @var EntityEvent&MockObject $event */
274
        $event = $this->createMock(EntityEvent::class);
275
276
        $persistService->expects($this->once())
277
            ->method('createEvent')
278
            ->with(EntityEventName::CREATE, $entity, $options)
279
            ->willReturn($event);
280
281
        $this->eventDispatcher->expects($this->once())
282
            ->method('dispatch')
283
            ->with($event)
284
            ->willReturn($event);
285
286
        $event->expects($this->once())
287
            ->method('getEntity')
288
            ->willReturn($entity);
289
290
        $this->assertSame($entity, $persistService->save($entity, $options));
291
    }
292
293
    /**
294
     * @return array<mixed>
295
     */
296
    public function getSaveWillInsertAndReturnEntityWithNoIdData(): array
297
    {
298
        return [
299
            [
300
301
            ],
302
        ];
303
    }
304
305
    /**
306
     * Assert that if an exception occurs during the dispatch of the delete event, the delete_error event will be
307
     * dispatched with the entity error event containing the caught exception
308
     *
309
     * @throws PersistenceException
310
     */
311
    public function testDeleteWillTriggerDeleteErrorEventOnError(): void
312
    {
313
        $entityName = EntityInterface::class;
314
315
        /** @var PersistService&MockObject $persistService */
316
        $persistService = $this->getMockBuilder(PersistService::class)
317
            ->setConstructorArgs([
318
                $entityName,
319
                $this->entityManager,
320
                $this->eventDispatcher,
321
                $this->logger,
322
            ])->onlyMethods(['createEvent', 'createErrorEvent'])
323
            ->getMock();
324
325
        /** @var EntityInterface&MockObject $entity */
326
        $entity = $this->createMock(EntityInterface::class);
327
        $options = [];
328
329
        /** @var EntityEvent&MockObject $event */
330
        $event = $this->createMock(EntityEvent::class);
331
332
        $persistService->expects($this->once())
333
            ->method('createEvent')
334
            ->with(EntityEventName::DELETE, $entity, $options)
335
            ->willReturn($event);
336
337
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
338
        $exceptionCode = 123;
339
        $exception = new EventListenerException($exceptionMessage, $exceptionCode);
340
341
        /** @var EntityErrorEvent&MockObject $errorEvent */
342
        $errorEvent = $this->createMock(EntityErrorEvent::class);
343
344
        $this->eventDispatcher->expects($this->exactly(2))
345
            ->method('dispatch')
346
            ->withConsecutive([$event], [$errorEvent])
347
            ->willReturnOnConsecutiveCalls(
348
                $this->throwException($exception),
349
                $errorEvent
350
            );
351
352
        $persistService->expects($this->once())
353
            ->method('createErrorEvent')
354
            ->with(EntityEventName::DELETE_ERROR, $exception)
355
            ->willReturn($errorEvent);
356
357
        $this->assertFalse($persistService->delete($entity, $options));
358
    }
359
360
    /**
361
     * Assert that the delete event is dispatched when
362
     *
363
     * @throws PersistenceException
364
     */
365
    public function testDeleteWillDispatchDeleteEventAndReturnTrue(): void
366
    {
367
        $entityName = EntityInterface::class;
368
369
        /** @var PersistService&MockObject $persistService */
370
        $persistService = $this->getMockBuilder(PersistService::class)
371
            ->setConstructorArgs([
372
                $entityName,
373
                $this->entityManager,
374
                $this->eventDispatcher,
375
                $this->logger,
376
            ])->onlyMethods(['createEvent'])
377
            ->getMock();
378
379
        /** @var EntityInterface&MockObject $entity */
380
        $entity = $this->createMock(EntityInterface::class);
381
        $options = [];
382
383
        /** @var EntityEvent&MockObject $event */
384
        $event = $this->createMock(EntityEvent::class);
385
386
        $persistService->expects($this->once())
387
            ->method('createEvent')
388
            ->with(EntityEventName::DELETE, $entity, $options)
389
            ->willReturn($event);
390
391
        $this->eventDispatcher->expects($this->once())
392
            ->method('dispatch')
393
            ->with($event)
394
            ->willReturn($event);
395
396
        $this->assertTrue($persistService->delete($entity, $options));
397
    }
398
399
    /**
400
     * Assert that a PersistenceException will be thrown by persist() if the provided entity instance is not an
401
     * instance of the mapped entity class
402
     */
403
    public function testPersistWillThrowPersistenceExceptionIfProvidedEntityIsAnInvalidType(): void
404
    {
405
        $entityName = \stdClass::class;
406
407
        $persistService = new PersistService(
408
            $entityName, // Invalid entity class name...
409
            $this->entityManager,
410
            $this->eventDispatcher,
411
            $this->logger
412
        );
413
414
        /** @var EntityInterface&MockObject $entity */
415
        $entity = $this->createMock(EntityInterface::class);
416
417
        $errorMessage = sprintf(
418
            'The \'entity\' argument must be an object of type \'%s\'; \'%s\' provided in \'%s::%s\'',
419
            $entityName,
420
            get_class($entity),
421
            PersistService::class,
422
            'persist'
423
        );
424
425
        $this->logger->expects($this->once())
426
            ->method('error')
427
            ->with($errorMessage);
428
429
        $this->expectException(PersistenceException::class);
430
        $this->expectExceptionMessage($errorMessage);
431
432
        $persistService->persist($entity);
433
    }
434
435
    /**
436
     * Assert that if the $entity provided to persist() cannot be persisted any raised exception is caught, logged
437
     * and then rethrown as a PersistenceException
438
     */
439
    public function testPersistWillThrowPersistenceExceptionIfTheEntityCannotBePersisted(): void
440
    {
441
        $persistService = new PersistService(
442
            $this->entityName,
443
            $this->entityManager,
444
            $this->eventDispatcher,
445
            $this->logger
446
        );
447
448
        /** @var EntityInterface&MockObject $entity */
449
        $entity = $this->createMock(EntityInterface::class);
450
451
        $exceptionMessage = 'This is a test error message for persist()';
452
        $exceptionCode = 456;
453
        $exception = new \Error($exceptionMessage, $exceptionCode);
454
455
        $this->entityManager->expects($this->once())
456
            ->method('persist')
457
            ->with($entity)
458
            ->willThrowException($exception);
459
460
        $errorMessage = sprintf(
461
            'The persist operation failed for entity \'%s\': %s',
462
            $this->entityName,
463
            $exceptionMessage
464
        );
465
466
        $this->logger->expects($this->once())
467
            ->method('error')
468
            ->with($errorMessage, ['exception' => $exception]);
469
470
        $this->expectException(PersistenceException::class);
471
        $this->expectExceptionMessage($errorMessage);
472
        $this->expectExceptionCode($exceptionCode);
473
474
        $persistService->persist($entity);
475
    }
476
477
    /**
478
     * Assert that persist() will successfully proxy the provided $entity to the entity manager persist()
479
     *
480
     * @throws PersistenceException
481
     */
482
    public function testPersist(): void
483
    {
484
        $persistService = new PersistService(
485
            $this->entityName,
486
            $this->entityManager,
487
            $this->eventDispatcher,
488
            $this->logger
489
        );
490
491
        /** @var EntityInterface&MockObject $entity */
492
        $entity = $this->createMock(EntityInterface::class);
493
494
        $this->entityManager->expects($this->once())
495
            ->method('persist')
496
            ->with($entity);
497
498
        $persistService->persist($entity);
499
    }
500
501
    /**
502
     * Assert that exception raised from flush() are logged and rethrown as PersistenceException
503
     *
504
     * @throws PersistenceException
505
     */
506
    public function testFlushExceptionsAreLoggedAndRethrownAsPersistenceException(): void
507
    {
508
        $persistService = new PersistService(
509
            $this->entityName,
510
            $this->entityManager,
511
            $this->eventDispatcher,
512
            $this->logger
513
        );
514
515
        $exceptionMessage = 'This is a test error message for flush()';
516
        $exceptionCode = 999;
517
        $exception = new \Error($exceptionMessage, $exceptionCode);
518
519
        $this->entityManager->expects($this->once())
520
            ->method('flush')
521
            ->willThrowException($exception);
522
523
        $errorMessage = sprintf(
524
            'The flush operation failed for entity \'%s\': %s',
525
            $this->entityName,
526
            $exceptionMessage
527
        );
528
529
        $this->logger->expects($this->once())
530
            ->method('error')
531
            ->with($errorMessage, ['exception' => $exception, 'entity_name' => $this->entityName]);
532
533
        $this->expectException(PersistenceException::class);
534
        $this->expectExceptionMessage($errorMessage);
535
        $this->expectExceptionCode($exceptionCode);
536
537
        $persistService->flush();
538
    }
539
540
    /**
541
     * Assert that flush() will call the internal entity manager flush()
542
     *
543
     * @throws PersistenceException
544
     */
545
    public function testFlush(): void
546
    {
547
        $persistService = new PersistService(
548
            $this->entityName,
549
            $this->entityManager,
550
            $this->eventDispatcher,
551
            $this->logger
552
        );
553
554
        $this->entityManager->expects($this->once())->method('flush');
555
556
        $persistService->flush();
557
    }
558
559
    /**
560
     * Assert that exceptions raised in clear() are logged and rethrown as PersistenceException
561
     *
562
     * @throw  PersistenceException
563
     */
564
    public function testClearExceptionsAreLoggedAndRethrownAsPersistenceException(): void
565
    {
566
        $persistService = new PersistService(
567
            $this->entityName,
568
            $this->entityManager,
569
            $this->eventDispatcher,
570
            $this->logger
571
        );
572
573
        $exceptionMessage = 'This is a test exception message for clear()';
574
        $exceptionCode = 888;
575
        $exception = new \Error($exceptionMessage, $exceptionCode);
576
577
        $this->entityManager->expects($this->once())
578
            ->method('clear')
579
            ->willThrowException($exception);
580
581
        $errorMessage = sprintf(
582
            'The clear operation failed for entity \'%s\': %s',
583
            $this->entityName,
584
            $exceptionMessage
585
        );
586
587
        $this->logger->expects($this->once())
588
            ->method('error')
589
            ->with($errorMessage, ['exception' => $exception, 'entity_name' => $this->entityName]);
590
591
        $this->expectException(PersistenceException::class);
592
        $this->expectExceptionMessage($errorMessage);
593
        $this->expectExceptionCode($exceptionCode);
594
595
        $persistService->clear();
596
    }
597
598
    /**
599
     * Assert that calls to clear() will proxy to the internal entity manager clear()
600
     *
601
     * @throws PersistenceException
602
     */
603
    public function testClear(): void
604
    {
605
        $persistService = new PersistService(
606
            $this->entityName,
607
            $this->entityManager,
608
            $this->eventDispatcher,
609
            $this->logger
610
        );
611
612
        $this->entityManager->expects($this->once())->method('clear');
613
614
        $persistService->clear();
615
    }
616
617
    /**
618
     * Assert a PersistenceException is thrown from refresh() if the provided Entity is not managed by this
619
     * repository class
620
     *
621
     * @throws PersistenceException
622
     */
623
    public function testRefreshWillThrowPersistenceExceptionForInvalidEntity(): void
624
    {
625
        $entity = new class() implements EntityInterface {
626
            use EntityTrait;
627
        };
628
629
        $entity2 = new class() implements EntityInterface {
630
            use EntityTrait;
631
        };
632
633
        $this->entityName = get_class($entity2);
634
635
        $persistService = new PersistService(
636
            $this->entityName,
637
            $this->entityManager,
638
            $this->eventDispatcher,
639
            $this->logger
640
        );
641
642
        $this->entityManager->expects($this->never())
643
            ->method('refresh')
644
            ->with($entity);
645
646
        $this->expectException(PersistenceException::class);
647
        $this->expectExceptionMessage(
648
            sprintf(
649
                'The \'entity\' argument must be an object of type \'%s\'; \'%s\' provided in \'%s\'',
650
                $this->entityName,
651
                get_class($entity),
652
                PersistService::class . '::refresh'
653
            )
654
        );
655
656
        $persistService->refresh($entity);
657
    }
658
659
    /**
660
     * Assert a PersistenceException is thrown from refresh() if the refresh() action fails
661
     *
662
     * @throws PersistenceException
663
     */
664
    public function testRefreshError(): void
665
    {
666
        $persistService = new PersistService(
667
            $this->entityName,
668
            $this->entityManager,
669
            $this->eventDispatcher,
670
            $this->logger
671
        );
672
673
        /** @var EntityInterface&MockObject $entity */
674
        $entity = $this->createMock(EntityInterface::class);
675
676
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
677
        $exceptionCode = 987;
678
        $exception = new \RuntimeException($exceptionMessage, $exceptionCode);
679
680
        $this->entityManager->expects($this->once())
681
            ->method('refresh')
682
            ->with($entity)
683
            ->willThrowException($exception);
684
685
        $this->expectException(PersistenceException::class);
686
        $this->expectExceptionCode($exceptionCode);
687
        $this->expectExceptionMessage(
688
            sprintf(
689
                'The refresh operation failed for entity \'%s\' : %s',
690
                $this->entityName,
691
                $exceptionMessage
692
            )
693
        );
694
695
        $persistService->refresh($entity);
696
    }
697
698
    /**
699
     * Assert calls to refresh() will result in the $entity being passed to EntityManager::refresh()
700
     *
701
     * @throws PersistenceException
702
     */
703
    public function testRefresh(): void
704
    {
705
        $persistService = new PersistService(
706
            $this->entityName,
707
            $this->entityManager,
708
            $this->eventDispatcher,
709
            $this->logger
710
        );
711
712
        /** @var EntityInterface&MockObject $entity */
713
        $entity = $this->createMock(EntityInterface::class);
714
715
        $this->entityManager->expects($this->once())
716
            ->method('refresh')
717
            ->with($entity);
718
719
        $persistService->refresh($entity);
720
    }
721
722
    /**
723
     * Assert calls to beginTransaction() will proxy to the managed EntityManager instance
724
     *
725
     * @throws PersistenceException
726
     */
727
    public function testBeginTransaction(): void
728
    {
729
        $persistService = new PersistService(
730
            $this->entityName,
731
            $this->entityManager,
732
            $this->eventDispatcher,
733
            $this->logger
734
        );
735
736
        $this->entityManager->expects($this->once())->method('beginTransaction');
737
738
        $persistService->beginTransaction();
739
    }
740
741
    /**
742
     * Assert calls to beginTransaction() will throw a PersistenceException on error
743
     *
744
     * @throws PersistenceException
745
     */
746
    public function testBeginTransactionError(): void
747
    {
748
        $persistService = new PersistService(
749
            $this->entityName,
750
            $this->entityManager,
751
            $this->eventDispatcher,
752
            $this->logger
753
        );
754
755
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
756
        $exceptionCode = 123;
757
        $exception = new \RuntimeException($exceptionMessage, $exceptionCode);
758
759
        $this->entityManager->expects($this->once())
760
            ->method('beginTransaction')
761
            ->willThrowException($exception);
762
763
        $this->expectException(PersistenceException::class);
764
        $this->expectExceptionMessage(sprintf('Failed to start transaction : %s', $exceptionMessage));
765
        $this->expectExceptionCode($exceptionCode);
766
767
        $persistService->beginTransaction();
768
    }
769
770
    /**
771
     * Assert calls to commitTransaction() will proxy to the managed EntityManager instance
772
     *
773
     * @throws PersistenceException
774
     */
775
    public function testCommitTransaction(): void
776
    {
777
        $persistService = new PersistService(
778
            $this->entityName,
779
            $this->entityManager,
780
            $this->eventDispatcher,
781
            $this->logger
782
        );
783
784
        $this->entityManager->expects($this->once())->method('commit');
785
786
        $persistService->commitTransaction();
787
    }
788
789
    /**
790
     * Assert calls to commitTransaction() will throw a PersistenceException on error
791
     *
792
     * @throws PersistenceException
793
     */
794
    public function testCommitTransactionError(): void
795
    {
796
        $persistService = new PersistService(
797
            $this->entityName,
798
            $this->entityManager,
799
            $this->eventDispatcher,
800
            $this->logger
801
        );
802
803
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
804
        $exceptionCode = 123;
805
        $exception = new \RuntimeException($exceptionMessage, $exceptionCode);
806
807
        $this->entityManager->expects($this->once())
808
            ->method('commit')
809
            ->willThrowException($exception);
810
811
        $this->expectException(PersistenceException::class);
812
        $this->expectExceptionMessage(sprintf('Failed to commit transaction : %s', $exceptionMessage));
813
        $this->expectExceptionCode($exceptionCode);
814
815
        $persistService->commitTransaction();
816
    }
817
818
    /**
819
     * Assert calls to rollbackTransaction() will proxy to the managed EntityManager instance
820
     *
821
     * @throws PersistenceException
822
     */
823
    public function testRollbackTransaction(): void
824
    {
825
        $persistService = new PersistService(
826
            $this->entityName,
827
            $this->entityManager,
828
            $this->eventDispatcher,
829
            $this->logger
830
        );
831
832
        $this->entityManager->expects($this->once())->method('rollback');
833
834
        $persistService->rollbackTransaction();
835
    }
836
837
    /**
838
     * Assert calls to rollbackTransaction() will throw a PersistenceException on error
839
     *
840
     * @throws PersistenceException
841
     */
842
    public function testRollbackTransactionError(): void
843
    {
844
        $persistService = new PersistService(
845
            $this->entityName,
846
            $this->entityManager,
847
            $this->eventDispatcher,
848
            $this->logger
849
        );
850
851
        $exceptionMessage = 'This is a test exception message for ' . __FUNCTION__;
852
        $exceptionCode = 123;
853
        $exception = new \RuntimeException($exceptionMessage, $exceptionCode);
854
855
        $this->entityManager->expects($this->once())
856
            ->method('rollback')
857
            ->willThrowException($exception);
858
859
        $this->expectException(PersistenceException::class);
860
        $this->expectExceptionMessage(sprintf('Failed to rollback transaction : %s', $exceptionMessage));
861
        $this->expectExceptionCode($exceptionCode);
862
863
        $persistService->rollbackTransaction();
864
    }
865
}
866