Passed
Pull Request — main (#11)
by Jesús
02:20
created

ContainerTest   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 447
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 204
c 7
b 0
f 0
dl 0
loc 447
rs 10
wmc 16

52 Methods

Rating   Name   Duplication   Size   Complexity  
A hp$0 ➔ test_resolve_factory_service_with_random() 0 13 1
A hp$0 ➔ test_extend_non_existing_service() 0 6 1
A test_resolve_service_as_raw_string() 0 10 1
A test_resolve_object_from_instance_in_a_callable() 0 11 1
test_protect_service_cannot_be_extended() 0 13 ?
A test_has_service() 0 7 1
test_extend_existing_used_callable_service_then_error() 0 11 ?
A hp$0 ➔ test_resolve_non_factory_service_with_random() 0 11 1
A test_resolve_service_as_function() 0 10 1
A hp$0 ➔ test_extend_later_existing_frozen_callable_service_then_error() 0 16 1
A hp$0 ➔ test_service_not_extendable() 0 7 1
A hp$0 ➔ test_extend_existing_used_object_service_is_allowed() 0 11 1
A hp$0 ➔ test_extend_existing_object_service() 0 25 1
test_resolve_service_as_callable_class() 0 18 ?
A test_interface_not_registered_returns_null() 0 8 1
A test_has_not_existing_class() 0 6 1
A hp$0 ➔ test_extend_existing_callable_service() 0 23 1
test_extend_existing_array_service() 0 24 ?
A test_static_create_class_with_inner_dependencies_with_many_dependencies() 0 5 1
A test_use_mapped_interface_dependency() 0 11 1
A test_static_create_with_many_dependencies() 0 5 1
A hp$0 ➔ test_protect_service_is_not_resolved() 0 7 1
A hp$0 ➔ test_extend_existing_used_callable_service_then_error() 0 11 1
test_extend_later_existing_frozen_object_service_then_error() 0 16 ?
A hp$0 ➔ test_protect_service_cannot_be_extended() 0 13 1
A test_without_dependencies() 0 6 1
A test_get_non_existing_service() 0 5 1
A test_resolve_object_from_classname() 0 8 1
test_extend_non_existing_service() 0 6 ?
A hp$0 ➔ __invoke() 0 3 1
test_extend_later_existing_frozen_callable_service_then_error() 0 16 ?
A hp$0 ➔ test_extend_existing_array_service() 0 24 1
A hp$0 ➔ test_extend_later_existing_frozen_object_service_then_error() 0 16 1
A test_static_create_class_with_inner_dependencies_without_dependencies() 0 5 1
A test_static_create_with_dependencies() 0 5 1
A test_resolve_object_from_interface() 0 11 1
test_extend_existing_callable_service() 0 23 ?
A test_object_with_resolvable_dependencies() 0 6 1
test_service_not_extendable() 0 7 ?
A test_static_create_without_dependencies() 0 5 1
test_extend_existing_used_object_service_is_allowed() 0 11 ?
test_protect_service_is_not_resolved() 0 7 ?
A test_resolve_new_object() 0 13 1
A test_remove_existing_service() 0 7 1
A hp$0 ➔ test_resolve_service_as_callable_class() 0 18 1
A test_interface_dependency() 0 8 1
test_resolve_factory_service_with_random() 0 13 ?
test_set_existing_frozen_service() 0 8 ?
A test_resolve_object_from_callable_classname_in_a_callable() 0 8 1
A hp$0 ➔ test_set_existing_frozen_service() 0 8 1
test_resolve_non_factory_service_with_random() 0 11 ?
test_extend_existing_object_service() 0 25 ?
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GacelaTest\Unit;
6
7
use ArrayObject;
8
use Gacela\Container\Container;
9
use Gacela\Container\Exception\ContainerException;
10
use GacelaTest\Fake\ClassWithDependencyWithoutDependencies;
11
use GacelaTest\Fake\ClassWithInnerObjectDependencies;
12
use GacelaTest\Fake\ClassWithInterfaceDependencies;
13
use GacelaTest\Fake\ClassWithObjectDependencies;
14
use GacelaTest\Fake\ClassWithoutDependencies;
15
use GacelaTest\Fake\ClassWithRelationship;
16
use GacelaTest\Fake\Person;
17
use GacelaTest\Fake\PersonInterface;
18
use PHPUnit\Framework\TestCase;
19
20
final class ContainerTest extends TestCase
21
{
22
    public function test_static_create_without_dependencies(): void
23
    {
24
        $actual = Container::create(ClassWithoutDependencies::class);
25
26
        self::assertEquals(new ClassWithoutDependencies(), $actual);
27
    }
28
29
    public function test_static_create_class_with_inner_dependencies_without_dependencies(): void
30
    {
31
        $actual = Container::create(ClassWithDependencyWithoutDependencies::class);
32
33
        self::assertEquals(new ClassWithDependencyWithoutDependencies(new ClassWithoutDependencies()), $actual);
34
    }
35
36
    public function test_static_create_class_with_inner_dependencies_with_many_dependencies(): void
37
    {
38
        $actual = Container::create(ClassWithInnerObjectDependencies::class);
39
40
        self::assertEquals(new ClassWithInnerObjectDependencies(new ClassWithRelationship(new Person(), new Person())), $actual);
41
    }
42
43
    public function test_static_create_with_dependencies(): void
44
    {
45
        $actual = Container::create(ClassWithObjectDependencies::class);
46
47
        self::assertEquals(new ClassWithObjectDependencies(new Person()), $actual);
48
    }
49
50
    public function test_static_create_with_many_dependencies(): void
51
    {
52
        $actual = Container::create(ClassWithRelationship::class);
53
54
        self::assertEquals(new ClassWithRelationship(new Person(), new Person()), $actual);
55
    }
56
57
    public function test_without_dependencies(): void
58
    {
59
        $container = new Container();
60
        $actual = $container->get(ClassWithoutDependencies::class);
61
62
        self::assertEquals(new ClassWithoutDependencies(), $actual);
63
    }
64
65
    public function test_object_with_resolvable_dependencies(): void
66
    {
67
        $container = new Container();
68
        $actual = $container->get(ClassWithObjectDependencies::class);
69
70
        self::assertEquals(new ClassWithObjectDependencies(new Person()), $actual);
71
    }
72
73
    public function test_interface_dependency(): void
74
    {
75
        $container = new Container([
76
            PersonInterface::class => Person::class,
77
        ]);
78
        $actual = $container->get(ClassWithObjectDependencies::class);
79
80
        self::assertEquals(new ClassWithObjectDependencies(new Person()), $actual);
81
    }
82
83
    public function test_use_mapped_interface_dependency(): void
84
    {
85
        $person = new Person();
86
        $person->name = 'anything';
87
88
        $container = new Container([
89
            PersonInterface::class => $person,
90
        ]);
91
        $actual = $container->get(ClassWithInterfaceDependencies::class);
92
93
        self::assertEquals(new ClassWithInterfaceDependencies($person), $actual);
94
    }
95
96
    public function test_has_not_existing_class(): void
97
    {
98
        $container = new Container();
99
        $actual = $container->has(InexistentClass::class);
100
101
        self::assertFalse($actual);
102
    }
103
104
    public function test_resolve_object_from_interface(): void
105
    {
106
        $person = new Person();
107
        $person->name = 'person-name';
108
109
        $container = new Container([
110
            PersonInterface::class => $person,
111
        ]);
112
        $resolvedPerson = $container->get(PersonInterface::class);
113
114
        self::assertSame($resolvedPerson, $person);
115
    }
116
117
    public function test_resolve_new_object(): void
118
    {
119
        // We are registering 'PersonInterface::class', but 'Person::class' was not.
120
        // As result, a 'new Person()' will be resolved.
121
        $person = new Person();
122
        $person->name = 'person-name';
123
124
        $container = new Container([
125
            PersonInterface::class => $person,
126
        ]);
127
        $resolvedPerson = $container->get(Person::class);
128
129
        self::assertEquals($resolvedPerson, new Person()); // different objects!
130
    }
131
132
    public function test_interface_not_registered_returns_null(): void
133
    {
134
        $container = new Container([
135
            Person::class => new Person(),
136
        ]);
137
        $resolvedPerson = $container->get(PersonInterface::class);
138
139
        self::assertNull($resolvedPerson);
140
    }
141
142
    public function test_resolve_object_from_classname(): void
143
    {
144
        $container = new Container([
145
            PersonInterface::class => Person::class,
146
        ]);
147
        $resolvedPerson = $container->get(PersonInterface::class);
148
149
        self::assertEquals($resolvedPerson, new Person());
150
    }
151
152
    public function test_resolve_object_from_instance_in_a_callable(): void
153
    {
154
        $person = new Person();
155
        $person->name = 'person-name';
156
157
        $container = new Container([
158
            PersonInterface::class => static fn () => $person,
159
        ]);
160
        $resolvedPerson = $container->get(PersonInterface::class);
161
162
        self::assertEquals($resolvedPerson, $person);
163
    }
164
165
    public function test_resolve_object_from_callable_classname_in_a_callable(): void
166
    {
167
        $container = new Container([
168
            PersonInterface::class => static fn () => Person::class,
169
        ]);
170
        $resolvedPerson = $container->get(PersonInterface::class);
171
172
        self::assertEquals($resolvedPerson, new Person());
173
    }
174
175
    public function test_get_non_existing_service(): void
176
    {
177
        $container = new Container();
178
179
        self::assertNull($container->get('unknown-service_name'));
180
    }
181
182
    public function test_has_service(): void
183
    {
184
        $container = new Container();
185
        $container->set('service_name', 'value');
186
187
        self::assertTrue($container->has('service_name'));
188
        self::assertFalse($container->has('unknown-service_name'));
189
    }
190
191
    public function test_remove_existing_service(): void
192
    {
193
        $container = new Container();
194
        $container->set('service_name', 'value');
195
        $container->remove('service_name');
196
197
        self::assertNull($container->get('service_name'));
198
    }
199
200
    public function test_resolve_service_as_raw_string(): void
201
    {
202
        $container = new Container();
203
        $container->set('service_name', 'value');
204
205
        $resolvedService = $container->get('service_name');
206
        self::assertSame('value', $resolvedService);
207
208
        $cachedResolvedService = $container->get('service_name');
209
        self::assertSame('value', $cachedResolvedService);
210
    }
211
212
    public function test_resolve_service_as_function(): void
213
    {
214
        $container = new Container();
215
        $container->set('service_name', static fn () => 'value');
216
217
        $resolvedService = $container->get('service_name');
218
        self::assertSame('value', $resolvedService);
219
220
        $cachedResolvedService = $container->get('service_name');
221
        self::assertSame('value', $cachedResolvedService);
222
    }
223
224
    public function test_resolve_service_as_callable_class(): void
225
    {
226
        $container = new Container();
227
        $container->set(
228
            'service_name',
229
            new class() {
230
                public function __invoke(): string
231
                {
232
                    return 'value';
233
                }
234
            },
235
        );
236
237
        $resolvedService = $container->get('service_name');
238
        self::assertSame('value', $resolvedService);
239
240
        $cachedResolvedService = $container->get('service_name');
241
        self::assertSame('value', $cachedResolvedService);
242
    }
243
244
    public function test_resolve_non_factory_service_with_random(): void
245
    {
246
        $container = new Container();
247
        $container->set(
248
            'service_name',
249
            static fn () => 'value_' . random_int(0, PHP_INT_MAX),
250
        );
251
252
        self::assertSame(
253
            $container->get('service_name'),
254
            $container->get('service_name'),
255
        );
256
    }
257
258
    public function test_resolve_factory_service_with_random(): void
259
    {
260
        $container = new Container();
261
        $container->set(
262
            'service_name',
263
            $container->factory(
264
                static fn () => 'value_' . random_int(0, PHP_INT_MAX),
265
            ),
266
        );
267
268
        self::assertNotSame(
269
            $container->get('service_name'),
270
            $container->get('service_name'),
271
        );
272
    }
273
274
    public function test_extend_existing_callable_service(): void
275
    {
276
        $container = new Container();
277
        $container->set('n3', 3);
278
        $container->set('service_name', static fn () => new ArrayObject([1, 2]));
279
280
        $container->extend(
281
            'service_name',
282
            static function (ArrayObject $arrayObject, Container $container) {
283
                $arrayObject->append($container->get('n3'));
284
                return $arrayObject;
285
            },
286
        );
287
288
        $container->extend(
289
            'service_name',
290
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4),
291
        );
292
293
        /** @var ArrayObject $actual */
294
        $actual = $container->get('service_name');
295
296
        self::assertEquals(new ArrayObject([1, 2, 3, 4]), $actual);
297
    }
298
299
    public function test_extend_existing_object_service(): void
300
    {
301
        $container = new Container();
302
        $container->set('n3', 3);
303
        $container->set('service_name', new ArrayObject([1, 2]));
304
305
        $container->extend(
306
            'service_name',
307
            static function (ArrayObject $arrayObject, Container $container) {
308
                $arrayObject->append($container->get('n3'));
309
                return $arrayObject;
310
            },
311
        );
312
313
        $container->extend(
314
            'service_name',
315
            static function (ArrayObject $arrayObject): void {
316
                $arrayObject->append(4);
317
            },
318
        );
319
320
        /** @var ArrayObject $actual */
321
        $actual = $container->get('service_name');
322
323
        self::assertEquals(new ArrayObject([1, 2, 3, 4]), $actual);
324
    }
325
326
    public function test_extend_existing_array_service(): void
327
    {
328
        $container = new Container();
329
        $container->set('service_name', [1, 2]);
330
331
        $container->extend(
332
            'service_name',
333
            static function (array $arrayObject): array {
334
                $arrayObject[] = 3;
335
                return $arrayObject;
336
            },
337
        );
338
339
        $container->extend(
340
            'service_name',
341
            static function (array &$arrayObject): void {
342
                $arrayObject[] = 4;
343
            },
344
        );
345
346
        /** @var ArrayObject $actual */
347
        $actual = $container->get('service_name');
348
349
        self::assertEquals([1, 2, 3, 4], $actual);
350
    }
351
352
    public function test_extend_non_existing_service(): void
353
    {
354
        $container = new Container();
355
        $container->extend('service_name', static fn () => '');
356
357
        self::assertNull($container->get('service_name'));
358
    }
359
360
    public function test_service_not_extendable(): void
361
    {
362
        $container = new Container();
363
        $container->set('service_name', 'raw string');
364
365
        $this->expectExceptionObject(ContainerException::instanceNotExtendable());
366
        $container->extend('service_name', static fn (string $str) => $str);
367
    }
368
369
    public function test_extend_existing_used_object_service_is_allowed(): void
370
    {
371
        $container = new Container();
372
        $container->set('service_name', new ArrayObject([1, 2]));
373
        $container->get('service_name'); // and get frozen
374
375
        $this->expectExceptionObject(ContainerException::frozenInstanceExtend('service_name'));
376
377
        $container->extend(
378
            'service_name',
379
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3),
380
        );
381
    }
382
383
    public function test_extend_existing_used_callable_service_then_error(): void
384
    {
385
        $container = new Container();
386
        $container->set('service_name', static fn () => new ArrayObject([1, 2]));
387
        $container->get('service_name'); // and get frozen
388
389
        $this->expectExceptionObject(ContainerException::frozenInstanceExtend('service_name'));
390
391
        $container->extend(
392
            'service_name',
393
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3),
394
        );
395
    }
396
397
    public function test_extend_later_existing_frozen_object_service_then_error(): void
398
    {
399
        $container = new Container();
400
        $container->extend(
401
            'service_name',
402
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3),
403
        );
404
405
        $container->set('service_name', new ArrayObject([1, 2]));
406
        $container->get('service_name'); // and get frozen
407
408
        $this->expectExceptionObject(ContainerException::frozenInstanceExtend('service_name'));
409
410
        $container->extend(
411
            'service_name',
412
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4),
413
        );
414
    }
415
416
    public function test_extend_later_existing_frozen_callable_service_then_error(): void
417
    {
418
        $container = new Container();
419
        $container->extend(
420
            'service_name',
421
            static fn (ArrayObject $arrayObject) => $arrayObject->append(3),
422
        );
423
424
        $container->set('service_name', static fn () => new ArrayObject([1, 2]));
425
        $container->get('service_name'); // and get frozen
426
427
        $this->expectExceptionObject(ContainerException::frozenInstanceExtend('service_name'));
428
429
        $container->extend(
430
            'service_name',
431
            static fn (ArrayObject $arrayObject) => $arrayObject->append(4),
432
        );
433
    }
434
435
    public function test_set_existing_frozen_service(): void
436
    {
437
        $container = new Container();
438
        $container->set('service_name', static fn () => new ArrayObject([1, 2]));
439
        $container->get('service_name'); // and get frozen
440
441
        $this->expectExceptionObject(ContainerException::frozenInstanceOverride('service_name'));
442
        $container->set('service_name', static fn () => new ArrayObject([3]));
443
    }
444
445
    public function test_protect_service_is_not_resolved(): void
446
    {
447
        $container = new Container();
448
        $service = static fn () => 'value';
449
        $container->set('service_name', $container->protect($service));
450
451
        self::assertSame($service, $container->get('service_name'));
452
    }
453
454
    public function test_protect_service_cannot_be_extended(): void
455
    {
456
        $container = new Container();
457
        $container->set(
458
            'service_name',
459
            $container->protect(static fn () => new ArrayObject([1, 2])),
460
        );
461
462
        $this->expectExceptionObject(ContainerException::instanceProtected('service_name'));
463
464
        $container->extend(
465
            'service_name',
466
            static fn (ArrayObject $arrayObject) => $arrayObject,
467
        );
468
    }
469
}
470