mirror of
https://github.com/danog/psalm-plugin-phpunit.git
synced 2024-12-02 09:27:56 +01:00
Merge pull request #24 from weirdan/variadic-tests
Support variadics in test methods
This commit is contained in:
commit
e33ae73dc7
@ -231,10 +231,14 @@ class TestCaseHandler implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
$checkParam =
|
$checkParam =
|
||||||
/** @return void */
|
/**
|
||||||
|
* @param null|Type\Union $param_default_type
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
function (
|
function (
|
||||||
Type\Union $potential_argument_type,
|
Type\Union $potential_argument_type,
|
||||||
FunctionLikeParameter $param,
|
Type\Union $param_type,
|
||||||
|
$param_default_type,
|
||||||
int $param_offset
|
int $param_offset
|
||||||
) use (
|
) use (
|
||||||
$codebase,
|
$codebase,
|
||||||
@ -243,9 +247,8 @@ class TestCaseHandler implements
|
|||||||
$provider_return_type_string,
|
$provider_return_type_string,
|
||||||
$provider_docblock_location
|
$provider_docblock_location
|
||||||
) {
|
) {
|
||||||
assert(null !== $param->type);
|
$param_type = clone $param_type;
|
||||||
$param_type = clone $param->type;
|
if ($param_default_type) {
|
||||||
if ($param->default_type) {
|
|
||||||
$param_type->possibly_undefined = true;
|
$param_type->possibly_undefined = true;
|
||||||
}
|
}
|
||||||
if (self::isTypeContainedByType($codebase, $potential_argument_type, $param_type)) {
|
if (self::isTypeContainedByType($codebase, $potential_argument_type, $param_type)) {
|
||||||
@ -258,7 +261,7 @@ class TestCaseHandler implements
|
|||||||
. ' by ' . $provider_method_id . '():(' . $provider_return_type_string . ')',
|
. ' by ' . $provider_method_id . '():(' . $provider_return_type_string . ')',
|
||||||
$provider_docblock_location
|
$provider_docblock_location
|
||||||
));
|
));
|
||||||
} elseif ($potential_argument_type->possibly_undefined && !$param->default_type) {
|
} elseif ($potential_argument_type->possibly_undefined && !$param_default_type) {
|
||||||
IssueBuffer::accepts(new Issue\InvalidArgument(
|
IssueBuffer::accepts(new Issue\InvalidArgument(
|
||||||
'Argument ' . ($param_offset + 1) . ' of ' . $method_name
|
'Argument ' . ($param_offset + 1) . ' of ' . $method_name
|
||||||
. ' has no default value, but possibly undefined '
|
. ' has no default value, but possibly undefined '
|
||||||
@ -284,32 +287,60 @@ class TestCaseHandler implements
|
|||||||
// check that all of the required (?) params accept value type
|
// check that all of the required (?) params accept value type
|
||||||
$potential_argument_type = $dataset_type->type_params[1];
|
$potential_argument_type = $dataset_type->type_params[1];
|
||||||
foreach ($method_storage->params as $param_offset => $param) {
|
foreach ($method_storage->params as $param_offset => $param) {
|
||||||
$checkParam($potential_argument_type, $param, $param_offset);
|
assert(null !== $param->type);
|
||||||
|
$checkParam($potential_argument_type, $param->type, $param->default_type, $param_offset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// iterate over all params checking if corresponding value type is acceptable
|
// iterate over all params checking if corresponding value type is acceptable
|
||||||
// let's hope properties are sorted in array order
|
// let's hope properties are sorted in array order
|
||||||
$potential_argument_types = array_values($dataset_type->properties);
|
$potential_argument_types = array_values($dataset_type->properties);
|
||||||
|
|
||||||
if (count($potential_argument_types) < $method_storage->required_param_count) {
|
|
||||||
IssueBuffer::accepts(new Issue\TooFewArguments(
|
|
||||||
'Too few arguments for ' . $method_name
|
|
||||||
. ' - expecting ' . $method_storage->required_param_count
|
|
||||||
. ' but saw ' . count($potential_argument_types)
|
|
||||||
. ' provided by ' . $provider_method_id . '()'
|
|
||||||
. ':(' . $provider_return_type_string . ')',
|
|
||||||
$provider_docblock_location,
|
|
||||||
$method_name
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($method_storage->params as $param_offset => $param) {
|
foreach ($method_storage->params as $param_offset => $param) {
|
||||||
if (!isset($potential_argument_types[$param_offset])) {
|
if (!isset($potential_argument_types[$param_offset])) {
|
||||||
|
// variadics are never required
|
||||||
|
// and they always come last
|
||||||
|
if ($param->is_variadic) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// reached default params, so it's fine, but let's continue
|
||||||
|
// because MisplacedRequiredParam could be suppressed
|
||||||
|
if ($param->default_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IssueBuffer::accepts(new Issue\TooFewArguments(
|
||||||
|
'Too few arguments for ' . $method_name
|
||||||
|
. ' - expecting at least ' . ($param_offset + 1)
|
||||||
|
. ', but saw ' . count($potential_argument_types)
|
||||||
|
. ' provided by ' . $provider_method_id . '()'
|
||||||
|
. ':(' . $provider_return_type_string . ')',
|
||||||
|
$provider_docblock_location,
|
||||||
|
$method_name
|
||||||
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$potential_argument_type = $potential_argument_types[$param_offset];
|
$potential_argument_type = $potential_argument_types[$param_offset];
|
||||||
|
|
||||||
$checkParam($potential_argument_type, $param, $param_offset);
|
assert(null !== $param->type);
|
||||||
|
if ($param->is_variadic) {
|
||||||
|
/** @var Type\Atomic\TArray $variadic_type */
|
||||||
|
$variadic_type = $param->type->getTypes()['array'];
|
||||||
|
$variadic_param_type = $variadic_type->type_params[1] ?? Type::getMixed();
|
||||||
|
|
||||||
|
// check remaining argument types
|
||||||
|
for (; $param_offset < count($potential_argument_types); $param_offset++) {
|
||||||
|
$potential_argument_type = $potential_argument_types[$param_offset];
|
||||||
|
$checkParam(
|
||||||
|
$potential_argument_type,
|
||||||
|
$variadic_param_type,
|
||||||
|
$variadic_param_type,
|
||||||
|
$param_offset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$checkParam($potential_argument_type, $param->type, $param->default_type, $param_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,8 +469,8 @@ Feature: TestCase
|
|||||||
"""
|
"""
|
||||||
When I run Psalm
|
When I run Psalm
|
||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| TooFewArguments | Too few arguments for NS\MyTestCase::testSomething - expecting 2 but saw 1 provided by NS\MyTestCase::provide():(iterable<string, array{0:int}>) |
|
| TooFewArguments | Too few arguments for NS\MyTestCase::testSomething - expecting at least 2, but saw 1 provided by NS\MyTestCase::provide():(iterable<string, array{0:int}>) |
|
||||||
And I see no other errors
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Referenced providers are not marked as unused
|
Scenario: Referenced providers are not marked as unused
|
||||||
@ -857,3 +857,81 @@ Feature: TestCase
|
|||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidArgument | Argument 1 of NS\MyTestTrait::testSomething expects string, int provided by NS\MyTestTrait::provide():(iterable<int, array<array-key, int>>) |
|
| InvalidArgument | Argument 1 of NS\MyTestTrait::testSomething expects string, int provided by NS\MyTestTrait::provide():(iterable<int, array<array-key, int>>) |
|
||||||
And I see no other errors
|
And I see no other errors
|
||||||
|
|
||||||
|
Scenario: Providers may omit variadic part for variadic tests
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase {
|
||||||
|
/** @return iterable<string,array{int}> */
|
||||||
|
public function provide() {
|
||||||
|
yield "data set" => [1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dataProvider provide
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSomething(int $i, ...$rest) {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm
|
||||||
|
Then I see no errors
|
||||||
|
|
||||||
|
Scenario: Providers may omit non-varidic params with default for variadic tests
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase {
|
||||||
|
/** @return iterable<string,array{int}> */
|
||||||
|
public function provide() {
|
||||||
|
yield "data set" => [1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dataProvider provide
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSomething(int $i, string $s = "", ...$rest) {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm
|
||||||
|
Then I see no errors
|
||||||
|
|
||||||
|
Scenario: Providers may not omit non-varidic params with no default for variadic tests
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase {
|
||||||
|
/** @return iterable<string,array{int}> */
|
||||||
|
public function provide() {
|
||||||
|
yield "data set" => [1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dataProvider provide
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSomething(int $i, string $s, ...$rest) {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm
|
||||||
|
Then I see these errors
|
||||||
|
| Type | Message |
|
||||||
|
| TooFewArguments | Too few arguments for NS\MyTestCase::testSomething - expecting at least 2, but saw 1 provided by NS\MyTestCase::provide():(iterable<string, array{0:int}>) |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
|
Scenario: Providers generating incompatible datasets for variadic tests are reported
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase {
|
||||||
|
/** @return iterable<string,array{float,1?:string}> */
|
||||||
|
public function provide() {
|
||||||
|
yield "data set" => [1., "a"];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dataProvider provide
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSomething(float ...$rest) {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm
|
||||||
|
Then I see these errors
|
||||||
|
| Type | Message |
|
||||||
|
| InvalidArgument | Argument 2 of NS\MyTestCase::testSomething expects float, string provided by NS\MyTestCase::provide():(iterable<string, array{0:float, 1?:string}>) |
|
||||||
|
And I see no other errors
|
||||||
|
Loading…
Reference in New Issue
Block a user