diff --git a/analyzer-baseline.toml b/analyzer-baseline.toml index 7c072fde..44167033 100644 --- a/analyzer-baseline.toml +++ b/analyzer-baseline.toml @@ -3819,7 +3819,7 @@ count = 1 [[issues]] file = "src/Sql/Join.php" code = "mixed-argument" -message = "Invalid argument type for argument #2 of `sprintf`: expected `Stringable|null|scalar`, but found `mixed`." +message = "Invalid argument type for argument #1 of `PhpDb\\Sql\\Exception\\InvalidArgumentException::forInvalidJoinName`: expected `string`, but found `mixed`." count = 1 [[issues]] @@ -4917,7 +4917,7 @@ count = 1 [[issues]] file = "src/Sql/Sql.php" code = "possibly-invalid-argument" -message = 'Possible argument type mismatch for argument #2 of `sprintf`: expected `Stringable|null|scalar`, but possibly received `PhpDb\Sql\TableIdentifier|array|string`.' +message = 'Possible argument type mismatch for argument #1 of `PhpDb\Sql\Exception\InvalidArgumentException::forForeignTable`: expected `string`, but possibly received `PhpDb\Sql\TableIdentifier|array|string`.' count = 4 [[issues]] @@ -5537,3 +5537,21 @@ file = "src/TableGateway/TableGatewayInterface.php" code = "missing-api-or-internal" message = 'Interface `PhpDb\TableGateway\TableGatewayInterface` is missing an `@api` or `@internal` annotation.' count = 1 + +[[issues]] +file = "src/Sql/Predicate/Exception/ExceptionInterface.php" +code = "missing-api-or-internal" +message = 'Interface `PhpDb\Sql\Predicate\Exception\ExceptionInterface` is missing an `@api` or `@internal` annotation.' +count = 1 + +[[issues]] +file = "src/Sql/Predicate/Exception/InvalidArgumentException.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Sql\Predicate\Exception\InvalidArgumentException` should be declared `final`.' +count = 1 + +[[issues]] +file = "src/Sql/Predicate/Exception/RuntimeException.php" +code = "class-must-be-final" +message = 'Class `PhpDb\Sql\Predicate\Exception\RuntimeException` should be declared `final`.' +count = 1 diff --git a/lint-baseline.toml b/lint-baseline.toml index f4f30de4..4fca9308 100644 --- a/lint-baseline.toml +++ b/lint-baseline.toml @@ -838,7 +838,7 @@ count = 1 file = "src/Sql/Select.php" code = "halstead" message = "Method has a high halstead difficulty" -count = 1 +count = 2 [[issues]] file = "src/Sql/Select.php" @@ -8471,3 +8471,14 @@ file = "test/unit/TableGateway/TableGatewayTest.php" code = "strict-assertions" message = "Use strict assertions in PHPUnit tests." count = 2 +[[issues]] +file = "src/Sql/AbstractSql.php" +code = "halstead" +message = "Method has a high halstead difficulty" +count = 1 + +[[issues]] +file = "src/Sql/Ddl/Column/AbstractPrecisionColumn.php" +code = "halstead" +message = "Method has a high halstead difficulty" +count = 1 diff --git a/mago.toml b/mago.toml index 5ef92248..eca8c95f 100644 --- a/mago.toml +++ b/mago.toml @@ -11,6 +11,13 @@ parentheses-around-new-in-member-access = true [linter] baseline = "lint-baseline.toml" +[linter.rules] +# Exception classes are message catalogues: one template and one named constructor per +# condition, per the convention in docs/book/exceptions.md. The method count tracks the +# number of distinct failures a component can report, so the maintainability signal does +# not apply. "test/" repeats the phpdb-qa-tools default, which this key replaces. +too-many-methods = { exclude = ["test/", "src/Sql/Exception/"] } + [analyzer] baseline = "analyzer-baseline.toml" class-initializers = [ diff --git a/src/Sql/AbstractSql.php b/src/Sql/AbstractSql.php index 7c9140da..b5e818d8 100644 --- a/src/Sql/AbstractSql.php +++ b/src/Sql/AbstractSql.php @@ -16,7 +16,6 @@ use PhpDb\Sql\Argument\Value; use PhpDb\Sql\Argument\Values; use PhpDb\Sql\Platform\PlatformDecoratorInterface; -use ValueError; use function count; use function current; @@ -26,7 +25,6 @@ use function is_string; use function key; use function rtrim; -use function sprintf; use function str_replace; use function strtoupper; use function vsprintf; @@ -108,9 +106,7 @@ protected function createSqlFromSpecificationAndParameters(array|string $specifi } if (! isset($specificationString)) { - throw new Exception\RuntimeException( - 'A number of parameters was found that is not supported by this specification', - ); + throw Exception\RuntimeException::forUnsupportedParameterCount(); } $topParameters = []; @@ -126,10 +122,7 @@ protected function createSqlFromSpecificationAndParameters(array|string $specifi } if (! isset($paramSpecs[$position][$ppCount])) { - throw new Exception\RuntimeException(sprintf( - 'A number of parameters (%d) was found that is not supported by this specification', - $ppCount, - )); + throw Exception\RuntimeException::forUnsupportedParameterCountOf($ppCount); } $multiParamValues[] = vsprintf($paramSpecs[$position][$ppCount], $multiParamsForPosition); @@ -139,10 +132,7 @@ protected function createSqlFromSpecificationAndParameters(array|string $specifi } elseif (null !== $paramSpecs[$position]) { $ppCount = count($paramsForPosition); if (! isset($paramSpecs[$position][$ppCount])) { - throw new Exception\RuntimeException(sprintf( - 'A number of parameters (%d) was found that is not supported by this specification', - $ppCount, - )); + throw Exception\RuntimeException::forUnsupportedParameterCountOf($ppCount); } $topParameters[] = vsprintf($paramSpecs[$position][$ppCount], $paramsForPosition); @@ -261,7 +251,7 @@ protected function processExpression( $driver, $parameterContainer, ), - default => throw new Exception\InvalidArgumentException('Unknown argument type'), + default => throw Exception\InvalidArgumentException::forUnknownArgumentType(), }; } @@ -287,7 +277,7 @@ protected function processExpressionOrSelect( $parameterContainer, "{$namedParameterPrefix}{$vIndex}subpart", ), - default => throw new ValueError('Invalid Argument type'), + default => throw Exception\InvalidArgumentException::forInvalidArgumentType(), }; } diff --git a/src/Sql/Ddl/Column/AbstractLengthColumn.php b/src/Sql/Ddl/Column/AbstractLengthColumn.php index eae34660..abc4e19a 100644 --- a/src/Sql/Ddl/Column/AbstractLengthColumn.php +++ b/src/Sql/Ddl/Column/AbstractLengthColumn.php @@ -9,7 +9,6 @@ use PhpDb\Sql\Exception\InvalidArgumentException; use function array_splice; -use function sprintf; use function strlen; use function substr; @@ -48,11 +47,7 @@ public function getExpressionData(): array $hasLength = '' !== $lengthExpression && '0' !== $lengthExpression; if (! $hasLength && $this->lengthRequired) { - throw new InvalidArgumentException(sprintf( - 'Column "%s" of type %s requires a length', - $this->name, - $this->type, - )); + throw InvalidArgumentException::forMissingColumnLength($this->name, $this->type); } $expressionData = parent::getExpressionData(); diff --git a/src/Sql/Ddl/Column/AbstractPrecisionColumn.php b/src/Sql/Ddl/Column/AbstractPrecisionColumn.php index 5d37f29b..744ad4fd 100644 --- a/src/Sql/Ddl/Column/AbstractPrecisionColumn.php +++ b/src/Sql/Ddl/Column/AbstractPrecisionColumn.php @@ -7,8 +7,6 @@ use Override; use PhpDb\Sql\Exception\InvalidArgumentException; -use function sprintf; - abstract class AbstractPrecisionColumn extends AbstractLengthColumn { protected ?int $decimal; @@ -59,11 +57,7 @@ protected function getLengthExpression(): string } if (null === $this->length) { - throw new InvalidArgumentException(sprintf( - 'Column "%s" of type %s has a decimal scale but no digits', - $this->name, - $this->type, - )); + throw InvalidArgumentException::forMissingDecimalDigits($this->name, $this->type); } return "{$this->length},{$this->decimal}"; diff --git a/src/Sql/Ddl/Column/Integer.php b/src/Sql/Ddl/Column/Integer.php index c816d4e6..9a8d50e9 100644 --- a/src/Sql/Ddl/Column/Integer.php +++ b/src/Sql/Ddl/Column/Integer.php @@ -12,7 +12,6 @@ use function ctype_digit; use function is_int; use function is_string; -use function sprintf; use function strlen; use function substr; @@ -57,9 +56,6 @@ private function normaliseDisplayWidth(mixed $length): string return $length; } - throw new InvalidArgumentException(sprintf( - 'Column "%s" length option must be a non-negative integer', - $this->name, - )); + throw InvalidArgumentException::forInvalidColumnLength($this->name); } } diff --git a/src/Sql/Ddl/Constraint/Check.php b/src/Sql/Ddl/Constraint/Check.php index 1490d197..31a9d962 100644 --- a/src/Sql/Ddl/Constraint/Check.php +++ b/src/Sql/Ddl/Constraint/Check.php @@ -28,7 +28,7 @@ class Check extends AbstractConstraint public function __construct(string|ExpressionInterface $expression, ?string $name = null) { if ('' === $expression) { - throw new InvalidArgumentException('Check constraint expression must not be an empty string.'); + throw InvalidArgumentException::forEmptyCheckExpression(); } parent::__construct(null, $name); diff --git a/src/Sql/Exception/InvalidArgumentException.php b/src/Sql/Exception/InvalidArgumentException.php index ebd13288..14b7f39f 100644 --- a/src/Sql/Exception/InvalidArgumentException.php +++ b/src/Sql/Exception/InvalidArgumentException.php @@ -6,4 +6,193 @@ use PhpDb\Exception; -class InvalidArgumentException extends Exception\InvalidArgumentException {} +use function sprintf; + +class InvalidArgumentException extends Exception\InvalidArgumentException +{ + final public const string ALREADY_COMBINED = + 'This Select object is already combined' + . ' and cannot be combined with multiple Selects objects'; + + final public const string EMPTY_CHECK_EXPRESSION = + 'Check constraint expression must not be' + . ' an empty string.'; + + final public const string EMPTY_EXPRESSION = 'Supplied expression must not be an empty string.'; + + final public const string EMPTY_PREFIX = '$prefix must be a valid table prefix or null, empty string given'; + + final public const string EMPTY_SCHEMA = '$schema must be a valid schema name or null, empty string given'; + + final public const string EMPTY_SEPARATOR = '$separator must be a valid table separator, empty string given'; + + final public const string EMPTY_TABLE = '$table must be a valid table name, empty string given'; + + final public const string FOREIGN_TABLE = + 'This Sql object is intended to work with only the table "%s"' + . ' provided at construction time.'; + + final public const string INVALID_ARGUMENT_TYPE = 'Invalid Argument type'; + + final public const string INVALID_COLUMN_LENGTH = + 'Column "%s" length option must be' + . ' a non-negative integer'; + + final public const string INVALID_FROM_ARRAY = + 'from() expects $table as an array' + . ' is a single element associative array'; + + final public const string INVALID_JOIN_NAME = "join() expects '%s' as a single element associative array"; + + final public const string INVALID_MAGIC_PROPERTY = 'Not a valid magic property for this object'; + + final public const string INVALID_SPECIFICATION_NAME = 'Not a valid specification name.'; + + final public const string MISSING_COLUMN_LENGTH = 'Column "%s" of type %s requires a length'; + + final public const string MISSING_DECIMAL_DIGITS = + 'Column "%s" of type %s has a decimal scale' + . ' but no digits'; + + final public const string MISSING_VALUES_OR_SELECT = 'values or select should be present'; + + final public const string NON_NUMERIC_PARAMETER = '%s expects parameter to be numeric, "%s" given'; + + final public const string NON_STRING_VALUE_KEY = 'set() expects a string for the value key'; + + final public const string READ_ONLY_CONSTRUCTOR_STATE = + 'Since this object was created with a table' + . ' and/or schema in the constructor, it is read only.'; + + final public const string SELECT_WITH_MERGE_FLAG = + 'A PhpDb\Sql\Select instance cannot be provided' + . ' with the merge flag'; + + final public const string UNKNOWN_ARGUMENT_TYPE = 'Unknown argument type'; + + final public const string UNKNOWN_COLUMN_KEY = 'The key %s was not found in this objects column list'; + + final public const string VALUES_WITH_MERGE_FLAG = + 'An array of values cannot be provided with the merge flag' + . ' when a PhpDb\Sql\Select instance already exists as the value source'; + + public static function forAlreadyCombined(): self + { + return new self(self::ALREADY_COMBINED); + } + + public static function forEmptyCheckExpression(): self + { + return new self(self::EMPTY_CHECK_EXPRESSION); + } + + public static function forEmptyExpression(): self + { + return new self(self::EMPTY_EXPRESSION); + } + + public static function forEmptyPrefix(): self + { + return new self(self::EMPTY_PREFIX); + } + + public static function forEmptySchema(): self + { + return new self(self::EMPTY_SCHEMA); + } + + public static function forEmptySeparator(): self + { + return new self(self::EMPTY_SEPARATOR); + } + + public static function forEmptyTable(): self + { + return new self(self::EMPTY_TABLE); + } + + public static function forForeignTable(string $table): self + { + return new self(sprintf(self::FOREIGN_TABLE, $table)); + } + + public static function forInvalidArgumentType(): self + { + return new self(self::INVALID_ARGUMENT_TYPE); + } + + public static function forInvalidColumnLength(string $name): self + { + return new self(sprintf(self::INVALID_COLUMN_LENGTH, $name)); + } + + public static function forInvalidFromArray(): self + { + return new self(self::INVALID_FROM_ARRAY); + } + + public static function forInvalidJoinName(string $name): self + { + return new self(sprintf(self::INVALID_JOIN_NAME, $name)); + } + + public static function forInvalidMagicProperty(): self + { + return new self(self::INVALID_MAGIC_PROPERTY); + } + + public static function forInvalidSpecificationName(): self + { + return new self(self::INVALID_SPECIFICATION_NAME); + } + + public static function forMissingColumnLength(string $name, string $type): self + { + return new self(sprintf(self::MISSING_COLUMN_LENGTH, $name, $type)); + } + + public static function forMissingDecimalDigits(string $name, string $type): self + { + return new self(sprintf(self::MISSING_DECIMAL_DIGITS, $name, $type)); + } + + public static function forMissingValuesOrSelect(): self + { + return new self(self::MISSING_VALUES_OR_SELECT); + } + + public static function forNonNumericParameter(string $method, string $givenType): self + { + return new self(sprintf(self::NON_NUMERIC_PARAMETER, $method, $givenType)); + } + + public static function forNonStringValueKey(): self + { + return new self(self::NON_STRING_VALUE_KEY); + } + + public static function forReadOnlyConstructorState(): self + { + return new self(self::READ_ONLY_CONSTRUCTOR_STATE); + } + + public static function forSelectWithMergeFlag(): self + { + return new self(self::SELECT_WITH_MERGE_FLAG); + } + + public static function forUnknownArgumentType(): self + { + return new self(self::UNKNOWN_ARGUMENT_TYPE); + } + + public static function forUnknownColumnKey(string $name): self + { + return new self(sprintf(self::UNKNOWN_COLUMN_KEY, $name)); + } + + public static function forValuesWithMergeFlag(): self + { + return new self(self::VALUES_WITH_MERGE_FLAG); + } +} diff --git a/src/Sql/Exception/RuntimeException.php b/src/Sql/Exception/RuntimeException.php index 382a34e9..bb9e184e 100644 --- a/src/Sql/Exception/RuntimeException.php +++ b/src/Sql/Exception/RuntimeException.php @@ -6,4 +6,59 @@ use PhpDb\Exception; -class RuntimeException extends Exception\RuntimeException {} +use function sprintf; + +class RuntimeException extends Exception\RuntimeException +{ + final public const string REPLACEMENT_MISMATCH = + 'The number of replacements in the expression' + . ' does not match the number of parameters'; + + final public const string SUBJECT_NOT_IMPLEMENTING = + 'The subject does not appear to implement %s,' + . ' thus calling %s has no effect'; + + final public const string SUBJECT_NOT_PREPARABLE_SQL_INTERFACE = + 'The subject does not implement' + . ' PreparableSqlInterface'; + + final public const string SUBJECT_NOT_SQL_INTERFACE = 'The subject does not implement SqlInterface'; + + final public const string UNSUPPORTED_PARAMETER_COUNT = + 'A number of parameters was found' + . ' that is not supported by this specification'; + + final public const string UNSUPPORTED_PARAMETER_COUNT_OF = + 'A number of parameters (%d) was found' + . ' that is not supported by this specification'; + + public static function forReplacementMismatch(): self + { + return new self(self::REPLACEMENT_MISMATCH); + } + + public static function forSubjectNotImplementing(string $interface, string $method): self + { + return new self(sprintf(self::SUBJECT_NOT_IMPLEMENTING, $interface, $method)); + } + + public static function forSubjectNotPreparableSqlInterface(): self + { + return new self(self::SUBJECT_NOT_PREPARABLE_SQL_INTERFACE); + } + + public static function forSubjectNotSqlInterface(): self + { + return new self(self::SUBJECT_NOT_SQL_INTERFACE); + } + + public static function forUnsupportedParameterCount(): self + { + return new self(self::UNSUPPORTED_PARAMETER_COUNT); + } + + public static function forUnsupportedParameterCountOf(int $count): self + { + return new self(sprintf(self::UNSUPPORTED_PARAMETER_COUNT_OF, $count)); + } +} diff --git a/src/Sql/Expression.php b/src/Sql/Expression.php index 1c96c1d3..f89e3c79 100644 --- a/src/Sql/Expression.php +++ b/src/Sql/Expression.php @@ -84,9 +84,7 @@ public function getExpressionData(): array if ($count !== $parametersCount) { preg_match_all('/:\w*/', $specification, $matches); if (count(array_unique($matches[0])) !== $parametersCount) { - throw new Exception\RuntimeException( - 'The number of replacements in the expression does not match the number of parameters', - ); + throw Exception\RuntimeException::forReplacementMismatch(); } } @@ -107,7 +105,7 @@ public function getParameters(): array public function setExpression(string $expression): self { if ('' === $expression) { - throw new Exception\InvalidArgumentException('Supplied expression must not be an empty string.'); + throw Exception\InvalidArgumentException::forEmptyExpression(); } $this->expression = $expression; diff --git a/src/Sql/Insert.php b/src/Sql/Insert.php index 1d39afdb..46f67ff4 100644 --- a/src/Sql/Insert.php +++ b/src/Sql/Insert.php @@ -107,9 +107,7 @@ public function values(array|Select $values, string $flag = self::VALUES_SET): s { if ($values instanceof Select) { if (self::VALUES_MERGE === $flag) { - throw new Exception\InvalidArgumentException( - 'A PhpDb\Sql\Select instance cannot be provided with the merge flag', - ); + throw Exception\InvalidArgumentException::forSelectWithMergeFlag(); } $this->select = $values; @@ -117,10 +115,7 @@ public function values(array|Select $values, string $flag = self::VALUES_SET): s } if (null !== $this->select && self::VALUES_MERGE === $flag) { - throw new Exception\InvalidArgumentException( - 'An array of values cannot be provided with the merge flag when a PhpDb\Sql\Select' - . ' instance already exists as the value source', - ); + throw Exception\InvalidArgumentException::forValuesWithMergeFlag(); } if (self::VALUES_SET === $flag) { @@ -146,7 +141,7 @@ protected function processInsert( } if (! $this->columns) { - throw new Exception\InvalidArgumentException('values or select should be present'); + throw Exception\InvalidArgumentException::forMissingValuesOrSelect(); } $columns = []; @@ -231,9 +226,7 @@ private function isAssocativeArray(array $array): bool public function __get(string $name): mixed { if (! array_key_exists($name, $this->columns)) { - throw new Exception\InvalidArgumentException( - "The key {$name} was not found in this objects column list", - ); + throw Exception\InvalidArgumentException::forUnknownColumnKey($name); } return $this->columns[$name]; @@ -272,9 +265,7 @@ public function __set(string $name, mixed $value): void public function __unset(string $name) { if (! array_key_exists($name, $this->columns)) { - throw new Exception\InvalidArgumentException( - "The key {$name} was not found in this objects column list", - ); + throw Exception\InvalidArgumentException::forUnknownColumnKey($name); } unset($this->columns[$name]); diff --git a/src/Sql/Join.php b/src/Sql/Join.php index 84cca012..c4bba6d3 100644 --- a/src/Sql/Join.php +++ b/src/Sql/Join.php @@ -14,7 +14,6 @@ use function is_array; use function is_string; use function key; -use function sprintf; /** * Aggregate JOIN specifications. @@ -95,9 +94,7 @@ public function join( string $type = self::JOIN_INNER, ): static { if (is_array($name) && (! is_string(key($name)) || count($name) !== 1)) { - throw new Exception\InvalidArgumentException( - sprintf("join() expects '%s' as a single element associative array", array_shift($name)), - ); + throw Exception\InvalidArgumentException::forInvalidJoinName(array_shift($name)); } if (! is_array($columns)) { diff --git a/src/Sql/Platform/AbstractPlatform.php b/src/Sql/Platform/AbstractPlatform.php index 5aee9708..20b6ac48 100644 --- a/src/Sql/Platform/AbstractPlatform.php +++ b/src/Sql/Platform/AbstractPlatform.php @@ -35,10 +35,7 @@ public function getDecorators(): array public function getSqlString(?PlatformInterface $adapterPlatform = null): string { if (! $this->subject instanceof SqlInterface) { - throw new Exception\RuntimeException( - 'The subject does not appear to implement PhpDb\Sql\SqlInterface, thus calling ' - . 'getSqlString() has no effect', - ); + throw Exception\RuntimeException::forSubjectNotImplementing(SqlInterface::class, 'getSqlString()'); } return $this->getTypeDecorator($this->subject)->getSqlString($adapterPlatform); @@ -69,9 +66,9 @@ public function prepareStatement( StatementContainerInterface $statementContainer, ): StatementContainerInterface { if (! $this->subject instanceof PreparableSqlInterface) { - throw new Exception\RuntimeException( - 'The subject does not appear to implement PhpDb\Sql\PreparableSqlInterface, thus calling ' - . 'prepareStatement() has no effect', + throw Exception\RuntimeException::forSubjectNotImplementing( + PreparableSqlInterface::class, + 'prepareStatement()', ); } diff --git a/src/Sql/Platform/Platform.php b/src/Sql/Platform/Platform.php index 1c073d59..abadd243 100644 --- a/src/Sql/Platform/Platform.php +++ b/src/Sql/Platform/Platform.php @@ -62,10 +62,7 @@ public function getDecorators(): array public function getSqlString(?PlatformInterface $adapterPlatform = null): string { if (! $this->subject instanceof SqlInterface) { - throw new Exception\RuntimeException( - 'The subject does not appear to implement PhpDb\Sql\SqlInterface, thus calling ' - . 'prepareStatement() has no effect', - ); + throw Exception\RuntimeException::forSubjectNotImplementing(SqlInterface::class, 'getSqlString()'); } $adapterPlatform = $this->resolvePlatform($adapterPlatform); @@ -115,9 +112,9 @@ public function prepareStatement( StatementContainerInterface $statementContainer, ): StatementContainerInterface { if (! $this->subject instanceof PreparableSqlInterface) { - throw new Exception\RuntimeException( - 'The subject does not appear to implement PhpDb\Sql\PreparableSqlInterface, thus calling ' - . 'prepareStatement() has no effect', + throw Exception\RuntimeException::forSubjectNotImplementing( + PreparableSqlInterface::class, + 'prepareStatement()', ); } diff --git a/src/Sql/Predicate/Between.php b/src/Sql/Predicate/Between.php index c7f0b097..138e9154 100644 --- a/src/Sql/Predicate/Between.php +++ b/src/Sql/Predicate/Between.php @@ -4,12 +4,12 @@ namespace PhpDb\Sql\Predicate; -use LogicException; use Override; use PhpDb\Sql\AbstractExpression; use PhpDb\Sql\Argument\Identifier; use PhpDb\Sql\Argument\Value; use PhpDb\Sql\ArgumentInterface; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; class Between extends AbstractExpression implements PredicateInterface { @@ -47,15 +47,15 @@ public function __construct( public function getExpressionData(): array { if (! $this->identifier instanceof ArgumentInterface) { - throw new LogicException('Identifier must be specified'); + throw InvalidArgumentException::forMissingIdentifier(); } if (! $this->minValue instanceof ArgumentInterface) { - throw new LogicException('minValue must be specified'); + throw InvalidArgumentException::forMissingMinValue(); } if (! $this->maxValue instanceof ArgumentInterface) { - throw new LogicException('maxValue must be specified'); + throw InvalidArgumentException::forMissingMaxValue(); } $identifierSpec = $this->identifier->getSpecification(); diff --git a/src/Sql/Predicate/Exception/InvalidArgumentException.php b/src/Sql/Predicate/Exception/InvalidArgumentException.php new file mode 100644 index 00000000..e94e87db --- /dev/null +++ b/src/Sql/Predicate/Exception/InvalidArgumentException.php @@ -0,0 +1,73 @@ +identifier instanceof ArgumentInterface) { - throw new InvalidArgumentException('Identifier must be specified'); + throw InvalidArgumentException::forMissingIdentifier(); } if (! $this->valueSet instanceof ArgumentInterface) { - throw new InvalidArgumentException('Value set must be provided for IN predicate'); + throw InvalidArgumentException::forMissingValueSet(); } $identifierSpec = $this->identifier->getSpecification(); diff --git a/src/Sql/Predicate/IsNull.php b/src/Sql/Predicate/IsNull.php index 5e94af32..2b561d01 100644 --- a/src/Sql/Predicate/IsNull.php +++ b/src/Sql/Predicate/IsNull.php @@ -8,7 +8,7 @@ use PhpDb\Sql\AbstractExpression; use PhpDb\Sql\Argument\Identifier; use PhpDb\Sql\ArgumentInterface; -use PhpDb\Sql\Exception\InvalidArgumentException; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; class IsNull extends AbstractExpression implements PredicateInterface { @@ -31,7 +31,7 @@ public function __construct(string|ArgumentInterface|null $identifier = null) public function getExpressionData(): array { if (! $this->identifier instanceof ArgumentInterface) { - throw new InvalidArgumentException('Identifier must be specified'); + throw InvalidArgumentException::forMissingIdentifier(); } $identifierSpec = $this->identifier->getSpecification(); diff --git a/src/Sql/Predicate/Like.php b/src/Sql/Predicate/Like.php index 7ceebe99..f0e87d83 100644 --- a/src/Sql/Predicate/Like.php +++ b/src/Sql/Predicate/Like.php @@ -9,7 +9,7 @@ use PhpDb\Sql\Argument\Identifier; use PhpDb\Sql\Argument\Value; use PhpDb\Sql\ArgumentInterface; -use PhpDb\Sql\Exception\InvalidArgumentException; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; class Like extends AbstractExpression implements PredicateInterface { @@ -38,11 +38,11 @@ public function __construct( public function getExpressionData(): array { if (! $this->identifier instanceof ArgumentInterface) { - throw new InvalidArgumentException('Identifier must be specified'); + throw InvalidArgumentException::forMissingIdentifier(); } if (! $this->like instanceof ArgumentInterface) { - throw new InvalidArgumentException('Like expression must be specified'); + throw InvalidArgumentException::forMissingLikeExpression(); } $identifierSpec = $this->identifier->getSpecification(); diff --git a/src/Sql/Predicate/Operator.php b/src/Sql/Predicate/Operator.php index 22c5ec38..a4971d4b 100644 --- a/src/Sql/Predicate/Operator.php +++ b/src/Sql/Predicate/Operator.php @@ -10,8 +10,8 @@ use PhpDb\Sql\Argument\Select; use PhpDb\Sql\Argument\Value; use PhpDb\Sql\ArgumentInterface; -use PhpDb\Sql\Exception\InvalidArgumentException; use PhpDb\Sql\ExpressionInterface; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PhpDb\Sql\SqlInterface; class Operator extends AbstractExpression implements PredicateInterface @@ -70,11 +70,11 @@ public function __construct( public function getExpressionData(): array { if (! $this->left instanceof ArgumentInterface) { - throw new InvalidArgumentException('Left expression must be specified'); + throw InvalidArgumentException::forMissingLeftExpression(); } if (! $this->right instanceof ArgumentInterface) { - throw new InvalidArgumentException('Right expression must be specified'); + throw InvalidArgumentException::forMissingRightExpression(); } $leftSpec = $this->left->getSpecification(); diff --git a/src/Sql/Predicate/Predicate.php b/src/Sql/Predicate/Predicate.php index 5a69b204..9704d52f 100644 --- a/src/Sql/Predicate/Predicate.php +++ b/src/Sql/Predicate/Predicate.php @@ -5,8 +5,8 @@ namespace PhpDb\Sql\Predicate; use PhpDb\Sql\ArgumentInterface; -use PhpDb\Sql\Exception\RuntimeException; use PhpDb\Sql\ExpressionInterface; +use PhpDb\Sql\Predicate\Exception\RuntimeException; /** * @property Predicate $and @@ -347,11 +347,13 @@ public function setUnnest(?Predicate $predicate = null): void /** * Indicate end of nested predicate + * + * @throws RuntimeException If this predicate is not nested. */ public function unnest(): self { if (! $this->unnest instanceof Predicate) { - throw new RuntimeException('Not nested'); + throw RuntimeException::forNotNested(); } $unnest = $this->unnest; @@ -372,6 +374,8 @@ protected function getNextPredicateCombineOperator(): string /** * Overloading * Overloads "or", "and", "nest", and "unnest" + * + * @throws RuntimeException If "unnest" is accessed on a predicate that is not nested. */ public function __get(string $name): self { diff --git a/src/Sql/Predicate/PredicateSet.php b/src/Sql/Predicate/PredicateSet.php index da34454b..93ca6484 100644 --- a/src/Sql/Predicate/PredicateSet.php +++ b/src/Sql/Predicate/PredicateSet.php @@ -7,7 +7,6 @@ use Closure; use Countable; use Override; -use PhpDb\Sql\Exception; use PhpDb\Sql\Expression; use PhpDb\Sql\Predicate\Expression as PredicateExpression; use ReturnTypeWillChange; @@ -60,9 +59,7 @@ public function addPredicate(PredicateInterface $predicate, ?string $combination match ($combination) { self::OP_AND => $this->andPredicate($predicate), self::OP_OR => $this->orPredicate($predicate), - default => throw new Exception\InvalidArgumentException( - "Invalid combination: expected 'AND' or 'OR'", - ), + default => throw Exception\InvalidArgumentException::forInvalidCombination(), }; return $this; @@ -107,9 +104,7 @@ public function addPredicates( } elseif (is_array($pvalue)) { $predicate = new In($pkey, $pvalue); } elseif ($pvalue instanceof PredicateInterface) { - throw new Exception\InvalidArgumentException( - 'Using Predicate must not use string keys', - ); + throw Exception\InvalidArgumentException::forPredicateWithStringKey(); } else { $predicate = new Operator($pkey, Operator::OP_EQ, $pvalue); } diff --git a/src/Sql/Select.php b/src/Sql/Select.php index 9b494f79..9aa88fe3 100644 --- a/src/Sql/Select.php +++ b/src/Sql/Select.php @@ -24,7 +24,6 @@ use function key; use function method_exists; use function preg_split; -use function sprintf; use function str_contains; use function strcasecmp; use function stripos; @@ -198,9 +197,7 @@ public function columns(array $columns, bool $prefixColumnsWithTable = true): st public function combine(Select $select, string $type = self::COMBINE_UNION, string $modifier = ''): static { if ([] !== $this->combine) { - throw new Exception\InvalidArgumentException( - 'This Select object is already combined and cannot be combined with multiple Selects objects', - ); + throw Exception\InvalidArgumentException::forAlreadyCombined(); } $this->combine = [ @@ -219,15 +216,11 @@ public function combine(Select $select, string $type = self::COMBINE_UNION, stri public function from(array|string|TableIdentifier $table): static { if ($this->tableReadOnly) { - throw new Exception\InvalidArgumentException( - 'Since this object was created with a table and/or schema in the constructor, it is read only.', - ); + throw Exception\InvalidArgumentException::forReadOnlyConstructorState(); } if (is_array($table) && (! is_string(key($table)) || count($table) !== 1)) { - throw new Exception\InvalidArgumentException( - 'from() expects $table as an array is a single element associative array', - ); + throw Exception\InvalidArgumentException::forInvalidFromArray(); } $this->table = $table; @@ -314,11 +307,7 @@ public function join( public function limit(int|string $limit): static { if (! is_numeric($limit)) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects parameter to be numeric, "%s" given', - __METHOD__, - gettype($limit), - )); + throw Exception\InvalidArgumentException::forNonNumericParameter(__METHOD__, gettype($limit)); } $this->limit = $limit; @@ -331,11 +320,7 @@ public function limit(int|string $limit): static public function offset(int|string $offset): static { if (! is_numeric($offset)) { - throw new Exception\InvalidArgumentException(sprintf( - '%s expects parameter to be numeric, "%s" given', - __METHOD__, - gettype($offset), - )); + throw Exception\InvalidArgumentException::forNonNumericParameter(__METHOD__, gettype($offset)); } $this->offset = $offset; @@ -379,9 +364,7 @@ public function reset(string $part): static switch ($part) { case self::TABLE: if ($this->tableReadOnly) { - throw new Exception\InvalidArgumentException( - 'Since this object was created with a table and/or schema in the constructor, it is read only.', - ); + throw Exception\InvalidArgumentException::forReadOnlyConstructorState(); } $this->table = null; @@ -427,7 +410,7 @@ public function reset(string $part): static public function setSpecification(string $index, array|string $specification): static { if (! method_exists($this, "process{$index}")) { - throw new Exception\InvalidArgumentException('Not a valid specification name.'); + throw Exception\InvalidArgumentException::forInvalidSpecificationName(); } $this->specifications[$index] = $specification; @@ -799,7 +782,7 @@ public function __get(string $name): Where|Join|Having 'where' => $this->getWhere(), 'having' => $this->getHaving(), 'joins' => $this->getJoins(), - default => throw new Exception\InvalidArgumentException('Not a valid magic property for this object'), + default => throw Exception\InvalidArgumentException::forInvalidMagicProperty(), }; } } diff --git a/src/Sql/Sql.php b/src/Sql/Sql.php index 8d68fbfb..dbff8df9 100644 --- a/src/Sql/Sql.php +++ b/src/Sql/Sql.php @@ -7,8 +7,6 @@ use PhpDb\Adapter\AdapterInterface; use PhpDb\Adapter\Driver\StatementInterface; -use function sprintf; - class Sql { protected AdapterInterface $adapter; @@ -32,9 +30,7 @@ public function __construct( public function buildSqlString(SqlInterface $sqlObject, ?AdapterInterface $adapter = null): string { if (! $this->sqlPlatform instanceof SqlInterface) { - throw new Exception\RuntimeException( - 'The subject does not implement SqlInterface', - ); + throw Exception\RuntimeException::forSubjectNotSqlInterface(); } $this->sqlPlatform->setSubject($sqlObject); @@ -47,10 +43,7 @@ public function buildSqlString(SqlInterface $sqlObject, ?AdapterInterface $adapt public function delete(string|TableIdentifier|null $table = null): Delete { if (null !== $this->table && null !== $table) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table, - )); + throw Exception\InvalidArgumentException::forForeignTable($this->table); } return new Delete($table ?: $this->table); @@ -79,10 +72,7 @@ public function hasTable(): bool public function insert(string|TableIdentifier|null $table = null): Insert { if (null !== $this->table && null !== $table) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table, - )); + throw Exception\InvalidArgumentException::forForeignTable($this->table); } return new Insert($table ?: $this->table); @@ -94,9 +84,7 @@ public function prepareStatementForSqlObject( ?AdapterInterface $adapter = null, ): StatementInterface { if (! $this->sqlPlatform instanceof PreparableSqlInterface) { - throw new Exception\RuntimeException( - 'The subject does not implement PreparableSqlInterface', - ); + throw Exception\RuntimeException::forSubjectNotPreparableSqlInterface(); } $adapter ??= $this->adapter; @@ -111,10 +99,7 @@ public function prepareStatementForSqlObject( public function select(string|TableIdentifier|null $table = null): Select { if (null !== $this->table && null !== $table) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table, - )); + throw Exception\InvalidArgumentException::forForeignTable($this->table); } return new Select($table ?: $this->table); @@ -133,10 +118,7 @@ public function setTable(array|string|TableIdentifier $table): self public function update(string|TableIdentifier|null $table = null): Update { if (null !== $this->table && null !== $table) { - throw new Exception\InvalidArgumentException(sprintf( - 'This Sql object is intended to work with only the table "%s" provided at construction time.', - $this->table, - )); + throw Exception\InvalidArgumentException::forForeignTable($this->table); } return new Update($table ?: $this->table); diff --git a/src/Sql/TableIdentifier.php b/src/Sql/TableIdentifier.php index 5537b3b7..f0735ae5 100644 --- a/src/Sql/TableIdentifier.php +++ b/src/Sql/TableIdentifier.php @@ -18,27 +18,19 @@ public function __construct( protected ?string $separator = self::SEPARATOR, ) { if ('' === $table) { - throw new Exception\InvalidArgumentException( - '$table must be a valid table name, empty string given', - ); + throw Exception\InvalidArgumentException::forEmptyTable(); } if ('' === $schema) { - throw new Exception\InvalidArgumentException( - '$schema must be a valid schema name or null, empty string given', - ); + throw Exception\InvalidArgumentException::forEmptySchema(); } if ('' === $prefix) { - throw new Exception\InvalidArgumentException( - '$prefix must be a valid table prefix or null, empty string given', - ); + throw Exception\InvalidArgumentException::forEmptyPrefix(); } if ('' === $separator) { - throw new Exception\InvalidArgumentException( - '$separator must be a valid table separator, empty string given', - ); + throw Exception\InvalidArgumentException::forEmptySeparator(); } } diff --git a/src/Sql/TableIdentifierFactory.php b/src/Sql/TableIdentifierFactory.php index af0d23c1..0988cbf5 100644 --- a/src/Sql/TableIdentifierFactory.php +++ b/src/Sql/TableIdentifierFactory.php @@ -24,15 +24,11 @@ public function __construct( private ?string $separator = TableIdentifier::SEPARATOR, ) { if ('' === $prefix) { - throw new Exception\InvalidArgumentException( - '$prefix must be a valid table prefix or null, empty string given', - ); + throw Exception\InvalidArgumentException::forEmptyPrefix(); } if ('' === $separator) { - throw new Exception\InvalidArgumentException( - '$separator must be a valid table separator, empty string given', - ); + throw Exception\InvalidArgumentException::forEmptySeparator(); } } diff --git a/src/Sql/Update.php b/src/Sql/Update.php index 71826c8c..13d4e849 100644 --- a/src/Sql/Update.php +++ b/src/Sql/Update.php @@ -115,7 +115,7 @@ public function set(array $values, string|int $flag = self::VALUES_SET): static $priority = is_numeric($flag) ? $flag : 0; foreach ($values as $k => $v) { if (! is_string($k)) { - throw new Exception\InvalidArgumentException('set() expects a string for the value key'); + throw Exception\InvalidArgumentException::forNonStringValueKey(); } $set->insert($k, $v, $priority); diff --git a/test/unit/Exception/ExceptionHierarchyTest.php b/test/unit/Exception/ExceptionHierarchyTest.php index b096016a..978f0df8 100644 --- a/test/unit/Exception/ExceptionHierarchyTest.php +++ b/test/unit/Exception/ExceptionHierarchyTest.php @@ -12,6 +12,7 @@ use PhpDb\ResultSet\Exception as ResultSetException; use PhpDb\RowGateway\Exception as RowGatewayException; use PhpDb\Sql\Exception as SqlException; +use PhpDb\Sql\Predicate\Exception as PredicateException; use PhpDb\TableGateway\Exception as TableGatewayException; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\DataProvider; @@ -67,6 +68,8 @@ final class ExceptionHierarchyTest extends TestCase DbException\InvalidArgumentException::class => InvalidArgumentException::class, DbException\RuntimeException::class => RuntimeException::class, DbException\UnexpectedValueException::class => UnexpectedValueException::class, + PredicateException\InvalidArgumentException::class => InvalidArgumentException::class, + PredicateException\RuntimeException::class => RuntimeException::class, MetadataException\InvalidArgumentException::class => InvalidArgumentException::class, MetadataException\RuntimeException::class => RuntimeException::class, ResultSetException\InvalidArgumentException::class => InvalidArgumentException::class, diff --git a/test/unit/Sql/AbstractSqlTest.php b/test/unit/Sql/AbstractSqlTest.php index 33eb427e..f4676d54 100644 --- a/test/unit/Sql/AbstractSqlTest.php +++ b/test/unit/Sql/AbstractSqlTest.php @@ -40,6 +40,7 @@ use function key; use function next; use function preg_match; +use function sprintf; use function uniqid; #[IgnoreDeprecations] @@ -78,8 +79,8 @@ public function testCreateSqlFromSpecificationThrowsOnParameterCountMismatch(): ], ]; - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('A number of parameters was found that is not supported by this specification'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(RuntimeException::UNSUPPORTED_PARAMETER_COUNT); $method->invoke($this->abstractSql, $specifications, ['col1', 'table', 'extra']); } @@ -97,8 +98,8 @@ public function testCreateSqlFromSpecNonCombinedByThrowsOnUnsupportedCount(): vo ]; $params = [['a', 'b']]; - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('A number of parameters (2)'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(sprintf(RuntimeException::UNSUPPORTED_PARAMETER_COUNT_OF, 2)); $method->invoke($this->abstractSql, $spec, $params); } @@ -137,8 +138,8 @@ public function testCreateSqlFromSpecWithCombinedByThrowsOnUnsupportedCount(): v ]; $params = [[['a', 'b']], 'table1']; - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('A number of parameters (2)'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(sprintf(RuntimeException::UNSUPPORTED_PARAMETER_COUNT_OF, 2)); $method->invoke($this->abstractSql, $spec, $params); } @@ -229,8 +230,8 @@ public function getValue(): string $expression = new Expression('?', [$unknownArg]); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Unknown argument type'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::UNKNOWN_ARGUMENT_TYPE); $this->invokeProcessExpressionMethod($expression); } diff --git a/test/unit/Sql/ArgumentTest.php b/test/unit/Sql/ArgumentTest.php index 59d51363..f5f6737f 100644 --- a/test/unit/Sql/ArgumentTest.php +++ b/test/unit/Sql/ArgumentTest.php @@ -24,7 +24,7 @@ final class ArgumentTest extends TestCase { public function testConstructorThrowsExceptionForInvalidSelectType(): void { - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpParamsInspection */ /** @noinspection PhpExpressionResultUnusedInspection */ new ArgumentSelect('simple_value'); /** @phpstan-ignore-line */ diff --git a/test/unit/Sql/CombineTest.php b/test/unit/Sql/CombineTest.php index 409dba0a..a44595d1 100644 --- a/test/unit/Sql/CombineTest.php +++ b/test/unit/Sql/CombineTest.php @@ -224,7 +224,7 @@ public function testPrepareStatementWithModifier(): void public function testRejectsInvalidStatement(): void { - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpParamsInspection */ $this->combine->combine('foo'); diff --git a/test/unit/Sql/Ddl/Column/AbstractPrecisionColumnTest.php b/test/unit/Sql/Ddl/Column/AbstractPrecisionColumnTest.php index 743fc301..26c831aa 100644 --- a/test/unit/Sql/Ddl/Column/AbstractPrecisionColumnTest.php +++ b/test/unit/Sql/Ddl/Column/AbstractPrecisionColumnTest.php @@ -13,6 +13,8 @@ use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(AbstractPrecisionColumn::class, 'setDigits')] #[CoversMethod(AbstractPrecisionColumn::class, 'getDigits')] #[CoversMethod(AbstractPrecisionColumn::class, 'setDecimal')] @@ -155,8 +157,8 @@ public function throwsWhenDecimalIsSetWithoutDigits(): void ->onlyMethods([]) ->getMock(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "foo" of type INTEGER has a decimal scale but no digits'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::MISSING_DECIMAL_DIGITS, 'foo', 'INTEGER')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Column/DecimalTest.php b/test/unit/Sql/Ddl/Column/DecimalTest.php index 5f9aaba8..adae7968 100644 --- a/test/unit/Sql/Ddl/Column/DecimalTest.php +++ b/test/unit/Sql/Ddl/Column/DecimalTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(Decimal::class, 'getExpressionData')] #[CoversMethod(AbstractPrecisionColumn::class, '__construct')] #[CoversMethod(AbstractPrecisionColumn::class, 'setDigits')] @@ -130,8 +132,8 @@ public function throwsWhenDecimalIsSetWithoutDigits(): void { $column = new Decimal('price', null, 2); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "price" of type DECIMAL has a decimal scale but no digits'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::MISSING_DECIMAL_DIGITS, 'price', 'DECIMAL')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Column/DoubleTest.php b/test/unit/Sql/Ddl/Column/DoubleTest.php index 548b1b2c..f361ca50 100644 --- a/test/unit/Sql/Ddl/Column/DoubleTest.php +++ b/test/unit/Sql/Ddl/Column/DoubleTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(Double::class, 'getExpressionData')] #[CoversMethod(AbstractPrecisionColumn::class, 'getLengthExpression')] #[CoversMethod(AbstractLengthColumn::class, 'getExpressionData')] @@ -62,8 +64,8 @@ public function throwsWhenDecimalIsSetWithoutDigits(): void { $column = new Double('f', null, 2); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "f" of type DOUBLE has a decimal scale but no digits'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::MISSING_DECIMAL_DIGITS, 'f', 'DOUBLE')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Column/FloatingTest.php b/test/unit/Sql/Ddl/Column/FloatingTest.php index cfafef7b..9d405f63 100644 --- a/test/unit/Sql/Ddl/Column/FloatingTest.php +++ b/test/unit/Sql/Ddl/Column/FloatingTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(Floating::class, 'getExpressionData')] #[CoversMethod(AbstractPrecisionColumn::class, 'getLengthExpression')] #[CoversMethod(AbstractLengthColumn::class, 'getExpressionData')] @@ -62,8 +64,8 @@ public function throwsWhenDecimalIsSetWithoutDigits(): void { $column = new Floating('f', null, 2); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "f" of type FLOAT has a decimal scale but no digits'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::MISSING_DECIMAL_DIGITS, 'f', 'FLOAT')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Column/IntegerTest.php b/test/unit/Sql/Ddl/Column/IntegerTest.php index dd26f090..e7c4e2a1 100644 --- a/test/unit/Sql/Ddl/Column/IntegerTest.php +++ b/test/unit/Sql/Ddl/Column/IntegerTest.php @@ -18,6 +18,8 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(Integer::class, '__construct')] #[CoversMethod(Integer::class, 'getExpressionData')] #[CoversMethod(Integer::class, 'normaliseDisplayWidth')] @@ -160,8 +162,8 @@ public function throwsWhenLengthOptionIsNotANonNegativeInteger(bool|int|string $ { $column = new Integer('i', false, null, ['length' => $length]); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "i" length option must be a non-negative integer'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::INVALID_COLUMN_LENGTH, 'i')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Column/VarbinaryTest.php b/test/unit/Sql/Ddl/Column/VarbinaryTest.php index bd660b58..7c1ccf58 100644 --- a/test/unit/Sql/Ddl/Column/VarbinaryTest.php +++ b/test/unit/Sql/Ddl/Column/VarbinaryTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(Varbinary::class, 'getExpressionData')] #[CoversMethod(AbstractLengthColumn::class, 'getExpressionData')] #[Group('unit')] @@ -50,8 +52,8 @@ public function throwsWhenRenderedWithoutLength(?int $length): void { $column = new Varbinary('data', $length); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "data" of type VARBINARY requires a length'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::MISSING_COLUMN_LENGTH, 'data', 'VARBINARY')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Column/VarcharTest.php b/test/unit/Sql/Ddl/Column/VarcharTest.php index 5f9ffcc9..c63bbdf3 100644 --- a/test/unit/Sql/Ddl/Column/VarcharTest.php +++ b/test/unit/Sql/Ddl/Column/VarcharTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use function sprintf; + #[CoversMethod(Varchar::class, 'getExpressionData')] #[CoversMethod(AbstractLengthColumn::class, '__construct')] #[CoversMethod(AbstractLengthColumn::class, 'setLength')] @@ -90,8 +92,8 @@ public function throwsWhenRenderedWithoutLength(?int $length): void { $column = new Varchar('name', $length); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Column "name" of type VARCHAR requires a length'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::MISSING_COLUMN_LENGTH, 'name', 'VARCHAR')); $column->getExpressionData(); } diff --git a/test/unit/Sql/Ddl/Constraint/CheckTest.php b/test/unit/Sql/Ddl/Constraint/CheckTest.php index 93fff318..38a98273 100644 --- a/test/unit/Sql/Ddl/Constraint/CheckTest.php +++ b/test/unit/Sql/Ddl/Constraint/CheckTest.php @@ -126,8 +126,8 @@ public function testGetExpressionData(): void #[Test] public function throwsWhenExpressionIsEmpty(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Check constraint expression must not be an empty string.'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_CHECK_EXPRESSION); new Check(''); } diff --git a/test/unit/Sql/Exception/InvalidArgumentExceptionTest.php b/test/unit/Sql/Exception/InvalidArgumentExceptionTest.php new file mode 100644 index 00000000..83ed79ab --- /dev/null +++ b/test/unit/Sql/Exception/InvalidArgumentExceptionTest.php @@ -0,0 +1,188 @@ +, string}> */ + public static function namedConstructorProvider(): array + { + return [ + 'missing decimal digits' => [ + 'forMissingDecimalDigits', + ['price', 'DECIMAL'], + InvalidArgumentException::MISSING_DECIMAL_DIGITS, + ], + 'missing column length' => [ + 'forMissingColumnLength', + ['name', 'VARCHAR'], + InvalidArgumentException::MISSING_COLUMN_LENGTH, + ], + 'invalid column length' => [ + 'forInvalidColumnLength', + ['age'], + InvalidArgumentException::INVALID_COLUMN_LENGTH, + ], + 'empty check expression' => [ + 'forEmptyCheckExpression', + [], + InvalidArgumentException::EMPTY_CHECK_EXPRESSION, + ], + 'already combined' => [ + 'forAlreadyCombined', + [], + InvalidArgumentException::ALREADY_COMBINED, + ], + 'empty expression' => [ + 'forEmptyExpression', + [], + InvalidArgumentException::EMPTY_EXPRESSION, + ], + 'empty prefix' => [ + 'forEmptyPrefix', + [], + InvalidArgumentException::EMPTY_PREFIX, + ], + 'empty schema' => [ + 'forEmptySchema', + [], + InvalidArgumentException::EMPTY_SCHEMA, + ], + 'empty separator' => [ + 'forEmptySeparator', + [], + InvalidArgumentException::EMPTY_SEPARATOR, + ], + 'empty table' => [ + 'forEmptyTable', + [], + InvalidArgumentException::EMPTY_TABLE, + ], + 'foreign table' => [ + 'forForeignTable', + ['users'], + InvalidArgumentException::FOREIGN_TABLE, + ], + 'invalid argument type' => [ + 'forInvalidArgumentType', + [], + InvalidArgumentException::INVALID_ARGUMENT_TYPE, + ], + 'invalid from array' => [ + 'forInvalidFromArray', + [], + InvalidArgumentException::INVALID_FROM_ARRAY, + ], + 'invalid join name' => [ + 'forInvalidJoinName', + ['orders'], + InvalidArgumentException::INVALID_JOIN_NAME, + ], + 'invalid magic property' => [ + 'forInvalidMagicProperty', + [], + InvalidArgumentException::INVALID_MAGIC_PROPERTY, + ], + 'invalid specification name' => [ + 'forInvalidSpecificationName', + [], + InvalidArgumentException::INVALID_SPECIFICATION_NAME, + ], + 'missing values or select' => [ + 'forMissingValuesOrSelect', + [], + InvalidArgumentException::MISSING_VALUES_OR_SELECT, + ], + 'non numeric parameter' => [ + 'forNonNumericParameter', + ['PhpDb\\Sql\\Select::limit', 'string'], + InvalidArgumentException::NON_NUMERIC_PARAMETER, + ], + 'non string value key' => [ + 'forNonStringValueKey', + [], + InvalidArgumentException::NON_STRING_VALUE_KEY, + ], + 'read only constructor state' => [ + 'forReadOnlyConstructorState', + [], + InvalidArgumentException::READ_ONLY_CONSTRUCTOR_STATE, + ], + 'select with merge flag' => [ + 'forSelectWithMergeFlag', + [], + InvalidArgumentException::SELECT_WITH_MERGE_FLAG, + ], + 'unknown argument type' => [ + 'forUnknownArgumentType', + [], + InvalidArgumentException::UNKNOWN_ARGUMENT_TYPE, + ], + 'unknown column key' => [ + 'forUnknownColumnKey', + ['email'], + InvalidArgumentException::UNKNOWN_COLUMN_KEY, + ], + 'values with merge flag' => [ + 'forValuesWithMergeFlag', + [], + InvalidArgumentException::VALUES_WITH_MERGE_FLAG, + ], + ]; + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorRendersItsTemplate(string $method, array $arguments, string $template): void + { + $exception = InvalidArgumentException::{$method}(...$arguments); + + self::assertSame(sprintf($template, ...$arguments), $exception->getMessage()); + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorReturnsTheComponentExceptionType(string $method, array $arguments): void + { + self::assertInstanceOf(ExceptionInterface::class, InvalidArgumentException::{$method}(...$arguments)); + } +} diff --git a/test/unit/Sql/Exception/RuntimeExceptionTest.php b/test/unit/Sql/Exception/RuntimeExceptionTest.php new file mode 100644 index 00000000..01a8996d --- /dev/null +++ b/test/unit/Sql/Exception/RuntimeExceptionTest.php @@ -0,0 +1,81 @@ +, string}> */ + public static function namedConstructorProvider(): array + { + return [ + 'replacement mismatch' => [ + 'forReplacementMismatch', + [], + RuntimeException::REPLACEMENT_MISMATCH, + ], + 'subject not implementing' => [ + 'forSubjectNotImplementing', + [SqlInterface::class, 'getSqlString()'], + RuntimeException::SUBJECT_NOT_IMPLEMENTING, + ], + 'subject not preparable sql interface' => [ + 'forSubjectNotPreparableSqlInterface', + [], + RuntimeException::SUBJECT_NOT_PREPARABLE_SQL_INTERFACE, + ], + 'subject not sql interface' => [ + 'forSubjectNotSqlInterface', + [], + RuntimeException::SUBJECT_NOT_SQL_INTERFACE, + ], + 'unsupported parameter count' => [ + 'forUnsupportedParameterCount', + [], + RuntimeException::UNSUPPORTED_PARAMETER_COUNT, + ], + 'unsupported parameter count of' => [ + 'forUnsupportedParameterCountOf', + [2], + RuntimeException::UNSUPPORTED_PARAMETER_COUNT_OF, + ], + ]; + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorRendersItsTemplate(string $method, array $arguments, string $template): void + { + $exception = RuntimeException::{$method}(...$arguments); + + self::assertSame(sprintf($template, ...$arguments), $exception->getMessage()); + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorReturnsTheComponentExceptionType(string $method, array $arguments): void + { + self::assertInstanceOf(ExceptionInterface::class, RuntimeException::{$method}(...$arguments)); + } +} diff --git a/test/unit/Sql/ExpressionTest.php b/test/unit/Sql/ExpressionTest.php index ee2f37c5..2900869f 100644 --- a/test/unit/Sql/ExpressionTest.php +++ b/test/unit/Sql/ExpressionTest.php @@ -56,7 +56,7 @@ public function testConstructorWithFalsyValidParameters(mixed $falsyParameter): public function testConstructorWithInvalidParameter(): void { - $this->expectException(TypeError::class); + self::expectException(TypeError::class); new Expression('?', (object) []); } @@ -111,8 +111,8 @@ public function testGetExpressionDataThrowsExceptionWhenParameterCountMismatch() { $expression = new Expression('? AND ?', [1]); // Two placeholders but only one parameter - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage( + self::expectException(RuntimeException::class); + self::expectExceptionMessage( 'The number of replacements in the expression does not match the number of parameters', ); $expression->getExpressionData(); @@ -198,13 +198,13 @@ public function testSetExpression(): void public function testSetExpressionException(): void { $expression = new Expression(); - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpStrictTypeCheckingInspection */ $expression->setExpression(null); $expression = new Expression(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Supplied expression must not be an empty string.'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_EXPRESSION); $expression->setExpression(''); } @@ -212,7 +212,7 @@ public function testSetExpressionThrowsOnEmptyString(): void { $expression = new Expression(); - $this->expectException(InvalidArgumentException::class); + self::expectException(InvalidArgumentException::class); $expression->setExpression(''); } diff --git a/test/unit/Sql/InsertIgnoreTest.php b/test/unit/Sql/InsertIgnoreTest.php index d73efb27..151bc997 100644 --- a/test/unit/Sql/InsertIgnoreTest.php +++ b/test/unit/Sql/InsertIgnoreTest.php @@ -326,8 +326,8 @@ public function testValuesThrowsExceptionWhenArrayMergeOverSelect(): void { $this->insert->values(new Select()); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'An array of values cannot be provided with the merge flag when a PhpDb\Sql\Select instance already ' . 'exists as the value source', ); @@ -336,7 +336,7 @@ public function testValuesThrowsExceptionWhenArrayMergeOverSelect(): void public function testValuesThrowsExceptionWhenNotArrayOrSelect(): void { - $this->expectException(TypeError::class); + self::expectException(TypeError::class); $this->insert->values(5); } @@ -344,8 +344,8 @@ public function testValuesThrowsExceptionWhenSelectMergeOverArray(): void { $this->insert->values(['foo' => 'bar']); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('A PhpDb\Sql\Select instance cannot be provided with the merge flag'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::SELECT_WITH_MERGE_FLAG); $this->insert->values(new Select(), Insert::VALUES_MERGE); } diff --git a/test/unit/Sql/InsertTest.php b/test/unit/Sql/InsertTest.php index bde66673..a06e1ccc 100644 --- a/test/unit/Sql/InsertTest.php +++ b/test/unit/Sql/InsertTest.php @@ -28,6 +28,8 @@ use ReflectionException; use TypeError; +use function sprintf; + #[IgnoreDeprecations] #[RequiresPhp('<= 8.6')] #[CoversMethod(Insert::class, '__construct')] @@ -170,8 +172,8 @@ public function testGetSqlStringThrowsExceptionWhenNoValuesOrSelect(): void { $this->insert->into('foo'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('values or select should be present'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_VALUES_OR_SELECT); $this->insert->getSqlString(new TrustingSql92Platform()); } @@ -190,8 +192,8 @@ public function testGetSqlStringUsingColumnsAndValuesMethods(): void public function testGetThrowsExceptionForNonExistentColumn(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The key nonexistent was not found in this objects column list'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::UNKNOWN_COLUMN_KEY, 'nonexistent')); $value = $this->insert->nonexistent; } @@ -387,8 +389,8 @@ public function testSpecificationconstantsCouldBeOverridedByExtensionInPrepareSt public function testUnsetThrowsExceptionForNonExistentColumn(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The key nonexistent was not found in this objects column list'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(sprintf(InvalidArgumentException::UNKNOWN_COLUMN_KEY, 'nonexistent')); unset($this->insert->nonexistent); } @@ -426,8 +428,8 @@ public function testValuesThrowsExceptionWhenArrayMergeOverSelect(): void { $this->insert->values(new Select()); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'An array of values cannot be provided with the merge flag when a PhpDb\Sql\Select instance already ' . 'exists as the value source', ); @@ -436,7 +438,7 @@ public function testValuesThrowsExceptionWhenArrayMergeOverSelect(): void public function testValuesThrowsExceptionWhenNotArrayOrSelect(): void { - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @psalm-suppress InvalidArgument */ $this->insert->values(5); } @@ -445,8 +447,8 @@ public function testValuesThrowsExceptionWhenSelectMergeOverArray(): void { $this->insert->values(['foo' => 'bar']); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('A PhpDb\Sql\Select instance cannot be provided with the merge flag'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::SELECT_WITH_MERGE_FLAG); $this->insert->values(new Select(), Insert::VALUES_MERGE); } diff --git a/test/unit/Sql/JoinTest.php b/test/unit/Sql/JoinTest.php index 2936b497..f7066c34 100644 --- a/test/unit/Sql/JoinTest.php +++ b/test/unit/Sql/JoinTest.php @@ -89,8 +89,8 @@ public function testJoinThrowsOnInvalidMultiElementArray(): void { $join = new Join(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("expects 'b' as a single element associative array"); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage("expects 'b' as a single element associative array"); $join->join(['a' => 'b', 'c' => 'd'], 'on'); } @@ -98,7 +98,7 @@ public function testJoinWillThrowAnExceptionIfNameIsNoValid(): void { $join = new Join(); - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpArgumentWithoutNamedIdentifierInspection */ $join->join([], false); } diff --git a/test/unit/Sql/Platform/AbstractPlatformTest.php b/test/unit/Sql/Platform/AbstractPlatformTest.php index 81601824..f62d5ab8 100644 --- a/test/unit/Sql/Platform/AbstractPlatformTest.php +++ b/test/unit/Sql/Platform/AbstractPlatformTest.php @@ -18,6 +18,8 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; +use function sprintf; + #[Group('unit')] #[CoversMethod(AbstractPlatform::class, 'setSubject')] #[CoversMethod(AbstractPlatform::class, 'setTypeDecorator')] @@ -45,8 +47,12 @@ public function testGetSqlStringThrowsWhenSubjectNotSqlInterface(): void $subject = $this->createMock(PreparableSqlInterface::class); $this->platform->setSubject($subject); - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('The subject does not appear to implement'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(sprintf( + RuntimeException::SUBJECT_NOT_IMPLEMENTING, + SqlInterface::class, + 'getSqlString()', + )); $this->platform->getSqlString(); } @@ -106,8 +112,12 @@ public function testPrepareStatementThrowsWhenSubjectNotPreparable(): void $adapter = $this->createMock(AdapterInterface::class); $statement = new StatementContainer(); - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('The subject does not appear to implement'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(sprintf( + RuntimeException::SUBJECT_NOT_IMPLEMENTING, + PreparableSqlInterface::class, + 'prepareStatement()', + )); $this->platform->prepareStatement($adapter, $statement); } diff --git a/test/unit/Sql/Platform/PlatformTest.php b/test/unit/Sql/Platform/PlatformTest.php index 21d1e1bc..c2112b11 100644 --- a/test/unit/Sql/Platform/PlatformTest.php +++ b/test/unit/Sql/Platform/PlatformTest.php @@ -73,7 +73,7 @@ public function testGetSqlStringThrowsWhenSubjectNotSqlInterface(): void $subject = $this->createMock(PreparableSqlInterface::class); $platform->setSubject($subject); - $this->expectException(RuntimeException::class); + self::expectException(RuntimeException::class); $platform->getSqlString($adapterPlatform); } @@ -142,7 +142,7 @@ public function testPrepareStatementThrowsWhenSubjectNotPreparable(): void $adapter = $this->resolveAdapter('sql92'); $statement = new StatementContainer(); - $this->expectException(RuntimeException::class); + self::expectException(RuntimeException::class); $platform->prepareStatement($adapter, $statement); } diff --git a/test/unit/Sql/Predicate/BetweenTest.php b/test/unit/Sql/Predicate/BetweenTest.php index a7e1a508..426d8ed3 100644 --- a/test/unit/Sql/Predicate/BetweenTest.php +++ b/test/unit/Sql/Predicate/BetweenTest.php @@ -4,12 +4,12 @@ namespace PhpDbTest\Sql\Predicate; -use LogicException; use Override; use PhpDb\Sql\Argument; use PhpDb\Sql\ArgumentInterface; use PhpDb\Sql\ArgumentType; use PhpDb\Sql\Predicate\Between; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\TestCase; @@ -93,8 +93,8 @@ public function testGetExpressionDataThrowsExceptionWhenIdentifierNotSet(): void $between = new Between(); $between->setMinValue(1)->setMaxValue(10); - $this->expectException(LogicException::class); - $this->expectExceptionMessage('Identifier must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_IDENTIFIER); $between->getExpressionData(); } @@ -103,8 +103,8 @@ public function testGetExpressionDataThrowsExceptionWhenMaxValueNotSet(): void $between = new Between(); $between->setIdentifier('foo')->setMinValue(1); - $this->expectException(LogicException::class); - $this->expectExceptionMessage('maxValue must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_MAX_VALUE); $between->getExpressionData(); } @@ -113,8 +113,8 @@ public function testGetExpressionDataThrowsExceptionWhenMinValueNotSet(): void $between = new Between(); $between->setIdentifier('foo')->setMaxValue(10); - $this->expectException(LogicException::class); - $this->expectExceptionMessage('minValue must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_MIN_VALUE); $between->getExpressionData(); } diff --git a/test/unit/Sql/Predicate/Exception/InvalidArgumentExceptionTest.php b/test/unit/Sql/Predicate/Exception/InvalidArgumentExceptionTest.php new file mode 100644 index 00000000..8160e359 --- /dev/null +++ b/test/unit/Sql/Predicate/Exception/InvalidArgumentExceptionTest.php @@ -0,0 +1,98 @@ +, string}> */ + public static function namedConstructorProvider(): array + { + return [ + 'invalid combination' => [ + 'forInvalidCombination', + [], + InvalidArgumentException::INVALID_COMBINATION, + ], + 'missing identifier' => [ + 'forMissingIdentifier', + [], + InvalidArgumentException::MISSING_IDENTIFIER, + ], + 'missing left expression' => [ + 'forMissingLeftExpression', + [], + InvalidArgumentException::MISSING_LEFT_EXPRESSION, + ], + 'missing like expression' => [ + 'forMissingLikeExpression', + [], + InvalidArgumentException::MISSING_LIKE_EXPRESSION, + ], + 'missing max value' => [ + 'forMissingMaxValue', + [], + InvalidArgumentException::MISSING_MAX_VALUE, + ], + 'missing min value' => [ + 'forMissingMinValue', + [], + InvalidArgumentException::MISSING_MIN_VALUE, + ], + 'missing right expression' => [ + 'forMissingRightExpression', + [], + InvalidArgumentException::MISSING_RIGHT_EXPRESSION, + ], + 'missing value set' => [ + 'forMissingValueSet', + [], + InvalidArgumentException::MISSING_VALUE_SET, + ], + 'predicate with string key' => [ + 'forPredicateWithStringKey', + [], + InvalidArgumentException::PREDICATE_WITH_STRING_KEY, + ], + ]; + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorRendersItsTemplate(string $method, array $arguments, string $template): void + { + $exception = InvalidArgumentException::{$method}(...$arguments); + + self::assertSame(sprintf($template, ...$arguments), $exception->getMessage()); + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorReturnsTheComponentExceptionType(string $method, array $arguments): void + { + self::assertInstanceOf(ExceptionInterface::class, InvalidArgumentException::{$method}(...$arguments)); + } +} diff --git a/test/unit/Sql/Predicate/Exception/RuntimeExceptionTest.php b/test/unit/Sql/Predicate/Exception/RuntimeExceptionTest.php new file mode 100644 index 00000000..e26ed147 --- /dev/null +++ b/test/unit/Sql/Predicate/Exception/RuntimeExceptionTest.php @@ -0,0 +1,50 @@ +, string}> */ + public static function namedConstructorProvider(): array + { + return [ + 'not nested' => [ + 'forNotNested', + [], + RuntimeException::NOT_NESTED, + ], + ]; + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorRendersItsTemplate(string $method, array $arguments, string $template): void + { + $exception = RuntimeException::{$method}(...$arguments); + + self::assertSame(sprintf($template, ...$arguments), $exception->getMessage()); + } + + /** @param list $arguments */ + #[Test] + #[DataProvider('namedConstructorProvider')] + public function namedConstructorReturnsTheComponentExceptionType(string $method, array $arguments): void + { + self::assertInstanceOf(ExceptionInterface::class, RuntimeException::{$method}(...$arguments)); + } +} diff --git a/test/unit/Sql/Predicate/InTest.php b/test/unit/Sql/Predicate/InTest.php index cd73bb90..dce40df1 100644 --- a/test/unit/Sql/Predicate/InTest.php +++ b/test/unit/Sql/Predicate/InTest.php @@ -9,7 +9,7 @@ use PhpDb\Sql\Argument\Values; use PhpDb\Sql\ArgumentInterface; use PhpDb\Sql\ArgumentType; -use PhpDb\Sql\Exception\InvalidArgumentException; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PhpDb\Sql\Predicate\In; use PhpDb\Sql\Select; use PHPUnit\Framework\Attributes\CoversMethod; @@ -71,8 +71,8 @@ public function testGetExpressionDataThrowsExceptionWhenIdentifierNotSet(): void $in = new In(); $in->setValueSet([1, 2]); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Identifier must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_IDENTIFIER); $in->getExpressionData(); } @@ -81,8 +81,8 @@ public function testGetExpressionDataThrowsExceptionWhenValueSetNotSet(): void $in = new In(); $in->setIdentifier('foo'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Value set must be provided for IN predicate'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_VALUE_SET); $in->getExpressionData(); } diff --git a/test/unit/Sql/Predicate/IsNullTest.php b/test/unit/Sql/Predicate/IsNullTest.php index 2f22c906..18660afc 100644 --- a/test/unit/Sql/Predicate/IsNullTest.php +++ b/test/unit/Sql/Predicate/IsNullTest.php @@ -7,7 +7,7 @@ use PhpDb\Sql\Argument\Identifier; use PhpDb\Sql\ArgumentInterface; use PhpDb\Sql\ArgumentType; -use PhpDb\Sql\Exception\InvalidArgumentException; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PhpDb\Sql\Predicate\IsNotNull; use PhpDb\Sql\Predicate\IsNull; use PHPUnit\Framework\Attributes\CoversMethod; @@ -44,8 +44,8 @@ public function testGetExpressionDataThrowsExceptionWhenIdentifierNotSet(): void { $isNull = new IsNull(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Identifier must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_IDENTIFIER); $isNull->getExpressionData(); } diff --git a/test/unit/Sql/Predicate/LikeTest.php b/test/unit/Sql/Predicate/LikeTest.php index b7fbcc22..e569f0e6 100644 --- a/test/unit/Sql/Predicate/LikeTest.php +++ b/test/unit/Sql/Predicate/LikeTest.php @@ -7,7 +7,7 @@ use PhpDb\Sql\Argument; use PhpDb\Sql\ArgumentInterface; use PhpDb\Sql\ArgumentType; -use PhpDb\Sql\Exception\InvalidArgumentException; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PhpDb\Sql\Predicate\Like; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\TestCase; @@ -146,8 +146,8 @@ public function testGetExpressionDataThrowsExceptionWhenIdentifierNotSet(): void $like = new Like(); $like->setLike('foo%'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Identifier must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_IDENTIFIER); $like->getExpressionData(); } @@ -156,8 +156,8 @@ public function testGetExpressionDataThrowsExceptionWhenLikeNotSet(): void $like = new Like(); $like->setIdentifier('bar'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Like expression must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_LIKE_EXPRESSION); $like->getExpressionData(); } diff --git a/test/unit/Sql/Predicate/OperatorTest.php b/test/unit/Sql/Predicate/OperatorTest.php index 77f89657..b2f7a1fb 100644 --- a/test/unit/Sql/Predicate/OperatorTest.php +++ b/test/unit/Sql/Predicate/OperatorTest.php @@ -9,8 +9,8 @@ use PhpDb\Sql\Argument\Value; use PhpDb\Sql\ArgumentInterface; use PhpDb\Sql\ArgumentType; -use PhpDb\Sql\Exception\InvalidArgumentException; use PhpDb\Sql\Expression; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PhpDb\Sql\Predicate\Operator; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\Group; @@ -81,8 +81,8 @@ public function testGetExpressionDataThrowsExceptionWhenLeftNotSet(): void $operator = new Operator(); $operator->setRight('value'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Left expression must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_LEFT_EXPRESSION); $operator->getExpressionData(); } @@ -91,8 +91,8 @@ public function testGetExpressionDataThrowsExceptionWhenRightNotSet(): void $operator = new Operator(); $operator->setLeft('left'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Right expression must be specified'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::MISSING_RIGHT_EXPRESSION); $operator->getExpressionData(); } diff --git a/test/unit/Sql/Predicate/PredicateSetTest.php b/test/unit/Sql/Predicate/PredicateSetTest.php index 68328adf..f3f52996 100644 --- a/test/unit/Sql/Predicate/PredicateSetTest.php +++ b/test/unit/Sql/Predicate/PredicateSetTest.php @@ -5,8 +5,8 @@ namespace PhpDbTest\Sql\Predicate; use PhpDb\Sql\Argument; -use PhpDb\Sql\Exception\InvalidArgumentException; use PhpDb\Sql\Expression as SqlExpression; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException; use PhpDb\Sql\Predicate\Expression; use PhpDb\Sql\Predicate\In; use PhpDb\Sql\Predicate\IsNotNull; @@ -87,7 +87,7 @@ public function testAddPredicates(): void self::assertSame($predicateSet, $what); }); - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpStrictTypeCheckingInspection */ $predicateSet->addPredicates(null); } @@ -97,8 +97,8 @@ public function testAddPredicatesThrowsWhenStringKeyUsedWithPredicateInterface() $predicateSet = new PredicateSet(); $mock = $this->createMock(PredicateInterface::class); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Using Predicate must not use string keys'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::PREDICATE_WITH_STRING_KEY); $predicateSet->addPredicates(['key' => $mock]); } @@ -154,8 +154,8 @@ public function testAddPredicateThrowsOnInvalidCombination(): void { $predicateSet = new PredicateSet(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("Invalid combination: expected 'AND' or 'OR'"); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage("Invalid combination: expected 'AND' or 'OR'"); $predicateSet->addPredicate(new IsNull('foo'), 'XOR'); } diff --git a/test/unit/Sql/Predicate/PredicateTest.php b/test/unit/Sql/Predicate/PredicateTest.php index 80f31cbd..fbbb5335 100644 --- a/test/unit/Sql/Predicate/PredicateTest.php +++ b/test/unit/Sql/Predicate/PredicateTest.php @@ -8,8 +8,8 @@ use PhpDb\Adapter\Exception\VunerablePlatformQuoteException; use PhpDb\Adapter\Platform\Sql92; use PhpDb\Sql\Argument; -use PhpDb\Sql\Exception\RuntimeException; use PhpDb\Sql\Expression; +use PhpDb\Sql\Predicate\Exception\RuntimeException; use PhpDb\Sql\Predicate\Predicate; use PhpDb\Sql\Predicate\PredicateInterface; use PhpDb\Sql\Select; @@ -409,8 +409,8 @@ public function testUnnestThrowsWhenNotNested(): void { $predicate = new Predicate(); - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('Not nested'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(RuntimeException::NOT_NESTED); $predicate->unnest(); } @@ -469,7 +469,7 @@ private function makeSqlString(Predicate $where): string // } finally { // ErrorHandler::stop(); // } - $this->expectException(VunerablePlatformQuoteException::class); + self::expectException(VunerablePlatformQuoteException::class); return $select->getSqlString(new Sql92()); } } diff --git a/test/unit/Sql/SelectTest.php b/test/unit/Sql/SelectTest.php index 636a6680..04377154 100644 --- a/test/unit/Sql/SelectTest.php +++ b/test/unit/Sql/SelectTest.php @@ -17,6 +17,7 @@ use PhpDb\Sql\Having; use PhpDb\Sql\Join; use PhpDb\Sql\Predicate; +use PhpDb\Sql\Predicate\Exception\InvalidArgumentException as PredicateInvalidArgumentException; use PhpDb\Sql\Predicate\In; use PhpDb\Sql\Predicate\IsNotNull; use PhpDb\Sql\Predicate\Literal; @@ -836,8 +837,8 @@ public static function providerData(): array public function testBadJoin(): void { $select = new Select(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("expects 'foo' as"); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage("expects 'foo' as"); $select->join(['foo'], 'x = y'); } @@ -957,7 +958,7 @@ public function testCombineThrowsWhenAlreadyCombined(): void $select->from('t1'); $select->combine(new Select('t2')); - $this->expectException(InvalidArgumentException::class); + self::expectException(InvalidArgumentException::class); $select->combine(new Select('t3')); } @@ -1009,8 +1010,8 @@ public function testFromThrowsExceptionForInvalidArrayFormat(): void { $select = new Select(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('from() expects $table as an array is a single element associative array'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::INVALID_FROM_ARRAY); $select->from(['foo', 'bar']); // Numeric array instead of associative } @@ -1018,7 +1019,7 @@ public function testFromThrowsExceptionForInvalidTableType(): void { $select = new Select(); - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection ALL */ $select->from(123); } @@ -1027,8 +1028,8 @@ public function testFromThrowsExceptionWhenTableReadOnly(): void { $select = new Select('foo'); // Creating with table makes it read-only - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'Since this object was created with a table and/or schema in the constructor, it is read only.', ); $select->from('bar'); @@ -1068,8 +1069,8 @@ public function testGetThrowsExceptionForInvalidProperty(): void { $select = new Select(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Not a valid magic property for this object'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::INVALID_MAGIC_PROPERTY); /** @noinspection ALL */ $value = $select->invalidProperty; /** @phpstan-ignore-line */ } @@ -1215,8 +1216,8 @@ public function testLimit(): void public function testLimitExceptionOnInvalidParameter(): void { $select = new Select(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage(Select::class . '::limit expects parameter to be numeric'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(Select::class . '::limit expects parameter to be numeric'); $select->limit('foobar'); } @@ -1261,8 +1262,8 @@ public function testOffset(): void public function testOffsetExceptionOnInvalidParameter(): void { $select = new Select(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage(Select::class . '::offset expects parameter to be numeric'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(Select::class . '::offset expects parameter to be numeric'); $select->offset('foobar'); } @@ -1556,8 +1557,8 @@ public function testResetTableThrowsWhenTableReadOnly(): void { $select = new Select('foo'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('read only'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::READ_ONLY_CONSTRUCTOR_STATE); $select->reset(Select::TABLE); } @@ -1595,8 +1596,8 @@ public function testSetSpecificationThrowsExceptionForInvalidName(): void { $select = new Select(); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Not a valid specification name.'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::INVALID_SPECIFICATION_NAME); $select->setSpecification('invalid_spec', 'some spec'); } @@ -1644,8 +1645,8 @@ public function testWhereArgument1IsAssociativeArrayIsPredicate(): void 'name' => new Predicate\Literal("name = 'Ralph'"), 'age' => new Predicate\Expression('age = ?', 33), ]; - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Using Predicate must not use string keys'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(PredicateInvalidArgumentException::PREDICATE_WITH_STRING_KEY); $select->where($where); } diff --git a/test/unit/Sql/SqlTest.php b/test/unit/Sql/SqlTest.php index 3ea0e9fa..39bcedc9 100644 --- a/test/unit/Sql/SqlTest.php +++ b/test/unit/Sql/SqlTest.php @@ -59,7 +59,7 @@ public function test__construct(): void $sql->setTable('foo'); self::assertSame('foo', $sql->getTable()); - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpStrictTypeCheckingInspection */ $sql->setTable(null); } @@ -87,8 +87,8 @@ public function testBuildSqlStringThrowsWhenPlatformNotSqlInterface(): void $sql = new Sql($adapter); - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('does not implement SqlInterface'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(RuntimeException::SUBJECT_NOT_SQL_INTERFACE); $sql->buildSqlString($this->sql->select()); } @@ -99,8 +99,8 @@ public function testDelete(): void self::assertInstanceOf(Delete::class, $delete); self::assertSame('foo', $delete->getRawState('table')); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->delete('bar'); @@ -108,8 +108,8 @@ public function testDelete(): void public function testDeleteThrowsWhenTableConflicts(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->delete(new TableIdentifier('bar')); @@ -126,8 +126,8 @@ public function testInsert(): void self::assertInstanceOf(Insert::class, $insert); self::assertSame('foo', $insert->getRawState('table')); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->insert('bar'); @@ -135,8 +135,8 @@ public function testInsert(): void public function testInsertThrowsWhenTableConflicts(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->insert(new TableIdentifier('bar')); @@ -165,8 +165,8 @@ public function testPrepareStatementThrowsWhenPlatformNotPreparable(): void $sql = new Sql($adapter); - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('does not implement PreparableSqlInterface'); + self::expectException(RuntimeException::class); + self::expectExceptionMessage(RuntimeException::SUBJECT_NOT_PREPARABLE_SQL_INTERFACE); $sql->prepareStatementForSqlObject($this->sql->select()); } @@ -176,8 +176,8 @@ public function testSelect(): void self::assertInstanceOf(Select::class, $select); self::assertSame('foo', $select->getRawState('table')); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->select('bar'); @@ -185,8 +185,8 @@ public function testSelect(): void public function testSelectThrowsWhenTableConflicts(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->select(new TableIdentifier('bar')); @@ -198,8 +198,8 @@ public function testUpdate(): void self::assertInstanceOf(Update::class, $update); self::assertSame('foo', $update->getRawState('table')); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->update('bar'); @@ -207,8 +207,8 @@ public function testUpdate(): void public function testUpdateThrowsWhenTableConflicts(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( 'This Sql object is intended to work with only the table "foo" provided at construction time.', ); $this->sql->update(new TableIdentifier('bar')); diff --git a/test/unit/Sql/TableIdentifierFactoryTest.php b/test/unit/Sql/TableIdentifierFactoryTest.php index a3139aed..7d7b88bb 100644 --- a/test/unit/Sql/TableIdentifierFactoryTest.php +++ b/test/unit/Sql/TableIdentifierFactoryTest.php @@ -107,8 +107,8 @@ public function testRejectsEmptyStringCallTimePrefix(): void { $factory = new TableIdentifierFactory('backup'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$prefix must be a valid table prefix or null, empty string given'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_PREFIX); $factory('users', null, ''); } @@ -116,29 +116,29 @@ public function testRejectsEmptyStringCallTimeSeparator(): void { $factory = new TableIdentifierFactory('backup'); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$separator must be a valid table separator, empty string given'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_SEPARATOR); $factory('users', null, null, ''); } public function testRejectsEmptyStringPrefix(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$prefix must be a valid table prefix or null, empty string given'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_PREFIX); new TableIdentifierFactory(''); } public function testRejectsEmptyStringSeparator(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$separator must be a valid table separator, empty string given'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_SEPARATOR); new TableIdentifierFactory('backup', ''); } public function testRejectsEmptyStringSeparatorWithoutPrefix(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$separator must be a valid table separator, empty string given'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_SEPARATOR); new TableIdentifierFactory(null, ''); } diff --git a/test/unit/Sql/TableIdentifierTest.php b/test/unit/Sql/TableIdentifierTest.php index 27b66a7f..27fa7034 100644 --- a/test/unit/Sql/TableIdentifierTest.php +++ b/test/unit/Sql/TableIdentifierTest.php @@ -162,15 +162,15 @@ public function testGetUnprefixedTableReturnsTableAsGiven(): void public function testRejectsEmptyStringSeparatorWithoutPrefix(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('$separator must be a valid table separator, empty string given'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::EMPTY_SEPARATOR); new TableIdentifier('foo', null, null, ''); } #[DataProvider('invalidNameArgumentProvider')] public function testRejectsInvalidPrefix(mixed $invalidPrefix): void { - $this->expectException('' === $invalidPrefix ? InvalidArgumentException::class : TypeError::class); + self::expectException('' === $invalidPrefix ? InvalidArgumentException::class : TypeError::class); /** @psalm-suppress MixedArgument */ new TableIdentifier('foo', 'bar', $invalidPrefix); } @@ -178,7 +178,7 @@ public function testRejectsInvalidPrefix(mixed $invalidPrefix): void #[DataProvider('invalidNameArgumentProvider')] public function testRejectsInvalidSchema(mixed $invalidSchema): void { - $this->expectException('' === $invalidSchema ? InvalidArgumentException::class : TypeError::class); + self::expectException('' === $invalidSchema ? InvalidArgumentException::class : TypeError::class); /** @psalm-suppress MixedArgument */ new TableIdentifier('foo', $invalidSchema); } @@ -186,7 +186,7 @@ public function testRejectsInvalidSchema(mixed $invalidSchema): void #[DataProvider('invalidNameArgumentProvider')] public function testRejectsInvalidSeparator(mixed $invalidSeparator): void { - $this->expectException('' === $invalidSeparator ? InvalidArgumentException::class : TypeError::class); + self::expectException('' === $invalidSeparator ? InvalidArgumentException::class : TypeError::class); /** @psalm-suppress MixedArgument */ new TableIdentifier('foo', 'bar', 'backup', $invalidSeparator); } @@ -194,7 +194,7 @@ public function testRejectsInvalidSeparator(mixed $invalidSeparator): void #[DataProvider('invalidTableProvider')] public function testRejectsInvalidTable(mixed $invalidTable): void { - $this->expectException('' === $invalidTable ? InvalidArgumentException::class : TypeError::class); + self::expectException('' === $invalidTable ? InvalidArgumentException::class : TypeError::class); /** @psalm-suppress MixedArgument */ new TableIdentifier($invalidTable); } diff --git a/test/unit/Sql/UpdateTest.php b/test/unit/Sql/UpdateTest.php index 1e23e4b7..f8131084 100644 --- a/test/unit/Sql/UpdateTest.php +++ b/test/unit/Sql/UpdateTest.php @@ -392,8 +392,8 @@ public function testSetWithMergeFlag(): void public function testSetWithNonStringKeyThrowsException(): void { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('set() expects a string for the value key'); + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage(InvalidArgumentException::NON_STRING_VALUE_KEY); /** @psalm-suppress InvalidArgument - Testing invalid argument handling */ $this->update->set([0 => 'value']); @@ -541,7 +541,7 @@ public function testWhere(): void self::assertSame($where, $what); }); - $this->expectException(TypeError::class); + self::expectException(TypeError::class); /** @noinspection PhpStrictTypeCheckingInspection */ $this->update->where(null); }