diff --git a/config/sets/phpunit120.php b/config/sets/phpunit120.php index 5a1fc60b..66211939 100644 --- a/config/sets/phpunit120.php +++ b/config/sets/phpunit120.php @@ -3,8 +3,9 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\PHPUnit\PHPUnit120\Rector\Class_\AssertIsTypeMethodCallRector; use Rector\PHPUnit\PHPUnit120\Rector\Class_\RemoveOverrideFinalConstructTestCaseRector; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->rule(RemoveOverrideFinalConstructTestCaseRector::class); + $rectorConfig->rules([RemoveOverrideFinalConstructTestCaseRector::class, AssertIsTypeMethodCallRector::class]); }; diff --git a/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/AssertIsTypeMethodCallRectorTest.php b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/AssertIsTypeMethodCallRectorTest.php new file mode 100644 index 00000000..065b81c4 --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/AssertIsTypeMethodCallRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/Fixture/fixture.php.inc b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/Fixture/fixture.php.inc new file mode 100644 index 00000000..e27a9bab --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/Fixture/fixture.php.inc @@ -0,0 +1,61 @@ +assertThat([], $this->isType('array')); + $this->assertThat(true, $this->isType('bool')); + $this->assertThat(true, $this->isType('boolean')); + $this->assertThat(fn () => 0, $this->isType('callable')); + $this->assertThat(1.0, $this->isType('float')); + $this->assertThat(1.0, $this->isType('double')); + $this->assertThat(1, $this->isType('int')); + $this->assertThat(1, $this->isType('integer')); + $this->assertThat([], $this->isType('iterable')); + $this->assertThat(null, $this->isType('null')); + $this->assertThat(12, $this->isType('numeric')); + $this->assertThat(new \stdClass(), $this->isType('object')); + $this->assertThat(1.0, $this->isType('real')); + $this->assertThat($resource, $this->isType('resource')); + $this->assertThat($closedResource, $this->isType('resource (closed)')); + $this->assertThat('', $this->isType('scalar')); + $this->assertThat('', $this->isType('string')); + } +} +?> +----- +assertThat([], $this->isArray()); + $this->assertThat(true, $this->isBool()); + $this->assertThat(true, $this->isBool()); + $this->assertThat(fn () => 0, $this->isCallable()); + $this->assertThat(1.0, $this->isFloat()); + $this->assertThat(1.0, $this->isFloat()); + $this->assertThat(1, $this->isInt()); + $this->assertThat(1, $this->isInt()); + $this->assertThat([], $this->isIterable()); + $this->assertThat(null, $this->isNull()); + $this->assertThat(12, $this->isNumeric()); + $this->assertThat(new \stdClass(), $this->isObject()); + $this->assertThat(1.0, $this->isFloat()); + $this->assertThat($resource, $this->isResource()); + $this->assertThat($closedResource, $this->isClosedResource()); + $this->assertThat('', $this->isScalar()); + $this->assertThat('', $this->isString()); + } +} +?> diff --git a/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/Fixture/static_fixture.php.inc b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/Fixture/static_fixture.php.inc new file mode 100644 index 00000000..d4be198d --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/Fixture/static_fixture.php.inc @@ -0,0 +1,61 @@ +assertThat([], self::isType('array')); + $this->assertThat(true, self::isType('bool')); + $this->assertThat(true, self::isType('boolean')); + $this->assertThat(fn () => 0, self::isType('callable')); + $this->assertThat(1.0, self::isType('float')); + $this->assertThat(1.0, self::isType('double')); + $this->assertThat(1, self::isType('int')); + $this->assertThat(1, self::isType('integer')); + $this->assertThat([], self::isType('iterable')); + $this->assertThat(null, self::isType('null')); + $this->assertThat(12, self::isType('numeric')); + $this->assertThat(new \stdClass(), self::isType('object')); + $this->assertThat(1.0, self::isType('real')); + $this->assertThat($resource, self::isType('resource')); + $this->assertThat($closedResource, self::isType('resource (closed)')); + $this->assertThat('', self::isType('scalar')); + $this->assertThat('', self::isType('string')); + } +} +?> +----- +assertThat([], self::isArray()); + $this->assertThat(true, self::isBool()); + $this->assertThat(true, self::isBool()); + $this->assertThat(fn () => 0, self::isCallable()); + $this->assertThat(1.0, self::isFloat()); + $this->assertThat(1.0, self::isFloat()); + $this->assertThat(1, self::isInt()); + $this->assertThat(1, self::isInt()); + $this->assertThat([], self::isIterable()); + $this->assertThat(null, self::isNull()); + $this->assertThat(12, self::isNumeric()); + $this->assertThat(new \stdClass(), self::isObject()); + $this->assertThat(1.0, self::isFloat()); + $this->assertThat($resource, self::isResource()); + $this->assertThat($closedResource, self::isClosedResource()); + $this->assertThat('', self::isScalar()); + $this->assertThat('', self::isString()); + } +} +?> diff --git a/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/config/configured_rule.php b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/config/configured_rule.php new file mode 100644 index 00000000..9ab8439a --- /dev/null +++ b/rules-tests/PHPUnit120/Rector/MethodCall/AssertIsTypeMethodCallRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(AssertIsTypeMethodCallRector::class); +}; diff --git a/rules/PHPUnit120/Rector/Class_/AssertIsTypeMethodCallRector.php b/rules/PHPUnit120/Rector/Class_/AssertIsTypeMethodCallRector.php new file mode 100644 index 00000000..76e24571 --- /dev/null +++ b/rules/PHPUnit120/Rector/Class_/AssertIsTypeMethodCallRector.php @@ -0,0 +1,127 @@ + 'isArray', + 'bool' => 'isBool', + 'boolean' => 'isBool', + 'callable' => 'isCallable', + 'double' => 'isFloat', + 'float' => 'isFloat', + 'integer' => 'isInt', + 'int' => 'isInt', + 'iterable' => 'isIterable', + 'null' => 'isNull', + 'numeric' => 'isNumeric', + 'object' => 'isObject', + 'real' => 'isFloat', + 'resource' => 'isResource', + 'resource (closed)' => 'isClosedResource', + 'scalar' => 'isScalar', + 'string' => 'isString', + ]; + + public function __construct( + private readonly ValueResolver $valueResolver, + private readonly TestsNodeAnalyzer $testsNodeAnalyzer, + ) { + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Replaces `Assert::isType()` calls with type-specific `Assert::is*()` calls', + [ + new CodeSample( + <<<'CODE_SAMPLE' + use PHPUnit\Framework\TestCase; + + final class SomeClass extends TestCase + { + public function testMethod(): void + { + $this->assertThat([], $this->isType('array')); + } + } + CODE_SAMPLE + , + <<<'CODE_SAMPLE' + use PHPUnit\Framework\TestCase; + + final class SomeClass extends TestCase + { + public function testMethod(): void + { + $this->assertThat([], $this->isArray()); + } + } + CODE_SAMPLE + , + ), + ], + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [MethodCall::class, StaticCall::class]; + } + + /** + * @param MethodCall|StaticCall $node + */ + public function refactor(Node $node): Node|null + { + if ($node->isFirstClassCallable()) { + return null; + } + + if (! $this->testsNodeAnalyzer->isPHPUnitTestCaseCall($node) || ! $this->isName($node->name, 'isType')) { + return null; + } + + if (count($node->getArgs()) !== 1) { + return null; + } + + $arg = $node->getArg('type', 0); + if (! $arg instanceof Arg) { + return null; + } + + $argValue = $this->valueResolver->getValue($arg); + if (isset(self::IS_TYPE_VALUE_TO_METHOD[$argValue])) { + if ($node instanceof MethodCall) { + return new MethodCall($node->var, self::IS_TYPE_VALUE_TO_METHOD[$argValue]); + } + + return new StaticCall($node->class, self::IS_TYPE_VALUE_TO_METHOD[$argValue]); + + } + + return null; + } +}