diff --git a/src/Type/PHPUnit/Assert/AssertTypeSpecifyingExtensionHelper.php b/src/Type/PHPUnit/Assert/AssertTypeSpecifyingExtensionHelper.php index 1507a13..34d86ca 100644 --- a/src/Type/PHPUnit/Assert/AssertTypeSpecifyingExtensionHelper.php +++ b/src/Type/PHPUnit/Assert/AssertTypeSpecifyingExtensionHelper.php @@ -276,6 +276,21 @@ private static function getExpressionResolvers(): array 'ObjectHasAttribute' => static function (Scope $scope, Arg $property, Arg $object): FuncCall { return new FuncCall(new Name('property_exists'), [$object, $property]); }, + 'Contains' => static function (Scope $scope, Arg $needle, Arg $haystack): Expr { + return new Expr\BinaryOp\BooleanOr( + new Expr\Instanceof_($haystack->value, new Name('Traversable')), + new FuncCall(new Name('in_array'), [$needle, $haystack, new Arg(new ConstFetch(new Name('true')))]) + ); + }, + 'ContainsEquals' => static function (Scope $scope, Arg $needle, Arg $haystack): Expr { + return new Expr\BinaryOp\BooleanOr( + new Expr\Instanceof_($haystack->value, new Name('Traversable')), + new Expr\BinaryOp\BooleanAnd( + new Expr\BooleanNot(new Expr\Empty_($haystack->value)), + new FuncCall(new Name('in_array'), [$needle, $haystack, new Arg(new ConstFetch(new Name('false')))]) + ) + ); + }, 'ContainsOnlyInstancesOf' => static function (Scope $scope, Arg $className, Arg $haystack): Expr { return new Expr\BinaryOp\BooleanOr( new Expr\Instanceof_($haystack->value, new Name('Traversable')), diff --git a/tests/Type/PHPUnit/data/assert-function.php b/tests/Type/PHPUnit/data/assert-function.php index 84102c9..15c4371 100644 --- a/tests/Type/PHPUnit/data/assert-function.php +++ b/tests/Type/PHPUnit/data/assert-function.php @@ -4,6 +4,8 @@ use function PHPStan\Testing\assertType; use function PHPUnit\Framework\assertArrayHasKey; +use function PHPUnit\Framework\assertContains; +use function PHPUnit\Framework\assertContainsEquals; use function PHPUnit\Framework\assertContainsOnlyInstancesOf; use function PHPUnit\Framework\assertEmpty; use function PHPUnit\Framework\assertInstanceOf; @@ -61,6 +63,24 @@ public function testEmpty($a): void assertType("0|0.0|''|'0'|array{}|Countable|EmptyIterator|false|null", $a); } + public function contains(array $a, \Traversable $b): void + { + assertContains('foo', $a); + assertType('non-empty-array', $a); + + assertContains('foo', $b); + assertType('Traversable', $b); + } + + public function containsEquals(array $a, \Traversable $b): void + { + assertContainsEquals('foo', $a); + assertType('non-empty-array', $a); + + assertContainsEquals('foo', $b); + assertType('Traversable', $b); + } + public function containsOnlyInstancesOf(array $a, \Traversable $b): void { assertContainsOnlyInstancesOf(\stdClass::class, $a);