Skip to content

Commit

Permalink
Add TestWithAnnotationToAttributeRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jul 12, 2023
1 parent 4414d46 commit f8d95a7
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 12 deletions.
19 changes: 9 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,31 @@
},
"require-dev": {
"rector/rector-src": "dev-main",
"phpunit/phpunit": "^10.1",
"phpstan/phpstan": "^1.10.15",
"symplify/phpstan-rules": "^11.3",
"phpunit/phpunit": "^10.2",
"phpstan/phpstan": "^1.10.25",
"symplify/phpstan-rules": "^11.4",
"symplify/phpstan-extensions": "^11.2",
"symplify/easy-coding-standard": "^11.3",
"symplify/easy-coding-standard": "^11.5",
"symplify/rule-doc-generator": "^11.2",
"rector/phpstan-rules": "^0.6",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan-strict-rules": "^1.4.5",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-strict-rules": "^1.5",
"phpstan/phpstan-webmozart-assert": "^1.2.2",
"symplify/vendor-patches": "^11.2.0",
"symplify/easy-ci": "^11.2.0",
"rector/rector-generator": "^0.6.14",
"rector/rector-debugging": "dev-main",
"rector/rector-generator": "^0.6.15",
"tomasvotruba/type-coverage": "^0.1",
"tomasvotruba/unused-public": "^0.1",
"tomasvotruba/cognitive-complexity": "^0.1"
},
"autoload": {
"psr-4": {
"Rector\\PHPUnit\\": "src"
"Rector\\PHPUnit\\": ["src", "rules"]
}
},
"autoload-dev": {
"psr-4": {
"Rector\\PHPUnit\\Tests\\": "tests"
"Rector\\PHPUnit\\Tests\\": ["tests", "rules-tests"]
},
"classmap": [
"stubs"
Expand Down
4 changes: 2 additions & 2 deletions config/sets/annotations-to-attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Rector\Config\RectorConfig;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use Rector\PHPUnit\AnnotationsToAttributes\Rector\ClassMethod\TestWithAnnotationToAttributeRector;
use Rector\PHPUnit\Rector\Class_\AnnotationWithValueToAttributeRector;
use Rector\PHPUnit\Rector\Class_\CoversAnnotationWithValueToAttributeRector;
use Rector\PHPUnit\Rector\ClassMethod\DataProviderAnnotationToAttributeRector;
Expand All @@ -13,6 +14,7 @@

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rules([
TestWithAnnotationToAttributeRector::class,
DataProviderAnnotationToAttributeRector::class,
CoversAnnotationWithValueToAttributeRector::class,

Expand Down Expand Up @@ -47,8 +49,6 @@
new AnnotationWithValueToAttribute('group', 'PHPUnit\Framework\Attributes\Group'),
new AnnotationWithValueToAttribute('ticket', 'PHPUnit\Framework\Attributes\Ticket'),
new AnnotationWithValueToAttribute('uses', 'PHPUnit\Framework\Attributes\UsesClass'),
new AnnotationWithValueToAttribute('testWith', 'PHPUnit\Framework\Attributes\TestWith'),
new AnnotationWithValueToAttribute('testwith', 'PHPUnit\Framework\Attributes\TestWith'),
new AnnotationWithValueToAttribute('testDox', 'PHPUnit\Framework\Attributes\TestDox'),
new AnnotationWithValueToAttribute('testdox', 'PHPUnit\Framework\Attributes\TestDox'),

Expand Down
1 change: 1 addition & 0 deletions config/sets/level/up-to-phpunit-91.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@

use Rector\Config\RectorConfig;

/** @deprecated Use PHPUnitSetList::PHPUNIT_10 directly */
return static function (RectorConfig $rectorConfig): void {
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Rector\PHPUnit\Tests\AnnotationsToAttributes\Rector\ClassMethod\TestWithAnnotationToAttributeRector\Fixture;

use PHPUnit\Framework\TestCase;

final class SomeFixture extends TestCase
{
/**
* @testWith ["foo"]
* ["bar"]
*/
public function testOne(): void
{
}
}

?>
-----
<?php

namespace Rector\PHPUnit\Tests\AnnotationsToAttributes\Rector\ClassMethod\TestWithAnnotationToAttributeRector\Fixture;

use PHPUnit\Framework\TestCase;

final class SomeFixture extends TestCase
{
#[\PHPUnit\Framework\Attributes\TestWith(['foo'])]
#[\PHPUnit\Framework\Attributes\TestWith(['bar'])]
public function testOne(): void
{
}
}

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

declare(strict_types=1);

namespace Rector\PHPUnit\Tests\AnnotationsToAttributes\Rector\ClassMethod\TestWithAnnotationToAttributeRector;

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class TestWithAnnotationToAttributeRectorTest extends AbstractRectorTestCase
{
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\PHPUnit\AnnotationsToAttributes\Rector\ClassMethod\TestWithAnnotationToAttributeRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/../../../../../../config/config.php');

$rectorConfig->rule(TestWithAnnotationToAttributeRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

declare(strict_types=1);

namespace Rector\PHPUnit\AnnotationsToAttributes\Rector\ClassMethod;

use Nette\Utils\Json;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTagRemover;
use Rector\Core\Rector\AbstractRector;
use Rector\PhpAttribute\NodeFactory\PhpAttributeGroupFactory;
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @changelog https://docs.phpunit.de/en/10.0/annotations.html#testwith
* @changelog https://docs.phpunit.de/en/10.2/attributes.html#testwith
*
* @see \Rector\PHPUnit\Tests\AnnotationsToAttributes\Rector\ClassMethod\TestWithAnnotationToAttributeRector\TestWithAnnotationToAttributeRectorTest
*/
final class TestWithAnnotationToAttributeRector extends AbstractRector
{
public function __construct(
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
private readonly PhpAttributeGroupFactory $phpAttributeGroupFactory,
private readonly PhpDocTagRemover $phpDocTagRemover,
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Change @testWith() annotation to #[TestWith] attribute',
[
new CodeSample(
<<<'CODE_SAMPLE'
use PHPUnit\Framework\TestCase;
final class SomeFixture extends TestCase
{
/**
* @testWith ["foo"]
* ["bar"]
*/
public function test(): void
{
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\TestWith;
final class SomeFixture extends TestCase
{
#[TestWith(['foo'])]
#[TestWith(['bar'])]
public function test(): void
{
}
}
CODE_SAMPLE
),
]
);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}

/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->testsNodeAnalyzer->isTestClassMethod($node)) {
return null;
}

$phpDocInfo = $this->phpDocInfoFactory->createFromNode($node);

$testWithPhpDocTagNodes = $phpDocInfo->getTagsByName('testWith');
if ($testWithPhpDocTagNodes === []) {
return null;
}

$attributeGroups = [];

foreach ($testWithPhpDocTagNodes as $testWithPhpDocTagNode) {
/** @var PhpDocTagNode $testWithPhpDocTagNode */
if (! $testWithPhpDocTagNode->value instanceof GenericTagValueNode) {
// not supported yet
continue;
}

// test from doc blocks
$this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $testWithPhpDocTagNode);

$genericTagValueNode = $testWithPhpDocTagNode->value;
$testWithItems = explode("\n", trim($genericTagValueNode->value));

foreach ($testWithItems as $testWithItem) {
$jsonArray = Json::decode(trim($testWithItem));
$attributeGroups[] = $this->phpAttributeGroupFactory->createFromClassWithItems('PHPUnit\Framework\Attributes\TestWith', [$jsonArray]);
}
}

$node->attrGroups = array_merge($node->attrGroups, $attributeGroups);

return $node;
}
}

0 comments on commit f8d95a7

Please sign in to comment.