Skip to content

Commit 8e0e3be

Browse files
committed
Make isSatisfiedBy() less annoying, scan tests with PHPStan
1 parent c7ba896 commit 8e0e3be

File tree

6 files changed

+31
-25
lines changed

6 files changed

+31
-25
lines changed

phpstan.neon.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ parameters:
33
treatPhpDocTypesAsCertain: false
44
paths:
55
- src
6+
- tests

src/Prototype.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ private static function convertReflectionType(?\ReflectionType $type) : ?BaseTyp
4646
return $type === null ? null : self::convertReflectionTypeInner($type);
4747
}
4848

49-
public static function createFromCallable(\Closure $callable) : Prototype{
49+
public static function fromClosure(\Closure $callable) : Prototype{
5050
$reflection = new \ReflectionFunction($callable);
5151

5252
$returnType = new ReturnInfo(self::convertReflectionType($reflection->getReturnType()), $reflection->returnsReference());
@@ -77,20 +77,18 @@ public function __construct(ReturnInfo $returnType, ParameterInfo ...$parameters
7777
}
7878
}
7979

80-
public function isSatisfiedBy(\Closure $callable) : bool{
81-
$other = self::createFromCallable($callable);
82-
83-
if(!$this->returnInfo->isSatisfiedBy($other->returnInfo)){
80+
public function isSatisfiedBy(Prototype $callable) : bool{
81+
if(!$this->returnInfo->isSatisfiedBy($callable->returnInfo)){
8482
return false;
8583
}
8684

87-
if($other->requiredParameterCount > $this->requiredParameterCount){
85+
if($callable->requiredParameterCount > $this->requiredParameterCount){
8886
return false;
8987
}
9088

9189
$last = null;
9290

93-
foreach($other->parameters as $position => $parameter){
91+
foreach($callable->parameters as $position => $parameter){
9492
// Parameters that exist in the prototype must always be satisfied directly
9593
if(isset($this->parameters[$position])){
9694
if(!$this->parameters[$position]->isSatisfiedBy($parameter)){

tests/Base/Fixtures/ClassImplementingInvoke.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@
44

55
class ClassImplementingInvoke
66
{
7-
public function __invoke() {}
7+
public function __invoke() : mixed{
8+
return null;
9+
}
810
}

tests/Base/Fixtures/ClassImplementingIteratorAggregate.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22

33
namespace DaveRandom\CallbackValidator\Test\Base\Fixtures;
44

5+
/**
6+
* @phpstan-implements \IteratorAggregate<mixed, mixed>
7+
*/
58
abstract class ClassImplementingIteratorAggregate implements \IteratorAggregate {}

tests/Base/PrototypeTest.php

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ public static function returnCovarianceProvider() : \Generator{
1616
yield [function() : void{}, function() : void{}, true, "same type"];
1717
yield [function(){}, function() : void{}, true, "unspecified type allows not returning anything (the same as void)"];
1818

19-
yield [function() : int{ return 0; }, function(){}, false, "given function might return nothing, which is not allowed by an int type"];
20-
yield [function() : mixed{ return 0; }, function(){}, false, "given function might return nothing, which is not allowed by a mixed type"];
19+
yield [function() : int{ die(); }, function(){}, false, "given function might return nothing, which is not allowed by an int type"];
20+
yield [function() : mixed{ die(); }, function(){}, false, "given function might return nothing, which is not allowed by a mixed type"];
2121

22-
yield [function() : int|string{ return 0; }, function() : int{ return 0; }, true, "given function returns a type which is covariant with required"];
23-
yield [function() : int{ return 0; }, function() : int|string{ return 0; }, false, "given function returns a type which is not covariant with required"];
24-
yield [function() : float{ return 0; }, function() : int{ return 0; }, true, "int is covariant with float"];
22+
yield [function() : int|string{ die(); }, function() : int{ die(); }, true, "given function returns a type which is covariant with required"];
23+
yield [function() : int{ die(); }, function() : int|string{ die(); }, false, "given function returns a type which is not covariant with required"];
24+
yield [function() : float{ die(); }, function() : int{ die(); }, true, "int is covariant with float"];
2525

26-
yield [function() : Interface1{}, function() : Interface1&Interface2{}, true, "covariant intersection type"];
27-
yield [function() : Interface1&Interface2{}, function() : Interface1{}, false, "given type not covariant with required intersection"];
26+
yield [function() : Interface1{ die(); }, function() : Interface1&Interface2{ die(); }, true, "covariant intersection type"];
27+
yield [function() : Interface1&Interface2{ die(); }, function() : Interface1{ die(); }, false, "given type not covariant with required intersection"];
2828

29-
yield [function() : mixed{}, function() : int{}, true, "int is covariant with mixed"];
30-
yield [function() : mixed{}, function() : int|string{}, true, "int|string is covariant with mixed"];
31-
yield [function() : mixed{}, function() : Interface1&Interface2{}, true, "intersection is covariant with mixed"];
32-
yield [function() : mixed{}, function() : void{}, false, "void is not covariant with mixed"];
29+
yield [function() : mixed{ die(); }, function() : int{ die(); }, true, "int is covariant with mixed"];
30+
yield [function() : mixed{ die(); }, function() : int|string{ die(); }, true, "int|string is covariant with mixed"];
31+
yield [function() : mixed{ die(); }, function() : Interface1&Interface2{ die(); }, true, "intersection is covariant with mixed"];
32+
yield [function() : mixed{ die(); }, function() : void{}, false, "void is not covariant with mixed"];
3333
}
3434

3535
public static function paramContravarianceProvider() : \Generator{
@@ -81,10 +81,11 @@ public static function paramContravarianceProvider() : \Generator{
8181
#[DataProvider('returnCovarianceProvider')]
8282
#[DataProvider('paramContravarianceProvider')]
8383
public function testCompatibility(\Closure $required, \Closure $given, bool $matches, string $reason) : void{
84-
$required = Prototype::createFromCallable($required);
84+
$required = Prototype::fromClosure($required);
85+
$given = Prototype::fromClosure($given);
8586

8687
$serializedRequire = (string) $required;
87-
$serializedGiven = (string) Prototype::createFromCallable($given);
88+
$serializedGiven = (string) $given;
8889
self::assertSame($required->isSatisfiedBy($given), $matches, $reason . " ($serializedRequire, $serializedGiven)");
8990
}
9091
}

tests/Php82/PrototypeTest.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ class PrototypeTest extends TestCase{
1212

1313
public static function returnCovarianceProvider() : \Generator{
1414
//DNF types - PHP 8.2+ only
15-
yield [function() : (Interface1&Interface2)|string{}, function() : Interface1{}, false, "given type not covariant with any part of required union"];
16-
yield [function() : (Interface1&Interface2)|string{}, function() : Interface1&Interface2{}, true, "given type covariant with at least 1 part of required union"];
15+
yield [function() : (Interface1&Interface2)|string{ die(); }, function() : Interface1{ die(); }, false, "given type not covariant with any part of required union"];
16+
yield [function() : (Interface1&Interface2)|string{ die(); }, function() : Interface1&Interface2{ die(); }, true, "given type covariant with at least 1 part of required union"];
1717
}
1818

1919
public static function paramContravarianceProvider() : \Generator{
@@ -27,10 +27,11 @@ public static function paramContravarianceProvider() : \Generator{
2727
#[DataProvider('returnCovarianceProvider')]
2828
#[DataProvider('paramContravarianceProvider')]
2929
public function testCompatibility(\Closure $required, \Closure $given, bool $matches, string $reason) : void{
30-
$required = Prototype::createFromCallable($required);
30+
$required = Prototype::fromClosure($required);
31+
$given = Prototype::fromClosure($given);
3132

3233
$serializedRequire = (string) $required;
33-
$serializedGiven = (string) Prototype::createFromCallable($given);
34+
$serializedGiven = (string) $given;
3435
self::assertSame($required->isSatisfiedBy($given), $matches, $reason . " ($serializedRequire, $serializedGiven)");
3536
}
3637
}

0 commit comments

Comments
 (0)