1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00
psalm/tests/StubTest.php

555 lines
14 KiB
PHP

<?php
namespace Psalm\Tests;
use Psalm\Checker\FileChecker;
use Psalm\Config;
use Psalm\Context;
class StubTest extends TestCase
{
/** @var TestConfig */
protected static $config;
/**
* @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');
}
}
/**
* @return void
*/
public function setUp()
{
FileChecker::clearCache();
$this->file_provider = new Provider\FakeFileProvider();
}
/**
* @param Config $config
*
* @return \Psalm\Checker\ProjectChecker
*/
private function getProjectCheckerWithConfig(Config $config)
{
$project_checker = new \Psalm\Checker\ProjectChecker(
$config,
new \Psalm\Provider\Providers(
$this->file_provider,
new Provider\FakeParserCacheProvider()
)
);
$config->visitComposerAutoloadFiles($project_checker, false);
return $project_checker;
}
/**
* @expectedException \Psalm\Exception\ConfigException
* @expectedExceptionMessage Cannot resolve stubfile path
*
* @return void
*/
public function testNonexistentStubFile()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
Config::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="stubs/invalidfile.php" />
</stubs>
</psalm>'
)
);
}
/**
* @return void
*/
public function testStubFile()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/systemclass.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
$a = new SystemClass();
echo SystemClass::HELLO;
$b = $a->foo(5, "hello");
$c = SystemClass::bar(5, "hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testNamespacedStubClass()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/namespaced_class.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
$a = new Foo\SystemClass();
echo Foo\SystemClass::HELLO;
$b = $a->foo(5, "hello");
$c = Foo\SystemClass::bar(5, "hello");
echo Foo\BAR;'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testStubFunction()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/custom_functions.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
echo barBar("hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testPolyfilledFunction()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm
autoloader="tests/stubs/polyfill.php"
>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
$a = random_bytes(16);
$b = new_random_bytes(16);'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testStubFunctionWithFunctionExists()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/custom_functions.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
function_exists("fooBar");
echo barBar("hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testNamespacedStubFunctionWithFunctionExists()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/custom_functions.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
namespace A;
function_exists("fooBar");
echo barBar("hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage UndefinedFunction - /src/somefile.php:2 - Function barBar does not exist
*
* @return void
*/
public function testNoStubFunction()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
echo barBar("hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testNamespacedStubFunction()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/namespaced_functions.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
echo Foo\barBar("hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testConditionalNamespacedStubFunction()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/conditional_namespaced_functions.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
echo Foo\barBar("hello");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testStubFileWithExistingClassDefinition()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/logicexception.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
$a = new LogicException(5);'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @return void
*/
public function testStubFileWithPartialClassDefinitionWithMoreMethods()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/partial_class.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
namespace Foo;
class PartiallyStubbedClass {
/**
* @param string $a
* @return object
*/
public function foo(string $a) {
return new self;
}
public function bar(int $i) : void {}
}
class A {}
(new PartiallyStubbedClass())->foo(A::class);
(new PartiallyStubbedClass())->bar(5);'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage TypeCoercion
*
* @return void
*/
public function testStubFileWithPartialClassDefinitionWithCoercion()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/partial_class.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
namespace Foo;
class PartiallyStubbedClass {
/**
* @param string $a
* @return object
*/
public function foo(string $a) {
return new self;
}
}
(new PartiallyStubbedClass())->foo("dasda");'
);
$this->analyzeFile($file_path, new Context());
}
/**
* @expectedException \Psalm\Exception\CodeException
* @expectedExceptionMessage InvalidReturnStatement
*
* @return void
*/
public function testStubFileWithPartialClassDefinitionGeneralReturnType()
{
$this->project_checker = $this->getProjectCheckerWithConfig(
TestConfig::loadFromXML(
dirname(__DIR__),
'<?xml version="1.0"?>
<psalm>
<projectFiles>
<directory name="src" />
</projectFiles>
<stubs>
<file name="tests/stubs/partial_class.php" />
</stubs>
</psalm>'
)
);
$file_path = getcwd() . '/src/somefile.php';
$this->addFile(
$file_path,
'<?php
namespace Foo;
class PartiallyStubbedClass {
/**
* @param string $a
* @return object
*/
public function foo(string $a) {
return new \stdClass;
}
}'
);
$this->analyzeFile($file_path, new Context());
}
}