mirror of
https://github.com/danog/psalm-plugin-phpunit.git
synced 2024-11-27 12:35:02 +01:00
Tweak dead code detection on TestCase descendants
- Don't report TestCase descendants as unused - Don't report test methods as unused - Don't report providers referenced by test methods as unused Refs psalm/phpunit-psalm-plugin#13 /cc @SignpostMarv
This commit is contained in:
parent
330b3a1ef6
commit
4fe3c88aca
@ -53,7 +53,17 @@ class TestCaseHandler implements AfterClassLikeVisitInterface, AfterClassLikeAna
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var MethodStorage $method_storage */
|
// add a fake reference to test class to prevent it from being marked as unused
|
||||||
|
// it would have been easier to add a suppression, but that's only possible
|
||||||
|
// since 3.0.17 (vimeo/psalm#1353)
|
||||||
|
//
|
||||||
|
// This should always pass, we're calling it for the side-effect
|
||||||
|
// of adding self-reference
|
||||||
|
|
||||||
|
if (!$codebase->classOrInterfaceExists($class_storage->name, $class_storage->location)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($class_storage->methods as $method_name => $method_storage) {
|
foreach ($class_storage->methods as $method_name => $method_storage) {
|
||||||
if (!$method_storage->location) {
|
if (!$method_storage->location) {
|
||||||
continue;
|
continue;
|
||||||
@ -69,6 +79,13 @@ class TestCaseHandler implements AfterClassLikeVisitInterface, AfterClassLikeAna
|
|||||||
|
|
||||||
$method_id = $class_storage->name . '::' . $method_storage->cased_name;
|
$method_id = $class_storage->name . '::' . $method_storage->cased_name;
|
||||||
|
|
||||||
|
if (0 !== strpos($method_storage->cased_name, 'test')
|
||||||
|
&& !isset($specials['test'])) {
|
||||||
|
continue; // skip non-test methods
|
||||||
|
}
|
||||||
|
|
||||||
|
$method_storage->suppressed_issues[] = 'PossiblyUnusedMethod';
|
||||||
|
|
||||||
if (!isset($specials['dataProvider'])) {
|
if (!isset($specials['dataProvider'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -79,7 +96,8 @@ class TestCaseHandler implements AfterClassLikeVisitInterface, AfterClassLikeAna
|
|||||||
$provider_docblock_location = clone $method_storage->location;
|
$provider_docblock_location = clone $method_storage->location;
|
||||||
$provider_docblock_location->setCommentLine($line);
|
$provider_docblock_location->setCommentLine($line);
|
||||||
|
|
||||||
if (!$codebase->methodExists($provider_method_id)) {
|
// methodExists also can mark methods as used (weird, but handy)
|
||||||
|
if (!$codebase->methodExists($provider_method_id, $provider_docblock_location, $method_id)) {
|
||||||
IssueBuffer::accepts(new Issue\UndefinedMethod(
|
IssueBuffer::accepts(new Issue\UndefinedMethod(
|
||||||
'Provider method ' . $provider_method_id . ' is not defined',
|
'Provider method ' . $provider_method_id . ' is not defined',
|
||||||
$provider_docblock_location,
|
$provider_docblock_location,
|
||||||
|
@ -41,6 +41,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidArgument | Argument 1 of PHPUnit\Framework\TestCase::expectException expects class-string<Throwable>, NS\MyTestCase::class provided |
|
| InvalidArgument | Argument 1 of PHPUnit\Framework\TestCase::expectException expects class-string<Throwable>, NS\MyTestCase::class provided |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: TestCase::expectException() accepts throwables
|
Scenario: TestCase::expectException() accepts throwables
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -144,6 +145,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| MissingConstructor | NS\MyTestCase has an uninitialized variable $this->i, but no constructor |
|
| MissingConstructor | NS\MyTestCase has an uninitialized variable $this->i, but no constructor |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Missing data provider is reported
|
Scenario: Missing data provider is reported
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -192,6 +194,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidReturnType | Providers must return iterable<int\|string, array<array-key, mixed>>, iterable<int, int> provided |
|
| InvalidReturnType | Providers must return iterable<int\|string, array<array-key, mixed>>, iterable<int, int> provided |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Valid iterable data provider is allowed
|
Scenario: Valid iterable data provider is allowed
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -240,6 +243,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidReturnType | Providers must return iterable<int\|string, array<array-key, mixed>>, Generator<int, int, mixed, void> provided |
|
| InvalidReturnType | Providers must return iterable<int\|string, array<array-key, mixed>>, Generator<int, int, mixed, void> provided |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Valid generator data provider is allowed
|
Scenario: Valid generator data provider is allowed
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -288,6 +292,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidReturnType | Providers must return iterable<int\|string, array<array-key, mixed>>, array<int, int> provided |
|
| InvalidReturnType | Providers must return iterable<int\|string, array<array-key, mixed>>, array<int, int> provided |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Valid array data provider is allowed
|
Scenario: Valid array data provider is allowed
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -363,6 +368,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\MyTestCase::provide():(iterable<string, array{0:string}>) |
|
| InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\MyTestCase::provide():(iterable<string, array{0:string}>) |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Invalid dataset array is reported
|
Scenario: Invalid dataset array is reported
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -388,6 +394,7 @@ Feature: TestCase
|
|||||||
Then I see these errors
|
Then I see these errors
|
||||||
| Type | Message |
|
| Type | Message |
|
||||||
| PossiblyInvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string\|int provided by NS\MyTestCase::provide():(iterable<string, array<int, string\|int>>) |
|
| PossiblyInvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string\|int provided by NS\MyTestCase::provide():(iterable<string, array<int, string\|int>>) |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
Scenario: Shape dataset with missing params is reported
|
Scenario: Shape dataset with missing params is reported
|
||||||
Given I have the following code
|
Given I have the following code
|
||||||
@ -413,3 +420,119 @@ Feature: TestCase
|
|||||||
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 2 but saw 1 provided by NS\MyTestCase::provide():(iterable<string, array{0:int}>) |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
|
Scenario: Referenced providers are not marked as unused
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase
|
||||||
|
{
|
||||||
|
/** @return iterable<string,array{int}> */
|
||||||
|
public function provide() {
|
||||||
|
yield "data set name" => [1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
* @psalm-suppress UnusedMethod
|
||||||
|
* @dataProvider provide
|
||||||
|
*/
|
||||||
|
public function testSomething(int $int) {
|
||||||
|
$this->assertEquals(1, $int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new MyTestCase;
|
||||||
|
"""
|
||||||
|
When I run Psalm with dead code detection
|
||||||
|
Then I see no errors
|
||||||
|
|
||||||
|
Scenario: Unreferenced providers are marked as unused
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase
|
||||||
|
{
|
||||||
|
/** @return iterable<string,array{int}> */
|
||||||
|
public function provide() {
|
||||||
|
yield "data set name" => [1];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
* @psalm-suppress UnusedMethod
|
||||||
|
*/
|
||||||
|
public function testSomething(int $int) {
|
||||||
|
$this->assertEquals(1, $int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new MyTestCase;
|
||||||
|
"""
|
||||||
|
When I run Psalm with dead code detection
|
||||||
|
Then I see these errors
|
||||||
|
| Type | Message |
|
||||||
|
| PossiblyUnusedMethod | Cannot find public calls to method NS\MyTestCase::provide |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
|
Scenario: Test method are never marked as unused
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSomething(int $int) {
|
||||||
|
$this->assertEquals(1, $int);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function somethingElse(int $int) {
|
||||||
|
$this->assertEquals(1, $int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new MyTestCase;
|
||||||
|
"""
|
||||||
|
When I run Psalm with dead code detection
|
||||||
|
Then I see no errors
|
||||||
|
|
||||||
|
Scenario: Unreferenced non-test methods are marked as unused
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function somethingElse(int $int) {
|
||||||
|
$this->assertEquals(1, $int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new MyTestCase;
|
||||||
|
"""
|
||||||
|
When I run Psalm with dead code detection
|
||||||
|
Then I see these errors
|
||||||
|
| Type | Message |
|
||||||
|
| PossiblyUnusedMethod | Cannot find public calls to method NS\MyTestCase::somethingElse |
|
||||||
|
And I see no other errors
|
||||||
|
|
||||||
|
Scenario: Unreferenced TestCase descendants are never marked as unused
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class MyTestCase extends TestCase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm with dead code detection
|
||||||
|
Then I see no errors
|
||||||
|
|
||||||
|
Scenario: Unreferenced non-test classes are marked as unused
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
class UtilityClass
|
||||||
|
{
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm with dead code detection
|
||||||
|
Then I see these errors
|
||||||
|
| Type | Message |
|
||||||
|
| UnusedClass | Class NS\UtilityClass is never used |
|
||||||
|
And I see no other errors
|
||||||
|
Loading…
Reference in New Issue
Block a user