diff --git a/src/Rule/Extractor/Declaration/PublicMethodNamedExtractor.php b/src/Rule/Extractor/Declaration/PublicMethodNamedExtractor.php index b04f7193..8719df58 100644 --- a/src/Rule/Extractor/Declaration/PublicMethodNamedExtractor.php +++ b/src/Rule/Extractor/Declaration/PublicMethodNamedExtractor.php @@ -25,25 +25,19 @@ protected function meetsDeclaration(Node $node, Scope $scope, array $params = [] $reflectionClass = $node->getClassReflection()->getNativeReflection(); $methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC); - $methodsWithoutConstructor = array_filter( + $methodsMeetingDeclaration = array_filter( $methods, - fn ($method) => $method->getName() !== '__construct' - ); - - foreach ($methodsWithoutConstructor as $method) { - if ($params['isRegex'] === true) { - if (preg_match($params['name'], $method->getName()) !== 1) { + function ($method) use ($params) { + if ($method->getName() === '__construct') { return false; } - continue; - } - - if ($method->getName() !== $params['name']) { - return false; + return $params['isRegex'] === true + ? preg_match($params['name'], $method->getName()) === 1 + : $method->getName() === $params['name']; } - } + ); - return true; + return count($methodsMeetingDeclaration) === 1; } } diff --git a/tests/fixtures/Special/ClassWithTwoSimilarlyNamedMethods.php b/tests/fixtures/Special/ClassWithTwoSimilarlyNamedMethods.php new file mode 100644 index 00000000..2008bce5 --- /dev/null +++ b/tests/fixtures/Special/ClassWithTwoSimilarlyNamedMethods.php @@ -0,0 +1,18 @@ + + * @internal + * @coversNothing + */ +class MoreThanOnePublicMethodNamedWithRegexTest extends RuleTestCase +{ + public const RULE_NAME = 'testFixtureClassShouldHaveOnlyOnePublicMethodNamed'; + + public function testRule(): void + { + // Should succeed as 'foo' is not named like 'ba*' + $this->analyse(['tests/fixtures/Special/ClassWithTwoUnrelatedNamedMethods.php'], []); + } + + protected function getRule(): Rule + { + $testParser = FakeTestParser::create( + self::RULE_NAME, + ClassWithTwoUnrelatedNamedMethods::class, + [new Classname(FixtureClass::class, false)], + [], + [], + ['name' => '/^ba[a-zA-Z0-9]+/', 'isRegex' => true] + ); + + return new HasOnlyOnePublicMethodNamedRule( + new StatementBuilderFactory($testParser), + new Configuration(false, true, false), + self::createReflectionProvider(), + self::getContainer()->getByType(FileTypeMapper::class) + ); + } +} diff --git a/tests/unit/rules/ShouldHaveOnlyOnePublicMethodNamed/SimilarlyNamedPublicMethodsNamedWithRegexTest.php b/tests/unit/rules/ShouldHaveOnlyOnePublicMethodNamed/SimilarlyNamedPublicMethodsNamedWithRegexTest.php new file mode 100644 index 00000000..ce95cf6c --- /dev/null +++ b/tests/unit/rules/ShouldHaveOnlyOnePublicMethodNamed/SimilarlyNamedPublicMethodsNamedWithRegexTest.php @@ -0,0 +1,50 @@ + + * @internal + * @coversNothing + */ +class SimilarlyNamedPublicMethodsNamedWithRegexTest extends RuleTestCase +{ + public const RULE_NAME = 'testFixtureClassShouldHaveOnlyOnePublicMethodNamed'; + + public function testRule(): void + { + $this->analyse(['tests/fixtures/Special/ClassWithTwoSimilarlyNamedMethods.php'], [ + [sprintf('%s should have only one public method named %s', ClassWithTwoSimilarlyNamedMethods::class, '/^example[a-zA-Z0-9]+/'), 7], + ]); + } + + protected function getRule(): Rule + { + $testParser = FakeTestParser::create( + self::RULE_NAME, + ShouldHaveOnlyOnePublicMethodNamed::class, + [new Classname(ClassWithTwoSimilarlyNamedMethods::class, false)], + [], + [], + ['name' => '/^example[a-zA-Z0-9]+/', 'isRegex' => true] + ); + + return new HasOnlyOnePublicMethodNamedRule( + new StatementBuilderFactory($testParser), + new Configuration(false, true, false), + self::createReflectionProvider(), + self::getContainer()->getByType(FileTypeMapper::class) + ); + } +}