1 | <?php |
||||||||||||||
2 | |||||||||||||||
3 | namespace Zenstruck\Callback\Tests; |
||||||||||||||
4 | |||||||||||||||
5 | use PHPUnit\Framework\TestCase; |
||||||||||||||
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) {}); |
||||||||||||||
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
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
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...
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
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) {}; |
||||||||||||||
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) {}; |
||||||||||||||
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\';'); |
||||||||||||||
326 | |||||||||||||||
327 | $this->assertSame('ret', Callback::createFor($callback)->invokeAll(Parameter::typed(Object1::class, new Object1()))); |
||||||||||||||
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) {}); |
||||||||||||||
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;'); |
||||||||||||||
361 | $callback = Callback::createFor($callback); |
||||||||||||||
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;'); |
||||||||||||||
435 | |||||||||||||||
436 | $ret = Callback::createFor($callback) |
||||||||||||||
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;'); |
||||||||||||||
458 | $ret = Callback::createFor($callback) |
||||||||||||||
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;'); |
||||||||||||||
476 | |||||||||||||||
477 | Callback::createFor($callback) |
||||||||||||||
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
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
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...
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
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...
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
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...
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
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...
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
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...
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
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
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
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...
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
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...
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
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
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
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...
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
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...
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
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...
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
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...
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
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
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
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...
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
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...
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
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 | class Object1 |
||||||||||||||
587 | { |
||||||||||||||
588 | } |
||||||||||||||
589 | |||||||||||||||
590 | class Object2 extends Object1 |
||||||||||||||
591 | { |
||||||||||||||
592 | } |
||||||||||||||
593 | |||||||||||||||
594 | class Object3 |
||||||||||||||
595 | { |
||||||||||||||
596 | } |
||||||||||||||
597 | |||||||||||||||
598 | class Object4 |
||||||||||||||
599 | { |
||||||||||||||
600 | public function __invoke() |
||||||||||||||
601 | { |
||||||||||||||
602 | } |
||||||||||||||
603 | |||||||||||||||
604 | public static function staticMethod() |
||||||||||||||
605 | { |
||||||||||||||
606 | } |
||||||||||||||
607 | } |
||||||||||||||
608 | |||||||||||||||
609 | class Object5 |
||||||||||||||
610 | { |
||||||||||||||
611 | public function __toString(): string |
||||||||||||||
612 | { |
||||||||||||||
613 | return 'value'; |
||||||||||||||
614 | } |
||||||||||||||
615 | } |
||||||||||||||
616 | |||||||||||||||
617 | function test_function() |
||||||||||||||
618 | { |
||||||||||||||
619 | } |
||||||||||||||
620 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.