44
55namespace Rector \PhpSpecToPHPUnit \Rector \Class_ ;
66
7+ use PhpParser \Node \Stmt \ClassMethod ;
8+ use PhpParser \Node \Identifier ;
79use PhpParser \Node ;
810use PhpParser \Node \Expr ;
911use PhpParser \Node \Expr \Assign ;
1214use PhpParser \Node \Expr \PropertyFetch ;
1315use PhpParser \Node \Expr \Variable ;
1416use PhpParser \Node \Stmt \Class_ ;
15- use PHPStan \Node \ClassMethod ;
17+ use PhpParser \Node \Stmt \Property ;
18+ use PhpParser \NodeFinder ;
1619use Rector \PhpSpecToPHPUnit \Enum \PhpSpecMethodName ;
1720use Rector \PhpSpecToPHPUnit \Enum \PHPUnitMethodName ;
1821use Rector \PhpSpecToPHPUnit \Enum \ProphecyPromisesToPHPUnitAssertMap ;
1922use Rector \PhpSpecToPHPUnit \Naming \PhpSpecRenaming ;
2023use Rector \PhpSpecToPHPUnit \Naming \SystemMethodDetector ;
2124use Rector \PhpSpecToPHPUnit \NodeFactory \AssertMethodCallFactory ;
2225use Rector \PhpSpecToPHPUnit \NodeFactory \BeConstructedWithAssignFactory ;
26+ use Rector \PhpSpecToPHPUnit \NodeFactory \SetUpInstanceFactory ;
27+ use Rector \PhpSpecToPHPUnit \ValueObject \TestedObject ;
2328use Rector \Rector \AbstractRector ;
29+ use Rector \ValueObject \MethodName ;
2430use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
2531use Symplify \RuleDocGenerator \ValueObject \RuleDefinition ;
2632
2935 */
3036final class PromisesToAssertsRector extends AbstractRector
3137{
38+ private NodeFinder $ nodeFinder ;
39+
3240 public function __construct (
3341 private readonly PhpSpecRenaming $ phpSpecRenaming ,
3442 private readonly AssertMethodCallFactory $ assertMethodCallFactory ,
3543 private readonly BeConstructedWithAssignFactory $ beConstructedWithAssignFactory ,
44+ private readonly SetUpInstanceFactory $ setUpInstanceFactory ,
3645 ) {
46+ $ this ->nodeFinder = new NodeFinder ();
3747 }
3848
3949 /**
@@ -58,6 +68,8 @@ public function refactor(Node $node): Node|null
5868
5969 $ localMethodNames = $ this ->getLocalMethodNames ($ node );
6070
71+ $ needsSetUp = true ;
72+
6173 foreach ($ node ->getMethods () as $ classMethod ) {
6274 if (! $ classMethod ->isPublic ()) {
6375 continue ;
@@ -68,9 +80,15 @@ public function refactor(Node $node): Node|null
6880 $ classMethod ,
6981 [PhpSpecMethodName::LET , PhpSpecMethodName::LET_GO , PhpSpecMethodName::GET_MATCHERS ]
7082 )) {
83+ $ needsSetUp = false ;
7184 continue ;
7285 }
7386
87+ // if all methods have this call, no need to add setUp()
88+ if ($ this ->hasBeConstructedMethodCall ($ classMethod )) {
89+ $ needsSetUp = false ;
90+ }
91+
7492 $ this ->traverseNodesWithCallable ($ classMethod , function (Node $ node ) use (
7593 $ class ,
7694 $ testedObjectPropertyFetch ,
@@ -179,6 +197,16 @@ public function refactor(Node $node): Node|null
179197 return null ;
180198 }
181199
200+ // add setUp() method with the property
201+ if ($ needsSetUp && ! $ class ->getMethod (MethodName::SET_UP )) {
202+ $ testedObject = $ this ->phpSpecRenaming ->resolveTestedObject ($ node );
203+ $ setUpClassMethod = $ this ->setUpInstanceFactory ->createSetUpClassMethod ($ testedObject );
204+
205+ $ testedObjectProperty = $ this ->createTestedObjectProperty ($ testedObject );
206+
207+ $ class ->stmts = array_merge ([$ testedObjectProperty , $ setUpClassMethod ], $ class ->stmts );
208+ }
209+
182210 return $ node ;
183211 }
184212
@@ -248,4 +276,29 @@ private function getLocalMethodNames(Class_ $class): array
248276 /** @var string[] $localMethodNames */
249277 return $ localMethodNames ;
250278 }
279+
280+ private function createTestedObjectProperty (TestedObject $ testedObject ): Property
281+ {
282+ return $ this ->nodeFactory ->createPrivatePropertyFromNameAndType (
283+ $ testedObject ->getPropertyName (),
284+ $ testedObject ->getTestedObjectType ()
285+ );
286+ }
287+
288+ private function hasBeConstructedMethodCall (ClassMethod $ classMethod ): bool
289+ {
290+ $ methodCall = $ this ->nodeFinder ->findFirst ((array ) $ classMethod ->stmts , function (Node $ node ): bool {
291+ if (! $ node instanceof MethodCall) {
292+ return false ;
293+ }
294+
295+ if (! $ node ->name instanceof Identifier) {
296+ return false ;
297+ }
298+
299+ return $ node ->name ->toString () === 'beConstructedWith ' ;
300+ });
301+
302+ return $ methodCall instanceof MethodCall;
303+ }
251304}
0 commit comments