Skip to content

Commit 18911e5

Browse files
kubawerlossebastianbergmann
authored andcommitted
Fix variadic function as callback
1 parent f860ec8 commit 18911e5

File tree

4 files changed

+40
-4
lines changed

4 files changed

+40
-4
lines changed

.psalm/baseline.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@
442442
'arguments_call' => $this->argumentsForCall,
443443
'return_declaration' => !empty($this->returnType->asString()) ? (': ' . $this->returnType->asString()) : '',
444444
'return_type' => $this->returnType->asString(),
445-
'arguments_count' => !empty($this->argumentsForCall) ? substr_count($this->argumentsForCall, ',') + 1 : 0,
445+
'arguments_count' => $argumentsCount,
446446
'class_name' => $this->className,
447447
'method_name' => $this->methodName,
448448
'modifier' => $this->modifier,

src/Framework/Constraint/Callback.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010
namespace PHPUnit\Framework\Constraint;
1111

12+
use ReflectionFunction;
13+
1214
/**
1315
* @psalm-template CallbackInput of mixed
1416
*
@@ -37,14 +39,32 @@ public function toString(): string
3739
return 'is accepted by specified callback';
3840
}
3941

42+
/**
43+
* @psalm-suppress ArgumentTypeCoercion
44+
*/
45+
public function hasVariadicParam(): bool
46+
{
47+
foreach ((new ReflectionFunction($this->callback))->getParameters() as $parameter) {
48+
if ($parameter->isVariadic()) {
49+
return true;
50+
}
51+
}
52+
53+
return false;
54+
}
55+
4056
/**
4157
* Evaluates the constraint for parameter $value. Returns true if the
4258
* constraint is met, false otherwise.
4359
*
4460
* @psalm-param CallbackInput $other
61+
*
62+
* @psalm-suppress InvalidArgument
4563
*/
4664
protected function matches(mixed $other): bool
4765
{
48-
return ($this->callback)($other);
66+
return $this->hasVariadicParam()
67+
? ($this->callback)(...$other)
68+
: ($this->callback)($other);
4969
}
5070
}

src/Framework/MockObject/Generator/MockMethod.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
namespace PHPUnit\Framework\MockObject\Generator;
1111

12+
use const PHP_INT_MAX;
1213
use function count;
1314
use function explode;
1415
use function implode;
@@ -17,6 +18,7 @@
1718
use function preg_match;
1819
use function preg_replace;
1920
use function sprintf;
21+
use function str_contains;
2022
use function strlen;
2123
use function strpos;
2224
use function substr;
@@ -211,13 +213,21 @@ public function generateCode(): string
211213

212214
$template = $this->loadTemplate($templateFile);
213215

216+
$argumentsCount = 0;
217+
218+
if (str_contains($this->argumentsForCall, '...')) {
219+
$argumentsCount = PHP_INT_MAX; // @todo: change it to null and update end-to-end tests
220+
} elseif (!empty($this->argumentsForCall)) {
221+
$argumentsCount = substr_count($this->argumentsForCall, ',') + 1;
222+
}
223+
214224
$template->setVar(
215225
[
216226
'arguments_decl' => $this->argumentsForDeclaration,
217227
'arguments_call' => $this->argumentsForCall,
218228
'return_declaration' => !empty($this->returnType->asString()) ? (': ' . $this->returnType->asString()) : '',
219229
'return_type' => $this->returnType->asString(),
220-
'arguments_count' => !empty($this->argumentsForCall) ? substr_count($this->argumentsForCall, ',') + 1 : 0,
230+
'arguments_count' => $argumentsCount,
221231
'class_name' => $this->className,
222232
'method_name' => $this->methodName,
223233
'modifier' => $this->modifier,

src/Framework/MockObject/Runtime/Rule/Parameters.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use function count;
1313
use function sprintf;
1414
use Exception;
15+
use PHPUnit\Framework\Constraint\Callback;
1516
use PHPUnit\Framework\Constraint\Constraint;
1617
use PHPUnit\Framework\Constraint\IsAnything;
1718
use PHPUnit\Framework\Constraint\IsEqual;
@@ -108,8 +109,13 @@ private function doVerify(): bool
108109
}
109110

110111
foreach ($this->parameters as $i => $parameter) {
112+
if ($parameter instanceof Callback && $parameter->hasVariadicParam()) {
113+
$other = $this->invocation->parameters();
114+
} else {
115+
$other = $this->invocation->parameters()[$i];
116+
}
111117
$parameter->evaluate(
112-
$this->invocation->parameters()[$i],
118+
$other,
113119
sprintf(
114120
'Parameter %s for invocation %s does not match expected ' .
115121
'value.',

0 commit comments

Comments
 (0)