Skip to content

Commit

Permalink
feat: add support for covers attributes (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
simPod authored Mar 13, 2023
1 parent fc78501 commit b5fa1c2
Show file tree
Hide file tree
Showing 13 changed files with 71 additions and 19 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ Consider src namespace `Ns` and test namespace `Ns/Tests` then for test `Ns/Test
You can use `@covers` or `@coversDefaultClass` annotations to link test with tested class.
Use `@coversNothing` annotation to skip this check.

`#[CoversNothing]` and `#[CoversClass]` attributes are supported.

Don't forget to enable `"forceCoversAnnotation="true"` in phpunit config file.

```php
Expand Down
6 changes: 6 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$className of attribute class PHPUnit\\\\Framework\\\\Attributes\\\\CoversClass constructor expects class\\-string, string given\\.$#"
count: 2
path: tests/TestCheck/Fixtures/EveryTestHasSameNamespaceAsCoveredClass/tests/IgnoreMultipleCoversTest.php
3 changes: 3 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ parameters:
- %currentWorkingDirectory%/tests
ignoreErrors:
- "~Call to static method PHPUnit\\\\Framework\\\\Assert::assertTrue\\(\\) with true will always evaluate to true~"

includes:
- phpstan-baseline.neon
21 changes: 21 additions & 0 deletions src/TestCheck/EveryTestHasGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Cdn77\TestUtils\TestCheck;

use Cdn77\EntityFqnExtractor\ClassExtractor;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

Expand All @@ -25,6 +26,26 @@ public function run(TestCase $testCaseContext): void
{
foreach ($this->filePathNames as $filePathName) {
$classReflection = new ReflectionClass(ClassExtractor::get($filePathName));
if ($classReflection->isAbstract()) {
continue;
}

$groupAttributes = $classReflection->getAttributes(Group::class);
foreach ($groupAttributes as $groupAttribute) {
$testCaseContext::assertContains(
$groupAttribute->getArguments()[0],
$this->allowedGroups,
sprintf(
'Test "%s" has invalid @group annotation "%s"',
$classReflection->getName(),
$groupAttribute->getArguments()[0],
),
);
}

if ($groupAttributes !== []) {
continue;
}

$this->validateDocComment($testCaseContext, $classReflection);
}
Expand Down
17 changes: 12 additions & 5 deletions src/TestCheck/EveryTestHasSameNamespaceAsCoveredClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
namespace Cdn77\TestUtils\TestCheck;

use Cdn77\EntityFqnExtractor\ClassExtractor;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

Expand Down Expand Up @@ -38,22 +40,27 @@ public function run(TestCase $testCaseContext): void
foreach ($this->filePathNames as $file) {
$classReflection = new ReflectionClass(ClassExtractor::get($file));

$attributesCoversClass = $classReflection->getAttributes(CoversClass::class);
$attributesCoversNothing = $classReflection->getAttributes(CoversNothing::class);

$docComment = $classReflection->getDocComment();
if ($docComment === false) {
$docComment = '';
}

$matchesCovers = preg_match_all(self::PatternCovers, $docComment, $coversMatches) > 0;
$matchesCoversNothing = preg_match(self::PatternCoversNothing, $docComment) === 1;
$hasCovers = preg_match_all(self::PatternCovers, $docComment, $coversMatches) > 0
|| $attributesCoversClass !== [];
$hasCoversNothing = preg_match(self::PatternCoversNothing, $docComment) === 1
|| $attributesCoversNothing !== [];

if ($matchesCovers && $matchesCoversNothing) {
if ($hasCovers && $hasCoversNothing) {
$testCaseContext::fail(sprintf(
'Test file "%s" contains both @covers and @coversNothing annotations.',
'Specifying CoversClass and CoversNothing attributes at the same time makes no sense (in "%s").',
$file,
));
}

if ($matchesCoversNothing || $matchesCovers) {
if ($hasCoversNothing || $hasCovers) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static function providerFail(): Generator
{
yield [
'CoversAndCoversNothingTest.php',
'contains both @covers and @coversNothing annotations',
'Specifying CoversClass and CoversNothing attributes at the same time',
];

yield [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

namespace Cdn77\TestUtils\Tests\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass;

/** @covers \Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass\SameNamespace */
use Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass\SameNamespace;
use PHPUnit\Framework\Attributes\CoversClass;

#[CoversClass(SameNamespace::class)]
final class CoveredClassWithSomeWhitespaceTest
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

namespace Cdn77\TestUtils\Tests\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass;

/**
* @coversNothing
* @covers \stdClass
*/
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversNothing;
use stdClass;

#[CoversClass(stdClass::class)]
#[CoversNothing()]
final class CoversAndCoversNothingTest
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Cdn77\TestUtils\Tests\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass;

/** @coversNothing */
use PHPUnit\Framework\Attributes\CoversNothing;

#[CoversNothing]
final class CoversNothingTest
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace Cdn77\TestUtils\Tests\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass;

/**
* @covers Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsTestedClass\A
* @covers Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsTestedClass\B
*/
use PHPUnit\Framework\Attributes\CoversClass;

#[CoversClass('\Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsTestedClass\A')]
#[CoversClass('\Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsTestedClass\B')]
final class IgnoreMultipleCoversTest
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Cdn77\TestUtils\Tests\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass;

/** @covers Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass\SameNamespace */
use PHPUnit\Framework\Attributes\CoversClass;

#[CoversClass('\Cdn77\TestUtils\Tests\TestCheck\Fixtures\EveryTestHasSameNamespaceAsCoveredClass\SameNamespace')]
final class SameNamespaceAsLinkedCoveredClassTest
{
}
4 changes: 3 additions & 1 deletion tests/TestCheck/Fixtures/WithGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Cdn77\TestUtils\Tests\TestCheck\Fixtures;

/** @group unit */
use PHPUnit\Framework\Attributes\Group;

#[Group('unit')]
final class WithGroup
{
}
4 changes: 3 additions & 1 deletion tests/TestCheck/Fixtures/WithUnlistedGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Cdn77\TestUtils\Tests\TestCheck\Fixtures;

/** @group Eheu, raptus advena! */
use PHPUnit\Framework\Attributes\Group;

#[Group('Eheu, raptus advena!')]
final class WithUnlistedGroup
{
}

0 comments on commit b5fa1c2

Please sign in to comment.