Passed
Push — feature/extend-raw-array ( 2d84a7 )
by Chema
04:29
created

php$0 ➔ test_extend_existing_array_service()   A

Complexity

Conditions 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GacelaTest\Unit\Framework\Container;
6
7
use ArrayObject;
8
use Gacela\Framework\Container\Container;
9
use Gacela\Framework\Container\Exception\ContainerException;
10
use Gacela\Framework\Container\Exception\ContainerKeyNotFoundException;
11
use PHPUnit\Framework\TestCase;
12
use stdClass;
13
14
final class ContainerTest extends TestCase
15
{
16
    private Container $container;
17
18
    public function setUp(): void
19
    {
20
        $this->container = new Container();
21
    }
22
23
    public function test_get_non_existing_service(): void
24
    {
25
        $this->expectException(ContainerKeyNotFoundException::class);
26
        $this->container->get('unknown-service_name');
27
    }
28
29
    public function test_has_service(): void
30
    {
31
        $this->container->set('service_name', 'value');
32
33
        self::assertTrue($this->container->has('service_name'));
34
        self::assertFalse($this->container->has('unknown-service_name'));
35
    }
36
37
    public function test_remove_existing_service(): void
38
    {
39
        $this->container->set('service_name', 'value');
40
        $this->container->remove('service_name');
41
42
        $this->expectException(ContainerKeyNotFoundException::class);
43
        $this->container->get('service_name');
44
    }
45
46
    public function test_resolve_service_as_raw_string(): void
47
    {
48
        $this->container->set('service_name', 'value');
49
50
        $resolvedService = $this->container->get('service_name');
51
        self::assertSame('value', $resolvedService);
52
53
        $cachedResolvedService = $this->container->get('service_name');
54
        self::assertSame('value', $cachedResolvedService);
55
    }
56
57
    public function test_resolve_service_as_function(): void
58
    {
59
        $this->container->set('service_name', static fn () => 'value');
60
61
        $resolvedService = $this->container->get('service_name');
62
        self::assertSame('value', $resolvedService);
63
64
        $cachedResolvedService = $this->container->get('service_name');
65
        self::assertSame('value', $cachedResolvedService);
66
    }
67
68
    public function test_resolve_service_as_callable_class(): void
69
    {
70
        $this->container->set(
71
            'service_name',
72
            new class() {
73
                public function __invoke(): string
74
                {
75
                    return 'value';
76
                }
77
            }
78
        );
79
80
        $resolvedService = $this->container->get('service_name');
81
        self::assertSame('value', $resolvedService);
82
83
        $cachedResolvedService = $this->container->get('service_name');
84
        self::assertSame('value', $cachedResolvedService);
85
    }
86
87
    public function test_resolve_non_factory_service_with_random(): void
88
    {
89
        $this->container->set(
90
            'service_name',
91
            static fn () => 'value_' . random_int(0, PHP_INT_MAX)
92
        );
93
94
        self::assertSame(
95
            $this->container->get('service_name'),
96
            $this->container->get('service_name')
97
        );
98
    }
99
100
    public function test_resolve_factory_service_with_random(): void
101
    {
102
        $this->container->set(
103
            'service_name',
104
            $this->container->factory(
105
                static fn () => 'value_' . random_int(0, PHP_INT_MAX)
106
            )
107
        );
108
109
        self::assertNotSame(
110
            $this->container->get('service_name'),
111
            $this->container->get('service_name')
112
        );
113
    }
114
115
    public function test_resolve_factory_service_not_invokable(): void
116
    {
117
        $this->expectExceptionObject(ContainerException::serviceNotInvokable());
118
119
        $this->container->set(
120
            'service_name',
121
            $this->container->factory(new stdClass())
122
        );
123
    }
124
125
    public function test_extend_existing_callable_service(): void
126
    {
127
        $this->container->set('n3', 3);
128
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
129
130
        $this->container->extend(
131
            'service_name',
132
            static function (ArrayObject $arrayObject, Container $container) {
133
                $arrayObject->append($container->get('n3'));
134
                return $arrayObject;
135
            }
136
        );
137
138
        $this->container->extend(
139
            'service_name',
140
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4)
141
        );
142
143
        /** @var ArrayObject $actual */
144
        $actual = $this->container->get('service_name');
145
146
        self::assertEquals(new ArrayObject([1, 2, 3, 4]), $actual);
147
    }
148
149
    public function test_extend_existing_object_service(): void
150
    {
151
        $this->container->set('n3', 3);
152
        $this->container->set('service_name', new ArrayObject([1, 2]));
153
154
        $this->container->extend(
155
            'service_name',
156
            static function (ArrayObject $arrayObject, Container $container) {
157
                $arrayObject->append($container->get('n3'));
158
                return $arrayObject;
159
            }
160
        );
161
162
        $this->container->extend(
163
            'service_name',
164
            static function (ArrayObject $arrayObject): void {
165
                $arrayObject->append(4);
166
            }
167
        );
168
169
        /** @var ArrayObject $actual */
170
        $actual = $this->container->get('service_name');
171
172
        self::assertEquals(new ArrayObject([1, 2, 3, 4]), $actual);
173
    }
174
175
    public function test_extend_existing_array_service(): void
176
    {
177
        $this->container->set('service_name', [1, 2]);
178
179
        $this->container->extend(
180
            'service_name',
181
            static function (array $arrayObject): array {
182
                $arrayObject[] = 3;
183
                return $arrayObject;
184
            }
185
        );
186
187
        $this->container->extend(
188
            'service_name',
189
            static function (array &$arrayObject): void {
190
                $arrayObject[] = 4;
191
            }
192
        );
193
194
        /** @var ArrayObject $actual */
195
        $actual = $this->container->get('service_name');
196
197
        self::assertEquals([1, 2, 3, 4], $actual);
198
    }
199
200
    public function test_extend_non_existing_service(): void
201
    {
202
        $this->container->extend('service_name', static fn () => '');
203
204
        $this->expectException(ContainerKeyNotFoundException::class);
205
        $this->container->get('service_name');
206
    }
207
208
    public function test_service_not_extendable(): void
209
    {
210
        $this->container->set('service_name', 'raw string');
211
212
        $this->expectExceptionObject(ContainerException::serviceNotExtendable());
213
        $this->container->extend('service_name', static fn (string $str) => $str);
214
    }
215
216
    public function test_extend_existing_used_object_service_is_allowed(): void
217
    {
218
        $this->container->set('service_name', new ArrayObject([1, 2]));
219
        $this->container->get('service_name'); // and get frozen
220
221
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
222
223
        $this->container->extend(
224
            'service_name',
225
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
226
        );
227
    }
228
229
    public function test_extend_existing_used_callable_service_then_error(): void
230
    {
231
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
232
        $this->container->get('service_name'); // and get frozen
233
234
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
235
236
        $this->container->extend(
237
            'service_name',
238
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
239
        );
240
    }
241
242
    public function test_extend_later_existing_frozen_object_service_then_error(): void
243
    {
244
        $this->container->extend(
245
            'service_name',
246
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
247
        );
248
249
        $this->container->set('service_name', new ArrayObject([1, 2]));
250
        $this->container->get('service_name'); // and get frozen
251
252
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
253
254
        $this->container->extend(
255
            'service_name',
256
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4)
257
        );
258
    }
259
260
    public function test_extend_later_existing_frozen_callable_service_then_error(): void
261
    {
262
        $this->container->extend(
263
            'service_name',
264
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
265
        );
266
267
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
268
        $this->container->get('service_name'); // and get frozen
269
270
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
271
272
        $this->container->extend(
273
            'service_name',
274
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4)
275
        );
276
    }
277
278
    public function test_set_existing_frozen_service(): void
279
    {
280
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
281
        $this->container->get('service_name'); // and get frozen
282
283
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
284
        $this->container->set('service_name', static fn () => new ArrayObject([3]));
285
    }
286
287
    public function test_protect_service_is_not_resolved(): void
288
    {
289
        $service = static fn () => 'value';
290
        $this->container->set('service_name', $this->container->protect($service));
291
292
        self::assertSame($service, $this->container->get('service_name'));
293
    }
294
295
    public function test_protect_service_cannot_be_extended(): void
296
    {
297
        $this->container->set(
298
            'service_name',
299
            $this->container->protect(new ArrayObject([1, 2]))
300
        );
301
302
        $this->expectExceptionObject(ContainerException::serviceProtected('service_name'));
303
304
        $this->container->extend(
305
            'service_name',
306
            static fn (ArrayObject $arrayObject) => $arrayObject
307
        );
308
    }
309
}
310