mirror of
https://github.com/danog/psalm-plugin-phpunit.git
synced 2024-11-30 04:29:08 +01:00
Merge pull request #14 from weirdan/suppress-missing-constructor
Suppress missing constructor for TestCase descendants
This commit is contained in:
commit
949e3b235d
@ -21,6 +21,9 @@ class Plugin implements PluginEntryPointInterface
|
||||
$psalm->addStubFile(__DIR__ . '/stubs/MockBuilder.php');
|
||||
$psalm->addStubFile(__DIR__ . '/stubs/InvocationMocker.php');
|
||||
$psalm->addStubFile(__DIR__ . '/stubs/Prophecy.php');
|
||||
|
||||
class_exists(Hooks\TestCaseHandler::class, true);
|
||||
$psalm->registerHooksFromClass(Hooks\TestCaseHandler::class);
|
||||
}
|
||||
|
||||
private function packageVersionIs(string $package, string $op, string $ref): bool
|
||||
|
@ -27,7 +27,8 @@
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psalm\\PhpUnitPlugin\\": ["."]
|
||||
"Psalm\\PhpUnitPlugin\\": ["."],
|
||||
"Psalm\\PhpUnitPlugin\\Hooks\\": ["hooks"]
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
69
hooks/TestCaseHandler.php
Normal file
69
hooks/TestCaseHandler.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace Psalm\PhpUnitPlugin\Hooks;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PhpParser\Comment\Doc;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\DocComment;
|
||||
use Psalm\FileSource;
|
||||
use Psalm\Plugin\Hook\AfterClassLikeVisitInterface;
|
||||
use Psalm\Storage\ClassLikeStorage;
|
||||
|
||||
class TestCaseHandler implements AfterClassLikeVisitInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function afterClassLikeVisit(
|
||||
ClassLike $classNode,
|
||||
ClassLikeStorage $classStorage,
|
||||
FileSource $statements_source,
|
||||
Codebase $codebase,
|
||||
array &$file_replacements = []
|
||||
) {
|
||||
if ($codebase->classExtends($classStorage->name, TestCase::class)) {
|
||||
if (self::hasInitializers($classStorage, $classNode)) {
|
||||
$classStorage->suppressed_issues[] = 'MissingConstructor';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function hasInitializers(ClassLikeStorage $storage, ClassLike $stmt): bool
|
||||
{
|
||||
if (isset($storage->methods['setup'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($storage->methods as $method => $_) {
|
||||
$stmt_method = $stmt->getMethod($method);
|
||||
if (!$stmt_method) {
|
||||
throw new \RuntimeException('Failed to find ' . $method);
|
||||
}
|
||||
if (self::isBeforeInitializer($stmt_method)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function isBeforeInitializer(ClassMethod $method): bool
|
||||
{
|
||||
/** @var string[] $comments */
|
||||
$comments = $method->getAttribute('comments', []);
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
if (!$comment instanceof Doc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed_comment = DocComment::parse((string)$comment->getReformattedText());
|
||||
if (isset($parsed_comment['specials']['before'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ Feature: TestCase
|
||||
Given I have the following code preamble
|
||||
"""
|
||||
<?php
|
||||
namespace NS;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
"""
|
||||
@ -25,8 +26,8 @@ Feature: TestCase
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see these errors
|
||||
| Type | Message |
|
||||
| InvalidArgument | Argument 1 of PHPUnit\Framework\TestCase::expectException expects class-string<Throwable>, MyTestCase::class provided |
|
||||
| Type | Message |
|
||||
| InvalidArgument | Argument 1 of PHPUnit\Framework\TestCase::expectException expects class-string<Throwable>, NS\MyTestCase::class provided |
|
||||
|
||||
Scenario: TestCase::expectException() accepts throwables
|
||||
Given I have the following code
|
||||
@ -41,3 +42,92 @@ Feature: TestCase
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see no errors
|
||||
|
||||
Scenario: Stateful test case with setUp produces no MissingConstructor
|
||||
Given I have the following code
|
||||
"""
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
|
||||
interface I { public function work(): int; }
|
||||
|
||||
class MyTestCase extends TestCase
|
||||
{
|
||||
/** @var ObjectProphecy<I> */
|
||||
private $i;
|
||||
|
||||
/** @return void */
|
||||
public function setUp() {
|
||||
$this->i = $this->prophesize(I::class);
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
public function testSomething() {
|
||||
$this->i->work()->willReturn(1);;
|
||||
$i = $this->i->reveal();
|
||||
$this->assertEquals(1, $i->work());
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see no errors
|
||||
|
||||
Scenario: Stateful test case with @before produces no MissingConstructor
|
||||
Given I have the following code
|
||||
"""
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
|
||||
interface I { public function work(): int; }
|
||||
|
||||
class MyTestCase extends TestCase
|
||||
{
|
||||
/** @var ObjectProphecy<I> */
|
||||
private $i;
|
||||
|
||||
/**
|
||||
* @before
|
||||
* @return void
|
||||
*/
|
||||
public function myInit() {
|
||||
$this->i = $this->prophesize(I::class);
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
public function testSomething() {
|
||||
$this->i->work()->willReturn(1);;
|
||||
$i = $this->i->reveal();
|
||||
$this->assertEquals(1, $i->work());
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see no errors
|
||||
|
||||
Scenario: Stateful test case without @before or setUp produces MissingConstructor
|
||||
Given I have the following code
|
||||
"""
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
|
||||
interface I { public function work(): int; }
|
||||
|
||||
class MyTestCase extends TestCase
|
||||
{
|
||||
/** @var ObjectProphecy<I> */
|
||||
private $i;
|
||||
|
||||
/** @return void */
|
||||
public function myInit() {
|
||||
$this->i = $this->prophesize(I::class);
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
public function testSomething() {
|
||||
$this->i->work()->willReturn(1);;
|
||||
$i = $this->i->reveal();
|
||||
$this->assertEquals(1, $i->work());
|
||||
}
|
||||
}
|
||||
"""
|
||||
When I run Psalm
|
||||
Then I see these errors
|
||||
| Type | Message |
|
||||
| MissingConstructor | NS\MyTestCase has an uninitialized variable $this->i, but no constructor |
|
||||
|
Loading…
Reference in New Issue
Block a user