diff --git a/.github/workflows/infection.yaml b/.github/workflows/infection.yaml index d84e28c..4920d9a 100644 --- a/.github/workflows/infection.yaml +++ b/.github/workflows/infection.yaml @@ -27,6 +27,6 @@ jobs: uses: "ramsey/composer-install@v1" - name: Run Infection - run: vendor/bin/roave-infection-static-analysis-plugin --min-msi=59 --min-covered-msi=93 --log-verbosity=none -s + run: vendor/bin/roave-infection-static-analysis-plugin --min-msi=59 --min-covered-msi=90 --log-verbosity=none -s env: INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }} diff --git a/composer.json b/composer.json index 9b697ea..d869395 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ }, "autoload-dev": { "psr-4": { - "Cdn77\\TestUtils\\Tests\\": "tests/" + "Cdn77\\TestUtils\\Tests\\": "tests/", + "Cdn77\\TestUtils\\Tests\\Tests\\TestCheck\\Fixtures\\EveryTestHasSameNamespaceAsTestedClass\\": "tests/TestCheck/Fixtures/EveryTestHasSameNamespaceAsTestedClass/tests" } }, "require": { diff --git a/src/TestCheck/EveryTestHasSameNamespaceAsTestedClass.php b/src/TestCheck/EveryTestHasSameNamespaceAsTestedClass.php index 7b6a2de..90a5e6a 100644 --- a/src/TestCheck/EveryTestHasSameNamespaceAsTestedClass.php +++ b/src/TestCheck/EveryTestHasSameNamespaceAsTestedClass.php @@ -12,20 +12,25 @@ use function Safe\preg_match; use function Safe\sprintf; use function Safe\substr; -use function str_replace; +use function strlen; +use function strpos; +use function substr_replace; use function trait_exists; final class EveryTestHasSameNamespaceAsTestedClass implements TestCheck { - private const PATTERN = '~\* @testedClass (?.+)\n~'; + private const PATTERN = '~\* @testedClass (?.+?)(?:\n| \*/)~'; /** @var iterable $filePathNames */ private iterable $filePathNames; + private string $testsNamespaceSuffix; + /** @param iterable $filePathNames */ - public function __construct(iterable $filePathNames) + public function __construct(iterable $filePathNames, string $testsNamespaceSuffix = 'Tests') { $this->filePathNames = $filePathNames; + $this->testsNamespaceSuffix = '\\' . $testsNamespaceSuffix . '\\'; } public function run(TestCase $testCaseContext) : void @@ -37,9 +42,7 @@ public function run(TestCase $testCaseContext) : void $docComment = $classReflection->getDocComment(); if ($docComment === false) { - $testCaseContext::fail( - sprintf('Test "%s" is missing phpdoc. See other tests for examples', $classReflection->getName()) - ); + $docComment = ''; } preg_match(self::PATTERN, $docComment, $targetClassMatches); @@ -50,7 +53,18 @@ public function run(TestCase $testCaseContext) : void $className = $classReflection->getName(); $classNameWithoutSuffix = substr($className, 0, -4); - $testedClassName = str_replace('\Tests\\', '\\', $classNameWithoutSuffix); + $pos = strpos($classNameWithoutSuffix, $this->testsNamespaceSuffix); + if ($pos === false) { + $testedClassName = $classNameWithoutSuffix; + } else { + $testedClassName = substr_replace( + $classNameWithoutSuffix, + '\\', + $pos, + strlen($this->testsNamespaceSuffix) + ); + } + if (class_exists($testedClassName) || trait_exists($testedClassName)) { continue; } diff --git a/tests/TestCheck/EveryTestHasSameNamespaceAsTestedClassTest.php b/tests/TestCheck/EveryTestHasSameNamespaceAsTestedClassTest.php new file mode 100644 index 0000000..6813790 --- /dev/null +++ b/tests/TestCheck/EveryTestHasSameNamespaceAsTestedClassTest.php @@ -0,0 +1,58 @@ +run($this); + } + + /** @return Generator> */ + public function providerSuccess() : Generator + { + yield ['SameNamespaceTest.php']; + yield ['SameNamespaceLinkedTest.php']; + yield ['NoLinkTest.php']; + } + + /** @dataProvider providerFail */ + public function testFail(string $filePath, string $error) : void + { + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage($error); + + $check = new EveryTestHasSameNamespaceAsTestedClass( + [__DIR__ . '/Fixtures/EveryTestHasSameNamespaceAsTestedClass/tests/' . $filePath], + 'Tests' + ); + $check->run($this); + } + + /** @return Generator> */ + public function providerFail() : Generator + { + yield [ + 'MissingAnnotationsTest.php', + 'is in the wrong namespace, has name different from tested class or is missing @testedClass annotation', + ]; + + yield [ + 'NonexistentLinkTest.php', + 'is pointing to an non-existing class', + ]; + } +} diff --git a/tests/TestCheck/Fixtures/EveryTestHasSameNamespaceAsTestedClass/SameNamespace.php b/tests/TestCheck/Fixtures/EveryTestHasSameNamespaceAsTestedClass/SameNamespace.php new file mode 100644 index 0000000..c45cb5c --- /dev/null +++ b/tests/TestCheck/Fixtures/EveryTestHasSameNamespaceAsTestedClass/SameNamespace.php @@ -0,0 +1,9 @@ +