-
-
Notifications
You must be signed in to change notification settings - Fork 679
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PHPUnit] Add TestListenerToHooksRector
- Loading branch information
1 parent
8aa22d2
commit 1e24821
Showing
5 changed files
with
350 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
services: | ||
Rector\PHPUnit\Rector\Class_\TestListenerToHooksRector: ~ |
174 changes: 174 additions & 0 deletions
174
packages/PHPUnit/src/Rector/Class_/TestListenerToHooksRector.php
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,174 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Rector\PHPUnit\Rector\Class_; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Identifier; | ||
use PhpParser\Node\Name\FullyQualified; | ||
use PhpParser\Node\Stmt\Class_; | ||
use PhpParser\Node\Stmt\ClassMethod; | ||
use Rector\Rector\AbstractRector; | ||
use Rector\RectorDefinition\CodeSample; | ||
use Rector\RectorDefinition\RectorDefinition; | ||
|
||
/** | ||
* @see https://github.com/sebastianbergmann/phpunit/issues/3388 | ||
* @see https://github.com/sebastianbergmann/phpunit/commit/34a0abd8b56a4a9de83c9e56384f462541a0f939 | ||
* | ||
* @see https://github.com/sebastianbergmann/phpunit/tree/master/src/Runner/Hook | ||
*/ | ||
final class TestListenerToHooksRector extends AbstractRector | ||
{ | ||
/** | ||
* @var string[][] | ||
*/ | ||
private $listenerMethodToHookInterfaces = [ | ||
'addIncompleteTest' => ['PHPUnit\Runner\AfterIncompleteTestHook', 'executeAfterIncompleteTest'], | ||
'addRiskyTest' => ['PHPUnit\Runner\AfterRiskyTestHook', 'executeAfterRiskyTest'], | ||
'addSkippedTest' => ['PHPUnit\Runner\AfterSkippedTestHook', 'executeAfterSkippedTest'], | ||
'addError' => ['PHPUnit\Runner\AfterTestErrorHook', 'executeAfterTestError'], | ||
'addFailure' => ['PHPUnit\Runner\AfterTestFailureHook', 'executeAfterTestFailure'], | ||
'addWarning' => ['PHPUnit\Runner\AfterTestWarningHook', 'executeAfterTestWarning'], | ||
# test | ||
'startTest' => ['PHPUnit\Runner\BeforeTestHook', 'executeBeforeTest'], | ||
'endTest' => ['PHPUnit\Runner\AfterTestHook', 'executeAfterTest'], | ||
# suite | ||
'startTestSuite' => ['PHPUnit\Runner\BeforeFirstTestHook', 'executeBeforeFirstTest'], | ||
'endTestSuite' => ['PHPUnit\Runner\AfterLastTestHook', 'executeAfterLastTest'], | ||
]; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
private $testListenerClass; | ||
|
||
public function __construct(string $testListenerClass = 'PHPUnit\Framework\TestListener') | ||
{ | ||
$this->testListenerClass = $testListenerClass; | ||
} | ||
|
||
public function getDefinition(): RectorDefinition | ||
{ | ||
return new RectorDefinition('Refactor "*TestListener.php" to particular "*Hook.php" files', [ | ||
new CodeSample( | ||
<<<'CODE_SAMPLE' | ||
namespace App\Tests; | ||
use PHPUnit\Framework\TestListener; | ||
final class BeforeListHook implements TestListener | ||
{ | ||
public function addError(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
public function addWarning(Test $test, Warning $e, float $time): void | ||
{ | ||
} | ||
public function addFailure(Test $test, AssertionFailedError $e, float $time): void | ||
{ | ||
} | ||
public function addIncompleteTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
public function addRiskyTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
public function addSkippedTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
public function startTestSuite(TestSuite $suite): void | ||
{ | ||
} | ||
public function endTestSuite(TestSuite $suite): void | ||
{ | ||
} | ||
public function startTest(Test $test): void | ||
{ | ||
echo 'start test!'; | ||
} | ||
public function endTest(Test $test, float $time): void | ||
{ | ||
echo $time; | ||
} | ||
} | ||
CODE_SAMPLE | ||
, | ||
<<<'CODE_SAMPLE' | ||
namespace App\Tests; | ||
final class BeforeListHook implements \PHPUnit\Runner\BeforeTestHook, \PHPUnit\Runner\AfterTestHook | ||
{ | ||
public function executeBeforeTest(Test $test): void | ||
{ | ||
echo 'start test!'; | ||
} | ||
public function executeAfterTest(Test $test, float $time): void | ||
{ | ||
echo $time; | ||
} | ||
} | ||
CODE_SAMPLE | ||
), | ||
]); | ||
} | ||
|
||
/** | ||
* List of nodes this class checks, classes that implement @see \PhpParser\Node | ||
* @return string[] | ||
*/ | ||
public function getNodeTypes(): array | ||
{ | ||
return [Class_::class]; | ||
} | ||
|
||
/** | ||
* Process Node of matched type | ||
* @param Class_ $node | ||
*/ | ||
public function refactor(Node $node): ?Node | ||
{ | ||
if (! $this->isType($node, $this->testListenerClass)) { | ||
return null; | ||
} | ||
|
||
foreach ($node->implements as $implement) { | ||
if ($this->isName($implement, $this->testListenerClass)) { | ||
$this->removeNode($implement); | ||
} | ||
} | ||
|
||
foreach ($node->getMethods() as $classMethod) { | ||
$this->processClassMethod($node, $classMethod); | ||
} | ||
|
||
return $node; | ||
} | ||
|
||
private function processClassMethod(Class_ $class, ClassMethod $classMethod): void | ||
{ | ||
foreach ($this->listenerMethodToHookInterfaces as $methodName => $hookClassAndMethod) { | ||
/** @var string $methodName */ | ||
if (! $this->isName($classMethod, $methodName)) { | ||
continue; | ||
} | ||
|
||
// remove empty methods | ||
if (empty($classMethod->stmts)) { | ||
$this->removeNode($classMethod); | ||
} else { | ||
$class->implements[] = new FullyQualified($hookClassAndMethod[0]); | ||
$classMethod->name = new Identifier($hookClassAndMethod[1]); | ||
} | ||
} | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
...es/PHPUnit/tests/Rector/Class_/TestListenerToHooksRector/Fixture/before_list_hook.php.inc
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,82 @@ | ||
<?php | ||
|
||
namespace Rector\PHPUnit\Tests\Rector\Class_\TryCatchToExpectExceptionRector\Fixture; | ||
|
||
use PHPUnit\Framework\AssertionFailedError; | ||
use PHPUnit\Framework\Test; | ||
use PHPUnit\Framework\TestListener; | ||
use PHPUnit\Framework\TestSuite; | ||
use PHPUnit\Framework\Warning; | ||
|
||
final class BeforeListHook implements TestListener | ||
{ | ||
public function addError(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function addWarning(Test $test, Warning $e, float $time): void | ||
{ | ||
} | ||
|
||
public function addFailure(Test $test, AssertionFailedError $e, float $time): void | ||
{ | ||
} | ||
|
||
public function addIncompleteTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function addRiskyTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function addSkippedTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function startTestSuite(TestSuite $suite): void | ||
{ | ||
} | ||
|
||
public function endTestSuite(TestSuite $suite): void | ||
{ | ||
} | ||
|
||
public function startTest(Test $test): void | ||
{ | ||
dump($test); | ||
echo 'start test!'; | ||
} | ||
|
||
public function endTest(Test $test, float $time): void | ||
{ | ||
dump($time); | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\PHPUnit\Tests\Rector\Class_\TryCatchToExpectExceptionRector\Fixture; | ||
|
||
use PHPUnit\Framework\AssertionFailedError; | ||
use PHPUnit\Framework\Test; | ||
use PHPUnit\Framework\TestListener; | ||
use PHPUnit\Framework\TestSuite; | ||
use PHPUnit\Framework\Warning; | ||
|
||
final class BeforeListHook implements \PHPUnit\Runner\BeforeTestHook, \PHPUnit\Runner\AfterTestHook | ||
{ | ||
public function executeBeforeTest(Test $test): void | ||
{ | ||
dump($test); | ||
echo 'start test!'; | ||
} | ||
public function executeAfterTest(Test $test, float $time): void | ||
{ | ||
dump($time); | ||
} | ||
} | ||
|
||
?> |
70 changes: 70 additions & 0 deletions
70
packages/PHPUnit/tests/Rector/Class_/TestListenerToHooksRector/Fixture/clear_it_all.php.inc
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,70 @@ | ||
<?php | ||
|
||
namespace Rector\PHPUnit\Tests\Rector\Class_\TryCatchToExpectExceptionRector\Fixture; | ||
|
||
use PHPUnit\Framework\AssertionFailedError; | ||
use PHPUnit\Framework\Test; | ||
use PHPUnit\Framework\TestListener; | ||
use PHPUnit\Framework\TestSuite; | ||
use PHPUnit\Framework\Warning; | ||
|
||
final class SomeListener implements TestListener | ||
{ | ||
public function addError(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function addWarning(Test $test, Warning $e, float $time): void | ||
{ | ||
} | ||
|
||
public function addFailure(Test $test, AssertionFailedError $e, float $time): void | ||
{ | ||
} | ||
|
||
public function addIncompleteTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function addRiskyTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function addSkippedTest(Test $test, \Throwable $t, float $time): void | ||
{ | ||
} | ||
|
||
public function startTestSuite(TestSuite $suite): void | ||
{ | ||
} | ||
|
||
public function endTestSuite(TestSuite $suite): void | ||
{ | ||
} | ||
|
||
public function startTest(Test $test): void | ||
{ | ||
} | ||
|
||
public function endTest(Test $test, float $time): void | ||
{ | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\PHPUnit\Tests\Rector\Class_\TryCatchToExpectExceptionRector\Fixture; | ||
|
||
use PHPUnit\Framework\AssertionFailedError; | ||
use PHPUnit\Framework\Test; | ||
use PHPUnit\Framework\TestListener; | ||
use PHPUnit\Framework\TestSuite; | ||
use PHPUnit\Framework\Warning; | ||
|
||
final class SomeListener implements TestListener | ||
{ | ||
} | ||
|
||
?> |
22 changes: 22 additions & 0 deletions
22
...s/PHPUnit/tests/Rector/Class_/TestListenerToHooksRector/TestListenerToHooksRectorTest.php
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,22 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Rector\PHPUnit\Tests\Rector\Class_\TestListenerToHooksRector; | ||
|
||
use Rector\PHPUnit\Rector\Class_\TestListenerToHooksRector; | ||
use Rector\Testing\PHPUnit\AbstractRectorTestCase; | ||
|
||
final class TestListenerToHooksRectorTest extends AbstractRectorTestCase | ||
{ | ||
public function test(): void | ||
{ | ||
$this->doTestFiles([ | ||
__DIR__ . '/Fixture/clear_it_all.php.inc', | ||
__DIR__ . '/Fixture/before_list_hook.php.inc', | ||
]); | ||
} | ||
|
||
public function getRectorClass(): string | ||
{ | ||
return TestListenerToHooksRector::class; | ||
} | ||
} |