mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Failed and regression tests for magic static methods
List failed tests: ``` 1) Psalm\Tests\MagicMethodAnnotationTest::testNoSealAllMethodsWithStatic Failed asserting that exception of type "Psalm\Exception\CodeException" is thrown. 2) Psalm\Tests\MagicMethodAnnotationTest::testSealAllMethodsWithoutFooWithStatic Failed asserting that exception of type "Psalm\Exception\CodeException" is thrown. 3) Psalm\Tests\MagicMethodAnnotationTest::testInvalidCode with data set "inheritSealedMethodsWithStatic" Failed asserting that exception of type "Psalm\Exception\CodeException" is thrown. ```
This commit is contained in:
parent
fe2c67ec89
commit
6e361aa9e6
@ -46,6 +46,35 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testPhpDocMethodWhenUndefinedWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->use_phpdoc_method_without_magic_or_parent = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
/**
|
||||
* @method static string getString()
|
||||
* @method static void setInteger(int $integer)
|
||||
* @method static mixed setString(int $integer)
|
||||
* @method static bool getBool(string $foo)
|
||||
* @method static (string|int)[] getArray()
|
||||
* @method static (callable() : string) getCallable()
|
||||
*/
|
||||
class Child {}
|
||||
|
||||
$a = Child::getString();
|
||||
Child::setInteger(4);
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
$b = Child::setString(5);
|
||||
$c = Child::getBool("hello");
|
||||
$d = Child::getArray();
|
||||
$e = Child::getCallable();',
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testPhpDocMethodWhenTemplated(): void
|
||||
{
|
||||
Config::getInstance()->use_phpdoc_method_without_magic_or_parent = true;
|
||||
@ -99,6 +128,28 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', $context);
|
||||
}
|
||||
|
||||
public function testAnnotationWithoutCallConfigWithStatic(): void
|
||||
{
|
||||
$this->expectExceptionMessage('UndefinedMethod');
|
||||
$this->expectException(CodeException::class);
|
||||
Config::getInstance()->use_phpdoc_method_without_magic_or_parent = false;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
/**
|
||||
* @method static string getString()
|
||||
*/
|
||||
class Child {}
|
||||
|
||||
Child::getString();',
|
||||
);
|
||||
|
||||
$context = new Context();
|
||||
|
||||
$this->analyzeFile('somefile.php', $context);
|
||||
}
|
||||
|
||||
public function testOverrideParentClassRetunType(): void
|
||||
{
|
||||
Config::getInstance()->use_phpdoc_method_without_magic_or_parent = true;
|
||||
@ -193,6 +244,48 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
'$e' => 'callable():string',
|
||||
],
|
||||
],
|
||||
'validSimpleAnnotationsWithStatic' => [
|
||||
'code' => '<?php
|
||||
class ParentClass {
|
||||
public function __callStatic(string $name, array $args) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @method static string getString() dsa sada
|
||||
* @method static void setInteger(int $integer) dsa sada
|
||||
* @method static mixed setString(int $integer) dsa sada
|
||||
* @method static mixed setMixed(mixed $foo) dsa sada
|
||||
* @method static mixed setImplicitMixed($foo) dsa sada
|
||||
* @method static mixed setAnotherImplicitMixed( $foo, $bar,$baz) dsa sada
|
||||
* @method static mixed setYetAnotherImplicitMixed( $foo ,$bar, $baz ) dsa sada
|
||||
* @method static bool getBool(string $foo) dsa sada
|
||||
* @method static (string|int)[] getArray() with some text dsa sada
|
||||
* @method static (callable() : string) getCallable() dsa sada
|
||||
* @method static static getInstance() dsa sada
|
||||
*/
|
||||
class Child extends ParentClass {}
|
||||
|
||||
$a = Child::getString();
|
||||
Child::setInteger(4);
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
$b = Child::setString(5);
|
||||
$c = Child::getBool("hello");
|
||||
$d = Child::getArray();
|
||||
$e = Child::getCallable();
|
||||
$f = Child::getInstance();
|
||||
Child::setMixed("hello");
|
||||
Child::setMixed(4);
|
||||
Child::setImplicitMixed("hello");
|
||||
Child::setImplicitMixed(4);',
|
||||
'assertions' => [
|
||||
'$a' => 'string',
|
||||
'$b' => 'mixed',
|
||||
'$c' => 'bool',
|
||||
'$d' => 'array<array-key, int|string>',
|
||||
'$e' => 'callable():string',
|
||||
'$f' => 'Child',
|
||||
],
|
||||
],
|
||||
'validAnnotationWithDefault' => [
|
||||
'code' => '<?php
|
||||
class ParentClass {
|
||||
@ -1116,6 +1209,20 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$b->foo();',
|
||||
'error_message' => 'UndefinedMagicMethod',
|
||||
],
|
||||
'inheritSealedMethodsWithStatic' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
* @psalm-seal-methods
|
||||
*/
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B::foo();',
|
||||
'error_message' => 'UndefinedMagicMethod',
|
||||
],
|
||||
'lonelyMethod' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
@ -1174,6 +1281,29 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithoutFooWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B::foo();
|
||||
',
|
||||
);
|
||||
|
||||
$error_message = 'UndefinedMagicMethod';
|
||||
$this->expectException(CodeException::class);
|
||||
$this->expectExceptionMessage($error_message);
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testNoSealAllMethods(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
@ -1199,6 +1329,30 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testNoSealAllMethodsWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
/** @psalm-no-seal-properties */
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B::foo();
|
||||
',
|
||||
);
|
||||
|
||||
$error_message = 'UndefinedMagicMethod';
|
||||
$this->expectException(CodeException::class);
|
||||
$this->expectExceptionMessage($error_message);
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithFoo(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
@ -1221,6 +1375,27 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithFooWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
public static function foo(): void {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B::foo();
|
||||
',
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithFooInSubclass(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
@ -1244,6 +1419,28 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithFooInSubclassWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public static function foo(): void {}
|
||||
}
|
||||
|
||||
B::foo();
|
||||
',
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithFooAnnotated(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
@ -1266,6 +1463,27 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsWithFooAnnotatedWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
/** @method static int foo() */
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B::foo();
|
||||
',
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsSetToFalse(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = false;
|
||||
@ -1287,6 +1505,26 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testSealAllMethodsSetToFalseWithStatic(): void
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = false;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public static function __callStatic(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
B::foo();
|
||||
',
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
public function testIntersectionTypeWhenMagicMethodDoesNotExistButIsProvidedBySecondType(): void
|
||||
{
|
||||
$this->addFile(
|
||||
|
Loading…
x
Reference in New Issue
Block a user