Passed
Pull Request — master (#6)
by
unknown
01:33
created

php$0 ➔ testInvokeReferencedArguments()   A

Complexity

Conditions 1

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 40
rs 9.28
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Injector\Tests;
6
7
use DateTime;
8
use DateTimeImmutable;
9
use DateTimeInterface;
10
use PHPUnit\Framework\TestCase;
11
use Psr\Container\ContainerInterface;
12
use Psr\Container\NotFoundExceptionInterface;
13
use stdClass;
14
use Yiisoft\Injector\Injector;
15
use Yiisoft\Injector\InvalidArgumentException;
16
use Yiisoft\Injector\MissingRequiredArgumentException;
17
use Yiisoft\Injector\Tests\Support\ColorInterface;
18
use Yiisoft\Injector\Tests\Support\EngineInterface;
19
use Yiisoft\Injector\Tests\Support\EngineMarkTwo;
20
use Yiisoft\Injector\Tests\Support\EngineZIL130;
21
use Yiisoft\Injector\Tests\Support\EngineVAZ2101;
22
use Yiisoft\Injector\Tests\Support\LightEngine;
23
use Yiisoft\Injector\Tests\Support\MakeEmptyConstructor;
24
use Yiisoft\Injector\Tests\Support\MakeEngineCollector;
25
use Yiisoft\Injector\Tests\Support\MakeEngineMatherWithParam;
26
use Yiisoft\Injector\Tests\Support\MakeNoConstructor;
27
use Yiisoft\Injector\Tests\Support\MakePrivateConstructor;
28
29
class InjectorTest extends TestCase
30
{
31
    /**
32
     * Injector should be able to invoke closure.
33
     */
34
    public function testInvokeClosure(): void
35
    {
36
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
37
38
        $getEngineName = fn (EngineInterface $engine) => $engine->getName();
39
40
        $engineName = (new Injector($container))->invoke($getEngineName);
41
42
        $this->assertSame('Mark Two', $engineName);
43
    }
44
45
    /**
46
     * Injector should be able to invoke array callable.
47
     */
48
    public function testInvokeCallableArray(): void
49
    {
50
        $container = $this->getContainer();
51
52
        $object = new EngineVAZ2101();
53
54
        $engine = (new Injector($container))->invoke([$object, 'rust'], ['index' => 5.0]);
55
56
        $this->assertInstanceOf(EngineVAZ2101::class, $engine);
57
    }
58
59
    /**
60
     * Injector should be able to invoke static method.
61
     */
62
    public function testInvokeStatic(): void
63
    {
64
        $container = $this->getContainer();
65
66
        $result = (new Injector($container))->invoke([EngineVAZ2101::class, 'isWroomWroom']);
67
68
        $this->assertIsBool($result);
69
    }
70
71
    /**
72
     * Injector should be able to invoke static method.
73
     */
74
    public function testInvokeAnonymousClass(): void
75
    {
76
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
77
        $class = new class() {
78
            public EngineInterface $engine;
79
            public function setEngine(EngineInterface $engine)
80
            {
81
                $this->engine = $engine;
82
            }
83
        };
84
85
        (new Injector($container))->invoke([$class, 'setEngine']);
86
87
        $this->assertInstanceOf(EngineInterface::class, $class->engine);
88
    }
89
90
    /**
91
     * Injector should be able to invoke method without arguments.
92
     */
93
    public function testInvokeWithoutArguments(): void
94
    {
95
        $container = $this->getContainer();
96
97
        $true = fn () => true;
98
99
        $result = (new Injector($container))->invoke($true);
100
101
        $this->assertTrue($result);
102
    }
103
104
    /**
105
     * Nullable arguments should be searched in container.
106
     */
107
    public function testWithNullableArgument(): void
108
    {
109
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
110
111
        $nullable = fn (?EngineInterface $engine) => $engine;
112
113
        $result = (new Injector($container))->invoke($nullable);
114
115
        $this->assertNotNull($result);
116
    }
117
118
    /**
119
     * Nullable arguments not found in container should be passed as `null`.
120
     */
121
    public function testWithNullableArgumentAndEmptyContainer(): void
122
    {
123
        $container = $this->getContainer();
124
125
        $nullable = fn (?EngineInterface $engine) => $engine;
126
127
        $result = (new Injector($container))->invoke($nullable);
128
129
        $this->assertNull($result);
130
    }
131
132
    /**
133
     * Nullable scalars should be set with `null` if not specified by name explicitly.
134
     */
135
    public function testWithNullableScalarArgument(): void
136
    {
137
        $container = $this->getContainer();
138
139
        $nullableInt = fn (?int $number) => $number;
140
141
        $result = (new Injector($container))->invoke($nullableInt);
142
143
        $this->assertNull($result);
144
    }
145
146
    /**
147
     * Optional scalar arguments should be set with default value if not specified by name explicitly.
148
     */
149
    public function testWithNullableOptionalArgument(): void
150
    {
151
        $container = $this->getContainer();
152
153
        $nullableInt = fn (?int $number = 6) => $number;
154
155
        $result = (new Injector($container))->invoke($nullableInt);
156
157
        $this->assertSame(6, $result);
158
    }
159
160
    /**
161
     * Optional arguments with `null` by default should be set with `null` if other value not specified in parameters
162
     * or container.
163
     */
164
    public function testWithNullableOptionalArgumentThatNull(): void
165
    {
166
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
167
168
        $callable = fn (EngineInterface $engine = null) => $engine;
169
170
        $result = (new Injector($container))->invoke($callable);
171
172
        $this->assertNotNull($result);
173
    }
174
175
    /**
176
     * An object for a typed argument can be specified in parameters without named key and without following the order.
177
     */
178
    public function testCustomDependency(): void
179
    {
180
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
181
        $needleEngine = new EngineZIL130();
182
183
        $getEngineName = fn (EngineInterface $engine) => $engine->getName();
184
185
        $engineName = (new Injector($container))->invoke(
186
            $getEngineName,
187
            [new stdClass(), $needleEngine, new DateTimeImmutable()]
188
        );
189
190
        $this->assertSame(EngineZIL130::NAME, $engineName);
191
    }
192
193
    /**
194
     * In this case, first argument will be set from parameters, and second argument from container.
195
     */
196
    public function testTwoEqualCustomArgumentsWithOneCustom(): void
197
    {
198
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
199
200
        $compareEngines = static function (EngineInterface $engine1, EngineInterface $engine2) {
201
            return $engine1->getPower() <=> $engine2->getPower();
202
        };
203
        $zilEngine = new EngineZIL130();
204
205
        $result = (new Injector($container))->invoke($compareEngines, [$zilEngine]);
206
207
        $this->assertSame(-1, $result);
208
    }
209
210
    /**
211
     * In this case, second argument will be set from parameters by name, and first argument from container.
212
     */
213
    public function testTwoEqualCustomArgumentsWithOneCustomNamedParameter(): void
214
    {
215
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
216
217
        $compareEngines = static function (EngineInterface $engine1, EngineInterface $engine2) {
218
            return $engine1->getPower() <=> $engine2->getPower();
219
        };
220
        $zilEngine = new EngineZIL130();
221
222
        $result = (new Injector($container))->invoke($compareEngines, ['engine2' => $zilEngine]);
223
224
        $this->assertSame(1, $result);
225
    }
226
227
    /**
228
     * Values for arguments are not matched by the greater similarity of parameter types and arguments, but simply pass
229
     * in order as is.
230
     */
231
    public function testExtendedArgumentsWithOneCustomNamedParameter2(): void
232
    {
233
        $container = $this->getContainer([LightEngine::class => new EngineVAZ2101()]);
234
235
        $concatEngineNames = static function (EngineInterface $engine1, LightEngine $engine2) {
236
            return $engine1->getName() . $engine2->getName();
237
        };
238
239
        $result = (new Injector($container))->invoke($concatEngineNames, [
240
            new EngineMarkTwo(), // LightEngine, EngineInterface
241
            new EngineZIL130(), // EngineInterface
242
        ]);
243
244
        $this->assertSame(EngineMarkTwo::NAME . EngineVAZ2101::NAME, $result);
245
    }
246
247
    public function testMissingRequiredTypedParameter(): void
248
    {
249
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
250
251
        $getEngineName = static function (EngineInterface $engine, string $two) {
0 ignored issues
show
Unused Code introduced by
The parameter $two is not used and could be removed. ( Ignorable by Annotation )

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

251
        $getEngineName = static function (EngineInterface $engine, /** @scrutinizer ignore-unused */ string $two) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
252
            return $engine->getName();
253
        };
254
255
        $injector = new Injector($container);
256
257
        $this->expectException(MissingRequiredArgumentException::class);
258
        $injector->invoke($getEngineName);
259
    }
260
261
    public function testMissingRequiredNotTypedParameter(): void
262
    {
263
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
264
265
        $getEngineName = static function (EngineInterface $engine, $two) {
0 ignored issues
show
Unused Code introduced by
The parameter $two is not used and could be removed. ( Ignorable by Annotation )

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

265
        $getEngineName = static function (EngineInterface $engine, /** @scrutinizer ignore-unused */ $two) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
266
            return $engine->getName();
267
        };
268
        $injector = new Injector($container);
269
270
        $this->expectException(MissingRequiredArgumentException::class);
271
272
        $injector->invoke($getEngineName);
273
    }
274
275
    public function testNotFoundException(): void
276
    {
277
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
278
279
        $getEngineName = static function (EngineInterface $engine, ColorInterface $color) {
0 ignored issues
show
Unused Code introduced by
The parameter $color is not used and could be removed. ( Ignorable by Annotation )

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

279
        $getEngineName = static function (EngineInterface $engine, /** @scrutinizer ignore-unused */ ColorInterface $color) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
280
            return $engine->getName();
281
        };
282
283
        $injector = new Injector($container);
284
285
        $this->expectException(NotFoundExceptionInterface::class);
286
        $injector->invoke($getEngineName);
287
    }
288
289
    /**
290
     * A values collection for a variadic argument can be passed as an array in a named parameter.
291
     */
292
    public function testAloneScalarVariadicArgumentAnsNamedParam(): void
293
    {
294
        $container = $this->getContainer();
295
296
        $callable = fn (...$var) => array_sum($var);
297
298
        $result = (new Injector($container))->invoke($callable, ['var' => [1, 2, 3]]);
299
300
        $this->assertSame(6, $result);
301
    }
302
303
    /**
304
     * If type of a variadic argument is a class and named parameter with values collection is not set then injector
305
     * will search for objects by class name among all unnamed parameters.
306
     */
307
    public function testVariadicArgumentUnnamedParams(): void
308
    {
309
        $container = $this->getContainer([DateTimeInterface::class => new DateTimeImmutable()]);
310
311
        $callable = fn (DateTimeInterface $dateTime, EngineInterface ...$engines) => count($engines);
312
313
        $result = (new Injector($container))->invoke(
314
            $callable,
315
            [new EngineZIL130(), new EngineVAZ2101(), new stdClass(), new EngineMarkTwo(), new stdClass()]
316
        );
317
318
        $this->assertSame(3, $result);
319
    }
320
321
    /**
322
     * If calling method have an untyped variadic argument then all remaining unnamed parameters will be passed.
323
     */
324
    public function testVariadicMixedArgumentWithMixedParams(): void
325
    {
326
        $container = $this->getContainer([DateTimeInterface::class => new DateTimeImmutable()]);
327
328
        $callable = fn (...$engines) => $engines;
329
330
        $result = (new Injector($container))->invoke(
331
            $callable,
332
            [new EngineZIL130(), new EngineVAZ2101(), new EngineMarkTwo(), new stdClass()]
333
        );
334
335
        $this->assertCount(4, $result);
336
    }
337
338
    /**
339
     * Any unnamed parameter can only be an object. Scalar, array, null and other values can only be named parameters.
340
     */
341
    public function testVariadicStringArgumentWithUnnamedStringsParams(): void
342
    {
343
        $container = $this->getContainer([DateTimeInterface::class => new DateTimeImmutable()]);
344
345
        $callable = fn (string ...$engines) => $engines;
346
347
        $this->expectException(\Exception::class);
348
349
        (new Injector($container))->invoke($callable, ['str 1', 'str 2', 'str 3']);
350
    }
351
352
    /**
353
     * In the absence of other values to a nullable variadic argument `null` is not passed by default.
354
     */
355
    public function testNullableVariadicArgument(): void
356
    {
357
        $container = $this->getContainer();
358
359
        $callable = fn (?EngineInterface ...$engines) => $engines;
360
361
        $result = (new Injector($container))->invoke($callable, []);
362
363
        $this->assertSame([], $result);
364
    }
365
366
    /**
367
     * Parameters that were passed but were not used are appended to the call so they could be obtained
368
     * with func_get_args().
369
     */
370
    public function testAppendingUnusedParams(): void
371
    {
372
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
373
374
        $callable = fn (?EngineInterface $engine, $id = 'test') => func_num_args();
0 ignored issues
show
Unused Code introduced by
The parameter $engine is not used and could be removed. ( Ignorable by Annotation )

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

374
        $callable = fn (/** @scrutinizer ignore-unused */ ?EngineInterface $engine, $id = 'test') => func_num_args();

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $id is not used and could be removed. ( Ignorable by Annotation )

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

374
        $callable = fn (?EngineInterface $engine, /** @scrutinizer ignore-unused */ $id = 'test') => func_num_args();

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
375
376
        $result = (new Injector($container))->invoke($callable, [new DateTimeImmutable(), new DateTimeImmutable()]);
377
378
        $this->assertSame(4, $result);
379
    }
380
381
    /**
382
     * Object type may be passed as unnamed parameter
383
     */
384
    public function testInvokeWithObjectType(): void
385
    {
386
        $container = $this->getContainer();
387
        $callable = fn (object $object) => get_class($object);
388
389
        $result = (new Injector($container))->invoke($callable, [new DateTimeImmutable()]);
390
391
        $this->assertSame(DateTimeImmutable::class, $result);
392
    }
393
394
    /**
395
     * Required `object` type should not be requested from the container
396
     */
397
    public function testInvokeWithRequiredObjectTypeWithoutInstance(): void
398
    {
399
        $container = $this->getContainer();
400
        $callable = fn (object $object) => get_class($object);
401
402
        $this->expectException(MissingRequiredArgumentException::class);
403
404
        (new Injector($container))->invoke($callable);
405
    }
406
407
    /**
408
     * Arguments passed by reference
409
     */
410
    public function testInvokeReferencedArguments(): void
411
    {
412
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
413
        $foo = 1;
414
        $bar = new stdClass();
415
        $baz = null;
416
        $callable = static function (
417
            int &$foo,
418
            object &$bar,
419
            &$baz,
420
            ?ColorInterface &$nullable,
421
            EngineInterface &$object, // from container
422
            DateTimeInterface &...$dates // collect all unnamed DateTimeInterface objects
423
        ) {
424
            $return = func_get_args();
425
            $bar = new DateTimeImmutable();
426
            $baz = false;
427
            $foo = count($dates);
428
            return $return;
429
        };
430
        $result = (new Injector($container))
431
            ->invoke($callable, [
432
                new DateTimeImmutable(),
433
                new DateTime(),
434
                new DateTime(),
435
                'foo' => &$foo,
436
                'bar' => $bar,
437
                'baz' => &$baz,
438
            ]);
439
440
        // passed
441
        $this->assertSame(1, $result[0]);
442
        $this->assertInstanceOf(stdClass::class, $result[1]);
443
        $this->assertNull($result[2]);
444
        $this->assertNull($result[3]);
445
        $this->assertInstanceOf(EngineMarkTwo::class, $result[4]);
446
        // transformed
447
        $this->assertSame(3, $foo); // count of DateTimeInterface objects
448
        $this->assertInstanceOf(stdClass::class, $bar);
449
        $this->assertFalse($baz);
450
    }
451
452
    public function testInvokeReferencedArgumentNamedVariadic(): void
453
    {
454
        $container = $this->getContainer();
455
456
        $callable = static function (DateTimeInterface &...$dates) {
457
            $dates[0] = false;
458
            $dates[1] = false;
459
            return count($dates);
460
        };
461
        $foo = new DateTimeImmutable();
462
        $bar = new DateTimeImmutable();
463
        $result = (new Injector($container))
464
            ->invoke($callable, [
465
                $foo,
466
                &$bar,
467
                new DateTime(),
468
            ]);
469
470
        $this->assertSame(3, $result);
471
        $this->assertInstanceOf(DateTimeImmutable::class, $foo);
472
        $this->assertFalse($bar);
473
    }
474
475
    /**
476
     * If argument passed by reference but it is not supported by function
477
     */
478
    public function testInvokeReferencedArgument(): void
479
    {
480
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
481
        $foo = 1;
482
        $callable = fn (int $foo) => ++$foo;
483
        $result = (new Injector($container))->invoke($callable, ['foo' => &$foo]);
484
485
        // $foo has been not changed
486
        $this->assertSame(1, $foo);
487
        $this->assertSame(2, $result);
488
    }
489
490
    public function testWrongNamedParam(): void
491
    {
492
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
493
494
        $callable = fn (EngineInterface $engine) => $engine;
495
496
        $this->expectException(\Throwable::class);
497
498
        (new Injector($container))->invoke($callable, ['engine' => new DateTimeImmutable()]);
499
    }
500
501
    public function testArrayArgumentWithUnnamedType(): void
502
    {
503
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
504
505
        $callable = fn (array $arg) => $arg;
506
507
        $this->expectException(MissingRequiredArgumentException::class);
508
509
        (new Injector($container))->invoke($callable, [['test']]);
510
    }
511
512
    public function testCallableArgumentWithUnnamedType(): void
513
    {
514
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
515
516
        $callable = fn (callable $arg) => $arg();
517
518
        $this->expectException(MissingRequiredArgumentException::class);
519
520
        (new Injector($container))->invoke($callable, [fn () => true]);
521
    }
522
523
    public function testIterableArgumentWithUnnamedType(): void
524
    {
525
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
526
527
        $callable = fn (iterable $arg) => $arg;
528
529
        $this->expectException(MissingRequiredArgumentException::class);
530
531
        (new Injector($container))->invoke($callable, [new \SplStack()]);
532
    }
533
534
    public function testUnnamedScalarParam(): void
535
    {
536
        $container = $this->getContainer();
537
538
        $getEngineName = fn () => 42;
539
540
        $this->expectException(InvalidArgumentException::class);
541
542
        (new Injector($container))->invoke($getEngineName, ['test']);
543
    }
544
545
    /**
546
     * Constructor method not defined
547
     */
548
    public function testMakeWithoutConstructor(): void
549
    {
550
        $container = $this->getContainer();
551
552
        $object = (new Injector($container))->make(MakeNoConstructor::class);
553
554
        $this->assertInstanceOf(MakeNoConstructor::class, $object);
555
    }
556
557
    /**
558
     * Constructor without arguments
559
     */
560
    public function testMakeWithoutArguments(): void
561
    {
562
        $container = $this->getContainer();
563
564
        $object = (new Injector($container))->make(MakeEmptyConstructor::class);
565
566
        $this->assertInstanceOf(MakeEmptyConstructor::class, $object);
567
    }
568
569
    /**
570
     * Private constructor unavailable from Injector context
571
     */
572
    public function testMakeWithPrivateConstructor(): void
573
    {
574
        $container = $this->getContainer();
575
576
        $this->expectException(\InvalidArgumentException::class);
577
        $this->expectExceptionMessageMatches('/not instantiable/');
578
579
        (new Injector($container))->make(MakePrivateConstructor::class);
580
    }
581
582
    public function testMakeInvalidClass(): void
583
    {
584
        $container = $this->getContainer();
585
586
        $this->expectException(\ReflectionException::class);
587
        $this->expectExceptionMessageMatches('/does not exist/');
588
589
        (new Injector($container))->make(UndefinedClassThatShouldNotBeDefined::class);
0 ignored issues
show
Bug introduced by
The type Yiisoft\Injector\Tests\U...sThatShouldNotBeDefined was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
590
    }
591
592
    public function testMakeInternalClass(): void
593
    {
594
        $container = $this->getContainer();
595
        $object = (new Injector($container))->make(DateTimeImmutable::class);
596
        $this->assertInstanceOf(DateTimeImmutable::class, $object);
597
    }
598
599
    public function testMakeAbstractClass(): void
600
    {
601
        $container = $this->getContainer();
602
        $this->expectException(\InvalidArgumentException::class);
603
        $this->expectExceptionMessageMatches('/not instantiable/');
604
        (new Injector($container))->make(LightEngine::class);
605
    }
606
607
    public function testMakeInterface(): void
608
    {
609
        $container = $this->getContainer();
610
        $this->expectException(\InvalidArgumentException::class);
611
        $this->expectExceptionMessageMatches('/not instantiable/');
612
        (new Injector($container))->make(EngineInterface::class);
613
    }
614
615
    public function testMakeWithVariadicFromContainer(): void
616
    {
617
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
618
619
        $object = (new Injector($container))->make(MakeEngineCollector::class, []);
620
621
        $this->assertSame(1, count($object->engines));
622
        $this->assertSame([$container->get(EngineInterface::class)], $object->engines);
623
    }
624
625
    public function testMakeWithVariadicFromArguments(): void
626
    {
627
        $container = $this->getContainer();
628
629
        $values = [new EngineMarkTwo(), new EngineVAZ2101()];
630
        $object = (new Injector($container))->make(MakeEngineCollector::class, $values);
631
632
        $this->assertSame($values, $object->engines);
633
    }
634
635
    public function testMakeWithCustomParam(): void
636
    {
637
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
638
639
        $object = (new Injector($container))
640
            ->make(MakeEngineMatherWithParam::class, [new EngineVAZ2101(), 'parameter' => 'power']);
641
642
        $this->assertNotSame($object->engine1, $object->engine2);
643
        $this->assertInstanceOf(EngineVAZ2101::class, $object->engine1);
644
        $this->assertNotSame(EngineMarkTwo::class, $object->engine2);
645
        $this->assertSame($object->parameter, 'power');
646
    }
647
648
    public function testMakeWithInvalidCustomParam(): void
649
    {
650
        $container = $this->getContainer([EngineInterface::class => new EngineMarkTwo()]);
651
652
        $this->expectException(\TypeError::class);
653
654
        (new Injector($container))->make(MakeEngineMatherWithParam::class, ['parameter' => 100500]);
655
    }
656
657
    private function getContainer(array $definitions = []): ContainerInterface
658
    {
659
        return new class($definitions) implements ContainerInterface {
660
            private array $definitions = [];
661
            public function __construct(array $definitions = [])
662
            {
663
                $this->definitions = $definitions;
664
            }
665
            public function get($id)
666
            {
667
                if (!$this->has($id)) {
668
                    throw new class() extends \Exception implements NotFoundExceptionInterface {
669
                    };
670
                }
671
                return $this->definitions[$id];
672
            }
673
            public function has($id)
674
            {
675
                return array_key_exists($id, $this->definitions);
676
            }
677
        };
678
    }
679
}
680