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

test_static_create_with_many_dependencies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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