Test Failed
Pull Request — master (#8)
by Alex
03:24
created

testPersistWillThrowPersistenceExceptionIfTheEntityCannotBePersisted()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

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