diff --git a/README.md b/README.md index 1321588..a17cf38 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ This extension specifies types of values passed to: * `Assert::notFalse` * `Assert::null` * `Assert::notNull` +* `Assert::eq` +* `Assert::notEq` * `Assert::same` * `Assert::notSame` * `Assert::greaterThan` diff --git a/composer.json b/composer.json index 78da0ae..8b1930a 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ ], "require": { "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^1.4.8" + "phpstan/phpstan": "^1.4.9" }, "require-dev": { "nikic/php-parser": "^4.13.0", diff --git a/src/Type/WebMozartAssert/AssertTypeSpecifyingExtension.php b/src/Type/WebMozartAssert/AssertTypeSpecifyingExtension.php index 6480d97..a2ff1ce 100644 --- a/src/Type/WebMozartAssert/AssertTypeSpecifyingExtension.php +++ b/src/Type/WebMozartAssert/AssertTypeSpecifyingExtension.php @@ -483,6 +483,15 @@ private static function getExpressionResolvers(): array new ConstFetch(new Name('null')) ); }, + 'eq' => static function (Scope $scope, Arg $value, Arg $value2): Expr { + return new Equal( + $value->value, + $value2->value + ); + }, + 'notEq' => static function (Scope $scope, Arg $value, Arg $value2): Expr { + return new BooleanNot(self::$resolvers['eq']($scope, $value, $value2)); + }, 'same' => static function (Scope $scope, Arg $value1, Arg $value2): Expr { return new Identical( $value1->value, diff --git a/tests/Type/WebMozartAssert/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/Type/WebMozartAssert/ImpossibleCheckTypeMethodCallRuleTest.php index de86487..440ebce 100644 --- a/tests/Type/WebMozartAssert/ImpossibleCheckTypeMethodCallRuleTest.php +++ b/tests/Type/WebMozartAssert/ImpossibleCheckTypeMethodCallRuleTest.php @@ -63,6 +63,84 @@ public function testExtension(): void ]); } + public function testEqNotEq(): void + { + $this->analyse([__DIR__ . '/data/impossible-check-eq-not-eq.php'], [ + [ + 'Call to static method Webmozart\Assert\Assert::eq() with stdClass and stdClass will always evaluate to true.', + 14, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with stdClass and stdClass will always evaluate to false.', + 15, + ], + /*[ + 'Call to static method Webmozart\Assert\Assert::eq() with 1 and \'1\' will always evaluate to true.', + 37, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with 1 and \'1\' will always evaluate to false.', + 38, + ],*/ + [ + 'Call to static method Webmozart\Assert\Assert::eq() with 1 and true will always evaluate to true.', + 39, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with 1 and true will always evaluate to false.', + 40, + ], + [ + 'Call to static method Webmozart\Assert\Assert::eq() with \'php\' and true will always evaluate to true.', + 41, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with \'php\' and true will always evaluate to false.', + 42, + ], + [ + 'Call to static method Webmozart\Assert\Assert::eq() with \'\' and false will always evaluate to true.', + 43, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with \'\' and false will always evaluate to false.', + 44, + ], + [ + 'Call to static method Webmozart\Assert\Assert::eq() with 1 and 1 will always evaluate to true.', + 46, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with 1 and 1 will always evaluate to false.', + 47, + ], + [ + 'Call to static method Webmozart\Assert\Assert::eq() with true and true will always evaluate to true.', + 48, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with true and true will always evaluate to false.', + 49, + ], + [ + 'Call to static method Webmozart\Assert\Assert::eq() with \'php\' and \'php\' will always evaluate to true.', + 50, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with \'php\' and \'php\' will always evaluate to false.', + 51, + ], + [ + 'Call to static method Webmozart\Assert\Assert::eq() with stdClass and null will always evaluate to false.', + 61, + ], + [ + 'Call to static method Webmozart\Assert\Assert::notEq() with stdClass and null will always evaluate to true.', + 62, + ], + ]); + } + public function testBug8(): void { $this->analyse([__DIR__ . '/data/bug-8.php'], [ diff --git a/tests/Type/WebMozartAssert/data/comparison.php b/tests/Type/WebMozartAssert/data/comparison.php index cc70a7f..afdafa9 100644 --- a/tests/Type/WebMozartAssert/data/comparison.php +++ b/tests/Type/WebMozartAssert/data/comparison.php @@ -43,6 +43,39 @@ public function notNull(?int $a): void \PHPStan\Testing\assertType('int', $a); } + /** + * @param non-empty-string $b2 + */ + public function eq(?bool $a, string $b1, string $b2, $c, ?bool $d): void + { + Assert::eq($a, null); + \PHPStan\Testing\assertType('false|null', $a); + + Assert::eq($b1, $b2); + \PHPStan\Testing\assertType('non-empty-string', $b1); + + Assert::eq($c, false); + \PHPStan\Testing\assertType('0|0.0|\'\'|\'0\'|array{}|false|null', $c); + + Assert::nullOrEq($d, true); + \PHPStan\Testing\assertType('true|null', $d); + } + + public function notEq(?bool $a, string $b, $c, ?bool $d): void + { + Assert::notEq($a, null); + \PHPStan\Testing\assertType('true', $a); + + Assert::notEq($b, ''); + \PHPStan\Testing\assertType('non-empty-string', $b); + + Assert::notEq($c, true); + \PHPStan\Testing\assertType('0|0.0|\'\'|\'0\'|array{}|false|null', $c); + + Assert::nullOrNotEq($d, true); + \PHPStan\Testing\assertType('false|null', $d); + } + public function same($a, $b): void { Assert::same($a, 1); diff --git a/tests/Type/WebMozartAssert/data/impossible-check-eq-not-eq.php b/tests/Type/WebMozartAssert/data/impossible-check-eq-not-eq.php new file mode 100644 index 0000000..553aa13 --- /dev/null +++ b/tests/Type/WebMozartAssert/data/impossible-check-eq-not-eq.php @@ -0,0 +1,70 @@ +