Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@
"symfony/console": "^7.1"
},
"require-dev": {
"rector/rector": "dev-main",
"nikic/php-parser": "^5.3.1",
"phpunit/phpunit": "^10.5",
"phpstan/phpstan": "^2.0",
"symplify/easy-coding-standard": "^12.1",
"rector/rector": "^2.0",
"nikic/php-parser": "^5.4",
"phpunit/phpunit": "^11.5",
"phpstan/phpstan": "^2.1",
"phpecs/phpecs": "^2.0",
"phpstan/extension-installer": "^1.3",
"symplify/rule-doc-generator": "^12.1",
"tomasvotruba/class-leak": "^0.2.5",
"tomasvotruba/class-leak": "^2.0",
"tracy/tracy": "^2.10"
},
"autoload": {
Expand All @@ -47,7 +46,7 @@
"phpstan": "vendor/bin/phpstan analyse --ansi",
"check-cs": "vendor/bin/ecs check --ansi",
"fix-cs": "vendor/bin/ecs check --fix --ansi",
"docs": "vendor/bin/rule-doc-generator generate src rules --output-file docs/rector_rules_overview.md --ansi"
"phpunit": "vendor/bin/phpunit --colors=always"
},
"minimum-stability": "dev",
"prefer-stable": true,
Expand Down
34 changes: 13 additions & 21 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,18 @@

use Rector\Config\RectorConfig;
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
use Rector\Set\ValueObject\SetList;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->importNames();

$rectorConfig->paths([__DIR__ . '/config', __DIR__ . '/src', __DIR__ . '/rules', __DIR__ . '/rules-tests']);

$rectorConfig->skip([
// for tests
'*/Source/*',

return RectorConfig::configure()
->withImportNames()
->withPaths([__DIR__ . '/config', __DIR__ . '/src', __DIR__ . '/rules', __DIR__ . '/rules-tests'])
->withSkip([
StringClassNameToClassConstantRector::class => [__DIR__ . '/src/DocFactory.php'],
]);

$rectorConfig->sets([
SetList::INSTANCEOF,
SetList::NAMING,
SetList::TYPE_DECLARATION,
SetList::DEAD_CODE,
SetList::CODE_QUALITY,
SetList::CODING_STYLE,
]);
};
])
->withPreparedSets(
instanceOf: true,
naming: true,
typeDeclarations: true,
deadCode: true,
codeQuality: true,
codingStyle: true,
);
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ use PhpSpec\ObjectBehavior;

final class PhpSpecPromises extends ObjectBehavior
{
private \Rector\PhpSpecToPHPUnit\Tests\Rector\Class_\PromisesToAssertsRector\Fixture\PhpSpecPromises $phpSpecPromises;
protected function setUp(): void
{
$this->phpSpecPromises = new \Rector\PhpSpecToPHPUnit\Tests\Rector\Class_\PromisesToAssertsRector\Fixture\PhpSpecPromises();
}
public function it_returns_id()
{
$this->assertSame(5, $this->phpSpecPromises->id());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace spec\Rector\PhpSpecToPHPUnit;

use PhpSpec\ObjectBehavior;

class TestClassMethod extends ObjectBehavior
class ShouldBeInstanceofMethod extends ObjectBehavior
{
public function let_1()
{
Expand Down Expand Up @@ -35,26 +35,31 @@ namespace spec\Rector\PhpSpecToPHPUnit;

use PhpSpec\ObjectBehavior;

class TestClassMethod extends ObjectBehavior
class ShouldBeInstanceofMethod extends ObjectBehavior
{
private \Rector\PhpSpecToPHPUnit\ShouldBeInstanceofMethod $shouldBeInstanceofMethod;
protected function setUp(): void
{
$this->shouldBeInstanceofMethod = new \Rector\PhpSpecToPHPUnit\ShouldBeInstanceofMethod();
}
public function let_1()
{
$this->assertInstanceOf(\stdClass::class, $this->testClassMethod);
$this->assertInstanceOf(\stdClass::class, $this->shouldBeInstanceofMethod);
}

public function let_2()
{
$this->assertInstanceOf(\stdClass::class, $this->testClassMethod);
$this->assertInstanceOf(\stdClass::class, $this->shouldBeInstanceofMethod);
}

public function let_3()
{
$this->assertInstanceOf(\stdClass::class, $this->testClassMethod);
$this->assertInstanceOf(\stdClass::class, $this->shouldBeInstanceofMethod);
}

public function let_4()
{
$this->assertInstanceOf(\stdClass::class, $this->testClassMethod);
$this->assertInstanceOf(\stdClass::class, $this->shouldBeInstanceofMethod);
}
}

Expand Down
27 changes: 3 additions & 24 deletions rules/Rector/Class_/ImplicitLetInitializationRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,18 @@

namespace Rector\PhpSpecToPHPUnit\Rector\Class_;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpSpecToPHPUnit\Enum\PhpSpecMethodName;
use Rector\PhpSpecToPHPUnit\Naming\PhpSpecRenaming;
use Rector\PhpSpecToPHPUnit\NodeFactory\SetUpInstanceFactory;
use Rector\PhpSpecToPHPUnit\NodeFinder\MethodCallFinder;
use Rector\PhpSpecToPHPUnit\ValueObject\TestedObject;
use Rector\Rector\AbstractRector;
use Rector\ValueObject\MethodName;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

Expand All @@ -34,6 +26,7 @@ final class ImplicitLetInitializationRector extends AbstractRector
{
public function __construct(
private readonly PhpSpecRenaming $phpSpecRenaming,
private readonly SetUpInstanceFactory $setUpInstanceFactory,
) {
}

Expand Down Expand Up @@ -108,26 +101,12 @@ public function refactor(Node $node): ?Node

$testedObjectProperty = $this->createTestedObjectProperty($testedObject);

$setUpClassMethod = $this->createSetUpClassMethod($testedObject);
$setUpClassMethod = $this->setUpInstanceFactory->createSetUpClassMethod($testedObject);
$node->stmts = [$testedObjectProperty, $setUpClassMethod, ...(array) $node->stmts];

return $node;
}

private function createSetUpClassMethod(TestedObject $testedObject): ClassMethod
{
$classMethod = new ClassMethod(MethodName::SET_UP);
$classMethod->returnType = new Identifier('void');
$classMethod->flags |= Modifiers::PROTECTED;

$propertyFetch = new PropertyFetch(new Variable('this'), $testedObject->getPropertyName());
$new = new New_(new FullyQualified($testedObject->getClassName()));

$classMethod->stmts = [new Expression(new Assign($propertyFetch, $new))];

return $classMethod;
}

private function createTestedObjectProperty(TestedObject $testedObject): Property
{
return $this->nodeFactory->createPrivatePropertyFromNameAndType(
Expand Down
55 changes: 54 additions & 1 deletion rules/Rector/Class_/PromisesToAssertsRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Rector\PhpSpecToPHPUnit\Rector\Class_;

use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Identifier;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
Expand All @@ -12,15 +14,19 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Node\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeFinder;
use Rector\PhpSpecToPHPUnit\Enum\PhpSpecMethodName;
use Rector\PhpSpecToPHPUnit\Enum\PHPUnitMethodName;
use Rector\PhpSpecToPHPUnit\Enum\ProphecyPromisesToPHPUnitAssertMap;
use Rector\PhpSpecToPHPUnit\Naming\PhpSpecRenaming;
use Rector\PhpSpecToPHPUnit\Naming\SystemMethodDetector;
use Rector\PhpSpecToPHPUnit\NodeFactory\AssertMethodCallFactory;
use Rector\PhpSpecToPHPUnit\NodeFactory\BeConstructedWithAssignFactory;
use Rector\PhpSpecToPHPUnit\NodeFactory\SetUpInstanceFactory;
use Rector\PhpSpecToPHPUnit\ValueObject\TestedObject;
use Rector\Rector\AbstractRector;
use Rector\ValueObject\MethodName;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

Expand All @@ -29,11 +35,15 @@
*/
final class PromisesToAssertsRector extends AbstractRector
{
private NodeFinder $nodeFinder;

public function __construct(
private readonly PhpSpecRenaming $phpSpecRenaming,
private readonly AssertMethodCallFactory $assertMethodCallFactory,
private readonly BeConstructedWithAssignFactory $beConstructedWithAssignFactory,
private readonly SetUpInstanceFactory $setUpInstanceFactory,
) {
$this->nodeFinder = new NodeFinder();
}

/**
Expand All @@ -58,6 +68,8 @@ public function refactor(Node $node): Node|null

$localMethodNames = $this->getLocalMethodNames($node);

$needsSetUp = true;

foreach ($node->getMethods() as $classMethod) {
if (! $classMethod->isPublic()) {
continue;
Expand All @@ -68,9 +80,15 @@ public function refactor(Node $node): Node|null
$classMethod,
[PhpSpecMethodName::LET, PhpSpecMethodName::LET_GO, PhpSpecMethodName::GET_MATCHERS]
)) {
$needsSetUp = false;
continue;
}

// if all methods have this call, no need to add setUp()
if ($this->hasBeConstructedMethodCall($classMethod)) {
$needsSetUp = false;
}

$this->traverseNodesWithCallable($classMethod, function (Node $node) use (
$class,
$testedObjectPropertyFetch,
Expand Down Expand Up @@ -179,6 +197,16 @@ public function refactor(Node $node): Node|null
return null;
}

// add setUp() method with the property
if ($needsSetUp && ! $class->getMethod(MethodName::SET_UP)) {
$testedObject = $this->phpSpecRenaming->resolveTestedObject($node);
$setUpClassMethod = $this->setUpInstanceFactory->createSetUpClassMethod($testedObject);

$testedObjectProperty = $this->createTestedObjectProperty($testedObject);

$class->stmts = array_merge([$testedObjectProperty, $setUpClassMethod], $class->stmts);
}

return $node;
}

Expand Down Expand Up @@ -248,4 +276,29 @@ private function getLocalMethodNames(Class_ $class): array
/** @var string[] $localMethodNames */
return $localMethodNames;
}

private function createTestedObjectProperty(TestedObject $testedObject): Property
{
return $this->nodeFactory->createPrivatePropertyFromNameAndType(
$testedObject->getPropertyName(),
$testedObject->getTestedObjectType()
);
}

private function hasBeConstructedMethodCall(ClassMethod $classMethod): bool
{
$methodCall = $this->nodeFinder->findFirst((array) $classMethod->stmts, function (Node $node): bool {
if (! $node instanceof MethodCall) {
return false;
}

if (! $node->name instanceof Identifier) {
return false;
}

return $node->name->toString() === 'beConstructedWith';
});

return $methodCall instanceof MethodCall;
}
}
34 changes: 34 additions & 0 deletions src/NodeFactory/SetUpInstanceFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Rector\PhpSpecToPHPUnit\NodeFactory;

use PhpParser\Modifiers;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\PhpSpecToPHPUnit\ValueObject\TestedObject;
use Rector\ValueObject\MethodName;

final class SetUpInstanceFactory
{
public function createSetUpClassMethod(TestedObject $testedObject): ClassMethod
{
$classMethod = new ClassMethod(MethodName::SET_UP);
$classMethod->returnType = new Identifier('void');
$classMethod->flags |= Modifiers::PROTECTED;

$propertyFetch = new PropertyFetch(new Variable('this'), $testedObject->getPropertyName());
$new = new New_(new FullyQualified($testedObject->getClassName()));

$classMethod->stmts = [new Expression(new Assign($propertyFetch, $new))];

return $classMethod;
}
}
2 changes: 1 addition & 1 deletion src/NodeFactory/WillReturnMapMethodCallFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private function createConsecutiveItemsArray(
PhpSpecMethodName::SHOULD_RETURN
);

if (empty($returnArgs)) {
if ($returnArgs === []) {
$returnArgs = $this->resolveInputArgs(
$consecutiveMethodCall->getMethodCall(),
PhpSpecMethodName::WILL_RETURN
Expand Down
41 changes: 41 additions & 0 deletions tests/Sets/Fixture/Sylius/add_setup.php.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace spec\Set\Sylius;

use PhpSpec\ObjectBehavior;

final class SomeTestedClassSpec extends ObjectBehavior
{
public function it_is_initializable(): void
{
$this->shouldHaveType(SomeTestedClass::class);
}

public function it_implements(): void
{
$this->shouldImplement(RandomInterface::class);
}
}

?>
-----
<?php

namespace Tests\Set\Sylius;

use PhpSpec\ObjectBehavior;

final class SomeTestedClassTest extends \PHPUnit\Framework\TestCase
{
private \Set\Sylius\SomeTestedClass $someTestedClass;
protected function setUp(): void
{
$this->someTestedClass = new \Set\Sylius\SomeTestedClass();
}
public function testImplements(): void
{
$this->assertInstanceOf(RandomInterface::class, $this->someTestedClass);
}
}

?>
Loading
Loading