Skip to content

Commit

Permalink
ADD implementation for TestTag on a class
Browse files Browse the repository at this point in the history
  • Loading branch information
DaveLiddament committed Aug 12, 2024
1 parent 6c5c145 commit 68a2e82
Show file tree
Hide file tree
Showing 13 changed files with 372 additions and 5 deletions.
25 changes: 20 additions & 5 deletions src/Rules/AbstractTestTagRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,40 @@ protected function getErrorOrNull(
string $class,
string $methodName,
): ?RuleError {
$callingClass = $scope->getClassReflection()?->getName();

$classReflection = $this->reflectionProvider->getClass($class);
$className = $classReflection->getName();
$nativeReflection = $classReflection->getNativeReflection();

$fullMethodName = "{$className}::{$methodName}";

if ($this->cache->hasEntry($className)) {
$isTestTagOnClass = $this->cache->getEntry($className);
} else {
$isTestTagOnClass = count($nativeReflection->getAttributes(TestTag::class)) > 0;
$this->cache->addEntry($className, $isTestTagOnClass);
}

if ($this->cache->hasEntry($fullMethodName)) {
$isTestTag = $this->cache->getEntry($fullMethodName);
$isTestTagOnMethod = $this->cache->getEntry($fullMethodName);
} else {
if ($nativeReflection->hasMethod($methodName)) {
$methodReflection = $nativeReflection->getMethod($methodName);
$isTestTag = count($methodReflection->getAttributes(TestTag::class)) > 0;
$isTestTagOnMethod = count($methodReflection->getAttributes(TestTag::class)) > 0;
} else {
$isTestTag = false;
$isTestTagOnMethod = false;
}
$this->cache->addEntry($fullMethodName, $isTestTag);
$this->cache->addEntry($fullMethodName, $isTestTagOnMethod);
}

$hasTestTag = $isTestTagOnClass || $isTestTagOnMethod;

if (!$hasTestTag) {
return null;
}

if (!$isTestTag) {
if ($isTestTagOnClass && ($className === $callingClass)) {
return null;
}

Expand Down
33 changes: 33 additions & 0 deletions tests/Rules/TestTagClassOnConstructorIngoredOnTestClassTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace DaveLiddament\PhpstanPhpLanguageExtensions\Tests\Rules;

use DaveLiddament\PhpstanPhpLanguageExtensions\Config\TestConfig;
use DaveLiddament\PhpstanPhpLanguageExtensions\Rules\TestTagNewCallRule;
use DaveLiddament\PhpstanRuleTestHelper\AbstractRuleTestCase;
use DaveLiddament\PhpstanRuleTestHelper\ErrorMessageFormatter;
use PHPStan\Rules\Rule;

/** @extends AbstractRuleTestCase<TestTagNewCallRule> */
class TestTagClassOnConstructorIngoredOnTestClassTest extends AbstractRuleTestCase
{
protected function getRule(): Rule
{
return new TestTagNewCallRule(
$this->createReflectionProvider(),
new TestConfig(TestConfig::CLASS_NAME),
);
}

public function testMethodCall(): void
{
$this->assertIssuesReported(__DIR__.'/data/testTag/testTagClassOnConstructorIgnoredInTestClass.php');
}

protected function getErrorFormatter(): ErrorMessageFormatter|string
{
return 'TestTagClassOnConstructorIgnoredOnTestClass\Person::__construct is a test tag and can only be called from test code';
}
}
33 changes: 33 additions & 0 deletions tests/Rules/TestTagClassOnConstructorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace DaveLiddament\PhpstanPhpLanguageExtensions\Tests\Rules;

use DaveLiddament\PhpstanPhpLanguageExtensions\Config\TestConfig;
use DaveLiddament\PhpstanPhpLanguageExtensions\Rules\TestTagNewCallRule;
use DaveLiddament\PhpstanRuleTestHelper\AbstractRuleTestCase;
use DaveLiddament\PhpstanRuleTestHelper\ErrorMessageFormatter;
use PHPStan\Rules\Rule;

/** @extends AbstractRuleTestCase<TestTagNewCallRule> */
class TestTagClassOnConstructorTest extends AbstractRuleTestCase
{
protected function getRule(): Rule
{
return new TestTagNewCallRule(
$this->createReflectionProvider(),
new TestConfig(TestConfig::CLASS_NAME),
);
}

public function testMethodCall(): void
{
$this->assertIssuesReported(__DIR__.'/data/testTag/testTagClassOnConstructor.php');
}

protected function getErrorFormatter(): ErrorMessageFormatter|string
{
return 'TestTagClassOnConstructor\Person::__construct is a test tag and can only be called from test code';
}
}
29 changes: 29 additions & 0 deletions tests/Rules/TestTagClassOnMethodIgnoredOnTestClassTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace DaveLiddament\PhpstanPhpLanguageExtensions\Tests\Rules;

use DaveLiddament\PhpstanPhpLanguageExtensions\Config\TestConfig;
use DaveLiddament\PhpstanPhpLanguageExtensions\Rules\TestTagMethodCallRule;
use DaveLiddament\PhpstanRuleTestHelper\AbstractRuleTestCase;
use PHPStan\Rules\Rule;

/** @extends AbstractRuleTestCase<TestTagMethodCallRule> */
class TestTagClassOnMethodIgnoredOnTestClassTest extends AbstractRuleTestCase
{
protected function getRule(): Rule
{
return new TestTagMethodCallRule(
$this->createReflectionProvider(),
new TestConfig(TestConfig::CLASS_NAME),
);
}

public function testMethodCall(): void
{
$this->assertIssuesReported(
__DIR__.'/data/testTag/testTagClassOnMethodIgnoredInTestClass.php',
);
}
}
33 changes: 33 additions & 0 deletions tests/Rules/TestTagClassOnMethodTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace DaveLiddament\PhpstanPhpLanguageExtensions\Tests\Rules;

use DaveLiddament\PhpstanPhpLanguageExtensions\Config\TestConfig;
use DaveLiddament\PhpstanPhpLanguageExtensions\Rules\TestTagMethodCallRule;
use DaveLiddament\PhpstanRuleTestHelper\AbstractRuleTestCase;
use DaveLiddament\PhpstanRuleTestHelper\ErrorMessageFormatter;
use PHPStan\Rules\Rule;

/** @extends AbstractRuleTestCase<TestTagMethodCallRule> */
class TestTagClassOnMethodTest extends AbstractRuleTestCase
{
protected function getRule(): Rule
{
return new TestTagMethodCallRule(
$this->createReflectionProvider(),
new TestConfig(TestConfig::CLASS_NAME),
);
}

public function testMethodCall(): void
{
$this->assertIssuesReported(__DIR__.'/data/testTag/testTagClassOnMethod.php');
}

protected function getErrorFormatter(): ErrorMessageFormatter|string
{
return 'TestTagClassOnMethod\Person::updateName is a test tag and can only be called from test code';
}
}
27 changes: 27 additions & 0 deletions tests/Rules/TestTagClassOnStaticIgnoredOnTestClassTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace DaveLiddament\PhpstanPhpLanguageExtensions\Tests\Rules;

use DaveLiddament\PhpstanPhpLanguageExtensions\Config\TestConfig;
use DaveLiddament\PhpstanPhpLanguageExtensions\Rules\TestTagStaticCallRule;
use DaveLiddament\PhpstanRuleTestHelper\AbstractRuleTestCase;
use PHPStan\Rules\Rule;

/** @extends AbstractRuleTestCase<TestTagStaticCallRule> */
class TestTagClassOnStaticIgnoredOnTestClassTest extends AbstractRuleTestCase
{
protected function getRule(): Rule
{
return new TestTagStaticCallRule(
$this->createReflectionProvider(),
new TestConfig(TestConfig::CLASS_NAME),
);
}

public function testMethodCall(): void
{
$this->assertIssuesReported(__DIR__.'/data/testTag/testTagClassOnStaticMethodIgnoredInTestClass.php');
}
}
32 changes: 32 additions & 0 deletions tests/Rules/TestTagClassOnStaticTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace DaveLiddament\PhpstanPhpLanguageExtensions\Tests\Rules;

use DaveLiddament\PhpstanPhpLanguageExtensions\Config\TestConfig;
use DaveLiddament\PhpstanPhpLanguageExtensions\Rules\TestTagStaticCallRule;
use DaveLiddament\PhpstanRuleTestHelper\AbstractRuleTestCase;
use PHPStan\Rules\Rule;

/** @extends AbstractRuleTestCase<TestTagStaticCallRule> */
final class TestTagClassOnStaticTest extends AbstractRuleTestCase
{
protected function getRule(): Rule
{
return new TestTagStaticCallRule(
$this->createReflectionProvider(),
new TestConfig(TestConfig::CLASS_NAME),
);
}

public function testMethodCall(): void
{
$this->assertIssuesReported(__DIR__.'/data/testTag/testTagClassOnStaticMethod.php');
}

protected function getErrorFormatter(): string
{
return 'TestTagClassOnStaticMethod\Person::updateName is a test tag and can only be called from test code';
}
}
31 changes: 31 additions & 0 deletions tests/Rules/data/testTag/testTagClassOnConstructor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace TestTagClassOnConstructor;

use DaveLiddament\PhpLanguageExtensions\TestTag;

#[TestTag]
class Person
{
public function __construct()
{
}

public static function create(): Person
{
return new Person(); // OK - whole class is marked with TestTag, so OK to call methods within it.
}

public static function createSelf(): self
{
return new self(); // OK - whole class is marked with TestTag, so OK to call methods within it.
}
}

class AnotherClass
{
public function buildPerson(): Person
{
return new Person(); // ERROR
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace TestTagClassOnConstructorIgnoredInTestClass;

use DaveLiddament\PhpLanguageExtensions\TestTag;

#[TestTag]
class Person
{
public function __construct()
{
}
}

class PersonTest
{
public function buildPerson(): Person
{
return new Person(); // OK TetTag called from a test class
}
}
32 changes: 32 additions & 0 deletions tests/Rules/data/testTag/testTagClassOnMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace TestTagClassOnMethod;

use DaveLiddament\PhpLanguageExtensions\TestTag;

#[TestTag]
class Person
{
public function updateName(): void
{
}

public function update(): void
{
$this->updateName(); // OK - whole class is marked with TestTag, so OK to call methods within it.
}
}

class Updater
{
public function updater(Person $person): void
{
$person->updateName(); // ERROR
}
}

$person = new Person();
$person->updateName(); // ERROR

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace TestTagClassOnMethodIgnoredInTestClass;

use DaveLiddament\PhpLanguageExtensions\TestTag;

#[TestTag]
class Person
{
public function updateName(): void
{
}
}

class PersonTest
{
public function updater(Person $person): void
{
$person->updateName(); // OK - Called from Test class
}
}


34 changes: 34 additions & 0 deletions tests/Rules/data/testTag/testTagClassOnStaticMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace TestTagClassOnStaticMethod;


use DaveLiddament\PhpLanguageExtensions\TestTag;

#[TestTag]
class Person
{
public static function updateName(): void
{
}

public static function update(): void
{
Person::updateName(); // OK - whole class is marked with TestTag, so OK to call methods within it.
}

public static function updateSelf(): void
{
self::updateName(); // OK - whole class is marked with TestTag, so OK to call methods within it.
}
}

class Updater
{
public function updater(): void
{
Person::updateName(); // ERROR
}
}

Person::updateName(); // ERROR
Loading

0 comments on commit 68a2e82

Please sign in to comment.