From eb0b69aa213ec7925264453770090ca4ca4bacaa Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 5 Nov 2024 23:55:54 +0100 Subject: [PATCH] [CodeQuality] Add SingleMockPropertyTypeRector (#401) --- composer.json | 2 +- config/sets/phpunit-code-quality.php | 2 + .../Fixture/skip_native_type.php.inc | 12 ++ .../Fixture/skip_sole_type.php.inc | 12 ++ .../Fixture/union_type_mock.php.inc | 29 +++++ .../SingleMockPropertyTypeRectorTest.php | 28 +++++ .../Source/AnyBook.php | 8 ++ .../config/configured_rule.php | 9 ++ .../Class_/SingleMockPropertyTypeRector.php | 112 ++++++++++++++++++ 9 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Fixture/skip_native_type.php.inc create mode 100644 rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Fixture/skip_sole_type.php.inc create mode 100644 rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Fixture/union_type_mock.php.inc create mode 100644 rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/SingleMockPropertyTypeRectorTest.php create mode 100644 rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Source/AnyBook.php create mode 100644 rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/config/configured_rule.php create mode 100644 rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php diff --git a/composer.json b/composer.json index 63c6cadc..53306108 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "symplify/easy-coding-standard": "^12.3", "phpstan/extension-installer": "^1.4", "phpstan/phpstan-webmozart-assert": "^1.2", - "symplify/vendor-patches": "^11.2", + "symplify/vendor-patches": "^11.3", "tracy/tracy": "^2.10", "tomasvotruba/class-leak": "^1.0", "rector/type-perfect": "^1.0", diff --git a/config/sets/phpunit-code-quality.php b/config/sets/phpunit-code-quality.php index 983fac18..eb5608fe 100644 --- a/config/sets/phpunit-code-quality.php +++ b/config/sets/phpunit-code-quality.php @@ -6,6 +6,7 @@ use Rector\PHPUnit\CodeQuality\Rector\Class_\ConstructClassMethodToSetUpTestCaseRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\NarrowUnusedSetUpDefinedPropertyRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector; +use Rector\PHPUnit\CodeQuality\Rector\Class_\SingleMockPropertyTypeRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\TestWithToDataProviderRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; use Rector\PHPUnit\CodeQuality\Rector\ClassMethod\DataProviderArrayItemsNewLinedRector; @@ -84,5 +85,6 @@ * @see https://davegebler.com/post/php/better-php-unit-testing-avoiding-mocks */ RemoveExpectAnyFromMockRector::class, + SingleMockPropertyTypeRector::class, ]); }; diff --git a/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Fixture/skip_native_type.php.inc b/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Fixture/skip_native_type.php.inc new file mode 100644 index 00000000..9a686c3d --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Fixture/skip_native_type.php.inc @@ -0,0 +1,12 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/SingleMockPropertyTypeRectorTest.php b/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/SingleMockPropertyTypeRectorTest.php new file mode 100644 index 00000000..ac557b68 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/SingleMockPropertyTypeRectorTest.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/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Source/AnyBook.php b/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Source/AnyBook.php new file mode 100644 index 00000000..ca5ddd77 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector/Source/AnyBook.php @@ -0,0 +1,8 @@ +withRules([SingleMockPropertyTypeRector::class]); diff --git a/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php b/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php new file mode 100644 index 00000000..ff63e4da --- /dev/null +++ b/rules/CodeQuality/Rector/Class_/SingleMockPropertyTypeRector.php @@ -0,0 +1,112 @@ +someEntityMock = $this->createMock(SimpleObject::class); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\MockObject\MockObject; + +final class MockingEntity extends TestCase +{ + private MockObject $someEntityMock; + + protected function setUp(): void + { + $this->someEntityMock = $this->createMock(SimpleObject::class); + } +} +CODE_SAMPLE + ), + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Class_ + { + if (! $this->testsNodeAnalyzer->isInTestClass($node)) { + return null; + } + + $hasChanged = false; + + foreach ($node->getProperties() as $property) { + if (! $property->type instanceof IntersectionType && ! $property->type instanceof UnionType) { + continue; + } + + $complexType = $property->type; + if (count($complexType->types) !== 2) { + continue; + } + + foreach ($complexType->types as $intersectionType) { + if ($this->isName($intersectionType, MockObject::class)) { + $property->type = $intersectionType; + $hasChanged = true; + + break; + } + } + } + + if (! $hasChanged) { + return null; + } + + return $node; + } +}