123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- <?php
- declare(strict_types=1);
- /*
- * This file is part of PHP CS Fixer.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- * Dariusz Rumiński <dariusz.ruminski@gmail.com>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- namespace PhpCsFixer\Tests\AutoReview;
- use PhpCsFixer\Preg;
- use PhpCsFixer\Tests\TestCase;
- /**
- * @internal
- *
- * @coversNothing
- *
- * @group auto-review
- * @group covers-nothing
- */
- final class DuplicatedTestsTest extends TestCase
- {
- /**
- * @dataProvider \PhpCsFixer\Tests\AutoReview\ProjectCodeTest::provideTestClassCases
- *
- * @param class-string $className
- */
- public function testThatTestMethodsAreNotDuplicatedBasedOnContent(string $className): void
- {
- $alreadyFoundMethods = [];
- $duplicates = [];
- foreach (self::getMethodsForDuplicateCheck($className) as $method) {
- if (!str_starts_with($method->getName(), 'test')) {
- continue;
- }
- $startLine = (int) $method->getStartLine();
- $length = (int) $method->getEndLine() - $startLine;
- if (3 === $length) { // open and closing brace are included - this checks for single line methods
- continue;
- }
- /** @var list<string> $source */
- $source = file((string) $method->getFileName());
- $candidateContent = implode('', \array_slice($source, $startLine, $length));
- if (str_contains($candidateContent, '$this->doTest(')) {
- continue;
- }
- $foundInDuplicates = false;
- foreach ($alreadyFoundMethods as $methodKey => $methodContent) {
- if ($candidateContent === $methodContent) {
- $duplicates[] = \sprintf('%s is duplicate of %s', $methodKey, $method->getName());
- $foundInDuplicates = true;
- }
- }
- if (!$foundInDuplicates) {
- $alreadyFoundMethods[$method->getName()] = $candidateContent;
- }
- }
- self::assertSame(
- [],
- $duplicates,
- \sprintf(
- "Duplicated methods found in %s:\n - %s",
- $className,
- implode("\n - ", $duplicates)
- )
- );
- }
- /**
- * @dataProvider \PhpCsFixer\Tests\AutoReview\ProjectCodeTest::provideTestClassCases
- *
- * @param class-string $className
- */
- public function testThatTestMethodsAreNotDuplicatedBasedOnName(string $className): void
- {
- $alreadyFoundMethods = [];
- $duplicates = [];
- foreach (self::getMethodsForDuplicateCheck($className) as $method) {
- foreach ($alreadyFoundMethods as $alreadyFoundMethod) {
- if (!str_starts_with($method->getName(), $alreadyFoundMethod)) {
- continue;
- }
- $suffix = substr($method->getName(), \strlen($alreadyFoundMethod));
- if (!Preg::match('/^\d{2,}/', $suffix)) {
- continue;
- }
- $duplicates[] = \sprintf(
- 'Method "%s" must be shorter, call "%s".',
- $method->getName(),
- $alreadyFoundMethod
- );
- }
- $alreadyFoundMethods[] = $method->getName();
- }
- self::assertSame(
- [],
- $duplicates,
- \sprintf(
- "Duplicated methods found in %s:\n - %s",
- $className,
- implode("\n - ", $duplicates)
- )
- );
- }
- /**
- * @param class-string $className
- *
- * @return list<\ReflectionMethod>
- */
- private static function getMethodsForDuplicateCheck(string $className): array
- {
- static $methodsForDuplicateCheckCache = [];
- if (!isset($methodsForDuplicateCheckCache[$className])) {
- $class = new \ReflectionClass($className);
- $methodsForDuplicateCheck = array_filter(
- $class->getMethods(\ReflectionMethod::IS_PUBLIC),
- static fn (\ReflectionMethod $method) => str_starts_with($method->getName(), 'test')
- && $method->getDeclaringClass()->getName() === $className
- /*
- * Why 4?
- * Open and closing brace are included, this checks for:
- * - single line methods
- * - single line methods with configs
- */
- && 4 < (int) $method->getEndLine() - (int) $method->getStartLine()
- );
- usort(
- $methodsForDuplicateCheck,
- static fn (\ReflectionMethod $method1, \ReflectionMethod $method2) => $method1->getName() <=> $method2->getName(),
- );
- $methodsForDuplicateCheckCache[$className] = $methodsForDuplicateCheck;
- }
- return $methodsForDuplicateCheckCache[$className];
- }
- }
|