phpstan/phpstan-phpunit

AssertArrayHasKey seems to be not supported

VincentLanglet opened this issue · 7 comments

Hi @ondrejmirtes, I just got an issue with my tests saying that an offset does not exist in an array.
I tried to add a assertArrayHasKey check, without success.

I think this assert is not handle by this plugin, am I wrong ?

I'll try to do a PR in order to add the support, I think I'll be able to copy the way isArray works.
https://github.com/phpstan/phpstan-phpunit/blob/master/src/Type/PHPUnit/Assert/AssertTypeSpecifyingExtensionHelper.php#L158

Yes, this should be easy enough.

@ondrejmirtes I'm not sure it the implementation in commit 6aaff11 is complete. assertArrayHasKey accepts an ArrayObject as well and PHPUnit will use offsetExists if an object is provided, but in the commit PHPStan will only allow arrays (as it uses array_key_exists).

@micheh Do you have a false-positive that stems from the current implementation?

I think at least that it stems from the current implementation.

Unit Test:

public function testArrayHasKey(): void
{
    $object = new ArrayObject(['test' => 'hello']);
    self::assertArrayHasKey('test', $object);

    $object2 = new ArrayObject(['test' => 'hello']);
    if ($object2->offsetExists('test') === false) {
        echo 'hello';
    }
}

In version 0.12.21 PHPStan now reports the error for the PHPUnit assertion ($object), but no error for the conditional ($object2):
Call to static method PHPUnit\Framework\Assert::assertArrayHasKey() with 'test' and ArrayObject<string, string> will always evaluate to false.

According to the phpdoc
https://github.com/sebastianbergmann/phpunit/blob/adeede29ca716930efb49ebe0fe1a5cab38af9c4/src/Framework/Assert.php#L95
ArrayAccess has to be supported too indeed.

Can you provide a fix @micheh ?

To support ArrayAccess properly I think this issue has to be fixed first: phpstan/phpstan#3323

With the current implementation,

'ArrayHasKey' => static function (Scope $scope, Arg $key, Arg $array): Expr {
return new Expr\BinaryOp\BooleanOr(
new Expr\BinaryOp\BooleanAnd(
new Expr\Instanceof_($array->value, new Name('ArrayAccess')),
new Expr\MethodCall($array->value, 'offsetExists', [$key])
),
new FuncCall(new Name('array_key_exists'), [$key, $array])
);
},

AssertArrayHasKey don't work anymore with array because of the issue phpstan/phpstan#11276