Completed
Push — 1.x ( dfb961...b65a8d )
by Kevin
34s queued 34s
created

Object6::closureSelf()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Zenstruck\Callback\Tests;
4
5
use PHPUnit\Framework\TestCase;
0 ignored issues
show
Bug introduced by
The type PHPUnit\Framework\TestCase 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...
6
use Zenstruck\Callback;
7
use Zenstruck\Callback\Argument;
8
use Zenstruck\Callback\Exception\UnresolveableArgument;
9
use Zenstruck\Callback\Parameter;
10
11
/**
12
 * @author Kevin Bond <[email protected]>
13
 */
14
final class CallbackTest extends TestCase
15
{
16
    /**
17
     * @test
18
     */
19
    public function create_must_be_callable(): void
20
    {
21
        $this->expectException(\InvalidArgumentException::class);
22
23
        Callback::createFor('not a callable');
24
    }
25
26
    /**
27
     * @test
28
     */
29
    public function invoke_all_can_enforce_min_arguments(): void
30
    {
31
        $callback = Callback::createFor(function() { return 'ret'; });
32
33
        $this->expectException(\ArgumentCountError::class);
34
35
        $callback->invokeAll(Parameter::untyped('foo'), 1);
36
    }
37
38
    /**
39
     * @test
40
     */
41
    public function invoke_all_with_no_arguments(): void
42
    {
43
        $actual = Callback::createFor(function() { return 'ret'; })
44
            ->invokeAll(Parameter::untyped('foo'))
45
        ;
46
47
        $this->assertSame('ret', $actual);
48
    }
49
50
    /**
51
     * @test
52
     */
53
    public function invoke_all_with_string_callable(): void
54
    {
55
        $actual = Callback::createFor('strtoupper')
56
            ->invokeAll(Parameter::union(
57
                Parameter::untyped('foobar'),
58
                Parameter::typed('string', 'foobar')
59
            )
60
        )
61
        ;
62
63
        $this->assertSame('FOOBAR', $actual);
64
    }
65
66
    /**
67
     * @test
68
     */
69
    public function invoke_all_untyped_argument(): void
70
    {
71
        $actual = Callback::createFor(function($string) { return \mb_strtoupper($string); })
72
            ->invokeAll(Parameter::untyped('foobar'))
73
        ;
74
75
        $this->assertSame('FOOBAR', $actual);
76
    }
77
78
    /**
79
     * @test
80
     */
81
    public function invoke_all_primitive_typed_argument(): void
82
    {
83
        $actual = Callback::createFor(function(string $string) { return \mb_strtoupper($string); })
84
            ->invokeAll(Parameter::typed('string', 'foobar'))
85
        ;
86
87
        $this->assertSame('FOOBAR', $actual);
88
    }
89
90
    /**
91
     * @test
92
     */
93
    public function invoke_all_class_arguments(): void
94
    {
95
        $object = new Object2();
96
        $function = static function(Object1 $object1, Object2 $object2, $object3) {
97
            return [
98
                'object1' => $object1,
99
                'object2' => $object2,
100
                'object3' => $object3,
101
            ];
102
        };
103
104
        $actual = Callback::createFor($function)
105
            ->invokeAll(Parameter::union(
106
                Parameter::untyped($object),
107
                Parameter::typed(Object1::class, $object)
108
            ))
109
        ;
110
111
        $this->assertSame(
112
            [
113
                'object1' => $object,
114
                'object2' => $object,
115
                'object3' => $object,
116
            ],
117
            $actual
118
        );
119
    }
120
121
    /**
122
     * @test
123
     */
124
    public function invoke_all_class_arguments_value_factories(): void
125
    {
126
        $function = static function(Object1 $object1, Object2 $object2, $object3) {
127
            return [
128
                'object1' => $object1,
129
                'object2' => $object2,
130
                'object3' => $object3,
131
            ];
132
        };
133
        $factoryArgs = [];
134
        $factory = Parameter::factory(static function($arg) use (&$factoryArgs) {
135
            $factoryArgs[] = $arg;
136
137
            if ($arg) {
138
                return new $arg();
139
            }
140
141
            return new Object1();
142
        });
143
144
        $ret = Callback::createFor($function)
145
            ->invokeAll(Parameter::union(
146
                Parameter::untyped($factory),
147
                Parameter::typed(Object1::class, $factory)
148
            ))
149
        ;
150
151
        $this->assertSame(['object1', 'object2', 'object3'], \array_keys($ret));
152
        $this->assertInstanceOf(Object1::class, $ret['object1']);
153
        $this->assertInstanceOf(Object2::class, $ret['object2']);
154
        $this->assertInstanceOf(Object1::class, $ret['object3']);
155
        $this->assertSame(
156
            [Object1::class, Object2::class, null],
157
            $factoryArgs
158
        );
159
    }
160
161
    /**
162
     * @test
163
     */
164
    public function invoke_all_unresolvable_parameter(): void
165
    {
166
        $callback = Callback::createFor(static function(Object1 $object1, Object2 $object2, Object3 $object3) {});
0 ignored issues
show
Unused Code introduced by
The parameter $object1 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

166
        $callback = Callback::createFor(static function(/** @scrutinizer ignore-unused */ Object1 $object1, Object2 $object2, Object3 $object3) {});

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 $object2 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

166
        $callback = Callback::createFor(static function(Object1 $object1, /** @scrutinizer ignore-unused */ Object2 $object2, Object3 $object3) {});

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 $object3 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

166
        $callback = Callback::createFor(static function(Object1 $object1, Object2 $object2, /** @scrutinizer ignore-unused */ Object3 $object3) {});

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...
167
168
        $this->expectException(UnresolveableArgument::class);
169
        $this->expectExceptionMessage('Unable to resolve argument 2 for callback. Expected type: "mixed|Zenstruck\Callback\Tests\Object1"');
170
171
        $callback->invokeAll(Parameter::union(
172
            Parameter::untyped(new Object1()),
173
            Parameter::typed(Object1::class, new Object1())
174
        ));
175
    }
176
177
    /**
178
     * @test
179
     */
180
    public function invoke_with_no_args(): void
181
    {
182
        $actual = Callback::createFor(function() { return 'ret'; })->invoke();
183
184
        $this->assertSame('ret', $actual);
185
    }
186
187
    /**
188
     * @test
189
     */
190
    public function invoke_with_too_few_parameters(): void
191
    {
192
        $this->expectException(\ArgumentCountError::class);
193
        $this->expectExceptionMessage('Too few arguments passed to "Zenstruck\Callback\Tests\CallbackTest');
194
        $this->expectExceptionMessage('Expected 2, got 1.');
195
196
        Callback::createFor(function(string $string, float $float, ?int $int = null) { return 'ret'; })->invoke('2');
0 ignored issues
show
Unused Code introduced by
The parameter $int 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

196
        Callback::createFor(function(string $string, float $float, /** @scrutinizer ignore-unused */ ?int $int = null) { return 'ret'; })->invoke('2');

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 $float 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

196
        Callback::createFor(function(string $string, /** @scrutinizer ignore-unused */ float $float, ?int $int = null) { return 'ret'; })->invoke('2');

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 $string 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

196
        Callback::createFor(function(/** @scrutinizer ignore-unused */ string $string, float $float, ?int $int = null) { return 'ret'; })->invoke('2');

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...
197
    }
198
199
    /**
200
     * @test
201
     */
202
    public function invoke_with_non_parameters(): void
203
    {
204
        $callback = Callback::createFor(
205
            function(string $string, float $float, ?int $int = null) { return [$string, $float, $int]; }
206
        );
207
208
        $this->assertSame(['value', 3.4, null], $callback->invoke('value', 3.4));
209
    }
210
211
    /**
212
     * @test
213
     */
214
    public function invoke_with_resolvable_args(): void
215
    {
216
        $object = new Object2();
217
        $function = static function(Object1 $object1, Object2 $object2, $object3, $extra) {
218
            return [
219
                'object1' => $object1,
220
                'object2' => $object2,
221
                'object3' => $object3,
222
                'extra' => $extra,
223
            ];
224
        };
225
226
        $actual = Callback::createFor($function)
227
            ->invoke(
228
                Parameter::typed(Object1::class, $object),
229
                Parameter::typed(Object2::class, $object),
230
                Parameter::untyped($object),
231
                'value'
232
            )
233
        ;
234
235
        $this->assertSame(
236
            [
237
                'object1' => $object,
238
                'object2' => $object,
239
                'object3' => $object,
240
                'extra' => 'value',
241
            ],
242
            $actual
243
        );
244
    }
245
246
    /**
247
     * @test
248
     */
249
    public function invoke_with_unresolvable_argument(): void
250
    {
251
        $object = new Object2();
252
        $function = static function(Object1 $object1, $object2, $object3, $extra) {};
0 ignored issues
show
Unused Code introduced by
The parameter $extra 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

252
        $function = static function(Object1 $object1, $object2, $object3, /** @scrutinizer ignore-unused */ $extra) {};

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 $object2 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

252
        $function = static function(Object1 $object1, /** @scrutinizer ignore-unused */ $object2, $object3, $extra) {};

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 $object3 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

252
        $function = static function(Object1 $object1, $object2, /** @scrutinizer ignore-unused */ $object3, $extra) {};

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 $object1 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

252
        $function = static function(/** @scrutinizer ignore-unused */ Object1 $object1, $object2, $object3, $extra) {};

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...
253
254
        $this->expectException(UnresolveableArgument::class);
255
        $this->expectExceptionMessage('Unable to resolve argument 2 for callback. Expected type: "Zenstruck\Callback\Tests\Object2"');
256
257
        Callback::createFor($function)
258
            ->invoke(
259
                Parameter::typed(Object1::class, $object),
260
                Parameter::typed(Object2::class, $object),
261
                Parameter::untyped($object),
262
                'value'
263
            )
264
        ;
265
    }
266
267
    /**
268
     * @test
269
     */
270
    public function invoke_with_not_enough_required_arguments(): void
271
    {
272
        $object = new Object2();
273
        $function = static function(Object1 $object1) {};
0 ignored issues
show
Unused Code introduced by
The parameter $object1 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

273
        $function = static function(/** @scrutinizer ignore-unused */ Object1 $object1) {};

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...
274
275
        $this->expectException(\ArgumentCountError::class);
276
        $this->expectExceptionMessage('No argument 2 for callable. Expected type: "Zenstruck\Callback\Tests\Object2"');
277
278
        Callback::createFor($function)
279
            ->invoke(
280
                Parameter::typed(Object1::class, $object),
281
                Parameter::typed(Object2::class, $object),
282
                Parameter::untyped($object),
283
                'value'
284
            )
285
        ;
286
    }
287
288
    /**
289
     * @test
290
     */
291
    public function can_mark_invoke_parameter_arguments_as_optional(): void
292
    {
293
        $actual = Callback::createFor(static function() { return 'ret'; })
294
            ->invoke(Parameter::typed('string', 'foobar')->optional())
295
        ;
296
297
        $this->assertSame('ret', $actual);
298
299
        $actual = Callback::createFor(static function(string $v) { return $v; })
300
            ->invoke(Parameter::typed('string', 'foobar')->optional())
301
        ;
302
303
        $this->assertSame('foobar', $actual);
304
    }
305
306
    /**
307
     * @test
308
     */
309
    public function is_stringable(): void
310
    {
311
        $this->assertStringMatchesFormat(__CLASS__.':%d', (string) Callback::createFor(function() {}));
312
        $this->assertStringMatchesFormat(__CLASS__.':%d', (string) Callback::createFor([$this, __METHOD__]));
313
        $this->assertStringMatchesFormat(Object4::class.':%d', (string) Callback::createFor(new Object4()));
314
        $this->assertStringMatchesFormat(Object4::class.':%d', (string) Callback::createFor([Object4::class, 'staticMethod']));
315
        $this->assertSame(__NAMESPACE__.'\test_function', (string) Callback::createFor(__NAMESPACE__.'\test_function'));
316
    }
317
318
    /**
319
     * @test
320
     * @requires PHP >= 8.0
321
     */
322
    public function invoke_can_support_union_typehints(): void
323
    {
324
        // hack to allow test suite to run on php 7 w/o syntax errors
325
        eval('$callback = fn(\Zenstruck\Callback\Tests\Object1|string $arg) => \'ret\';');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
326
327
        $this->assertSame('ret', Callback::createFor($callback)->invokeAll(Parameter::typed(Object1::class, new Object1())));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callback seems to be never defined.
Loading history...
328
        $this->assertSame('ret', Callback::createFor($callback)->invokeAll(Parameter::typed('string', 'value')));
329
        $this->assertSame('ret', Callback::createFor($callback)->invoke(Parameter::typed(Object1::class, new Object1())));
330
        $this->assertSame('ret', Callback::createFor($callback)->invoke(Parameter::typed('string', 'value')));
331
    }
332
333
    /**
334
     * @test
335
     */
336
    public function can_get_callback_arguments(): void
337
    {
338
        $callback = Callback::createFor(function(Object1 $a, $b, string $c) {});
0 ignored issues
show
Unused Code introduced by
The parameter $c 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

338
        $callback = Callback::createFor(function(Object1 $a, $b, /** @scrutinizer ignore-unused */ string $c) {});

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 $b 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

338
        $callback = Callback::createFor(function(Object1 $a, /** @scrutinizer ignore-unused */ $b, string $c) {});

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 $a 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

338
        $callback = Callback::createFor(function(/** @scrutinizer ignore-unused */ Object1 $a, $b, string $c) {});

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...
339
340
        $this->assertSame(Object1::class, $callback->argument(0)->type());
341
        $this->assertNull($callback->argument(1)->type());
342
        $this->assertSame('string', $callback->argument(2)->type());
343
        $this->assertSame(
344
            [
345
                Object1::class,
346
                null,
347
                'string',
348
            ],
349
            \array_map(function(Argument $a) { return $a->type(); }, $callback->arguments())
350
        );
351
    }
352
353
    /**
354
     * @test
355
     * @requires PHP >= 8.0
356
     */
357
    public function can_get_union_callback_arguments(): void
358
    {
359
        // hack to allow test suite to run on php 7 w/o syntax errors
360
        eval('$callback = fn(\Zenstruck\Callback\Tests\Object1|string $a, $b, string $c) => null;');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
361
        $callback = Callback::createFor($callback);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callback seems to be never defined.
Loading history...
362
363
        $this->assertSame(Object1::class.'|string', $callback->argument(0)->type());
364
        $this->assertNull($callback->argument(1)->type());
365
        $this->assertSame('string', $callback->argument(2)->type());
366
        $this->assertSame(
367
            [
368
                Object1::class.'|string',
369
                null,
370
                'string',
371
            ],
372
            \array_map(function(Argument $a) { return $a->type(); }, $callback->arguments())
373
        );
374
    }
375
376
    /**
377
     * @test
378
     */
379
    public function exception_thrown_when_trying_to_access_invalid_argument(): void
380
    {
381
        $this->expectException(\OutOfRangeException::class);
382
383
        Callback::createFor(function() {})->argument(0);
384
    }
385
386
    /**
387
     * @test
388
     */
389
    public function value_factory_injects_argument_if_type_hinted(): void
390
    {
391
        $callback = Callback::createFor(function(string $a, int $b, $c) { return [$a, $b, $c]; });
392
        $factory = Parameter::factory(function(Argument $argument) {
393
            if ($argument->supports('string', Argument::STRICT)) {
394
                return 'string';
395
            }
396
397
            if ($argument->supports('int')) {
398
                return 17;
399
            }
400
401
            return 'invalid';
402
        });
403
404
        $ret = $callback->invokeAll(
405
            Parameter::union(
406
                Parameter::typed('string', $factory),
407
                Parameter::typed('int', $factory),
408
                Parameter::untyped($factory)
409
            )
410
        );
411
412
        $this->assertSame(['string', 17, 'string'], $ret);
413
    }
414
415
    /**
416
     * @test
417
     */
418
    public function can_use_value_factory_with_no_argument(): void
419
    {
420
        $ret = Callback::createFor(function($value) { return $value; })
421
            ->invoke(Parameter::untyped(Parameter::factory(function() { return 'value'; })))
422
        ;
423
424
        $this->assertSame('value', $ret);
425
    }
426
427
    /**
428
     * @test
429
     * @requires PHP >= 8.0
430
     */
431
    public function value_factory_can_be_used_with_union_arguments_if_no_value_factory_argument(): void
432
    {
433
        // hack to allow test suite to run on php 7 w/o syntax errors
434
        eval('$callback = fn(\Zenstruck\Callback\Tests\Object1|string $a) => $a;');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
435
436
        $ret = Callback::createFor($callback)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callback seems to be never defined.
Loading history...
437
            ->invoke(Parameter::typed('string', Parameter::factory(function() { return 'value'; })))
438
        ;
439
440
        $this->assertSame('value', $ret);
441
    }
442
443
    /**
444
     * @test
445
     * @requires PHP >= 8.0
446
     */
447
    public function value_factory_can_be_used_with_union_arguments_as_array(): void
448
    {
449
        $array = [];
450
        $factory = Parameter::factory(function(array $types) use (&$array) {
451
            $array = $types;
452
453
            return 'value';
454
        });
455
456
        // hack to allow test suite to run on php 7 w/o syntax errors
457
        eval('$callback = fn(\Zenstruck\Callback\Tests\Object1|string $a) => $a;');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
458
        $ret = Callback::createFor($callback)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callback seems to be never defined.
Loading history...
459
            ->invoke(Parameter::typed('string', $factory))
460
        ;
461
462
        $this->assertSame('value', $ret);
463
        $this->assertSame([Object1::class, 'string'], $array);
464
    }
465
466
    /**
467
     * @test
468
     * @requires PHP >= 8.0
469
     */
470
    public function value_factory_cannot_accept_union_argument(): void
471
    {
472
        $this->expectException(\LogicException::class);
473
474
        // hack to allow test suite to run on php 7 w/o syntax errors
475
        eval('$callback = fn(\Zenstruck\Callback\Tests\Object1|string $a) => $a;');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
476
477
        Callback::createFor($callback)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callback seems to be never defined.
Loading history...
478
            ->invoke(Parameter::typed('string', Parameter::factory(function(string $type) { return $type; })))
479
        ;
480
    }
481
482
    /**
483
     * @test
484
     */
485
    public function argument_supports(): void
486
    {
487
        $callback1 = Callback::createFor(function(?Object1 $object, string $string, int $int, $noType, float $float, bool $bool) {});
0 ignored issues
show
Unused Code introduced by
The parameter $float 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

487
        $callback1 = Callback::createFor(function(?Object1 $object, string $string, int $int, $noType, /** @scrutinizer ignore-unused */ float $float, bool $bool) {});

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 $bool 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

487
        $callback1 = Callback::createFor(function(?Object1 $object, string $string, int $int, $noType, float $float, /** @scrutinizer ignore-unused */ bool $bool) {});

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 $noType 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

487
        $callback1 = Callback::createFor(function(?Object1 $object, string $string, int $int, /** @scrutinizer ignore-unused */ $noType, float $float, bool $bool) {});

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 $int 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

487
        $callback1 = Callback::createFor(function(?Object1 $object, string $string, /** @scrutinizer ignore-unused */ int $int, $noType, float $float, bool $bool) {});

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 $object 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

487
        $callback1 = Callback::createFor(function(/** @scrutinizer ignore-unused */ ?Object1 $object, string $string, int $int, $noType, float $float, bool $bool) {});

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 $string 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

487
        $callback1 = Callback::createFor(function(?Object1 $object, /** @scrutinizer ignore-unused */ string $string, int $int, $noType, float $float, bool $bool) {});

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...
488
        $callback2 = Callback::createFor(function(Object2 $object, string $string, $noType) {});
0 ignored issues
show
Unused Code introduced by
The parameter $object 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

488
        $callback2 = Callback::createFor(function(/** @scrutinizer ignore-unused */ Object2 $object, string $string, $noType) {});

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 $noType 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

488
        $callback2 = Callback::createFor(function(Object2 $object, string $string, /** @scrutinizer ignore-unused */ $noType) {});

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 $string 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

488
        $callback2 = Callback::createFor(function(Object2 $object, /** @scrutinizer ignore-unused */ string $string, $noType) {});

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...
489
490
        $this->assertTrue($callback1->argument(0)->supports(Object1::class));
491
        $this->assertTrue($callback1->argument(0)->supports(Object2::class));
492
        $this->assertTrue($callback1->argument(0)->supports('null'));
493
        $this->assertTrue($callback1->argument(0)->supports('NULL'));
494
        $this->assertFalse($callback1->argument(0)->supports('string'));
495
        $this->assertFalse($callback1->argument(0)->supports(Object3::class));
496
        $this->assertFalse($callback1->argument(0)->supports(Object2::class, Argument::CONTRAVARIANCE));
497
        $this->assertFalse($callback1->argument(0)->supports(Object2::class, Argument::EXACT));
498
        $this->assertTrue($callback1->argument(0)->supports(Object1::class, Argument::EXACT));
499
        $this->assertTrue($callback1->argument(0)->supports('null', Argument::EXACT));
500
501
        $this->assertTrue($callback1->argument(1)->supports('string'));
502
        $this->assertTrue($callback1->argument(1)->supports('int'));
503
        $this->assertTrue($callback1->argument(1)->supports('float'));
504
        $this->assertTrue($callback1->argument(1)->supports('bool'));
505
        $this->assertTrue($callback1->argument(1)->supports(Object5::class));
506
        $this->assertFalse($callback1->argument(1)->supports('int', Argument::STRICT));
507
        $this->assertFalse($callback1->argument(1)->supports(Object5::class, Argument::STRICT));
508
509
        $this->assertTrue($callback1->argument(2)->supports('int'));
510
        $this->assertTrue($callback1->argument(2)->supports('integer'));
511
        $this->assertTrue($callback1->argument(2)->supports('float'));
512
        $this->assertFalse($callback1->argument(2)->supports('float', Argument::STRICT));
513
        $this->assertTrue($callback1->argument(2)->supports('bool'));
514
        $this->assertFalse($callback1->argument(2)->supports('bool', Argument::STRICT));
515
        $this->assertTrue($callback1->argument(2)->supports('string'));
516
        $this->assertFalse($callback1->argument(2)->supports('string', Argument::STRICT));
517
518
        $this->assertTrue($callback1->argument(3)->supports(Object1::class));
519
        $this->assertTrue($callback1->argument(3)->supports(Object2::class));
520
        $this->assertTrue($callback1->argument(3)->supports('string'));
521
        $this->assertTrue($callback1->argument(3)->supports('int'));
522
523
        $this->assertTrue($callback1->argument(4)->supports('float'));
524
        $this->assertTrue($callback1->argument(4)->supports('double'));
525
        $this->assertTrue($callback1->argument(4)->supports('int'));
526
        $this->assertTrue($callback1->argument(4)->supports('int', Argument::STRICT));
527
        $this->assertFalse($callback1->argument(4)->supports('int', Argument::VERY_STRICT));
528
        $this->assertTrue($callback1->argument(4)->supports('string'));
529
        $this->assertFalse($callback1->argument(4)->supports('string', Argument::STRICT));
530
        $this->assertTrue($callback1->argument(4)->supports('bool'));
531
        $this->assertFalse($callback1->argument(4)->supports('bool', Argument::STRICT));
532
533
        $this->assertTrue($callback1->argument(5)->supports('bool'));
534
        $this->assertTrue($callback1->argument(5)->supports('boolean'));
535
        $this->assertTrue($callback1->argument(5)->supports('float'));
536
        $this->assertFalse($callback1->argument(5)->supports('float', Argument::STRICT));
537
        $this->assertTrue($callback1->argument(5)->supports('int'));
538
        $this->assertFalse($callback1->argument(5)->supports('int', Argument::STRICT));
539
        $this->assertTrue($callback1->argument(5)->supports('string'));
540
        $this->assertFalse($callback1->argument(5)->supports('string', Argument::STRICT));
541
542
        $this->assertTrue($callback2->argument(0)->supports(Object1::class, Argument::COVARIANCE|Argument::CONTRAVARIANCE));
543
        $this->assertFalse($callback2->argument(0)->supports(Object3::class, Argument::COVARIANCE|Argument::CONTRAVARIANCE));
544
    }
545
546
    /**
547
     * @test
548
     */
549
    public function argument_allows(): void
550
    {
551
        $callback1 = Callback::createFor(function(Object1 $object, string $string, int $int, $noType, float $float) {});
0 ignored issues
show
Unused Code introduced by
The parameter $float 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

551
        $callback1 = Callback::createFor(function(Object1 $object, string $string, int $int, $noType, /** @scrutinizer ignore-unused */ float $float) {});

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 $int 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

551
        $callback1 = Callback::createFor(function(Object1 $object, string $string, /** @scrutinizer ignore-unused */ int $int, $noType, float $float) {});

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 $noType 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

551
        $callback1 = Callback::createFor(function(Object1 $object, string $string, int $int, /** @scrutinizer ignore-unused */ $noType, float $float) {});

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 $object 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

551
        $callback1 = Callback::createFor(function(/** @scrutinizer ignore-unused */ Object1 $object, string $string, int $int, $noType, float $float) {});

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 $string 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

551
        $callback1 = Callback::createFor(function(Object1 $object, /** @scrutinizer ignore-unused */ string $string, int $int, $noType, float $float) {});

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...
552
        $callback2 = Callback::createFor(function(Object2 $object, string $string, $noType) {});
0 ignored issues
show
Unused Code introduced by
The parameter $string 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

552
        $callback2 = Callback::createFor(function(Object2 $object, /** @scrutinizer ignore-unused */ string $string, $noType) {});

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 $object 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

552
        $callback2 = Callback::createFor(function(/** @scrutinizer ignore-unused */ Object2 $object, string $string, $noType) {});

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 $noType 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

552
        $callback2 = Callback::createFor(function(Object2 $object, string $string, /** @scrutinizer ignore-unused */ $noType) {});

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...
553
554
        $this->assertTrue($callback1->argument(0)->allows(new Object1()));
555
        $this->assertTrue($callback1->argument(0)->allows(new Object2()));
556
        $this->assertFalse($callback1->argument(0)->allows('string'));
557
        $this->assertFalse($callback1->argument(0)->allows(new Object3()));
558
559
        $this->assertTrue($callback1->argument(1)->allows('string'));
560
        $this->assertTrue($callback1->argument(1)->allows(16));
561
        $this->assertTrue($callback1->argument(1)->allows(16.7));
562
        $this->assertTrue($callback1->argument(1)->allows(true));
563
        $this->assertFalse($callback1->argument(1)->allows(16, true));
564
565
        $this->assertTrue($callback1->argument(2)->allows(16));
566
        $this->assertTrue($callback1->argument(2)->allows('17'));
567
        $this->assertTrue($callback1->argument(2)->allows(18.0));
568
        $this->assertFalse($callback1->argument(2)->allows('string'), 'non-numeric strings are not allowed');
569
570
        $this->assertTrue($callback1->argument(3)->allows(new Object1()));
571
        $this->assertTrue($callback1->argument(3)->allows(new Object2()));
572
        $this->assertTrue($callback1->argument(3)->allows('string'));
573
        $this->assertTrue($callback1->argument(3)->allows(16));
574
575
        $this->assertTrue($callback1->argument(4)->allows(16));
576
        $this->assertTrue($callback1->argument(4)->allows('17'));
577
        $this->assertTrue($callback1->argument(4)->allows('17.3'));
578
        $this->assertTrue($callback1->argument(4)->allows(18.0));
579
        $this->assertFalse($callback1->argument(4)->allows('string'), 'non-numeric strings are not allowed');
580
581
        $this->assertFalse($callback2->argument(0)->allows(new Object1()));
582
        $this->assertFalse($callback2->argument(0)->allows(new Object3()));
583
    }
584
585
    /**
586
     * @test
587
     */
588
    public function self_parameter_type(): void
589
    {
590
        $callback = Callback::createFor(Object6::closureSelf());
591
592
        $this->assertSame(Object6::class, $callback->argument(0)->type());
593
594
        $this->assertTrue($callback->argument(0)->supports(Object6::class));
595
        $this->assertTrue($callback->argument(0)->supports(Object7::class));
596
        $this->assertFalse($callback->argument(0)->supports(Object5::class));
597
        $this->assertFalse($callback->argument(0)->supports('int'));
598
599
        $this->assertTrue($callback->argument(0)->allows(new Object6()));
600
        $this->assertTrue($callback->argument(0)->allows(new Object7()));
601
        $this->assertFalse($callback->argument(0)->allows(new Object5()));
602
        $this->assertFalse($callback->argument(0)->allows(6));
603
    }
604
605
    /**
606
     * @test
607
     */
608
    public function invoke_all_union_parameter_with_defaults(): void
609
    {
610
        $callback = Callback::createFor(function(string $a, ?\DateTimeInterface $b = null, $c = null) { return [$a, $b, $c]; });
611
612
        $ret = $callback->invokeAll(Parameter::union(
613
            Parameter::typed('string', 'a')
614
        ));
615
616
        $this->assertSame(['a', null, null], $ret);
617
618
        $ret = $callback->invokeAll(Parameter::union(
619
            Parameter::typed('string', 'a'),
620
            Parameter::typed(\DateTime::class, $b = new \DateTime())
621
        ));
622
623
        $this->assertSame(['a', $b, null], $ret);
624
625
        $ret = $callback->invokeAll(Parameter::union(
626
            Parameter::typed('string', 'a'),
627
            Parameter::untyped('c')
628
        ));
629
630
        $this->assertSame(['a', null, 'c'], $ret);
631
632
        $ret = $callback->invokeAll(Parameter::union(
633
            Parameter::untyped('c'),
634
            Parameter::typed('string', 'a'),
635
            Parameter::typed(\DateTime::class, $b = new \DateTime())
636
        ));
637
638
        $this->assertSame(['a', $b, 'c'], $ret);
639
640
        $ret = $callback->invokeAll(Parameter::union(
641
            Parameter::typed('string', 'a'),
642
            Parameter::typed(\DateTime::class, Parameter::factory(function() use ($b) { return $b; }))
643
        ));
644
645
        $this->assertSame(['a', $b, null], $ret);
646
    }
647
648
    /**
649
     * @test
650
     */
651
    public function to_string_object(): void
652
    {
653
        $callback = Callback::createFor(function(Object1 $o, string $s) {});
0 ignored issues
show
Unused Code introduced by
The parameter $o 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

653
        $callback = Callback::createFor(function(/** @scrutinizer ignore-unused */ Object1 $o, string $s) {});

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 $s 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

653
        $callback = Callback::createFor(function(Object1 $o, /** @scrutinizer ignore-unused */ string $s) {});

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...
654
655
        $this->assertFalse($callback->argument(0)->supports(Object5::class));
656
        $this->assertTrue($callback->argument(1)->supports(Object5::class));
657
658
        $this->assertFalse($callback->argument(0)->allows(new Object5()));
659
        $this->assertTrue($callback->argument(1)->allows(new Object5()));
660
    }
661
}
662
663
class Object1
664
{
665
}
666
667
class Object2 extends Object1
668
{
669
}
670
671
class Object3
672
{
673
}
674
675
class Object4
676
{
677
    public function __invoke()
678
    {
679
    }
680
681
    public static function staticMethod()
682
    {
683
    }
684
}
685
686
class Object5
687
{
688
    public function __toString(): string
689
    {
690
        return 'value';
691
    }
692
}
693
694
function test_function()
695
{
696
}
697
698
class Object6
699
{
700
    public static function closureSelf(): \Closure
701
    {
702
        return function(self $object) {
703
            return $object;
704
        };
705
    }
706
}
707
708
class Object7 extends Object6
709
{
710
}
711