1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00
psalm/tests/ConfigTest.php

504 lines
15 KiB
PHP
Raw Normal View History

2016-12-29 16:24:10 +01:00
<?php
namespace Psalm\Tests;
use Psalm\Checker\FileChecker;
use Psalm\Config;
use Psalm\Context;
2016-12-29 16:24:10 +01:00
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
class ConfigTest extends TestCase
2016-12-29 16:24:10 +01:00
{
/** @var TestConfig */
protected static $config;
/** @var \Psalm\Checker\ProjectChecker */
protected $project_checker;
/**
* @return void
*/
public static function setUpBeforeClass()
{
self::$config = new TestConfig();
if (!defined('PSALM_VERSION')) {
define('PSALM_VERSION', '2.0.0');
}
if (!defined('PHP_PARSER_VERSION')) {
define('PHP_PARSER_VERSION', '4.0.0');
}
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
2016-12-29 16:24:10 +01:00
public function setUp()
{
FileChecker::clearCache();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->file_provider = new Provider\FakeFileProvider();
2016-12-29 16:24:10 +01:00
}
2017-01-13 20:07:23 +01:00
/**
* @return string[]
* @psalm-return array<mixed, string>
*/
public static function getAllIssues()
{
return array_filter(
array_map(
2017-01-13 20:14:24 +01:00
/**
* @param string $file_name
2017-05-27 02:16:18 +02:00
*
2017-01-13 20:14:24 +01:00
* @return string
*/
function ($file_name) {
return substr($file_name, 0, -4);
},
scandir(dirname(__DIR__) . '/src/Psalm/Issue')
),
2017-01-13 20:14:24 +01:00
/**
* @param string $issue_name
2017-05-27 02:16:18 +02:00
*
2017-01-13 20:14:24 +01:00
* @return bool
*/
function ($issue_name) {
return !empty($issue_name)
&& $issue_name !== 'MethodIssue'
&& $issue_name !== 'PropertyIssue'
&& $issue_name !== 'ClassIssue'
&& $issue_name !== 'CodeIssue';
}
);
}
/**
* @param Config $config
*
* @return \Psalm\Checker\ProjectChecker
*/
private function getProjectCheckerWithConfig(Config $config)
{
return new \Psalm\Checker\ProjectChecker(
$config,
$this->file_provider,
2018-02-19 06:27:39 +01:00
new Provider\FakeParserCacheProvider(),
new \Psalm\Provider\NoCache\NoFileStorageCacheProvider(),
new \Psalm\Provider\NoCache\NoClassLikeStorageCacheProvider()
);
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
2016-12-29 16:24:10 +01:00
public function testBarebonesConfig()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
(string)getcwd(),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
2016-12-29 16:24:10 +01:00
$config = $this->project_checker->getConfig();
$this->assertTrue($config->isInProjectDirs(realpath('src/Psalm/Type.php')));
$this->assertFalse($config->isInProjectDirs(realpath('examples/StringChecker.php')));
2016-12-29 16:24:10 +01:00
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
public function testIgnoreProjectDirectory()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="src/Psalm/Checker" />
</ignoreFiles>
</projectFiles>
</psalm>'
)
);
$config = $this->project_checker->getConfig();
$this->assertTrue($config->isInProjectDirs(realpath('src/Psalm/Type.php')));
$this->assertFalse($config->isInProjectDirs(realpath('src/Psalm/Checker/FileChecker.php')));
$this->assertFalse($config->isInProjectDirs(realpath('examples/StringChecker.php')));
}
2016-12-30 02:07:42 +01:00
/**
* @return void
*/
public function testIgnoreWildcardProjectDirectory()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="src/**/Checker" />
</ignoreFiles>
</projectFiles>
</psalm>'
)
);
$config = $this->project_checker->getConfig();
$this->assertTrue($config->isInProjectDirs(realpath('src/Psalm/Type.php')));
$this->assertFalse($config->isInProjectDirs(realpath('src/Psalm/Checker/FileChecker.php')));
$this->assertFalse($config->isInProjectDirs(realpath('src/Psalm/Checker/Statements/ReturnChecker.php')));
$this->assertFalse($config->isInProjectDirs(realpath('examples/StringChecker.php')));
}
/**
* @return void
*/
public function testIgnoreWildcardFiles()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<file name="src/Psalm/Checker/*Checker.php" />
</ignoreFiles>
</projectFiles>
</psalm>'
)
);
$config = $this->project_checker->getConfig();
$this->assertTrue($config->isInProjectDirs(realpath('src/Psalm/Type.php')));
$this->assertFalse($config->isInProjectDirs(realpath('src/Psalm/Checker/FileChecker.php')));
$this->assertTrue($config->isInProjectDirs(realpath('src/Psalm/Checker/Statements/ReturnChecker.php')));
$this->assertFalse($config->isInProjectDirs(realpath('examples/StringChecker.php')));
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
2016-12-30 02:07:42 +01:00
public function testIssueHandler()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
<directory name="tests" />
</projectFiles>
<issueHandlers>
<MissingReturnType errorLevel="suppress" />
</issueHandlers>
</psalm>'
)
);
2016-12-30 02:07:42 +01:00
$config = $this->project_checker->getConfig();
$this->assertFalse($config->reportIssueInFile('MissingReturnType', realpath('tests/ConfigTest.php')));
$this->assertFalse($config->reportIssueInFile('MissingReturnType', realpath('src/Psalm/Type.php')));
2016-12-30 02:07:42 +01:00
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
2016-12-30 02:07:42 +01:00
public function testIssueHandlerWithCustomErrorLevels()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
<directory name="tests" />
</projectFiles>
<issueHandlers>
<MissingReturnType errorLevel="info">
<errorLevel type="suppress">
<directory name="tests" />
</errorLevel>
<errorLevel type="error">
<directory name="src/Psalm/Checker" />
</errorLevel>
</MissingReturnType>
<UndefinedClass>
<errorLevel type="suppress">
<referencedClass name="Psalm\Badger" />
</errorLevel>
</UndefinedClass>
<UndefinedMethod>
<errorLevel type="suppress">
<referencedMethod name="Psalm\Bodger::find1" />
</errorLevel>
</UndefinedMethod>
<UndefinedPropertyFetch>
<errorLevel type="suppress">
<referencedProperty name="Psalm\Bodger::$find3" />
</errorLevel>
</UndefinedPropertyFetch>
</issueHandlers>
</psalm>'
)
);
2016-12-30 02:07:42 +01:00
$config = $this->project_checker->getConfig();
$this->assertSame(
'info',
$config->getReportingLevelForFile(
'MissingReturnType',
realpath('src/Psalm/Type.php')
)
);
$this->assertSame(
'error',
$config->getReportingLevelForFile(
'MissingReturnType',
realpath('src/Psalm/Checker/FileChecker.php')
)
);
$this->assertSame(
'suppress',
$config->getReportingLevelForClass(
'UndefinedClass',
'Psalm\Badger'
)
);
$this->assertSame(
'error',
$config->getReportingLevelForClass(
'UndefinedClass',
'Psalm\Bodger'
)
);
$this->assertSame(
'suppress',
$config->getReportingLevelForMethod(
'UndefinedMethod',
'Psalm\Bodger::find1'
)
);
$this->assertSame(
'error',
$config->getReportingLevelForProperty(
'UndefinedMethod',
'Psalm\Bodger::$find3'
)
);
$this->assertSame(
'error',
$config->getReportingLevelForProperty(
'UndefinedMethod',
'Psalm\Bodger::$find4'
)
);
2016-12-30 02:07:42 +01:00
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
public function testAllPossibleIssues()
{
$all_possible_handlers = implode(
' ',
array_map(
2017-01-13 20:14:24 +01:00
/**
* @param string $issue_name
2017-05-27 02:16:18 +02:00
*
2017-01-13 20:14:24 +01:00
* @return string
*/
function ($issue_name) {
return '<' . $issue_name . ' errorLevel="suppress" />' . "\n";
},
self::getAllIssues()
)
);
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<issueHandlers>
' . $all_possible_handlers . '
</issueHandlers>
</psalm>'
)
);
}
/**
2017-01-13 20:07:23 +01:00
* @expectedException \Psalm\Exception\ConfigException
* @expectedExceptionMessage This element is not expected
2017-05-27 02:16:18 +02:00
*
2017-01-13 20:07:23 +01:00
* @return void
*/
public function testImpossibleIssue()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<issueHandlers>
<ImpossibleIssue errorLevel="suppress" />
</issueHandlers>
</psalm>'
)
);
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage MissingReturnType
2017-05-27 02:16:18 +02:00
*
* @return void
*/
public function testRequireVoidReturnTypeExists()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm
requireVoidReturnType="true">
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->addFile(
$file_path,
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
'<?php
function foo() {}'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testDoNotRequireVoidReturnTypeExists()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm
requireVoidReturnType="false">
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->addFile(
$file_path,
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
'<?php
function foo() {}'
);
$this->analyzeFile($file_path, new Context());
}
2017-02-13 05:59:33 +01:00
/**
* @return void
*/
public function testMethodCallMemoize()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm memoizeMethodCallResults="true">
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
class A {
function getFoo() : ?Foo {
return rand(0, 1) ? new Foo : null;
}
}
class Foo {
public function bar() : void {}
};
$a = new A();
if ($a->getFoo()) {
$a->getFoo()->bar();
}'
);
$this->analyzeFile($file_path, new Context());
}
2017-02-13 05:59:33 +01:00
/**
* @return void
*/
public function testTemplatedFiles()
{
foreach (['1.xml', '2.xml', '3.xml', '4.xml', '5.xml', '6.xml', '7.xml', '8.xml'] as $file_name) {
Config::loadFromXMLFile(
realpath(dirname(__DIR__) . '/assets/config_levels/' . $file_name),
dirname(__DIR__)
);
2017-02-13 05:59:33 +01:00
}
}
2016-12-29 16:24:10 +01:00
}