Passed
Push — master ( 895d0c...9b68ef )
by Alex
01:07 queued 12s
created

php$0 ➔ testImplementsFactoryInterface()   A

Complexity

Conditions 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 20
rs 9.6
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A AbstractFactoryTest.php$0 ➔ __invoke() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\LaminasFactory;
6
7
use Arp\LaminasFactory\AbstractFactory;
8
use Arp\LaminasFactory\FactoryInterface;
9
use ArpTest\LaminasFactory\TestDouble\GetServiceStdClassFactory;
10
use ArpTest\LaminasFactory\TestDouble\ServiceConfigStdClassFactory;
11
use Interop\Container\Exception\ContainerException;
12
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
13
use PHPUnit\Framework\MockObject\MockObject;
14
use PHPUnit\Framework\TestCase;
15
use Psr\Container\ContainerExceptionInterface;
16
use Psr\Container\ContainerInterface;
17
18
/**
19
 * @covers  \Arp\LaminasFactory\AbstractFactory
20
 *
21
 * @author  Alex Patterson <[email protected]>
22
 * @package ArpTest\LaminasFactory
23
 */
24
final class AbstractFactoryTest extends TestCase
25
{
26
    /**
27
     * @var ContainerInterface&MockObject
28
     */
29
    private $container;
30
31
    /**
32
     * @var string
33
     */
34
    private string $serviceName = \stdClass::class;
35
36
    /**
37
     * @var array<mixed>|null
38
     */
39
    private ?array $options = null;
40
41
    /**
42
     * Prepare the test case dependencies
43
     */
44
    public function setUp(): void
45
    {
46
        $this->container = $this->createMock(ContainerInterface::class);
47
    }
48
49
    /**
50
     * Assert that the factory implements FactoryInterface
51
     */
52
    public function testImplementsFactoryInterface(): void
53
    {
54
        $factory = new class () extends AbstractFactory {
55
            /**
56
             * @param ContainerInterface $container
57
             * @param string             $requestedName
58
             * @param array<mixed>|null  $options
59
             *
60
             * @return \stdClass
61
             */
62
            public function __invoke(
63
                ContainerInterface $container,
64
                string $requestedName,
65
                array $options = null
66
            ): \stdClass {
67
                return new \stdClass();
68
            }
69
        };
70
71
        $this->assertInstanceOf(FactoryInterface::class, $factory);
72
    }
73
74
    /**
75
     * Assert the stdClass can be correctly configured and returned from __invoke()
76
     */
77
    public function testInvokeWillReturnConfiguredStdClass(): void
78
    {
79
        $applicationOptionsService = 'config';
80
        $applicationOptions = [
81
            'arp' => [
82
                'services' => [
83
                    \stdClass::class => [
84
                        'foo' => 'bar',
85
                        123 => true,
86
                        'hello' => [
87
                            'clown' => 'world',
88
                        ],
89
                    ]
90
                ]
91
            ],
92
        ];
93
94
        $factory = new ServiceConfigStdClassFactory();
95
96
        $this->container->expects($this->once())
97
            ->method('has')
98
            ->with($applicationOptionsService)
99
            ->willReturn(true);
100
101
        $this->container->expects($this->once())
102
            ->method('get')
103
            ->with($applicationOptionsService)
104
            ->willReturn($applicationOptions);
105
106
        $stdObject = $factory($this->container, $this->serviceName, $this->options);
107
108
        $this->assertSame($applicationOptions['arp']['services'][\stdClass::class], $stdObject->options);
109
    }
110
111
    /**
112
     * @throws ContainerExceptionInterface
113
     */
114
    public function testGetServiceWillReturnServiceNameWhenProvidedNonStringValue(): void
115
    {
116
        $dependency = new \stdClass();
117
118
        $factory = new GetServiceStdClassFactory($dependency);
119
120
        $createdService = $factory($this->container, 'foo');
121
122
        $this->assertSame($createdService->dependency, $dependency);
123
    }
124
125
    /**
126
     * @throws ContainerExceptionInterface
127
     */
128
    public function testGetServiceWillThrowServiceNotCreatedExceptionIfTheProvidedServiceIsNotAValidService(): void
129
    {
130
        $requestedName = 'FooService';
131
        $dependencyName = 'BarService';
132
133
        $factory = new GetServiceStdClassFactory($dependencyName);
134
135
        $this->container->expects($this->once())
136
            ->method('has')
137
            ->with($dependencyName)
138
            ->willReturn(false);
139
140
        $this->expectException(ServiceNotFoundException::class);
141
        $this->expectExceptionMessage(
142
            sprintf(
143
                'The required \'%s\' dependency could not be found while creating service \'%s\'',
144
                $dependencyName,
145
                $requestedName
146
            )
147
        );
148
149
        $factory($this->container, $requestedName);
150
    }
151
152
    /**
153
     * @throws ContainerExceptionInterface
154
     */
155
    public function testGetServiceWillReThrowContainerContainerExceptionInterfaceErrors(): void
156
    {
157
        $requestedName = 'FooService';
158
        $dependencyName = \stdClass::class;
159
160
        $factory = new GetServiceStdClassFactory($dependencyName);
161
162
        /** @var ContainerException&MockObject $exception */
163
        $exception = $this->getMockForAbstractClass(ContainerException::class);
164
165
        $this->container->expects($this->once())
166
            ->method('get')
167
            ->with($dependencyName)
168
            ->willThrowException($exception);
169
170
        $this->expectException(ContainerException::class);
171
172
        $factory($this->container, $requestedName);
173
    }
174
175
    /**
176
     * @throws ContainerExceptionInterface
177
     */
178
    public function testGetServiceWillReThrowExceptionErrors(): void
179
    {
180
        $requestedName = 'FooService';
181
        $dependencyName = \stdClass::class;
182
183
        $factory = new GetServiceStdClassFactory($dependencyName);
184
185
        $exceptionCode = 777;
186
        /** @var ContainerException&MockObject $exception */
187
        $exception = new \Exception(
188
            'This is a test exception for test ' . __FUNCTION__,
189
            $exceptionCode
190
        );
191
192
        $this->container->expects($this->once())
193
            ->method('get')
194
            ->with($dependencyName)
195
            ->willThrowException($exception);
196
197
        $this->expectException(\Exception::class);
198
        $this->expectExceptionCode($exceptionCode);
199
        $this->expectExceptionMessage(
200
            sprintf(
201
                'The required \'%s\' dependency could not be created for service \'%s\'',
202
                $dependencyName,
203
                $requestedName
204
            )
205
        );
206
207
        $factory($this->container, $requestedName);
208
    }
209
}
210