php$0 ➔ testInvokeWillReturnConfiguredStdClass()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 32
rs 9.408
c 0
b 0
f 0
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\BuildServiceStdClassFactory;
10
use ArpTest\LaminasFactory\TestDouble\GetServiceStdClassFactory;
11
use ArpTest\LaminasFactory\TestDouble\ServiceConfigStdClassFactory;
12
use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
13
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
14
use Laminas\ServiceManager\ServiceLocatorInterface;
15
use PHPUnit\Framework\MockObject\MockObject;
16
use PHPUnit\Framework\TestCase;
17
use Psr\Container\ContainerExceptionInterface;
18
use Psr\Container\ContainerInterface;
19
20
/**
21
 * @covers \Arp\LaminasFactory\AbstractFactory
22
 */
23
final class AbstractFactoryTest extends TestCase
24
{
25
    /**
26
     * @var ContainerInterface&MockObject
27
     */
28
    private ContainerInterface $container;
29
30
    private string $serviceName = \stdClass::class;
31
32
    /**
33
     * @var array<mixed>|null
34
     */
35
    private ?array $options = null;
36
37
    public function setUp(): void
38
    {
39
        $this->container = $this->createMock(ContainerInterface::class);
40
    }
41
42
    public function testImplementsFactoryInterface(): void
43
    {
44
        $factory = new class () extends AbstractFactory {
45
            /**
46
             * @param ContainerInterface $container
47
             * @param string             $requestedName
48
             * @param array<mixed>|null  $options
49
             *
50
             * @return \stdClass
51
             */
52
            public function __invoke(
53
                ContainerInterface $container,
54
                string $requestedName,
55
                array $options = null
56
            ): \stdClass {
57
                return new \stdClass();
58
            }
59
        };
60
61
        $this->assertInstanceOf(FactoryInterface::class, $factory);
62
    }
63
64
    /**
65
     * @throws ContainerExceptionInterface
66
     */
67
    public function testInvokeWillReturnConfiguredStdClass(): void
68
    {
69
        $applicationOptionsService = 'config';
70
        $applicationOptions = [
71
            'arp' => [
72
                'services' => [
73
                    \stdClass::class => [
74
                        'foo' => 'bar',
75
                        123 => true,
76
                        'hello' => [
77
                            'clown' => 'world',
78
                        ],
79
                    ]
80
                ]
81
            ],
82
        ];
83
84
        $factory = new ServiceConfigStdClassFactory();
85
86
        $this->container->expects($this->once())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Psr\Container\ContainerInterface. ( Ignorable by Annotation )

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

86
        $this->container->/** @scrutinizer ignore-call */ 
87
                          expects($this->once())

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...
87
            ->method('has')
88
            ->with($applicationOptionsService)
89
            ->willReturn(true);
90
91
        $this->container->expects($this->once())
92
            ->method('get')
93
            ->with($applicationOptionsService)
94
            ->willReturn($applicationOptions);
95
96
        $stdObject = $factory($this->container, $this->serviceName, $this->options);
97
98
        $this->assertSame($applicationOptions['arp']['services'][\stdClass::class], $stdObject->options);
99
    }
100
101
    /**
102
     * @throws ContainerExceptionInterface
103
     */
104
    public function testGetServiceWillReturnServiceNameWhenProvidedNonStringValue(): void
105
    {
106
        $dependency = new \stdClass();
107
108
        $factory = new GetServiceStdClassFactory($dependency);
109
110
        $createdService = $factory($this->container, 'foo');
111
112
        $this->assertSame($createdService->dependency, $dependency);
113
    }
114
115
    /**
116
     * @throws ContainerExceptionInterface
117
     */
118
    public function testGetServiceWillThrowServiceNotCreatedExceptionIfTheProvidedServiceIsNotAValidService(): void
119
    {
120
        $requestedName = 'FooService';
121
        $dependencyName = 'BarService';
122
123
        $factory = new GetServiceStdClassFactory($dependencyName);
124
125
        $this->container->expects($this->once())
126
            ->method('has')
127
            ->with($dependencyName)
128
            ->willReturn(false);
129
130
        $this->expectException(ServiceNotFoundException::class);
131
        $this->expectExceptionMessage(
132
            sprintf(
133
                'The required \'%s\' dependency could not be found while creating service \'%s\'',
134
                $dependencyName,
135
                $requestedName
136
            )
137
        );
138
139
        $factory($this->container, $requestedName);
140
    }
141
142
    /**
143
     * @throws ContainerExceptionInterface
144
     */
145
    public function testGetServiceWillReThrowContainerContainerExceptionInterfaceErrors(): void
146
    {
147
        $requestedName = 'FooService';
148
        $dependencyName = \stdClass::class;
149
150
        $factory = new GetServiceStdClassFactory($dependencyName);
151
152
        /** @var ContainerExceptionInterface&MockObject $exception */
153
        $exception = new class () extends \Exception implements ContainerExceptionInterface {
154
        };
155
156
        $this->container->expects($this->once())
157
            ->method('get')
158
            ->with($dependencyName)
159
            ->willThrowException($exception);
160
161
        $this->expectException(ContainerExceptionInterface::class);
162
163
        $factory($this->container, $requestedName);
164
    }
165
166
    /**
167
     * @throws ContainerExceptionInterface
168
     */
169
    public function testGetServiceWillReThrowExceptionErrors(): void
170
    {
171
        $requestedName = 'FooService';
172
        $dependencyName = \stdClass::class;
173
174
        $factory = new GetServiceStdClassFactory($dependencyName);
175
176
        $exceptionCode = 777;
177
        $exception = new \Exception(
178
            'This is a test exception for test ' . __FUNCTION__,
179
            $exceptionCode
180
        );
181
182
        $this->container->expects($this->once())
183
            ->method('get')
184
            ->with($dependencyName)
185
            ->willThrowException($exception);
186
187
        $this->expectException(\Exception::class);
188
        $this->expectExceptionCode($exceptionCode);
189
        $this->expectExceptionMessage(
190
            sprintf(
191
                'The required \'%s\' dependency could not be created for service \'%s\'',
192
                $dependencyName,
193
                $requestedName
194
            )
195
        );
196
197
        $factory($this->container, $requestedName);
198
    }
199
200
    /**
201
     * @throws ContainerExceptionInterface
202
     */
203
    public function testBuildServiceWillThrowServiceNotCreatedExceptionIfTheProvidedServiceIsNotAValidService(): void
204
    {
205
        $requestedName = 'FooService';
206
        $dependencyName = 'BarService';
207
        $options = [
208
            'foo' => true,
209
        ];
210
211
        $factory = new BuildServiceStdClassFactory($dependencyName);
212
213
        /** @var ServiceLocatorInterface&MockObject $container */
214
        $container = $this->createMock(ServiceLocatorInterface::class);
215
216
        $exception = new \Exception('This is a test exception message');
217
218
        $container->expects($this->once())
219
            ->method('build')
220
            ->with($dependencyName, $options)
221
            ->willThrowException($exception);
222
223
        $this->expectException(ServiceNotCreatedException::class);
224
        $this->expectExceptionMessage(
225
            sprintf(
226
                'Failed to build service \'%s\' required as dependency of service \'%s\'',
227
                $dependencyName,
228
                $requestedName
229
            ),
230
        );
231
232
        $factory($container, $requestedName, $options);
233
    }
234
}
235