Browse Source

DX: check for duplicated test methods (#8124)

Kuba Werłos 7 months ago
parent
commit
2aa85eef15

+ 3 - 0
.github/workflows/sca.yml

@@ -74,6 +74,9 @@ jobs:
       - name: Check - trailing spaces
         run: ./dev-tools/check_trailing_spaces.sh
 
+      - name: Check - duplicate test methods
+        run: php ./dev-tools/check_duplicate_test_methods.php
+
       - name: Check - Composer's autoload
         run: composer dump-autoload --dry-run --optimize --strict-psr
 

+ 1 - 0
composer.json

@@ -127,6 +127,7 @@
         "self-check": [
             "./dev-tools/check_file_permissions.sh",
             "./dev-tools/check_trailing_spaces.sh",
+            "@php ./dev-tools/check_duplicate_test_methods.php",
             "@composer dump-autoload --dry-run --optimize --strict-psr",
             "@normalize",
             "@unused-deps",

+ 66 - 0
dev-tools/check_duplicate_test_methods.php

@@ -0,0 +1,66 @@
+#!/usr/bin/env php
+<?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.
+ */
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$testClassNames = array_filter(
+    array_keys(require __DIR__.'/../vendor/composer/autoload_classmap.php'),
+    static fn (string $className): bool => str_starts_with($className, 'PhpCsFixer\Tests\\')
+);
+
+if ([] === $testClassNames) {
+    echo 'Run: composer dump-autoload --optimize --working-dir=', realpath(__DIR__.'/..'), PHP_EOL;
+
+    exit(1);
+}
+
+$duplicatesFound = false;
+
+foreach ($testClassNames as $testClassName) {
+    $class = new ReflectionClass($testClassName);
+
+    $duplicates = [];
+    foreach ($class->getMethods() as $method) {
+        if (!str_starts_with($method->getName(), 'test')) {
+            continue;
+        }
+
+        $startLine = $method->getStartLine();
+        $length = $method->getEndLine() - $startLine;
+        if (3 === $length) { // open and closing brace are included - this checks for single line methods
+            continue;
+        }
+
+        $source = file($method->getFileName());
+        $content = implode('', array_slice($source, $startLine, $length));
+        if (str_contains($content, '$this->doTest(')) {
+            continue;
+        }
+
+        $found = false;
+        foreach ($duplicates as $name => $body) {
+            if ($content === $body) {
+                echo 'Duplicate in ', $testClassName, ': methods ', $name, ' and ', $method->getName(), PHP_EOL;
+                $duplicatesFound = true;
+                $found = true;
+            }
+        }
+        if (!$found) {
+            $duplicates[$method->getName()] = $content;
+        }
+    }
+}
+
+exit($duplicatesFound ? 1 : 0);

+ 12 - 12
tests/Linter/ProcessLinterProcessBuilderTest.php

@@ -33,12 +33,7 @@ final class ProcessLinterProcessBuilderTest extends TestCase
      */
     public function testPrepareCommandOnPhpOnLinuxOrMac(string $executable, string $file, string $expected): void
     {
-        $builder = new ProcessLinterProcessBuilder($executable);
-
-        self::assertSame(
-            $expected,
-            $builder->build($file)->getCommandLine()
-        );
+        $this->testPrepareCommand($executable, $file, $expected);
     }
 
     /**
@@ -58,12 +53,7 @@ final class ProcessLinterProcessBuilderTest extends TestCase
      */
     public function testPrepareCommandOnPhpOnWindows(string $executable, string $file, string $expected): void
     {
-        $builder = new ProcessLinterProcessBuilder($executable);
-
-        self::assertSame(
-            $expected,
-            $builder->build($file)->getCommandLine()
-        );
+        $this->testPrepareCommand($executable, $file, $expected);
     }
 
     /**
@@ -75,4 +65,14 @@ final class ProcessLinterProcessBuilderTest extends TestCase
 
         yield 'Windows-like' => ['C:\Program Files\php\php.exe', 'foo bar\baz.php', '"C:\Program Files\php\php.exe" -l "foo bar\baz.php"'];
     }
+
+    private function testPrepareCommand(string $executable, string $file, string $expected): void
+    {
+        $builder = new ProcessLinterProcessBuilder($executable);
+
+        self::assertSame(
+            $expected,
+            $builder->build($file)->getCommandLine()
+        );
+    }
 }

+ 2 - 2
tests/Tokenizer/Analyzer/Analysis/ArgumentAnalysisTest.php

@@ -67,7 +67,7 @@ final class ArgumentAnalysisTest extends TestCase
     public function testNoTypeFound(): void
     {
         $analysis = new ArgumentAnalysis('$name', 1, null, null);
-        self::assertFalse($analysis->hasDefault());
-        self::assertNull($analysis->getDefault());
+        self::assertFalse($analysis->hasTypeAnalysis());
+        self::assertNull($analysis->getTypeAnalysis());
     }
 }