Skip to content

Commit

Permalink
[PHPUnit] Add AddProphecyTraitRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Apr 1, 2020
1 parent 3be8fc5 commit e23321b
Show file tree
Hide file tree
Showing 24 changed files with 300 additions and 22 deletions.
2 changes: 2 additions & 0 deletions config/set/phpunit/phpunit91.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
services:
Rector\PHPUnit\Rector\Class_\AddProphecyTraitRector: null
33 changes: 29 additions & 4 deletions docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# All 481 Rectors Overview
# All 482 Rectors Overview

- [Projects](#projects)
- [General](#general)
Expand Down Expand Up @@ -3612,9 +3612,10 @@ Remove temporary *Uuid relation properties
Change array to ArrayCollection in setParameters method of query builder

```diff

-use Doctrine\ORM\EntityRepository;
+use Doctrine\Common\Collections\ArrayCollection;use Doctrine\ORM\EntityRepository;use Doctrine\ORM\Query\Parameter;
-
+use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityRepository;
+use Doctrine\ORM\Query\Parameter;

class SomeRepository extends EntityRepository
{
Expand Down Expand Up @@ -5131,6 +5132,30 @@ Tests without assertion will have @doesNotPerformAssertion

<br>

### `AddProphecyTraitRector`

- class: [`Rector\PHPUnit\Rector\Class_\AddProphecyTraitRector`](/../master/rules/phpunit/src/Rector/Class_/AddProphecyTraitRector.php)
- [test fixtures](/../master/rules/phpunit/tests/Rector/Class_/AddProphecyTraitRector/Fixture)

Add Prophecy trait for method using $this->prophesize()

```diff
use PHPUnit\Framework\TestCase;
+use Prophecy\PhpUnit\ProphecyTrait;

final class ExampleTest extends TestCase
{
+ use ProphecyTrait;
+
public function testOne(): void
{
$prophecy = $this->prophesize(\AnInterface::class);
}
}
```

<br>

### `AddSeeTestAnnotationRector`

- class: [`Rector\PHPUnit\Rector\Class_\AddSeeTestAnnotationRector`](/../master/rules/phpunit/src/Rector/Class_/AddSeeTestAnnotationRector.php)
Expand Down
7 changes: 4 additions & 3 deletions packages/post-rector/src/Application/PostFileProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class PostFileProcessor
*/
public function __construct(array $postRectors)
{
$this->sortByPriorityAndSetCommanders($postRectors);
$this->postRectors = $this->sortByPriority($postRectors);
}

/**
Expand All @@ -41,8 +41,9 @@ public function traverse(array $nodes): array

/**
* @param PostRectorInterface[] $postRectors
* @return PostRectorInterface[]
*/
private function sortByPriorityAndSetCommanders(array $postRectors): void
private function sortByPriority(array $postRectors): array
{
$postRectorsByPriority = [];

Expand All @@ -56,6 +57,6 @@ private function sortByPriorityAndSetCommanders(array $postRectors): void

krsort($postRectorsByPriority);

$this->postRectors = $postRectorsByPriority;
return $postRectorsByPriority;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ protected function configure(): void
{
$this->setName(CommandNaming::classToName(self::class));
$this->setAliases(['c']);
$this->setDescription('[Dev] Create a new Rector, in a proper location, with new tests');
$this->setDescription('[DEV] Create a new Rector, in a proper location, with new tests');
}

protected function execute(InputInterface $input, OutputInterface $output): int
Expand Down
3 changes: 1 addition & 2 deletions packages/rector-generator/src/TemplateVariablesFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name\FullyQualified;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Util\RectorStrings;
use Rector\RectorGenerator\ValueObject\Configuration;

final class TemplateVariablesFactory
Expand All @@ -32,7 +31,7 @@ public function createFromConfiguration(Configuration $configuration): array
{
$data = [
'_Package_' => $configuration->getPackage(),
'_package_' => RectorStrings::camelCaseToDashes($configuration->getPackage()),
'_package_' => $configuration->getPackageDirectory(),
'_Category_' => $configuration->getCategory(),
'_Description_' => $configuration->getDescription(),
'_Name_' => $configuration->getName(),
Expand Down
5 changes: 5 additions & 0 deletions packages/rector-generator/src/ValueObject/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public function getPackage(): string

public function getPackageDirectory(): string
{
// special cases
if ($this->package === 'PHPUnit') {
return 'phpunit';
}

return RectorStrings::camelCaseToDashes($this->package);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,9 @@ private function removeAssignsFromConstructor(ClassMethod $classMethod): void

private function removeUnusedProperties(Class_ $class): void
{
foreach (array_keys($this->propertyFetchToParamsToRemoveFromConstructor) as $propertyFetchName) {
$propertyFetchNames = array_keys($this->propertyFetchToParamsToRemoveFromConstructor);

foreach ($propertyFetchNames as $propertyFetchName) {
/** @var string $propertyFetchName */
$this->classManipulator->removeProperty($class, $propertyFetchName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ public function getSomething()
PHP
,
<<<'PHP'
use Doctrine\Common\Collections\ArrayCollection;use Doctrine\ORM\EntityRepository;use Doctrine\ORM\Query\Parameter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Parameter;
class SomeRepository extends EntityRepository
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
if (! $this->classManipulator->hasClassTrait($node, 'Gedmo\Timestampable\Traits\TimestampableEntity')) {
if (! $this->classManipulator->hasTrait($node, 'Gedmo\Timestampable\Traits\TimestampableEntity')) {
return null;
}

Expand Down
122 changes: 122 additions & 0 deletions rules/phpunit/src/Rector/Class_/AddProphecyTraitRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

declare(strict_types=1);

namespace Rector\PHPUnit\Rector\Class_;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\PhpParser\Node\Manipulator\ClassInsertManipulator;
use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator;
use Rector\Core\Rector\AbstractPHPUnitRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;

/**
* @see https://github.com/sebastianbergmann/phpunit/issues/4142
* @see https://github.com/sebastianbergmann/phpunit/issues/4141
* @see https://github.com/sebastianbergmann/phpunit/issues/4149
*
* @see \Rector\PHPUnit\Tests\Rector\Class_\AddProphecyTraitRector\AddProphecyTraitRectorTest
*/
final class AddProphecyTraitRector extends AbstractPHPUnitRector
{
/**
* @var string
*/
private const PROPHECY_TRAIT = 'Prophecy\PhpUnit\ProphecyTrait';

/**
* @var ClassInsertManipulator
*/
private $classInsertManipulator;

/**
* @var ClassManipulator
*/
private $classManipulator;

public function __construct(ClassManipulator $classManipulator, ClassInsertManipulator $classInsertManipulator)
{
$this->classInsertManipulator = $classInsertManipulator;
$this->classManipulator = $classManipulator;
}

public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Add Prophecy trait for method using $this->prophesize()', [
new CodeSample(
<<<'PHP'
use PHPUnit\Framework\TestCase;
final class ExampleTest extends TestCase
{
public function testOne(): void
{
$prophecy = $this->prophesize(\AnInterface::class);
}
}
PHP
,
<<<'PHP'
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
final class ExampleTest extends TestCase
{
use ProphecyTrait;
public function testOne(): void
{
$prophecy = $this->prophesize(\AnInterface::class);
}
}
PHP

),
]);
}

/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}

/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkipClass($node)) {
return null;
}

$this->classInsertManipulator->addAsFirstTrait($node, self::PROPHECY_TRAIT);

return $node;
}

private function hasProphesizeMethodCall(Class_ $node): bool
{
return (bool) $this->betterNodeFinder->findFirst($node, function (Node $node) {
return $this->isMethodCall($node, 'this', 'prophesize');
});
}

private function shouldSkipClass(Class_ $class): bool
{
if (! $this->isInTestClass($class)) {
return true;
}

$hasProphesizeMethodCall = $this->hasProphesizeMethodCall($class);
if ($hasProphesizeMethodCall === false) {
return true;
}

return $this->classManipulator->hasTrait($class, self::PROPHECY_TRAIT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Rector\PHPUnit\Tests\Rector\Class_\AddProphecyTraitRector;

use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\PHPUnit\Rector\Class_\AddProphecyTraitRector;

final class AddProphecyTraitRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}

public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

protected function getRectorClass(): string
{
return AddProphecyTraitRector::class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\Class_\AddProphecyTraitRector\Fixture;

use PHPUnit\Framework\TestCase;

final class ExampleTest extends TestCase
{
public function testOne(): void
{
$prophecy = $this->prophesize(\AnInterface::class);
}
}

?>
-----
<?php

namespace Rector\PHPUnit\Tests\Rector\Class_\AddProphecyTraitRector\Fixture;

use PHPUnit\Framework\TestCase;

final class ExampleTest extends TestCase
{
use \Prophecy\PhpUnit\ProphecyTrait;
public function testOne(): void
{
$prophecy = $this->prophesize(\AnInterface::class);
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\Class_\AddProphecyTraitRector\Fixture;

use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;

final class SkipIfAlreadyAdded extends TestCase
{
use ProphecyTrait;

public function testOne(): void
{
$prophecy = $this->prophesize(\AnInterface::class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\Class_\AddProphecyTraitRector\Fixture;

use PHPUnit\Framework\TestCase;
use stdClass;

final class SkipNonProphesizeTest extends TestCase
{
public function testOne(): void
{
$that = new stdClass();
$prophecy = $that->prophesize(\AnInterface::class);
}
}
2 changes: 1 addition & 1 deletion src/Console/Command/ScreenFileCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public function __construct(
protected function configure(): void
{
$this->setName(CommandNaming::classToName(self::class));
$this->setDescription('[Dev] Load file and print nodes meta data - super helpful to learn to build rules');
$this->setDescription('[DEV] Load file and print nodes meta data - super helpful to learn to build rules');

$this->addArgument(self::FILE_ARGUMENT, InputArgument::REQUIRED, 'Path to file to be screened');
}
Expand Down
2 changes: 1 addition & 1 deletion src/PhpParser/Node/Manipulator/ClassInsertManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public function addAsFirstTrait(Class_ $class, string $traitName): void
{
$trait = new TraitUse([new FullyQualified($traitName)]);

$this->addStatementToClassBeforeTypes($class, $trait, TraitUse::class, Property::class);
$this->addStatementToClassBeforeTypes($class, $trait, TraitUse::class, Property::class, ClassMethod::class);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/PhpParser/Node/Manipulator/ClassManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public function hasPropertyName(Class_ $node, string $name): bool
return false;
}

public function hasClassTrait(Class_ $class, string $desiredTrait): bool
public function hasTrait(Class_ $class, string $desiredTrait): bool
{
foreach ($class->getTraitUses() as $traitUse) {
if (! $this->nodeNameResolver->haveName($traitUse->traits, $desiredTrait)) {
Expand Down
Loading

0 comments on commit e23321b

Please sign in to comment.