-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
92fb18f
commit d686c82
Showing
4 changed files
with
214 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Rules\PHPUnit; | ||
|
||
use PhpParser\Node; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Node\InClassMethodNode; | ||
use PHPStan\Rules\RuleErrorBuilder; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* @implements \PHPStan\Rules\Rule<InClassMethodNode> | ||
*/ | ||
class ShouldCallParentMethodsRule implements \PHPStan\Rules\Rule | ||
{ | ||
|
||
public function getNodeType(): string | ||
{ | ||
return InClassMethodNode::class; | ||
} | ||
|
||
public function processNode(Node $node, Scope $scope): array | ||
{ | ||
/** @var InClassMethodNode $node */ | ||
$node = $node; | ||
|
||
if ($scope->getClassReflection() === null) { | ||
return []; | ||
} | ||
|
||
if (!$scope->getClassReflection()->isSubclassOf(TestCase::class)) { | ||
return []; | ||
} | ||
|
||
$parentClass = $scope->getClassReflection()->getParentClass(); | ||
|
||
if ($parentClass === false) { | ||
return []; | ||
} | ||
|
||
if ($parentClass->getName() === TestCase::class) { | ||
return []; | ||
} | ||
|
||
if (!in_array(strtolower($node->getOriginalNode()->name->name), ['setup', 'teardown'], true)) { | ||
return []; | ||
} | ||
|
||
$hasParentCall = $this->hasParentClassCall($node->getOriginalNode()->getStmts()); | ||
|
||
if (!$hasParentCall) { | ||
return [ | ||
RuleErrorBuilder::message( | ||
sprintf('Missing call to parent::%s method.', $node->getOriginalNode()->name->name) | ||
)->build(), | ||
]; | ||
} | ||
|
||
return []; | ||
} | ||
|
||
/** | ||
* @param Node\Stmt[]|null $stmts | ||
* | ||
* @return bool | ||
*/ | ||
private function hasParentClassCall(?array $stmts): bool | ||
{ | ||
if ($stmts === null) { | ||
return false; | ||
} | ||
|
||
foreach ($stmts as $stmt) { | ||
if (! $stmt instanceof Node\Stmt\Expression) { | ||
continue; | ||
} | ||
|
||
if (! $stmt->expr instanceof Node\Expr\StaticCall) { | ||
continue; | ||
} | ||
|
||
if (! $stmt->expr->class instanceof Node\Name) { | ||
continue; | ||
} | ||
|
||
$class = (string) $stmt->expr->class; | ||
|
||
if (strtolower($class) !== 'parent') { | ||
continue; | ||
} | ||
|
||
if (! $stmt->expr->name instanceof Node\Identifier) { | ||
continue; | ||
} | ||
|
||
if (in_array(strtolower($stmt->expr->name->name), ['setup', 'teardown'], true)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Rules\PHPUnit; | ||
|
||
use PHPStan\Rules\Rule; | ||
|
||
/** | ||
* @extends \PHPStan\Testing\RuleTestCase<ShouldCallParentMethodsRule> | ||
*/ | ||
class ShouldCallParentMethodsRuleTest extends \PHPStan\Testing\RuleTestCase | ||
{ | ||
|
||
protected function getRule(): Rule | ||
{ | ||
return new ShouldCallParentMethodsRule(); | ||
} | ||
|
||
public function testRule(): void | ||
{ | ||
$this->analyse([__DIR__ . '/data/missing-parent-method-calls.php'], [ | ||
[ | ||
'Missing call to parent::setUp method.', | ||
32, | ||
], | ||
[ | ||
'Missing call to parent::tearDown method.', | ||
63, | ||
], | ||
]); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?php | ||
|
||
namespace MissingParentMethodCalls; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
|
||
class FooTest extends TestCase | ||
{ | ||
public function setUp(): void | ||
{ | ||
$this->foo = true; | ||
} | ||
} | ||
|
||
class BaseTestCase extends TestCase | ||
{ | ||
public function setUp(): void | ||
{ | ||
$this->bar = true; | ||
} | ||
|
||
public function tearDown(): void | ||
{ | ||
$this->bar = null; | ||
} | ||
} | ||
|
||
class BazTest extends BaseTestCase | ||
{ | ||
private $baz; | ||
|
||
public function setUp(): void | ||
{ | ||
$this->baz = true; | ||
} | ||
|
||
public function baz(): bool | ||
{ | ||
return $this->baz; | ||
} | ||
} | ||
|
||
class BarBazTest extends BaseTestCase | ||
{ | ||
public function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
$this->barBaz = true; | ||
} | ||
} | ||
|
||
class FooBarBazTest extends BaseTestCase | ||
{ | ||
public function setUp(): void | ||
{ | ||
$result = 1 + 1; | ||
parent::setUp(); | ||
|
||
$this->fooBarBaz = $result; | ||
} | ||
|
||
public function tearDown(): void | ||
{ | ||
$this->fooBarBaz = null; | ||
} | ||
} | ||
|
||
class NormalBaseClass {} | ||
|
||
class NormalClass extends NormalBaseClass | ||
{ | ||
public function setUp() | ||
{ | ||
return true; | ||
} | ||
} |