Skip to content

Clean RuleTestCase #132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 6 additions & 181 deletions tests/src/RuleTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,26 @@

namespace Pepakriz\PHPStanExceptionRules;

use InvalidArgumentException;
use LogicException;
use Nette\Utils\Strings;
use PhpParser\PrettyPrinter\Standard;
use PHPStan\Analyser\Analyser;
use PHPStan\Analyser\Error;
use PHPStan\Analyser\FileAnalyser;
use PHPStan\Analyser\NodeScopeResolver;
use PHPStan\Analyser\TypeSpecifier;
use PHPStan\Broker\AnonymousClassNameHelper;
use PHPStan\Cache\Cache;
use PHPStan\Dependency\DependencyResolver;
use PHPStan\File\FileHelper;
use PHPStan\File\SimpleRelativePathHelper;
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
use PHPStan\PhpDoc\PhpDocNodeResolver;
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\PhpDoc\TypeNodeResolverExtension;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\Reflection\ReflectionProvider\DirectReflectionProviderProvider;
use PHPStan\Rules\Registry;
use PHPStan\Rules\Rule;
use PHPStan\Testing\TestCase;
use PHPStan\Type\FileTypeMapper;
use PHPStan\Type\MethodTypeSpecifyingExtension;
use PHPStan\Type\StaticMethodTypeSpecifyingExtension;
use function array_map;
use PHPStan\Testing\RuleTestCase as BaseRuleTestCase;
use function explode;
use function file_get_contents;
use function implode;
use function sprintf;
use function trim;

/**
* @template TRule of \PHPStan\Rules\Rule
* @extends BaseRuleTestCase<TRule>
*/
abstract class RuleTestCase extends TestCase
abstract class RuleTestCase extends BaseRuleTestCase
{

/**
* @var Analyser
*/
private $analyser;

/**
* @phpstan-return TRule
*/
abstract protected function getRule(): Rule;

protected function getTypeSpecifier(): TypeSpecifier
protected function analyseFile(string $file): void
{
return $this->createTypeSpecifier(
new Standard(),
$this->createBroker(),
$this->getMethodTypeSpecifyingExtensions(),
$this->getStaticMethodTypeSpecifyingExtensions()
);
$file = $this->getFileHelper()->normalizePath($file);
$this->analyse([$file], $this->parseExpectedErrors($file));
}

protected function createThrowsAnnotationReader(): ThrowsAnnotationReader
Expand All @@ -71,123 +33,6 @@ protected function createThrowsAnnotationReader(): ThrowsAnnotationReader
);
}

private function getAnalyser(): Analyser
{
if ($this->analyser === null) {
$registry = new Registry([$this->getRule()]);
$broker = $this->createBroker();
$printer = new Standard();

$currentWorkingDirectory = $this->getCurrentWorkingDirectory();
$fileHelper = new FileHelper($currentWorkingDirectory);
$relativePathHelper = new SimpleRelativePathHelper($currentWorkingDirectory);
$anonymousClassNameHelper = new AnonymousClassNameHelper($fileHelper, $relativePathHelper);

$typeSpecifier = $this->createTypeSpecifier(
$printer,
$broker,
$this->getMethodTypeSpecifyingExtensions(),
$this->getStaticMethodTypeSpecifyingExtensions()
);

$fileTypeMapper = new FileTypeMapper(
new DirectReflectionProviderProvider($broker),
$this->getParser(),
self::getContainer()->getByType(PhpDocStringResolver::class),
self::getContainer()->getByType(PhpDocNodeResolver::class),
$this->createMock(Cache::class),
$anonymousClassNameHelper
);
$phpDocInheritanceResolver = new PhpDocInheritanceResolver($fileTypeMapper);

$nodeScopeResolver = new NodeScopeResolver(
$broker,
self::getReflectors()[0],
$this->getClassReflectionExtensionRegistryProvider(),
$this->getParser(),
$fileTypeMapper,
$phpDocInheritanceResolver,
$fileHelper,
$typeSpecifier,
$this->shouldPolluteScopeWithLoopInitialAssignments(),
$this->shouldPolluteCatchScopeWithTryAssignments(),
$this->shouldPolluteScopeWithAlwaysIterableForeach(),
[],
[]
);

$fileAnalyser = new FileAnalyser(
$this->createScopeFactory($broker, $typeSpecifier),
$nodeScopeResolver,
$this->getParser(),
new DependencyResolver($broker),
$fileHelper,
$this->shouldReportUnmatchedIgnoredErrors()
);

$this->analyser = new Analyser($fileAnalyser, $registry, $nodeScopeResolver, 50);
}

return $this->analyser;
}

/**
* @return MethodTypeSpecifyingExtension[]
*/
protected function getMethodTypeSpecifyingExtensions(): array
{
return [];
}

/**
* @return StaticMethodTypeSpecifyingExtension[]
*/
protected function getStaticMethodTypeSpecifyingExtensions(): array
{
return [];
}

/**
* @return TypeNodeResolverExtension[]
*/
protected function getTypeNodeResolverExtensions(): array
{
return [];
}

public function analyse(string $file): void
{
$file = $this->getFileHelper()->normalizePath($file);
$expectedErrors = $this->parseExpectedErrors($file);
$actualErrors = $this->getAnalyser()->analyse([$file])->getUnorderedErrors();

$strictlyTypedSprintf = static function (int $line, string $message): string {
return sprintf('%02d: %s', $line, $message);
};

$expectedErrors = array_map(
static function (array $error) use ($strictlyTypedSprintf): string {
if (!isset($error[0])) {
throw new InvalidArgumentException('Missing expected error message.');
}
if (!isset($error[1])) {
throw new InvalidArgumentException('Missing expected file line.');
}
return $strictlyTypedSprintf($error[1], $error[0]);
},
$expectedErrors
);

$actualErrors = array_map(
static function (Error $error): string {
return sprintf('%02d: %s', $error->getLine(), $error->getMessage());
},
$actualErrors
);

self::assertSame(implode("\n", $expectedErrors), implode("\n", $actualErrors));
}

/**
* @return mixed[]
*/
Expand Down Expand Up @@ -217,24 +62,4 @@ private function parseExpectedErrors(string $file): array
return $expectedErrors;
}

protected function shouldPolluteScopeWithLoopInitialAssignments(): bool
{
return false;
}

protected function shouldPolluteCatchScopeWithTryAssignments(): bool
{
return false;
}

protected function shouldPolluteScopeWithAlwaysIterableForeach(): bool
{
return false;
}

protected function shouldReportUnmatchedIgnoredErrors(): bool
{
return true;
}

}
2 changes: 1 addition & 1 deletion tests/src/Rules/Bug113Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected function getRule(): Rule

public function testBasicThrows(): void
{
$this->analyse(__DIR__ . '/data/bug113.php');
$this->analyseFile(__DIR__ . '/data/bug113.php');
}

}
2 changes: 1 addition & 1 deletion tests/src/Rules/DeadCatchUnionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected function getRule(): Rule

public function test(): void
{
$this->analyse(__DIR__ . '/data/dead-catch-union.php');
$this->analyseFile(__DIR__ . '/data/dead-catch-union.php');
}

}
6 changes: 3 additions & 3 deletions tests/src/Rules/PhpInternalsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,20 @@ protected function getRule(): Rule

public function testPhpInternalFunctions(): void
{
$this->analyse(__DIR__ . '/data/throws-php-internal-functions.php');
$this->analyseFile(__DIR__ . '/data/throws-php-internal-functions.php');
}

/**
* @requires PHP 7.3
*/
public function testPhpInternalFunctionsPhp73(): void
{
$this->analyse(__DIR__ . '/data/throws-php-internal-functions-php7.3.php');
$this->analyseFile(__DIR__ . '/data/throws-php-internal-functions-php7.3.php');
}

public function testPhpInternalOperators(): void
{
$this->analyse(__DIR__ . '/data/throws-php-internal-operators.php');
$this->analyseFile(__DIR__ . '/data/throws-php-internal-operators.php');
}

}
6 changes: 3 additions & 3 deletions tests/src/Rules/ThrowsPhpDocInheritanceRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ protected function getRule(): Rule

public function testInheritance(): void
{
$this->analyse(__DIR__ . '/data/throws-inheritance.php');
$this->analyseFile(__DIR__ . '/data/throws-inheritance.php');
}

public function testInheritanceWithInterfaces(): void
{
$this->analyse(__DIR__ . '/data/throws-inheritance-interfaces.php');
$this->analyseFile(__DIR__ . '/data/throws-inheritance-interfaces.php');
}

public function testInheritanceWithOverriding(): void
{
$this->analyse(__DIR__ . '/data/throws-inheritance-overriding.php');
$this->analyseFile(__DIR__ . '/data/throws-inheritance-overriding.php');
}

}
28 changes: 14 additions & 14 deletions tests/src/Rules/ThrowsPhpDocRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,17 @@ protected function getRule(): Rule

public function testBasicThrows(): void
{
$this->analyse(__DIR__ . '/data/throws-annotations.php');
$this->analyseFile(__DIR__ . '/data/throws-annotations.php');
}

public function testTryCatch(): void
{
$this->analyse(__DIR__ . '/data/try-catch.php');
$this->analyseFile(__DIR__ . '/data/try-catch.php');
}

public function testUnusedThrows(): void
{
$this->analyse(__DIR__ . '/data/unused-throws.php');
$this->analyseFile(__DIR__ . '/data/unused-throws.php');
}

public function testUnusedCatches(): void
Expand All @@ -119,61 +119,61 @@ public function testUnusedCatches(): void
],
];

$this->analyse(__DIR__ . '/data/unused-catches.php');
$this->analyseFile(__DIR__ . '/data/unused-catches.php');
}

public function testAllUnusedCatches(): void
{
$this->reportUnusedCatchesOfUncheckedExceptions = true;
$this->analyse(__DIR__ . '/data/unused-catches-all.php');
$this->analyseFile(__DIR__ . '/data/unused-catches-all.php');
}

public function testIterators(): void
{
$this->analyse(__DIR__ . '/data/iterators.php');
$this->analyseFile(__DIR__ . '/data/iterators.php');
}

public function testCountable(): void
{
$this->analyse(__DIR__ . '/data/countables.php');
$this->analyseFile(__DIR__ . '/data/countables.php');
}

public function testJsonSerializable(): void
{
$this->analyse(__DIR__ . '/data/json-serializable.php');
$this->analyseFile(__DIR__ . '/data/json-serializable.php');
}

public function testDynamicExtension(): void
{
$this->analyse(__DIR__ . '/data/dynamic-extension.php');
$this->analyseFile(__DIR__ . '/data/dynamic-extension.php');
}

public function testUnsupportedCatchCheckedAndUnchecked(): void
{
$this->analyse(__DIR__ . '/data/unsupported-catch.php');
$this->analyseFile(__DIR__ . '/data/unsupported-catch.php');
}

public function testAnonymClass(): void
{
$this->analyse(__DIR__ . '/data/throws-anonym-class.php');
$this->analyseFile(__DIR__ . '/data/throws-anonym-class.php');
}

public function testThrowsInGlobalScope(): void
{
$this->reportCheckedThrowsInGlobalScope = true;
$this->analyse(__DIR__ . '/data/throws-in-global-scope.php');
$this->analyseFile(__DIR__ . '/data/throws-in-global-scope.php');
}

public function testMethodWhitelist(): void
{
$this->methodWhitelist = [TestCase::class => '/^test/'];
$this->analyse(__DIR__ . '/data/method-whitelisting.php');
$this->analyseFile(__DIR__ . '/data/method-whitelisting.php');
}

public function testIntentionallyUnusedThrows(): void
{
$this->reportUnusedCheckedThrowsInSubtypes = false;
$this->analyse(__DIR__ . '/data/intentionally-unused-throws.php');
$this->analyseFile(__DIR__ . '/data/intentionally-unused-throws.php');
}

}
2 changes: 1 addition & 1 deletion tests/src/Rules/UnreachableCatchRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected function getRule(): Rule

public function test(): void
{
$this->analyse(__DIR__ . '/data/unreachable-catches.php');
$this->analyseFile(__DIR__ . '/data/unreachable-catches.php');
}

}
2 changes: 1 addition & 1 deletion tests/src/Rules/UselessThrowsPhpDocRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ protected function getRule(): Rule

public function testBasicUselessThrows(): void
{
$this->analyse(__DIR__ . '/data/useless-throws.php');
$this->analyseFile(__DIR__ . '/data/useless-throws.php');
}

}