mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 12:55:26 +01:00
96056d329f
Convert deltafile format to new style proposed by weirdan Modify CallMapTest to use new format Modify InternalCallMapHandler to use new format Move assertions to base testcase
227 lines
6.5 KiB
PHP
227 lines
6.5 KiB
PHP
<?php
|
|
namespace Psalm\Tests;
|
|
|
|
use PHPUnit\Framework\TestCase as BaseTestCase;
|
|
use Psalm\Config;
|
|
use Psalm\Internal\Analyzer\FileAnalyzer;
|
|
use Psalm\Internal\Analyzer\ProjectAnalyzer;
|
|
use Psalm\Internal\Provider\FakeFileProvider;
|
|
use Psalm\Internal\Provider\Providers;
|
|
use Psalm\Internal\RuntimeCaches;
|
|
use Psalm\Internal\Type\TypeParser;
|
|
use Psalm\Internal\Type\TypeTokenizer;
|
|
use Psalm\Tests\Internal\Provider;
|
|
use Psalm\Type\Union;
|
|
use RuntimeException;
|
|
use Throwable;
|
|
|
|
use function array_filter;
|
|
use function count;
|
|
use function define;
|
|
use function defined;
|
|
use function getcwd;
|
|
use function ini_set;
|
|
use function is_string;
|
|
use function method_exists;
|
|
|
|
use const ARRAY_FILTER_USE_KEY;
|
|
use const DIRECTORY_SEPARATOR;
|
|
|
|
class TestCase extends BaseTestCase
|
|
{
|
|
/** @var string */
|
|
protected static $src_dir_path;
|
|
|
|
/** @var ProjectAnalyzer */
|
|
protected $project_analyzer;
|
|
|
|
/** @var FakeFileProvider */
|
|
protected $file_provider;
|
|
|
|
/** @var Config */
|
|
protected $testConfig;
|
|
|
|
public static function setUpBeforeClass() : void
|
|
{
|
|
ini_set('memory_limit', '-1');
|
|
|
|
if (!defined('PSALM_VERSION')) {
|
|
define('PSALM_VERSION', '4.0.0');
|
|
}
|
|
|
|
if (!defined('PHP_PARSER_VERSION')) {
|
|
define('PHP_PARSER_VERSION', '4.0.0');
|
|
}
|
|
|
|
parent::setUpBeforeClass();
|
|
self::$src_dir_path = getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;
|
|
}
|
|
|
|
protected function makeConfig() : Config
|
|
{
|
|
return new TestConfig();
|
|
}
|
|
|
|
public function setUp() : void
|
|
{
|
|
parent::setUp();
|
|
|
|
RuntimeCaches::clearAll();
|
|
|
|
$this->file_provider = new FakeFileProvider();
|
|
|
|
$this->testConfig = $this->makeConfig();
|
|
|
|
$providers = new Providers(
|
|
$this->file_provider,
|
|
new Provider\FakeParserCacheProvider()
|
|
);
|
|
|
|
$this->project_analyzer = new ProjectAnalyzer(
|
|
$this->testConfig,
|
|
$providers
|
|
);
|
|
|
|
$this->project_analyzer->setPhpVersion('7.4');
|
|
}
|
|
|
|
public function tearDown() : void
|
|
{
|
|
unset($this->project_analyzer, $this->file_provider, $this->testConfig);
|
|
RuntimeCaches::clearAll();
|
|
}
|
|
|
|
/**
|
|
* @param string $file_path
|
|
* @param string $contents
|
|
*
|
|
*/
|
|
public function addFile($file_path, $contents): void
|
|
{
|
|
$this->file_provider->registerFile($file_path, $contents);
|
|
$this->project_analyzer->getCodebase()->scanner->addFileToShallowScan($file_path);
|
|
}
|
|
|
|
/**
|
|
* @param string $file_path
|
|
*
|
|
*/
|
|
public function analyzeFile($file_path, \Psalm\Context $context, bool $track_unused_suppressions = true, bool $taint_flow_tracking = false): void
|
|
{
|
|
$codebase = $this->project_analyzer->getCodebase();
|
|
|
|
if ($taint_flow_tracking) {
|
|
$this->project_analyzer->trackTaintedInputs();
|
|
}
|
|
|
|
$codebase->addFilesToAnalyze([$file_path => $file_path]);
|
|
|
|
$codebase->scanFiles();
|
|
|
|
$codebase->config->visitStubFiles($codebase);
|
|
|
|
if ($codebase->alter_code) {
|
|
$this->project_analyzer->interpretRefactors();
|
|
}
|
|
|
|
$this->project_analyzer->trackUnusedSuppressions();
|
|
|
|
$file_analyzer = new FileAnalyzer(
|
|
$this->project_analyzer,
|
|
$file_path,
|
|
$codebase->config->shortenFileName($file_path)
|
|
);
|
|
$file_analyzer->analyze($context);
|
|
|
|
if ($codebase->taint_flow_graph) {
|
|
$codebase->taint_flow_graph->connectSinksAndSources();
|
|
}
|
|
|
|
if ($track_unused_suppressions) {
|
|
\Psalm\IssueBuffer::processUnusedSuppressions($codebase->file_provider);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param bool $withDataSet
|
|
*
|
|
*/
|
|
protected function getTestName($withDataSet = true): string
|
|
{
|
|
$name = parent::getName($withDataSet);
|
|
/**
|
|
* @psalm-suppress TypeDoesNotContainNull PHPUnit 8.2 made it non-nullable again
|
|
*/
|
|
if (null === $name) {
|
|
throw new RuntimeException('anonymous test - shouldn\'t happen');
|
|
}
|
|
|
|
return $name;
|
|
}
|
|
|
|
/**
|
|
* Compatibility alias
|
|
*/
|
|
public function expectExceptionMessageRegExp(string $regexp): void
|
|
{
|
|
if (method_exists($this, 'expectExceptionMessageMatches')) {
|
|
$this->expectExceptionMessageMatches($regexp);
|
|
} else {
|
|
/** @psalm-suppress UndefinedMethod */
|
|
parent::expectExceptionMessageRegExp($regexp);
|
|
}
|
|
}
|
|
|
|
public static function assertRegExp(string $pattern, string $string, string $message = ''): void
|
|
{
|
|
if (method_exists(self::class, 'assertMatchesRegularExpression')) {
|
|
self::assertMatchesRegularExpression($pattern, $string, $message);
|
|
} else {
|
|
parent::assertRegExp($pattern, $string, $message);
|
|
}
|
|
}
|
|
|
|
public static function assertArrayKeysAreStrings(array $array, string $message = ''): void
|
|
{
|
|
$validKeys = array_filter($array, 'is_string', ARRAY_FILTER_USE_KEY);
|
|
self::assertTrue(count($array) === count($validKeys), $message);
|
|
}
|
|
|
|
public static function assertArrayKeysAreZeroOrString(array $array, string $message = ''): void
|
|
{
|
|
$isZeroOrString = /** @param mixed $key */ function ($key): bool {
|
|
return $key === 0 || is_string($key);
|
|
};
|
|
$validKeys = array_filter($array, $isZeroOrString, ARRAY_FILTER_USE_KEY);
|
|
self::assertTrue(count($array) === count($validKeys), $message);
|
|
}
|
|
|
|
public static function assertArrayValuesAreArrays(array $array, string $message = ''): void
|
|
{
|
|
$validValues = array_filter($array, 'is_array');
|
|
self::assertTrue(count($array) === count($validValues), $message);
|
|
}
|
|
|
|
public static function assertArrayValuesAreStrings(array $array, string $message = ''): void
|
|
{
|
|
$validValues = array_filter($array, 'is_string');
|
|
self::assertTrue(count($array) === count($validValues), $message);
|
|
}
|
|
|
|
public static function assertStringIsParsableType(string $type, string $message = ''): void
|
|
{
|
|
if ($type === '') {
|
|
// Ignore empty types for now, as these are quite common for pecl libraries
|
|
self::assertTrue(true);
|
|
} else {
|
|
$union = null;
|
|
try {
|
|
$tokens = TypeTokenizer::tokenize($type);
|
|
$union = TypeParser::parseTokens($tokens);
|
|
} catch (Throwable $_e) {
|
|
}
|
|
self::assertInstanceOf(Union::class, $union, $message);
|
|
}
|
|
}
|
|
}
|