From 0fcb26efebd916444e6cbf803a6a84b17d48eaf4 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 5 May 2025 18:13:56 +0200 Subject: [PATCH 1/4] [phpunit 10] Add ParentTestClassConstructorRector --- config/sets/phpunit100.php | 2 + .../Fixture/mocking_helper.php.inc | 27 +++++ .../Fixture/skip_already_added.php.inc | 13 +++ .../ParentTestClassConstructorRectorTest.php | 28 ++++++ .../config/configured_rule.php | 10 ++ .../ParentTestClassConstructorRector.php | 99 +++++++++++++++++++ 6 files changed, 179 insertions(+) create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/mocking_helper.php.inc create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_already_added.php.inc create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/ParentTestClassConstructorRectorTest.php create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/config/configured_rule.php create mode 100644 rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php diff --git a/config/sets/phpunit100.php b/config/sets/phpunit100.php index c5417ad0..eb9045c4 100644 --- a/config/sets/phpunit100.php +++ b/config/sets/phpunit100.php @@ -4,6 +4,7 @@ use Rector\Config\RectorConfig; use Rector\PHPUnit\PHPUnit100\Rector\Class_\AddProphecyTraitRector; +use Rector\PHPUnit\PHPUnit100\Rector\Class_\ParentTestClassConstructorRector; use Rector\PHPUnit\PHPUnit100\Rector\Class_\PublicDataProviderClassMethodRector; use Rector\PHPUnit\PHPUnit100\Rector\Class_\StaticDataProviderClassMethodRector; use Rector\PHPUnit\PHPUnit100\Rector\MethodCall\PropertyExistsWithoutAssertRector; @@ -23,6 +24,7 @@ WithConsecutiveRector::class, RemoveSetMethodsMethodCallRector::class, PropertyExistsWithoutAssertRector::class, + ParentTestClassConstructorRector::class, ]); $rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [ diff --git a/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/mocking_helper.php.inc b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/mocking_helper.php.inc new file mode 100644 index 00000000..e1cff0cf --- /dev/null +++ b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/mocking_helper.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_already_added.php.inc b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_already_added.php.inc new file mode 100644 index 00000000..e6907dc2 --- /dev/null +++ b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_already_added.php.inc @@ -0,0 +1,13 @@ +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/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/config/configured_rule.php b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/config/configured_rule.php new file mode 100644 index 00000000..ef03034e --- /dev/null +++ b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(ParentTestClassConstructorRector::class); +}; diff --git a/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php b/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php new file mode 100644 index 00000000..488f8dbf --- /dev/null +++ b/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php @@ -0,0 +1,99 @@ +> + */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + if (! $this->testsNodeAnalyzer->isInTestClass($node)) { + return null; + } + + // it already has a constructor, skip as it might require specific tweaking + if ($node->getMethod(MethodName::CONSTRUCT)) { + return null; + } + + $constructorClassMethod = new ClassMethod(MethodName::CONSTRUCT); + $constructorClassMethod->flags |= Modifiers::PUBLIC; + $constructorClassMethod->stmts[] = new Expression($this->createParentConstructorCall()); + + $node->stmts = array_merge([$constructorClassMethod], $node->stmts); + + return $node; + } + + private function createParentConstructorCall(): StaticCall + { + $staticClassConstFetch = new ClassConstFetch(new Name('static'), 'class'); + + return new StaticCall(new Name('parent'), MethodName::CONSTRUCT, [new Arg($staticClassConstFetch)]); + } +} From b71925f3fa5eb53e75443ae45d065fe4261f3d7a Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 5 May 2025 18:40:02 +0200 Subject: [PATCH 2/4] skip test case and test classes as handled by PHPUnit --- .../Fixture/skip_in_case_of_test.php.inc | 9 +++++++ .../ParentTestClassConstructorRector.php | 24 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_in_case_of_test.php.inc diff --git a/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_in_case_of_test.php.inc b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_in_case_of_test.php.inc new file mode 100644 index 00000000..930ae207 --- /dev/null +++ b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_in_case_of_test.php.inc @@ -0,0 +1,9 @@ +shouldSkipClass($node)) { + return null; + } + // it already has a constructor, skip as it might require specific tweaking if ($node->getMethod(MethodName::CONSTRUCT)) { return null; @@ -96,4 +100,24 @@ private function createParentConstructorCall(): StaticCall return new StaticCall(new Name('parent'), MethodName::CONSTRUCT, [new Arg($staticClassConstFetch)]); } + + private function shouldSkipClass(Class_ $class): bool + { + if ($class->isAbstract()) { + return true; + } + + if ($class->isAnonymous()) { + return true; + } + + $className = $this->getName($class); + + // loaded automatically by PHPUnit + if (str_ends_with($className, 'Test')) { + return true; + } + + return str_ends_with($className, 'TestCase'); + } } From 132d17c3dc3422c151c4194789cb5ed8d2102acb Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 5 May 2025 18:40:38 +0200 Subject: [PATCH 3/4] skip abstract classes and test cases --- .../Fixture/skip_abstract_classes.php.inc | 9 +++++++++ .../Fixture/skip_in_case_of_test_case.php.inc | 9 +++++++++ .../Rector/Class_/ParentTestClassConstructorRector.php | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_abstract_classes.php.inc create mode 100644 rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_in_case_of_test_case.php.inc diff --git a/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_abstract_classes.php.inc b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_abstract_classes.php.inc new file mode 100644 index 00000000..fd52e97c --- /dev/null +++ b/rules-tests/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector/Fixture/skip_abstract_classes.php.inc @@ -0,0 +1,9 @@ + Date: Mon, 5 May 2025 18:41:58 +0200 Subject: [PATCH 4/4] note --- .../Rector/Class_/ParentTestClassConstructorRector.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php b/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php index 09556cdb..528e727a 100644 --- a/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php +++ b/rules/PHPUnit100/Rector/Class_/ParentTestClassConstructorRector.php @@ -20,6 +20,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** + * @see https://github.com/sebastianbergmann/phpunit/issues/3975 * @see https://github.com/sebastianbergmann/phpunit/commit/705874f1b867fd99865e43cb5eaea4e6d141582f * * @see \Rector\PHPUnit\Tests\PHPUnit100\Rector\Class_\ParentTestClassConstructorRector\ParentTestClassConstructorRectorTest @@ -114,10 +115,10 @@ private function shouldSkipClass(Class_ $class): bool $className = $this->getName($class); // loaded automatically by PHPUnit - if (str_ends_with($className, 'Test')) { + if (str_ends_with((string) $className, 'Test')) { return true; } - return str_ends_with($className, 'TestCase'); + return str_ends_with((string) $className, 'TestCase'); } }