diff --git a/src/Framework/Constraint/Object/ObjectEquals.php b/src/Framework/Constraint/Object/ObjectEquals.php index 3a2a0e03fbb..9819c7afdd4 100644 --- a/src/Framework/Constraint/Object/ObjectEquals.php +++ b/src/Framework/Constraint/Object/ObjectEquals.php @@ -11,6 +11,12 @@ use function get_class; use function is_object; +use PHPUnit\Framework\ActualValueIsNotAnObjectException; +use PHPUnit\Framework\ComparisonMethodDoesNotAcceptParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareBoolReturnTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareExactlyOneParameterException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotExistException; use ReflectionNamedType; use ReflectionObject; @@ -19,20 +25,6 @@ */ final class ObjectEquals extends Constraint { - private const ACTUAL_IS_NOT_AN_OBJECT = 1; - - private const ACTUAL_DOES_NOT_HAVE_METHOD = 2; - - private const METHOD_DOES_NOT_HAVE_BOOL_RETURN_TYPE = 3; - - private const METHOD_DOES_NOT_ACCEPT_EXACTLY_ONE_ARGUMENT = 4; - - private const PARAMETER_DOES_NOT_HAVE_DECLARED_TYPE = 5; - - private const EXPECTED_NOT_COMPATIBLE_WITH_PARAMETER_TYPE = 6; - - private const OBJECTS_ARE_NOT_EQUAL_ACCORDING_TO_METHOD = 7; - /** * @var object */ @@ -43,11 +35,6 @@ final class ObjectEquals extends Constraint */ private $method; - /** - * @var int - */ - private $failureReason; - public function __construct(object $object, string $method = 'equals') { $this->expected = $object; @@ -59,71 +46,85 @@ public function toString(): string return 'two objects are equal'; } + /** + * @throws ActualValueIsNotAnObjectException + * @throws ComparisonMethodDoesNotExistException + * @throws ComparisonMethodDoesNotDeclareBoolReturnTypeException + * @throws ComparisonMethodDoesNotDeclareExactlyOneParameterException + * @throws ComparisonMethodDoesNotDeclareParameterTypeException + * @throws ComparisonMethodDoesNotAcceptParameterTypeException + */ protected function matches($other): bool { if (!is_object($other)) { - $this->failureReason = self::ACTUAL_IS_NOT_AN_OBJECT; - - return false; + throw new ActualValueIsNotAnObjectException; } $object = new ReflectionObject($other); if (!$object->hasMethod($this->method)) { - $this->failureReason = self::ACTUAL_DOES_NOT_HAVE_METHOD; - - return false; + throw new ComparisonMethodDoesNotExistException( + get_class($other), + $this->method + ); } /** @noinspection PhpUnhandledExceptionInspection */ $method = $object->getMethod($this->method); if (!$method->hasReturnType()) { - $this->failureReason = self::METHOD_DOES_NOT_HAVE_BOOL_RETURN_TYPE; - - return false; + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + get_class($other), + $this->method + ); } $returnType = $method->getReturnType(); if (!$returnType instanceof ReflectionNamedType) { - $this->failureReason = self::METHOD_DOES_NOT_HAVE_BOOL_RETURN_TYPE; - - return false; + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + get_class($other), + $this->method + ); } if ($returnType->allowsNull()) { - $this->failureReason = self::METHOD_DOES_NOT_HAVE_BOOL_RETURN_TYPE; - - return false; + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + get_class($other), + $this->method + ); } if ($returnType->getName() !== 'bool') { - $this->failureReason = self::METHOD_DOES_NOT_HAVE_BOOL_RETURN_TYPE; - - return false; + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + get_class($other), + $this->method + ); } if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) { - $this->failureReason = self::METHOD_DOES_NOT_ACCEPT_EXACTLY_ONE_ARGUMENT; - - return false; + throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException( + get_class($other), + $this->method + ); } $parameter = $method->getParameters()[0]; if (!$parameter->hasType()) { - $this->failureReason = self::PARAMETER_DOES_NOT_HAVE_DECLARED_TYPE; - - return false; + throw new ComparisonMethodDoesNotDeclareParameterTypeException( + get_class($other), + $this->method + ); } $type = $parameter->getType(); if (!$type instanceof ReflectionNamedType) { - $this->failureReason = self::PARAMETER_DOES_NOT_HAVE_DECLARED_TYPE; - - return false; + throw new ComparisonMethodDoesNotDeclareParameterTypeException( + get_class($other), + $this->method + ); } $typeName = $type->getName(); @@ -133,73 +134,18 @@ protected function matches($other): bool } if (!$this->expected instanceof $typeName) { - $this->failureReason = self::EXPECTED_NOT_COMPATIBLE_WITH_PARAMETER_TYPE; - - return false; + throw new ComparisonMethodDoesNotAcceptParameterTypeException( + get_class($other), + $this->method, + get_class($this->expected) + ); } - if ($other->{$this->method}($this->expected)) { - return true; - } - - $this->failureReason = self::OBJECTS_ARE_NOT_EQUAL_ACCORDING_TO_METHOD; - - return false; + return $other->{$this->method}($this->expected); } protected function failureDescription($other): string { return $this->toString(); } - - protected function additionalFailureDescription($other): string - { - switch ($this->failureReason) { - case self::ACTUAL_IS_NOT_AN_OBJECT: - return 'Actual value is not an object.'; - - case self::ACTUAL_DOES_NOT_HAVE_METHOD: - return sprintf( - '%s::%s() does not exist.', - get_class($other), - $this->method - ); - - case self::METHOD_DOES_NOT_HAVE_BOOL_RETURN_TYPE: - return sprintf( - '%s::%s() does not declare a bool return type.', - get_class($other), - $this->method - ); - - case self::METHOD_DOES_NOT_ACCEPT_EXACTLY_ONE_ARGUMENT: - return sprintf( - '%s::%s() does not accept exactly one argument.', - get_class($other), - $this->method - ); - - case self::PARAMETER_DOES_NOT_HAVE_DECLARED_TYPE: - return sprintf( - 'Parameter of %s::%s() does not have a declared type.', - get_class($other), - $this->method - ); - - case self::EXPECTED_NOT_COMPATIBLE_WITH_PARAMETER_TYPE: - return sprintf( - '%s is not accepted an accepted argument type for %s::%s().', - get_class($this->expected), - get_class($other), - $this->method - ); - - default: - return sprintf( - 'The objects are not equal according to %s::%s().', - get_class($other), - $this->method - ); - } - } } diff --git a/src/Framework/Exception/ActualValueIsNotAnObjectException.php b/src/Framework/Exception/ActualValueIsNotAnObjectException.php new file mode 100644 index 00000000000..adae2829439 --- /dev/null +++ b/src/Framework/Exception/ActualValueIsNotAnObjectException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ActualValueIsNotAnObjectException extends Exception +{ + public function __construct() + { + parent::__construct( + 'Actual value is not an object', + 0, + null + ); + } + + public function __toString(): string + { + return $this->getMessage() . PHP_EOL; + } +} diff --git a/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php b/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php new file mode 100644 index 00000000000..ebd68f34c8e --- /dev/null +++ b/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function sprintf; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotAcceptParameterTypeException extends Exception +{ + public function __construct(string $className, string $methodName, string $type) + { + parent::__construct( + sprintf( + '%s is not an accepted argument type for comparison method %s::%s().', + $type, + $className, + $methodName + ), + 0, + null + ); + } + + public function __toString(): string + { + return $this->getMessage() . PHP_EOL; + } +} diff --git a/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php b/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php new file mode 100644 index 00000000000..20189cde4de --- /dev/null +++ b/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function sprintf; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareBoolReturnTypeException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Comparison method %s::%s() does not declare bool return type.', + $className, + $methodName + ), + 0, + null + ); + } + + public function __toString(): string + { + return $this->getMessage() . PHP_EOL; + } +} diff --git a/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php b/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php new file mode 100644 index 00000000000..bd09d87ccf1 --- /dev/null +++ b/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function sprintf; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareExactlyOneParameterException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Comparison method %s::%s() does not declare exactly one parameter.', + $className, + $methodName + ), + 0, + null + ); + } + + public function __toString(): string + { + return $this->getMessage() . PHP_EOL; + } +} diff --git a/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php b/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php new file mode 100644 index 00000000000..9bbb112eaf5 --- /dev/null +++ b/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function sprintf; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareParameterTypeException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Parameter of comparison method %s::%s() does not have a declared type.', + $className, + $methodName + ), + 0, + null + ); + } + + public function __toString(): string + { + return $this->getMessage() . PHP_EOL; + } +} diff --git a/src/Framework/Exception/ComparisonMethodDoesNotExistException.php b/src/Framework/Exception/ComparisonMethodDoesNotExistException.php new file mode 100644 index 00000000000..ad0e2d08895 --- /dev/null +++ b/src/Framework/Exception/ComparisonMethodDoesNotExistException.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function sprintf; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotExistException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Comparison method %s::%s() does not exist.', + $className, + $methodName + ), + 0, + null + ); + } + + public function __toString(): string + { + return $this->getMessage() . PHP_EOL; + } +} diff --git a/tests/unit/Framework/Constraint/ObjectEqualsTest.php b/tests/unit/Framework/Constraint/ObjectEqualsTest.php index 3f3388d8416..62b6a6a5f6c 100644 --- a/tests/unit/Framework/Constraint/ObjectEqualsTest.php +++ b/tests/unit/Framework/Constraint/ObjectEqualsTest.php @@ -9,6 +9,12 @@ */ namespace PHPUnit\Framework\Constraint; +use PHPUnit\Framework\ActualValueIsNotAnObjectException; +use PHPUnit\Framework\ComparisonMethodDoesNotAcceptParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareBoolReturnTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareExactlyOneParameterException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotExistException; use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; use PHPUnit\TestFixture\ObjectEquals\ValueObject; @@ -37,21 +43,24 @@ public function testAcceptsActualObjectWhenMethodSaysTheyAreEqual(): void public function testRejectsActualValueThatIsNotAnObject(): void { - $this->expectFailure('Actual value is not an object.'); + $this->expectException(ActualValueIsNotAnObjectException::class); + $this->expectExceptionMessage('Actual value is not an object'); (new ObjectEquals(new ValueObject(1)))->evaluate(null); } public function testRejectsActualObjectThatDoesNotHaveTheSpecifiedMethod(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithoutEqualsMethod::equals() does not exist.'); + $this->expectException(ComparisonMethodDoesNotExistException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithoutEqualsMethod::equals() does not exist.'); (new ObjectEquals(new ValueObjectWithoutEqualsMethod(1)))->evaluate(new ValueObjectWithoutEqualsMethod(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsNotDeclaredToReturnBool(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithoutReturnType::equals() does not declare a bool return type.'); + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithoutReturnType::equals() does not declare bool return type.'); (new ObjectEquals(new ValueObjectWithEqualsMethodWithoutReturnType(1)))->evaluate(new ValueObjectWithEqualsMethodWithoutReturnType(1)); } @@ -61,42 +70,48 @@ public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsNotDecla */ public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsDeclaredToReturnUnion(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithUnionReturnType::equals() does not declare a bool return type.'); + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithUnionReturnType::equals() does not declare bool return type.'); (new ObjectEquals(new ValueObjectWithEqualsMethodWithUnionReturnType(1)))->evaluate(new ValueObjectWithEqualsMethodWithUnionReturnType(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsDeclaredVoid(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithVoidReturnType::equals() does not declare a bool return type.'); + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithVoidReturnType::equals() does not declare bool return type.'); (new ObjectEquals(new ValueObjectWithEqualsMethodWithVoidReturnType(1)))->evaluate(new ValueObjectWithEqualsMethodWithVoidReturnType(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsDeclaredNullable(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithNullableReturnType::equals() does not declare a bool return type.'); + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithNullableReturnType::equals() does not declare bool return type.'); (new ObjectEquals(new ValueObjectWithEqualsMethodWithNullableReturnType(1)))->evaluate(new ValueObjectWithEqualsMethodWithNullableReturnType(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodDoesNotAcceptArguments(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotAcceptArguments::equals() does not accept exactly one argument.'); + $this->expectException(ComparisonMethodDoesNotDeclareExactlyOneParameterException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotAcceptArguments::equals() does not declare exactly one parameter.'); (new ObjectEquals(new ValueObjectWithEqualsMethodThatDoesNotAcceptArguments(1)))->evaluate(new ValueObjectWithEqualsMethodThatDoesNotAcceptArguments(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodAcceptsTooManyArguments(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatAcceptsTooManyArguments::equals() does not accept exactly one argument.'); + $this->expectException(ComparisonMethodDoesNotDeclareExactlyOneParameterException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatAcceptsTooManyArguments::equals() does not declare exactly one parameter.'); (new ObjectEquals(new ValueObjectWithEqualsMethodThatAcceptsTooManyArguments(1)))->evaluate(new ValueObjectWithEqualsMethodThatAcceptsTooManyArguments(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodDoesNotDeclareParameterType(): void { - $this->expectFailure('Parameter of PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType::equals() does not have a declared type.'); + $this->expectException(ComparisonMethodDoesNotDeclareParameterTypeException::class); + $this->expectExceptionMessage('Parameter of comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType::equals() does not have a declared type.'); (new ObjectEquals(new ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType(1)))->evaluate(new ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType(1)); } @@ -106,28 +121,25 @@ public function testRejectsActualObjectWhenTheSpecifiedMethodDoesNotDeclareParam */ public function testRejectsActualObjectWhenTheSpecifiedMethodHasUnionParameterType(): void { - $this->expectFailure('Parameter of PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasUnionParameterType::equals() does not have a declared type.'); + $this->expectException(ComparisonMethodDoesNotDeclareParameterTypeException::class); + $this->expectExceptionMessage('Parameter of comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasUnionParameterType::equals() does not have a declared type.'); (new ObjectEquals(new ValueObjectWithEqualsMethodThatHasUnionParameterType(1)))->evaluate(new ValueObjectWithEqualsMethodThatHasUnionParameterType(1)); } public function testRejectsActualObjectWhenTheSpecifiedMethodHasIncompatibleParameterType(): void { - $this->expectFailure('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType is not accepted an accepted argument type for PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType::equals().'); + $this->expectException(ComparisonMethodDoesNotAcceptParameterTypeException::class); + $this->expectExceptionMessage('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType is not an accepted argument type for comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType::equals().'); (new ObjectEquals(new ValueObjectWithEqualsMethodThatHasIncompatibleParameterType(1)))->evaluate(new ValueObjectWithEqualsMethodThatHasIncompatibleParameterType(1)); } public function testRejectsActualObjectWhenMethodSaysTheyAreNotEqual(): void { - $this->expectFailure('The objects are not equal according to PHPUnit\TestFixture\ObjectEquals\ValueObject::equals().'); + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage('Failed asserting that two objects are equal.'); (new ObjectEquals(new ValueObject(1)))->evaluate(new ValueObject(2)); } - - private function expectFailure(string $message): void - { - $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage('Failed asserting that two objects are equal.' . "\n" . $message); - } }