Skip to content
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

Indicate file on TypeInferenceTestCase validation errors #3166

Merged
merged 16 commits into from
Jul 11, 2024
26 changes: 26 additions & 0 deletions src/File/SystemAgnosticSimpleRelativePathHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

namespace PHPStan\File;

use function str_starts_with;
use function strlen;
use function substr;

class SystemAgnosticSimpleRelativePathHelper implements RelativePathHelper
{

public function __construct(private FileHelper $fileHelper)
{
}

public function getRelativePath(string $filename): string
{
$cwd = $this->fileHelper->getWorkingDirectory();
if ($cwd !== '' && str_starts_with($filename, $cwd)) {
return substr($filename, strlen($cwd) + 1);
}

return $filename;
}

}
32 changes: 26 additions & 6 deletions src/Testing/TypeInferenceTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPStan\DependencyInjection\Type\ParameterClosureTypeExtensionProvider;
use PHPStan\DependencyInjection\Type\ParameterOutTypeExtensionProvider;
use PHPStan\File\FileHelper;
use PHPStan\File\SystemAgnosticSimpleRelativePathHelper;
use PHPStan\Php\PhpVersion;
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
use PHPStan\PhpDoc\StubPhpDocProvider;
Expand Down Expand Up @@ -143,8 +144,14 @@ public function assertFileAsserts(
*/
public static function gatherAssertTypes(string $file): array
{
$fileHelper = self::getContainer()->getByType(FileHelper::class);

$relativePathHelper = new SystemAgnosticSimpleRelativePathHelper($fileHelper);

$file = $fileHelper->normalizePath($file);

$asserts = [];
self::processFile($file, static function (Node $node, Scope $scope) use (&$asserts, $file): void {
self::processFile($file, static function (Node $node, Scope $scope) use (&$asserts, $file, $relativePathHelper): void {
if (!$node instanceof Node\Expr\FuncCall) {
return;
}
Expand All @@ -157,21 +164,32 @@ public static function gatherAssertTypes(string $file): array
$functionName = $nameNode->toString();
if (in_array(strtolower($functionName), ['asserttype', 'assertnativetype', 'assertvariablecertainty'], true)) {
self::fail(sprintf(
'Missing use statement for %s() on line %d.',
'Missing use statement for %s() in %s on line %d.',
$functionName,
$relativePathHelper->getRelativePath($file),
$node->getStartLine(),
));
} elseif ($functionName === 'PHPStan\\Testing\\assertType') {
$expectedType = $scope->getType($node->getArgs()[0]->value);
if (!$expectedType instanceof ConstantScalarType) {
self::fail(sprintf('Expected type must be a literal string, %s given on line %d.', $expectedType->describe(VerbosityLevel::precise()), $node->getLine()));
self::fail(sprintf(
'Expected type must be a literal string, %s given in %s on line %d.',
$expectedType->describe(VerbosityLevel::precise()),
$relativePathHelper->getRelativePath($file),
$node->getLine(),
));
}
$actualType = $scope->getType($node->getArgs()[1]->value);
$assert = ['type', $file, $expectedType->getValue(), $actualType->describe(VerbosityLevel::precise()), $node->getStartLine()];
} elseif ($functionName === 'PHPStan\\Testing\\assertNativeType') {
$expectedType = $scope->getType($node->getArgs()[0]->value);
if (!$expectedType instanceof ConstantScalarType) {
self::fail(sprintf('Expected type must be a literal string, %s given on line %d.', $expectedType->describe(VerbosityLevel::precise()), $node->getLine()));
self::fail(sprintf(
'Expected type must be a literal string, %s given in %s on line %d.',
$expectedType->describe(VerbosityLevel::precise()),
$relativePathHelper->getRelativePath($file),
$node->getLine(),
));
}

$actualType = $scope->getNativeType($node->getArgs()[1]->value);
Expand Down Expand Up @@ -226,17 +244,19 @@ public static function gatherAssertTypes(string $file): array
}

self::fail(sprintf(
'Function %s imported with wrong namespace %s called on line %d.',
'Function %s imported with wrong namespace %s called in %s on line %d.',
$correctFunction,
$functionName,
$relativePathHelper->getRelativePath($file),
$node->getStartLine(),
));
}

if (count($node->getArgs()) !== 2) {
self::fail(sprintf(
'ERROR: Wrong %s() call on line %d.',
'ERROR: Wrong %s() call in %s on line %d.',
$functionName,
$relativePathHelper->getRelativePath($file),
$node->getStartLine(),
));
}
Expand Down
7 changes: 6 additions & 1 deletion tests/PHPStan/Analyser/PathConstantsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
namespace PHPStan\Analyser;

use PHPStan\Testing\TypeInferenceTestCase;
use const DIRECTORY_SEPARATOR;

class PathConstantsTest extends TypeInferenceTestCase
{

public function dataFileAsserts(): iterable
{
yield from $this->gatherAssertTypes(__DIR__ . '/data/pathConstants.php');
if (DIRECTORY_SEPARATOR === '\\') {
yield from $this->gatherAssertTypes(__DIR__ . '/data/pathConstants-win.php');
} else {
yield from $this->gatherAssertTypes(__DIR__ . '/data/pathConstants.php');
}
}

/**
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/data/pathConstants-win.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace PathConstantsTestWin;

\PHPStan\Testing\assertType('\'Analyser\\\\data\'', substr(__DIR__, -13));
\PHPStan\Testing\assertType('\'pathConstants-win.php\'', substr(__FILE__, -21));
50 changes: 41 additions & 9 deletions tests/PHPStan/Testing/TypeInferenceTestCaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,80 @@

namespace PHPStan\Testing;

use PHPStan\File\FileHelper;
use PHPUnit\Framework\AssertionFailedError;
use function sprintf;

final class TypeInferenceTestCaseTest extends TypeInferenceTestCase
{

public static function dataFileAssertionFailedErrors(): iterable
{
/** @var FileHelper $fileHelper */
$fileHelper = self::getContainer()->getByType(FileHelper::class);

yield [
__DIR__ . '/data/assert-certainty-missing-namespace.php',
'Missing use statement for assertVariableCertainty() on line 8.',
sprintf(
'Missing use statement for assertVariableCertainty() in %s on line 8.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-certainty-missing-namespace.php'),
),
];
yield [
__DIR__ . '/data/assert-native-type-missing-namespace.php',
'Missing use statement for assertNativeType() on line 6.',
sprintf(
'Missing use statement for assertNativeType() in %s on line 6.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-native-type-missing-namespace.php'),
),
];
yield [
__DIR__ . '/data/assert-type-missing-namespace.php',
'Missing use statement for assertType() on line 6.',
sprintf(
'Missing use statement for assertType() in %s on line 6.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-type-missing-namespace.php'),
),
];
yield [
__DIR__ . '/data/assert-certainty-wrong-namespace.php',
'Function PHPStan\Testing\assertVariableCertainty imported with wrong namespace SomeWrong\Namespace\assertVariableCertainty called on line 9.',
sprintf(
'Function PHPStan\Testing\assertVariableCertainty imported with wrong namespace SomeWrong\Namespace\assertVariableCertainty called in %s on line 9.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-certainty-wrong-namespace.php'),
),
];
yield [
__DIR__ . '/data/assert-native-type-wrong-namespace.php',
'Function PHPStan\Testing\assertNativeType imported with wrong namespace SomeWrong\Namespace\assertNativeType called on line 8.',
sprintf(
'Function PHPStan\Testing\assertNativeType imported with wrong namespace SomeWrong\Namespace\assertNativeType called in %s on line 8.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-native-type-wrong-namespace.php'),
),
];
yield [
__DIR__ . '/data/assert-type-wrong-namespace.php',
'Function PHPStan\Testing\assertType imported with wrong namespace SomeWrong\Namespace\assertType called on line 8.',
sprintf(
'Function PHPStan\Testing\assertType imported with wrong namespace SomeWrong\Namespace\assertType called in %s on line 8.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-type-wrong-namespace.php'),
),
];
yield [
__DIR__ . '/data/assert-certainty-case-insensitive.php',
'Missing use statement for assertvariablecertainty() on line 8.',
sprintf(
'Missing use statement for assertvariablecertainty() in %s on line 8.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-certainty-case-insensitive.php'),
),
];
yield [
__DIR__ . '/data/assert-native-type-case-insensitive.php',
'Missing use statement for assertNATIVEType() on line 6.',
sprintf(
'Missing use statement for assertNATIVEType() in %s on line 6.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-native-type-case-insensitive.php'),
),
];
yield [
__DIR__ . '/data/assert-type-case-insensitive.php',
'Missing use statement for assertTYPe() on line 6.',
sprintf(
'Missing use statement for assertTYPe() in %s on line 6.',
$fileHelper->normalizePath('tests/PHPStan/Testing/data/assert-type-case-insensitive.php'),
),
];
}

Expand Down
Loading