Passed
Push — feature/add-container-protect-... ( b82e87 )
by Chema
04:32
created

php$0 ➔ test_protect_service_cannot_be_extended()   A

Complexity

Conditions 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
cc 1
rs 9.8666
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_non_existing_service(): void
176
    {
177
        $this->container->extend('service_name', static fn () => '');
178
179
        $this->expectException(ContainerKeyNotFoundException::class);
180
        $this->container->get('service_name');
181
    }
182
183
    public function test_service_not_extendable(): void
184
    {
185
        $this->container->set('service_name', 'raw string');
186
187
        $this->expectExceptionObject(ContainerException::serviceNotExtendable());
188
        $this->container->extend('service_name', static fn (string $str) => $str);
189
    }
190
191
    public function test_extend_existing_used_object_service_is_allowed(): void
192
    {
193
        $this->container->set('service_name', new ArrayObject([1, 2]));
194
        $this->container->get('service_name'); // and get frozen
195
196
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
197
198
        $this->container->extend(
199
            'service_name',
200
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
201
        );
202
    }
203
204
    public function test_extend_existing_used_callable_service_then_error(): void
205
    {
206
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
207
        $this->container->get('service_name'); // and get frozen
208
209
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
210
211
        $this->container->extend(
212
            'service_name',
213
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
214
        );
215
    }
216
217
    public function test_extend_later_existing_frozen_object_service_then_error(): void
218
    {
219
        $this->container->extend(
220
            'service_name',
221
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
222
        );
223
224
        $this->container->set('service_name', new ArrayObject([1, 2]));
225
        $this->container->get('service_name'); // and get frozen
226
227
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
228
229
        $this->container->extend(
230
            'service_name',
231
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4)
232
        );
233
    }
234
235
    public function test_extend_later_existing_frozen_callable_service_then_error(): void
236
    {
237
        $this->container->extend(
238
            'service_name',
239
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3)
240
        );
241
242
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
243
        $this->container->get('service_name'); // and get frozen
244
245
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
246
247
        $this->container->extend(
248
            'service_name',
249
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4)
250
        );
251
    }
252
253
    public function test_set_existing_frozen_service(): void
254
    {
255
        $this->container->set('service_name', static fn () => new ArrayObject([1, 2]));
256
        $this->container->get('service_name'); // and get frozen
257
258
        $this->expectExceptionObject(ContainerException::serviceFrozen('service_name'));
259
        $this->container->set('service_name', static fn () => new ArrayObject([3]));
260
    }
261
262
    public function test_protect_service_is_not_resolved(): void
263
    {
264
        $service = static fn () => 'value';
265
        $this->container->set('service_name', $this->container->protect($service));
266
267
        self::assertSame($service, $this->container->get('service_name'));
268
    }
269
270
    public function test_protect_service_cannot_be_extended(): void
271
    {
272
        $this->container->set(
273
            'service_name',
274
            $this->container->protect(new ArrayObject([1, 2]))
275
        );
276
277
        $this->expectExceptionObject(ContainerException::serviceProtected('service_name'));
278
279
        $this->container->extend(
280
            'service_name',
281
            static fn (ArrayObject $arrayObject) => $arrayObject
282
        );
283
    }
284
}
285