diff --git a/lib/Transunit/Pass.php b/lib/Transunit/Pass.php index c697718..945c5e3 100644 --- a/lib/Transunit/Pass.php +++ b/lib/Transunit/Pass.php @@ -9,5 +9,6 @@ interface Pass { /** @param Node[] $ast */ public function find(NodeFinder $nodeFinder, $ast): array; + public function rewrite(Node $node): void; } diff --git a/lib/Transunit/Pass/AddTestMethodPrefixPass.php b/lib/Transunit/Pass/AddTestMethodPrefixPass.php new file mode 100644 index 0000000..7eb26a8 --- /dev/null +++ b/lib/Transunit/Pass/AddTestMethodPrefixPass.php @@ -0,0 +1,54 @@ +find($ast, function (Node $node) { + if ($node instanceof Node\Stmt\ClassMethod && !in_array($node->name->toString(), ['setUp', 'let'],true)) { + return $node; + } + + return null; + }); + } + + public function rewrite(Node $node): void + { + if (!$node instanceof Node\Stmt\ClassMethod) { + return; + } + + $this->addPrefix($node); + } + + /** + * public function test_it_should_do_something(): void { ... } + */ + private function addPrefix(Node\Stmt\ClassMethod $node): void + { + $methodName = $node->name->toString(); + + if (0 !== strpos($methodName, 'it_')) { + return; + } + + $node->name = new Node\Identifier('test_' . $methodName); + $node->flags = Modifiers::PUBLIC; + $node->returnType = new Node\Name('void'); + } +} diff --git a/lib/Transunit/Pass/AssertionPass.php b/lib/Transunit/Pass/AssertionPass.php index ff95cda..4902441 100644 --- a/lib/Transunit/Pass/AssertionPass.php +++ b/lib/Transunit/Pass/AssertionPass.php @@ -6,6 +6,12 @@ use PhpParser\Node; use Transunit\Pass; +/** + * ``` + * - $this->_testSubject->contractOut(47)->shouldReturn($agent47); + * + static::assertSame($agent47, $this->_testSubject->contractOut(47)); + * ``` + */ class AssertionPass implements Pass { public function find(NodeFinder $nodeFinder, $ast): array diff --git a/lib/Transunit/Pass/CallTestSubjectPass.php b/lib/Transunit/Pass/CallTestSubjectPass.php index 1fcf503..24531bd 100644 --- a/lib/Transunit/Pass/CallTestSubjectPass.php +++ b/lib/Transunit/Pass/CallTestSubjectPass.php @@ -6,6 +6,18 @@ use PhpParser\NodeFinder; use Transunit\Pass; +/** + * ``` + * function it_contracts_out_agents(AgentRepository $agentRepository, EventDispatcher $eventDispatcher, Agent $agent47, ContractEvent $event) + * { + * $this->agentRepository->find(47)->willReturn($agent47); + * $this->eventDispatcher->dispatch($event)->shouldBeCalled(); + * + * - $this->contractOut(47)->shouldReturn($agent47); + * + $this->_testSubject->contractOut(47)->shouldReturn($agent47); + * } + * ``` + */ class CallTestSubjectPass implements Pass { public function find(NodeFinder $nodeFinder, $ast): array diff --git a/lib/Transunit/Pass/GlobalCollaboratorPass.php b/lib/Transunit/Pass/GlobalCollaboratorPass.php index 1ce720c..76e1b79 100644 --- a/lib/Transunit/Pass/GlobalCollaboratorPass.php +++ b/lib/Transunit/Pass/GlobalCollaboratorPass.php @@ -7,6 +7,32 @@ use PhpParser\NodeFinder; use Transunit\Pass; +/** + * ``` + * class TestSubjectTest extends TestCase + * { + * use ProphecyTrait; + * + * + private ObjectProphecy|AgentRepository $agentRepository; + * + private ObjectProphecy|EventDispatcher $eventDispatcher; + * + * function let(AgentRepository $agentRepository, EventDispatcher $eventDispatcher) + * { + * $this->beConstructedWith($agentRepository, $eventDispatcher); + * } + * + * function it_contracts_out_agents(AgentRepository $agentRepository, EventDispatcher $eventDispatcher, Agent $agent47, ContractEvent $event) + * { + * - $agentRepository->find(47)->willReturn($agent47); + * + $this->agentRepository->find(47)->willReturn($agent47); + * + * - $eventDispatcher->dispatch($event)->shouldBeCalled(); + * + $this->eventDispatcher->dispatch($event)->shouldBeCalled(); + * + * $this->contractOut(47)->shouldReturn($agent47); + * } + * ``` + */ class GlobalCollaboratorPass implements Pass { public function find(NodeFinder $nodeFinder, $ast): array diff --git a/lib/Transunit/Pass/GlobalTestSubjectInstancePass.php b/lib/Transunit/Pass/GlobalTestSubjectInstancePass.php index 643b337..56c4219 100644 --- a/lib/Transunit/Pass/GlobalTestSubjectInstancePass.php +++ b/lib/Transunit/Pass/GlobalTestSubjectInstancePass.php @@ -7,6 +7,22 @@ use PhpParser\NodeFinder; use Transunit\Pass; +/** + * ``` + * class TestSubjectTest extends TestCase + * { + * use ProphecyTrait; + * + * + private TestSubject $_testSubject; + * + * - function let(AgentRepository $agentRepository, EventDispatcher $eventDispatcher) + * + protected function setUp(): void + * { + * - $this->beConstructedWith($agentRepository, $eventDispatcher); + * + $this->_testSubject = new TestSubject($this->agentRepository->reveal(), $this->eventDispatcher->reveal()); + * } + * ``` + */ class GlobalTestSubjectInstancePass implements Pass { public function find(NodeFinder $nodeFinder, $ast): array diff --git a/lib/Transunit/Pass/ProphesizeGlobalCollaboratorsPass.php b/lib/Transunit/Pass/ProphesizeGlobalCollaboratorsPass.php new file mode 100644 index 0000000..5829da1 --- /dev/null +++ b/lib/Transunit/Pass/ProphesizeGlobalCollaboratorsPass.php @@ -0,0 +1,86 @@ +agentRepository = $this->prophesize(AgentRepository::class); + * + $this->eventDispatcher = $this->prophesize(EventDispatcher::class); + * + * // ... + * } + * ``` + */ +class ProphesizeGlobalCollaboratorsPass implements Pass +{ + public function find(NodeFinder $nodeFinder, $ast): array + { + return $nodeFinder->find($ast, function (Node $node) { + if ($node instanceof Node\Stmt\ClassMethod && !in_array($node->name->toString(), ['setUp', 'let'],true)) { + return $node; + } + + return null; + }); + } + + public function rewrite(Node $node): void + { + if (!$node instanceof Node\Stmt\ClassMethod) { + return; + } + + $this->prophesizeGlobalCollaborators($node); + } + + /** + * protected function setUp(): void { + * $this->classCollaborator = $this->prophesize(ClassCollaborator::class); + * } + */ + private function prophesizeGlobalCollaborators(Node\Stmt\ClassMethod $node): void + { + if (!in_array($node->name->toString(), ['let', 'setUp'], true)) { + return; + } + + $newStmts = []; + + while (count($node->params) > 0) { + $param = array_pop($node->params); + + $newStmts[] = new Node\Stmt\Expression( + new Node\Expr\Assign( + // assign class property + new Node\Expr\PropertyFetch( + new Node\Expr\Variable('this'), + $param->var->name + ), + new Node\Expr\MethodCall( + new Node\Expr\Variable('this'), + 'prophesize', + [ + new Node\Arg(new Node\Expr\ClassConstFetch( + new Node\Name($param->type->toString()), + 'class' + )), + ] + ) + ) + ); + + foreach ($node->stmts as $currentStmt) { + $newStmts[] = $currentStmt; + } + } + + $node->stmts = $newStmts; + } +} diff --git a/lib/Transunit/Pass/TestMethodPass.php b/lib/Transunit/Pass/ProphesizeLocalCollaboratorsPass.php similarity index 55% rename from lib/Transunit/Pass/TestMethodPass.php rename to lib/Transunit/Pass/ProphesizeLocalCollaboratorsPass.php index 6ebfc75..f33fb87 100644 --- a/lib/Transunit/Pass/TestMethodPass.php +++ b/lib/Transunit/Pass/ProphesizeLocalCollaboratorsPass.php @@ -2,12 +2,23 @@ namespace Transunit\Pass; -use PhpParser\Modifiers; use PhpParser\Node; use PhpParser\NodeFinder; use Transunit\Pass; -class TestMethodPass implements Pass +/** + * ``` + * - public function test_it_handles_events(Event $event): void + * + public function test_it_handles_events(): void + * { + * + $event = $this->prophesize(Event::class); + * + * - $this->_testSubject->onKernelRequest($event); + * + $this->_testSubject->onKernelRequest($event->reveal()); + * } + * ``` + */ +class ProphesizeLocalCollaboratorsPass implements Pass { public function find(NodeFinder $nodeFinder, $ast): array { @@ -26,85 +37,9 @@ public function rewrite(Node $node): void return; } - $this->renameSetup($node); - $this->addPrefix($node); - $this->prophesizeGlobalCollaborators($node); $this->prophesizeLocalCollaborators($node); } - /** - * public function test_it_should_do_something(): void { ... } - */ - private function addPrefix(Node\Stmt\ClassMethod $node): void - { - $methodName = $node->name->toString(); - - if (0 !== strpos($methodName, 'it_')) { - return; - } - - $node->name = new Node\Identifier('test_' . $methodName); - $node->flags = Modifiers::PUBLIC; - $node->returnType = new Node\Name('void'); - } - - /** - * protected function setUp(): void { ... } - */ - private function renameSetup(Node\Stmt\ClassMethod $node): void - { - if ($node->name->toString() !== 'let') { - return; - } - - $node->name = new Node\Identifier('setUp'); - $node->flags = Modifiers::PROTECTED; - } - - /** - * protected function setUp(): void { - * $this->classCollaborator = $this->prophesize(ClassCollaborator::class); - * } - */ - private function prophesizeGlobalCollaborators(Node\Stmt\ClassMethod $node): void - { - if (!in_array($node->name->toString(), ['let', 'setUp'], true)) { - return; - } - - $newStmts = []; - - while (count($node->params) > 0) { - $param = array_pop($node->params); - - $newStmts[] = new Node\Stmt\Expression( - new Node\Expr\Assign( - // assign class property - new Node\Expr\PropertyFetch( - new Node\Expr\Variable('this'), - $param->var->name - ), - new Node\Expr\MethodCall( - new Node\Expr\Variable('this'), - 'prophesize', - [ - new Node\Arg(new Node\Expr\ClassConstFetch( - new Node\Name($param->type->toString()), - 'class' - )), - ] - ) - ) - ); - - foreach ($node->stmts as $currentStmt) { - $newStmts[] = $currentStmt; - } - } - - $node->stmts = $newStmts; - } - /** * public function test_it_should_do_something(): void { * $methodCollaborator = $this->prophesize(MethodCollaborator::class); diff --git a/lib/Transunit/Pass/RenameSetupPass.php b/lib/Transunit/Pass/RenameSetupPass.php new file mode 100644 index 0000000..816eaf1 --- /dev/null +++ b/lib/Transunit/Pass/RenameSetupPass.php @@ -0,0 +1,55 @@ +find($ast, function (Node $node) { + if ($node instanceof Node\Stmt\ClassMethod && !in_array($node->name->toString(), ['setUp', 'let'],true)) { + return $node; + } + + return null; + }); + } + + public function rewrite(Node $node): void + { + if (!$node instanceof Node\Stmt\ClassMethod) { + return; + } + + $this->renameSetup($node); + } + + /** + * protected function setUp(): void { ... } + */ + private function renameSetup(Node\Stmt\ClassMethod $node): void + { + if ($node->name->toString() !== 'let') { + return; + } + + $node->name = new Node\Identifier('setUp'); + $node->flags = Modifiers::PROTECTED; + } +} diff --git a/lib/Transunit/Transunit.php b/lib/Transunit/Transunit.php index 5965170..2e11236 100644 --- a/lib/Transunit/Transunit.php +++ b/lib/Transunit/Transunit.php @@ -53,7 +53,8 @@ private static function processFile(string $path): string $newStmts = $traverser->traverse($sourceAst); $nodeFinder = new NodeFinder(); - $passes = [ + + $rewritePasses = [ new Pass\MoveNamespacePass(), new Pass\ImportSubjectClassPass(), new Pass\ImportMockingLibraryPass(), @@ -64,11 +65,14 @@ private static function processFile(string $path): string new Pass\GlobalTestSubjectInstancePass(), new Pass\CallTestSubjectPass(), new Pass\AssertionPass(), - new Pass\TestMethodPass(), + new Pass\RenameSetupPass(), + new Pass\AddTestMethodPrefixPass(), + new Pass\ProphesizeGlobalCollaboratorsPass(), + new Pass\ProphesizeLocalCollaboratorsPass(), ]; /** @var Pass $pass */ - foreach ($passes as $pass) { + foreach ($rewritePasses as $pass) { $nodes = $pass->find($nodeFinder, $newStmts); foreach ($nodes as $node) { $pass->rewrite($node);