diff --git a/src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/BaseVariadicFunction.php b/src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/BaseVariadicFunction.php index 79c31dfb..b3bf10ad 100644 --- a/src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/BaseVariadicFunction.php +++ b/src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/BaseVariadicFunction.php @@ -81,6 +81,10 @@ private function feedParserWithNodesForNodeMappingPattern(Parser $parser, string // When nodeIndex=2, we're about to add the 3rd argument (total: 3) $foundMoreNodesThanMappingExpected = ($nodeIndex + 1) > $this->getMaxArgumentCount(); if ($foundMoreNodesThanMappingExpected) { + if ($this->getMinArgumentCount() === $this->getMaxArgumentCount()) { + throw InvalidArgumentForVariadicFunctionException::exactCount($this->getFunctionName(), $this->getMinArgumentCount()); + } + throw InvalidArgumentForVariadicFunctionException::between($this->getFunctionName(), $this->getMinArgumentCount(), $this->getMaxArgumentCount()); } @@ -114,6 +118,10 @@ protected function validateArguments(Node ...$arguments): void $maxArgumentCount = $this->getMaxArgumentCount(); $argumentCount = \count($arguments); + if ($minArgumentCount === $maxArgumentCount && $argumentCount !== $minArgumentCount) { + throw InvalidArgumentForVariadicFunctionException::exactCount($this->getFunctionName(), $this->getMinArgumentCount()); + } + if ($argumentCount < $minArgumentCount) { throw InvalidArgumentForVariadicFunctionException::atLeast($this->getFunctionName(), $this->getMinArgumentCount()); } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AllTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AllTest.php index 359ac51a..94741af2 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AllTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AllTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT c0_.id AS id_0 FROM ContainsArrays c0_ WHERE c0_.id > ALL(c0_.textArray)', + 'all elements match condition' => 'SELECT c0_.id AS id_0 FROM ContainsArrays c0_ WHERE c0_.id > ALL(c0_.textArray)', ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT e.id FROM %s e WHERE e.id > ALL_OF(e.textArray)', ContainsArrays::class), + 'all elements match condition' => \sprintf('SELECT e.id FROM %s e WHERE e.id > ALL_OF(e.textArray)', ContainsArrays::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php index baf979c0..9bd3236d 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php @@ -8,6 +8,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayPosition; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class ArrayPositionTest extends BaseVariadicFunctionTestCase @@ -31,6 +32,9 @@ protected function getExpectedSqlStatements(): array 'finds numeric element' => 'SELECT array_position(c0_.integerArray, 42) AS sclr_0 FROM ContainsArrays c0_', 'finds element using parameter' => 'SELECT array_position(c0_.textArray, ?) AS sclr_0 FROM ContainsArrays c0_', 'with start position' => "SELECT array_position(c0_.textArray, 'new-value', 2) AS sclr_0 FROM ContainsArrays c0_", + 'with zero start position' => "SELECT array_position(c0_.textArray, 'value', 0) AS sclr_0 FROM ContainsArrays c0_", + 'with negative start position' => "SELECT array_position(c0_.textArray, 'value', -1) AS sclr_0 FROM ContainsArrays c0_", + 'with arithmetic expression as start position' => "SELECT array_position(c0_.textArray, 'value', 1 + 1) AS sclr_0 FROM ContainsArrays c0_", ]; } @@ -41,26 +45,36 @@ protected function getDqlStatements(): array 'finds numeric element' => \sprintf('SELECT ARRAY_POSITION(e.integerArray, 42) FROM %s e', ContainsArrays::class), 'finds element using parameter' => \sprintf('SELECT ARRAY_POSITION(e.textArray, :dql_parameter) FROM %s e', ContainsArrays::class), 'with start position' => \sprintf("SELECT ARRAY_POSITION(e.textArray, 'new-value', 2) FROM %s e", ContainsArrays::class), + 'with zero start position' => \sprintf("SELECT ARRAY_POSITION(e.textArray, 'value', 0) FROM %s e", ContainsArrays::class), + 'with negative start position' => \sprintf("SELECT ARRAY_POSITION(e.textArray, 'value', -1) FROM %s e", ContainsArrays::class), + 'with arithmetic expression as start position' => \sprintf("SELECT ARRAY_POSITION(e.textArray, 'value', 1+1) FROM %s e", ContainsArrays::class), ]; } + #[DataProvider('provideInvalidArgumentCountCases')] #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_invalid_argument_count(string $dql, string $expectedMessage): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('array_position() requires at least 2 arguments'); + $this->expectExceptionMessage($expectedMessage); - $dql = \sprintf('SELECT ARRAY_POSITION(e.textArray) FROM %s e', ContainsArrays::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } - #[Test] - public function too_many_arguments_throws_exception(): void + /** + * @return array + */ + public static function provideInvalidArgumentCountCases(): array { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('array_position() requires between 2 and 3 arguments'); - - $dql = \sprintf("SELECT ARRAY_POSITION(e.textArray, 0, 1, 'extra_arg') FROM %s e", ContainsArrays::class); - $this->buildEntityManager()->createQuery($dql)->getSQL(); + return [ + 'too few arguments' => [ + \sprintf('SELECT ARRAY_POSITION(e.textArray) FROM %s e', ContainsArrays::class), + 'array_position() requires at least 2 arguments', + ], + 'too many arguments' => [ + \sprintf("SELECT ARRAY_POSITION(e.textArray, 0, 1, 'extra_arg') FROM %s e", ContainsArrays::class), + 'array_position() requires between 2 and 3 arguments', + ], + ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php index 1a9c30ef..60626991 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php @@ -42,7 +42,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean_value(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for array_to_json. Must be "true" or "false".'); @@ -52,7 +52,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('array_to_json() requires between 1 and 2 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CeilTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CeilTest.php index 03840638..68970767 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CeilTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CeilTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT CEIL(c0_.decimal1) AS sclr_0 FROM ContainsDecimals c0_', + 'rounds decimal up to nearest integer' => 'SELECT CEIL(c0_.decimal1) AS sclr_0 FROM ContainsDecimals c0_', ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT CEIL(e.decimal1) FROM %s e', ContainsDecimals::class), + 'rounds decimal up to nearest integer' => \sprintf('SELECT CEIL(e.decimal1) FROM %s e', ContainsDecimals::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateAddTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateAddTest.php index 095a2df8..f106e58c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateAddTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateAddTest.php @@ -9,6 +9,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\DateAdd; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidTimezoneException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class DateAddTest extends BaseVariadicFunctionTestCase @@ -28,50 +29,62 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'adds 1 day with timezone' => "SELECT date_add(c0_.datetimetz1, '1 day', 'Europe/Sofia') AS sclr_0 FROM ContainsDates c0_", - 'adds 2 hours with timezone' => "SELECT date_add(c0_.datetimetz1, '2 hours', 'UTC') AS sclr_0 FROM ContainsDates c0_", - 'adds 3 days without timezone' => "SELECT date_add(c0_.datetimetz1, '3 days') AS sclr_0 FROM ContainsDates c0_", - 'adds with WHERE clause' => "SELECT c0_.datetimetz1 AS datetimetz1_0 FROM ContainsDates c0_ WHERE date_add(c0_.datetimetz1, '1 day') = '2023-01-02 00:00:00'", + 'with timezone (3 arguments)' => "SELECT date_add(c0_.datetimetz1, '1 day', 'Europe/Sofia') AS sclr_0 FROM ContainsDates c0_", + 'without timezone (2 arguments)' => "SELECT date_add(c0_.datetimetz1, '3 days') AS sclr_0 FROM ContainsDates c0_", + 'used in WHERE clause' => "SELECT c0_.datetimetz1 AS datetimetz1_0 FROM ContainsDates c0_ WHERE date_add(c0_.datetimetz1, '1 day') = '2023-01-02 00:00:00'", ]; } protected function getDqlStatements(): array { return [ - 'adds 1 day with timezone' => \sprintf("SELECT DATE_ADD(e.datetimetz1, '1 day', 'Europe/Sofia') FROM %s e", ContainsDates::class), - 'adds 2 hours with timezone' => \sprintf("SELECT DATE_ADD(e.datetimetz1, '2 hours', 'UTC') FROM %s e", ContainsDates::class), - 'adds 3 days without timezone' => \sprintf("SELECT DATE_ADD(e.datetimetz1, '3 days') FROM %s e", ContainsDates::class), - 'adds with WHERE clause' => \sprintf("SELECT e.datetimetz1 FROM %s e WHERE DATE_ADD(e.datetimetz1, '1 day') = '2023-01-02 00:00:00'", ContainsDates::class), + 'with timezone (3 arguments)' => \sprintf("SELECT DATE_ADD(e.datetimetz1, '1 day', 'Europe/Sofia') FROM %s e", ContainsDates::class), + 'without timezone (2 arguments)' => \sprintf("SELECT DATE_ADD(e.datetimetz1, '3 days') FROM %s e", ContainsDates::class), + 'used in WHERE clause' => \sprintf("SELECT e.datetimetz1 FROM %s e WHERE DATE_ADD(e.datetimetz1, '1 day') = '2023-01-02 00:00:00'", ContainsDates::class), ]; } #[Test] - public function invalid_timezone_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { - $this->expectException(InvalidTimezoneException::class); - $this->expectExceptionMessage('Invalid timezone "Invalid/Timezone" provided for date_add'); + $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('date_add() requires at least 2 arguments'); - $dql = \sprintf("SELECT DATE_ADD(e.datetimetz1, '1 day', 'Invalid/Timezone') FROM %s e", ContainsDates::class); + $dql = \sprintf('SELECT DATE_ADD(e.datetimetz1) FROM %s e', ContainsDates::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('date_add() requires at least 2 arguments'); + $this->expectExceptionMessage('date_add() requires between 2 and 3 arguments'); - $dql = \sprintf('SELECT DATE_ADD(e.datetimetz1) FROM %s e', ContainsDates::class); + $dql = \sprintf("SELECT DATE_ADD(e.datetimetz1, '1 day', 'Europe/Sofia', 'extra_arg') FROM %s e", ContainsDates::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } + #[DataProvider('provideInvalidTimezoneValues')] #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_invalid_timezone(string $invalidTimezone): void { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('date_add() requires between 2 and 3 arguments'); + $this->expectException(InvalidTimezoneException::class); + $this->expectExceptionMessage(\sprintf('Invalid timezone "%s" provided for date_add. Must be a valid PHP timezone identifier.', $invalidTimezone)); - $dql = \sprintf("SELECT DATE_ADD(e.datetimetz1, '1 day', 'Europe/Sofia', 'extra_arg') FROM %s e", ContainsDates::class); + $dql = \sprintf("SELECT DATE_ADD(e.datetimetz1, '1 day', '%s') FROM %s e", $invalidTimezone, ContainsDates::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } + + /** + * @return array + */ + public static function provideInvalidTimezoneValues(): array + { + return [ + 'empty string' => [''], + 'whitespace only' => [' '], + 'numeric value' => ['123'], + 'invalid timezone' => ['Invalid/Timezone'], + ]; + } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php index d5693087..08dded17 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php @@ -19,22 +19,22 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT EXTRACT('DAY' FROM c0_.date1) AS sclr_0 FROM ContainsDates c0_", - "SELECT EXTRACT('MONTH' FROM c0_.date1) AS sclr_0 FROM ContainsDates c0_", - "SELECT EXTRACT('YEAR' FROM c0_.date1) AS sclr_0 FROM ContainsDates c0_", - "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE EXTRACT('DAY' FROM c0_.date1) = 7", - "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE EXTRACT('MONTH' FROM c0_.date1) = 12", + 'extracts day from date' => "SELECT EXTRACT('DAY' FROM c0_.date1) AS sclr_0 FROM ContainsDates c0_", + 'extracts month from date' => "SELECT EXTRACT('MONTH' FROM c0_.date1) AS sclr_0 FROM ContainsDates c0_", + 'extracts year from date' => "SELECT EXTRACT('YEAR' FROM c0_.date1) AS sclr_0 FROM ContainsDates c0_", + 'filters by extracted day' => "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE EXTRACT('DAY' FROM c0_.date1) = 7", + 'filters by extracted month' => "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE EXTRACT('MONTH' FROM c0_.date1) = 12", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT DATE_EXTRACT('DAY', e.date1) FROM %s e", ContainsDates::class), - \sprintf("SELECT DATE_EXTRACT('MONTH', e.date1) FROM %s e", ContainsDates::class), - \sprintf("SELECT DATE_EXTRACT('YEAR', e.date1) FROM %s e", ContainsDates::class), - \sprintf("SELECT e.date1 FROM %s e WHERE DATE_EXTRACT('DAY', e.date1) = 7", ContainsDates::class), - \sprintf("SELECT e.date1 FROM %s e WHERE DATE_EXTRACT('MONTH', e.date1) = 12", ContainsDates::class), + 'extracts day from date' => \sprintf("SELECT DATE_EXTRACT('DAY', e.date1) FROM %s e", ContainsDates::class), + 'extracts month from date' => \sprintf("SELECT DATE_EXTRACT('MONTH', e.date1) FROM %s e", ContainsDates::class), + 'extracts year from date' => \sprintf("SELECT DATE_EXTRACT('YEAR', e.date1) FROM %s e", ContainsDates::class), + 'filters by extracted day' => \sprintf("SELECT e.date1 FROM %s e WHERE DATE_EXTRACT('DAY', e.date1) = 7", ContainsDates::class), + 'filters by extracted month' => \sprintf("SELECT e.date1 FROM %s e WHERE DATE_EXTRACT('MONTH', e.date1) = 12", ContainsDates::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateOverlapsTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateOverlapsTest.php index 26524efc..3ec30c91 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateOverlapsTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateOverlapsTest.php @@ -19,29 +19,29 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, c0_.date2) OVERLAPS ('2001-12-21', '2001-12-25') = 0", - "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, c0_.date2) OVERLAPS ('2001-12-21', '2001-12-25') = 1", - "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, COALESCE(c0_.date2, CURRENT_DATE)) OVERLAPS ('2001-12-21', '2001-12-25') = 1", - "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, COALESCE(c0_.date2, CURRENT_DATE)) OVERLAPS ('2001-12-21', '2001-12-25') = 0", + 'checks non-overlapping date ranges' => "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, c0_.date2) OVERLAPS ('2001-12-21', '2001-12-25') = 0", + 'checks overlapping date ranges' => "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, c0_.date2) OVERLAPS ('2001-12-21', '2001-12-25') = 1", + 'checks overlapping with null handling true' => "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, COALESCE(c0_.date2, CURRENT_DATE)) OVERLAPS ('2001-12-21', '2001-12-25') = 1", + 'checks overlapping with null handling false' => "SELECT c0_.date1 AS date1_0 FROM ContainsDates c0_ WHERE (c0_.date1, COALESCE(c0_.date2, CURRENT_DATE)) OVERLAPS ('2001-12-21', '2001-12-25') = 0", ]; } protected function getDqlStatements(): array { return [ - \sprintf( + 'checks non-overlapping date ranges' => \sprintf( "SELECT e.date1 FROM %s e WHERE DATE_OVERLAPS(e.date1, e.date2, '2001-12-21', '2001-12-25') = 0", ContainsDates::class ), - \sprintf( + 'checks overlapping date ranges' => \sprintf( "SELECT e.date1 FROM %s e WHERE DATE_OVERLAPS(e.date1, e.date2, '2001-12-21', '2001-12-25') = TRUE", ContainsDates::class ), - \sprintf( + 'checks overlapping with null handling true' => \sprintf( "SELECT e.date1 FROM %s e WHERE DATE_OVERLAPS(e.date1, COALESCE(e.date2, CURRENT_DATE()), '2001-12-21', '2001-12-25') = 1", ContainsDates::class ), - \sprintf( + 'checks overlapping with null handling false' => \sprintf( "SELECT e.date1 FROM %s e WHERE DATE_OVERLAPS(e.date1, COALESCE(e.date2, CURRENT_DATE()), '2001-12-21', '2001-12-25') = FALSE", ContainsDates::class ), diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateSubtractTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateSubtractTest.php index 5d6d4c06..9a122b2d 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateSubtractTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateSubtractTest.php @@ -9,6 +9,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\DateSubtract; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidTimezoneException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class DateSubtractTest extends BaseVariadicFunctionTestCase @@ -28,48 +29,69 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'subtracts 1 day with timezone' => "SELECT date_subtract(c0_.datetimetz1, '1 day', 'Europe/Sofia') AS sclr_0 FROM ContainsDates c0_", - 'subtracts 2 hours with timezone' => "SELECT date_subtract(c0_.datetimetz1, '2 hours', 'UTC') AS sclr_0 FROM ContainsDates c0_", - 'subtracts 3 days without timezone' => "SELECT date_subtract(c0_.datetimetz1, '3 days') AS sclr_0 FROM ContainsDates c0_", + 'with timezone (3 arguments)' => "SELECT date_subtract(c0_.datetimetz1, '1 day', 'Europe/Sofia') AS sclr_0 FROM ContainsDates c0_", + 'without timezone (2 arguments)' => "SELECT date_subtract(c0_.datetimetz1, '3 days') AS sclr_0 FROM ContainsDates c0_", + 'used in WHERE clause' => "SELECT c0_.datetimetz1 AS datetimetz1_0 FROM ContainsDates c0_ WHERE date_subtract(c0_.datetimetz1, '1 day') = '2023-01-02 00:00:00'", ]; } protected function getDqlStatements(): array { return [ - 'subtracts 1 day with timezone' => \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '1 day', 'Europe/Sofia') FROM %s e", ContainsDates::class), - 'subtracts 2 hours with timezone' => \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '2 hours', 'UTC') FROM %s e", ContainsDates::class), - 'subtracts 3 days without timezone' => \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '3 days') FROM %s e", ContainsDates::class), + 'with timezone (3 arguments)' => \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '1 day', 'Europe/Sofia') FROM %s e", ContainsDates::class), + 'without timezone (2 arguments)' => \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '3 days') FROM %s e", ContainsDates::class), + 'used in WHERE clause' => \sprintf("SELECT e.datetimetz1 FROM %s e WHERE DATE_SUBTRACT(e.datetimetz1, '1 day') = '2023-01-02 00:00:00'", ContainsDates::class), ]; } + #[DataProvider('provideInvalidArgumentCountCases')] #[Test] - public function invalid_timezone_throws_exception(): void + public function throws_exception_for_invalid_argument_count(string $dql, string $expectedMessage): void { - $this->expectException(InvalidTimezoneException::class); - $this->expectExceptionMessage('Invalid timezone "Invalid/Timezone" provided for date_subtract'); + $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage($expectedMessage); - $dql = \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '1 day', 'Invalid/Timezone') FROM %s e", ContainsDates::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } - #[Test] - public function too_few_arguments_throws_exception(): void + /** + * @return array + */ + public static function provideInvalidArgumentCountCases(): array { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('date_subtract() requires at least 2 arguments'); - - $dql = \sprintf('SELECT DATE_SUBTRACT(e.datetimetz1) FROM %s e', ContainsDates::class); - $this->buildEntityManager()->createQuery($dql)->getSQL(); + return [ + 'too few arguments' => [ + \sprintf('SELECT DATE_SUBTRACT(e.datetimetz1) FROM %s e', ContainsDates::class), + 'date_subtract() requires at least 2 arguments', + ], + 'too many arguments' => [ + \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '1 day', 'Europe/Sofia', 'extra_arg') FROM %s e", ContainsDates::class), + 'date_subtract() requires between 2 and 3 arguments', + ], + ]; } + #[DataProvider('provideInvalidTimezoneValues')] #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_invalid_timezone(string $invalidTimezone): void { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('date_subtract() requires between 2 and 3 arguments'); + $this->expectException(InvalidTimezoneException::class); + $this->expectExceptionMessage(\sprintf('Invalid timezone "%s" provided for date_subtract. Must be a valid PHP timezone identifier.', $invalidTimezone)); - $dql = \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '1 day', 'Europe/Sofia', 'extra_arg') FROM %s e", ContainsDates::class); + $dql = \sprintf("SELECT DATE_SUBTRACT(e.datetimetz1, '1 day', '%s') FROM %s e", $invalidTimezone, ContainsDates::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } + + /** + * @return array + */ + public static function provideInvalidTimezoneValues(): array + { + return [ + 'empty string' => [''], + 'whitespace only' => [' '], + 'numeric value' => ['123'], + 'invalid timezone' => ['Invalid/Timezone'], + ]; + } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DistanceTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DistanceTest.php index 1d56d2d6..d0b64cb1 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DistanceTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DistanceTest.php @@ -19,18 +19,18 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.point1 <@> '(2.320041, 48.858889)') AS sclr_0 FROM ContainsPoints c0_", - 'SELECT (c0_.point1 <@> c0_.point2) AS sclr_0 FROM ContainsPoints c0_', - "SELECT ('(1.0, 1.0)' <@> '(2.0, 2.0)') AS sclr_0 FROM ContainsPoints c0_", + 'calculates distance between field and literal point' => "SELECT (c0_.point1 <@> '(2.320041, 48.858889)') AS sclr_0 FROM ContainsPoints c0_", + 'calculates distance between two point fields' => 'SELECT (c0_.point1 <@> c0_.point2) AS sclr_0 FROM ContainsPoints c0_', + 'calculates distance between two literal points' => "SELECT ('(1.0, 1.0)' <@> '(2.0, 2.0)') AS sclr_0 FROM ContainsPoints c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT DISTANCE(e.point1, '(2.320041, 48.858889)') FROM %s e", ContainsPoints::class), - \sprintf('SELECT DISTANCE(e.point1, e.point2) FROM %s e', ContainsPoints::class), - \sprintf("SELECT DISTANCE('(1.0, 1.0)', '(2.0, 2.0)') FROM %s e", ContainsPoints::class), + 'calculates distance between field and literal point' => \sprintf("SELECT DISTANCE(e.point1, '(2.320041, 48.858889)') FROM %s e", ContainsPoints::class), + 'calculates distance between two point fields' => \sprintf('SELECT DISTANCE(e.point1, e.point2) FROM %s e', ContainsPoints::class), + 'calculates distance between two literal points' => \sprintf("SELECT DISTANCE('(1.0, 1.0)', '(2.0, 2.0)') FROM %s e", ContainsPoints::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpLikeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpLikeTest.php index 05a4f20a..7b28b95c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpLikeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpLikeTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT regexp_like(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_", + 'checks if text matches regex pattern with flags' => "SELECT regexp_like(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT FLAGGED_REGEXP_LIKE(e.text1, 'pattern', 'i') FROM %s e", ContainsTexts::class), + 'checks if text matches regex pattern with flags' => \sprintf("SELECT FLAGGED_REGEXP_LIKE(e.text1, 'pattern', 'i') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpMatchTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpMatchTest.php index 6f567f97..bc914fde 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpMatchTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpMatchTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT regexp_match(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_", + 'matches text using regex with flags' => "SELECT regexp_match(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT FLAGGED_REGEXP_MATCH(e.text1, 'pattern', 'i') FROM %s e", ContainsTexts::class), + 'matches text using regex with flags' => \sprintf("SELECT FLAGGED_REGEXP_MATCH(e.text1, 'pattern', 'i') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpReplaceTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpReplaceTest.php index 7fd6d28a..519fd50b 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpReplaceTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FlaggedRegexpReplaceTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 'g') AS sclr_0 FROM ContainsTexts c0_", + 'replaces text using regex with flags' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 'g') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT FLAGGED_REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 'g') FROM %s e", ContainsTexts::class), + 'replaces text using regex with flags' => \sprintf("SELECT FLAGGED_REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 'g') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FloorTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FloorTest.php index 985491cb..b2912ecc 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FloorTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FloorTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT FLOOR(c0_.decimal1) AS sclr_0 FROM ContainsDecimals c0_', + 'rounds decimal down to nearest integer' => 'SELECT FLOOR(c0_.decimal1) AS sclr_0 FROM ContainsDecimals c0_', ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT FLOOR(e.decimal1) FROM %s e', ContainsDecimals::class), + 'rounds decimal down to nearest integer' => \sprintf('SELECT FLOOR(e.decimal1) FROM %s e', ContainsDecimals::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/GreatestTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/GreatestTest.php index 315e3c81..a94628cb 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/GreatestTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/GreatestTest.php @@ -43,7 +43,7 @@ protected function getDqlStatements(): array } #[Test] - public function throws_exception_when_single_argument_given(): void + public function throws_exception_for_insufficient_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php index 64e2b1f6..2132ef7c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.text1 ~* '.*Thomas.*') AS sclr_0 FROM ContainsTexts c0_", + 'case-insensitive regex pattern matching' => "SELECT (c0_.text1 ~* '.*Thomas.*') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT IREGEXP(e.text1, '.*Thomas.*') FROM %s e", ContainsTexts::class), + 'case-insensitive regex pattern matching' => \sprintf("SELECT IREGEXP(e.text1, '.*Thomas.*') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php index ec0ca344..103608ea 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT c0_.text1 ilike 'TEST' AS sclr_0 FROM ContainsTexts c0_", + 'case-insensitive pattern matching' => "SELECT c0_.text1 ilike 'TEST' AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT ILIKE(e.text1,'TEST') FROM %s e", ContainsTexts::class), + 'case-insensitive pattern matching' => \sprintf("SELECT ILIKE(e.text1,'TEST') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IsContainedByTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IsContainedByTest.php index 30c7ce79..909084c8 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IsContainedByTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IsContainedByTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.textArray <@ '{681,1185,1878}') AS sclr_0 FROM ContainsArrays c0_", + 'checks if left array is contained by right array' => "SELECT (c0_.textArray <@ '{681,1185,1878}') AS sclr_0 FROM ContainsArrays c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT IS_CONTAINED_BY(e.textArray, '{681,1185,1878}') FROM %s e", ContainsArrays::class), + 'checks if left array is contained by right array' => \sprintf("SELECT IS_CONTAINED_BY(e.textArray, '{681,1185,1878}') FROM %s e", ContainsArrays::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonBuildObjectTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonBuildObjectTest.php index ccfa0aba..25d5d76d 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonBuildObjectTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonBuildObjectTest.php @@ -27,27 +27,44 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT json_build_object('key1', c0_.object1) AS sclr_0 FROM ContainsJsons c0_", - "SELECT json_build_object('key1', UPPER('value1'), 'key2', 'value2') AS sclr_0 FROM ContainsJsons c0_", - "SELECT json_build_object('key1', c0_.object1, 'key2', c0_.object2) AS sclr_0 FROM ContainsJsons c0_", + 'builds JSON object with field value' => "SELECT json_build_object('key1', c0_.object1) AS sclr_0 FROM ContainsJsons c0_", + 'builds JSON object with function result and literal' => "SELECT json_build_object('key1', UPPER('value1'), 'key2', 'value2') AS sclr_0 FROM ContainsJsons c0_", + 'builds JSON object with multiple field values' => "SELECT json_build_object('key1', c0_.object1, 'key2', c0_.object2) AS sclr_0 FROM ContainsJsons c0_", + 'builds JSON object with many key-value pairs' => "SELECT json_build_object('k1', 'v1', 'k2', 'v2', 'k3', 'v3', 'k4', 'v4') AS sclr_0 FROM ContainsJsons c0_", + 'builds JSON object with numeric and boolean values' => "SELECT json_build_object('numeric_key', '123', 'boolean_key', 'true') AS sclr_0 FROM ContainsJsons c0_", + 'builds JSON object with mixed field and literal values' => "SELECT json_build_object('field_key', c0_.object1, 'literal_key', 'literal_value') AS sclr_0 FROM ContainsJsons c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT JSON_BUILD_OBJECT('key1', e.object1) FROM %s e", ContainsJsons::class), - \sprintf("SELECT JSON_BUILD_OBJECT('key1', UPPER('value1'), 'key2', 'value2') FROM %s e", ContainsJsons::class), - \sprintf("SELECT JSON_BUILD_OBJECT('key1', e.object1, 'key2', e.object2) FROM %s e", ContainsJsons::class), + 'builds JSON object with field value' => \sprintf("SELECT JSON_BUILD_OBJECT('key1', e.object1) FROM %s e", ContainsJsons::class), + 'builds JSON object with function result and literal' => \sprintf("SELECT JSON_BUILD_OBJECT('key1', UPPER('value1'), 'key2', 'value2') FROM %s e", ContainsJsons::class), + 'builds JSON object with multiple field values' => \sprintf("SELECT JSON_BUILD_OBJECT('key1', e.object1, 'key2', e.object2) FROM %s e", ContainsJsons::class), + 'builds JSON object with many key-value pairs' => \sprintf("SELECT JSON_BUILD_OBJECT('k1', 'v1', 'k2', 'v2', 'k3', 'v3', 'k4', 'v4') FROM %s e", ContainsJsons::class), + 'builds JSON object with numeric and boolean values' => \sprintf("SELECT JSON_BUILD_OBJECT('numeric_key', '123', 'boolean_key', 'true') FROM %s e", ContainsJsons::class), + 'builds JSON object with mixed field and literal values' => \sprintf("SELECT JSON_BUILD_OBJECT('field_key', e.object1, 'literal_key', 'literal_value') FROM %s e", ContainsJsons::class), ]; } #[Test] - public function throws_exception_when_odd_number_of_arguments_given(): void + public function throws_exception_for_odd_number_of_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('json_build_object() requires an even number of arguments'); - $dql = \sprintf("SELECT JSON_BUILD_OBJECT('key1', e.value1, 'key2') FROM %s e", ContainsJsons::class); - $this->assertSqlFromDql('', $dql); + $dql = \sprintf("SELECT JSON_BUILD_OBJECT('key1', e.object1, 'key2') FROM %s e", ContainsJsons::class); + $this->buildEntityManager()->createQuery($dql)->getSQL(); + } + + #[Test] + public function throws_exception_for_single_argument(): void + { + $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('json_build_object() requires at least 2 arguments'); + + $dql = \sprintf("SELECT JSON_BUILD_OBJECT('key1') FROM %s e", ContainsJsons::class); + $this->buildEntityManager()->createQuery($dql)->getSQL(); } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetObjectTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetObjectTest.php index 18a714c4..3c669e98 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetObjectTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetObjectTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.object1 #> '{residency}') AS sclr_0 FROM ContainsJsons c0_", + 'extracts JSON object at specified path' => "SELECT (c0_.object1 #> '{residency}') AS sclr_0 FROM ContainsJsons c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT JSON_GET_OBJECT(e.object1, '{residency}') FROM %s e", ContainsJsons::class), + 'extracts JSON object at specified path' => \sprintf("SELECT JSON_GET_OBJECT(e.object1, '{residency}') FROM %s e", ContainsJsons::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonValueTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonValueTest.php index c1654e0d..02749f81 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonValueTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonValueTest.php @@ -19,18 +19,18 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT json_value(c0_.object1, '$.name') AS sclr_0 FROM ContainsJsons c0_", - "SELECT json_value(c0_.object1, '$.address.city') AS sclr_0 FROM ContainsJsons c0_", - "SELECT json_value(c0_.object1, '$.items[0]') AS sclr_0 FROM ContainsJsons c0_", + 'extracts simple property value' => "SELECT json_value(c0_.object1, '$.name') AS sclr_0 FROM ContainsJsons c0_", + 'extracts nested property value' => "SELECT json_value(c0_.object1, '$.address.city') AS sclr_0 FROM ContainsJsons c0_", + 'extracts array element value' => "SELECT json_value(c0_.object1, '$.items[0]') AS sclr_0 FROM ContainsJsons c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT JSON_VALUE(e.object1, '$.name') FROM %s e", ContainsJsons::class), - \sprintf("SELECT JSON_VALUE(e.object1, '$.address.city') FROM %s e", ContainsJsons::class), - \sprintf("SELECT JSON_VALUE(e.object1, '$.items[0]') FROM %s e", ContainsJsons::class), + 'extracts simple property value' => \sprintf("SELECT JSON_VALUE(e.object1, '$.name') FROM %s e", ContainsJsons::class), + 'extracts nested property value' => \sprintf("SELECT JSON_VALUE(e.object1, '$.address.city') FROM %s e", ContainsJsons::class), + 'extracts array element value' => \sprintf("SELECT JSON_VALUE(e.object1, '$.items[0]') FROM %s e", ContainsJsons::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbBuildObjectTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbBuildObjectTest.php index 39d805a0..2bfbb369 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbBuildObjectTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbBuildObjectTest.php @@ -27,27 +27,44 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT jsonb_build_object('key1', c0_.object1) AS sclr_0 FROM ContainsJsons c0_", - "SELECT jsonb_build_object('key1', UPPER('value1'), 'key2', 'value2') AS sclr_0 FROM ContainsJsons c0_", - "SELECT jsonb_build_object('key1', c0_.object1, 'key2', c0_.object2) AS sclr_0 FROM ContainsJsons c0_", + 'builds JSONB object with field value' => "SELECT jsonb_build_object('key1', c0_.object1) AS sclr_0 FROM ContainsJsons c0_", + 'builds JSONB object with function result and literal' => "SELECT jsonb_build_object('key1', UPPER('value1'), 'key2', 'value2') AS sclr_0 FROM ContainsJsons c0_", + 'builds JSONB object with multiple field values' => "SELECT jsonb_build_object('key1', c0_.object1, 'key2', c0_.object2) AS sclr_0 FROM ContainsJsons c0_", + 'builds JSONB object with many key-value pairs' => "SELECT jsonb_build_object('k1', 'v1', 'k2', 'v2', 'k3', 'v3', 'k4', 'v4') AS sclr_0 FROM ContainsJsons c0_", + 'builds JSONB object with numeric and boolean values' => "SELECT jsonb_build_object('numeric_key', '123', 'boolean_key', 'true') AS sclr_0 FROM ContainsJsons c0_", + 'builds JSONB object with mixed field and literal values' => "SELECT jsonb_build_object('field_key', c0_.object1, 'literal_key', 'literal_value') AS sclr_0 FROM ContainsJsons c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT JSONB_BUILD_OBJECT('key1', e.object1) FROM %s e", ContainsJsons::class), - \sprintf("SELECT JSONB_BUILD_OBJECT('key1', UPPER('value1'), 'key2', 'value2') FROM %s e", ContainsJsons::class), - \sprintf("SELECT JSONB_BUILD_OBJECT('key1', e.object1, 'key2', e.object2) FROM %s e", ContainsJsons::class), + 'builds JSONB object with field value' => \sprintf("SELECT JSONB_BUILD_OBJECT('key1', e.object1) FROM %s e", ContainsJsons::class), + 'builds JSONB object with function result and literal' => \sprintf("SELECT JSONB_BUILD_OBJECT('key1', UPPER('value1'), 'key2', 'value2') FROM %s e", ContainsJsons::class), + 'builds JSONB object with multiple field values' => \sprintf("SELECT JSONB_BUILD_OBJECT('key1', e.object1, 'key2', e.object2) FROM %s e", ContainsJsons::class), + 'builds JSONB object with many key-value pairs' => \sprintf("SELECT JSONB_BUILD_OBJECT('k1', 'v1', 'k2', 'v2', 'k3', 'v3', 'k4', 'v4') FROM %s e", ContainsJsons::class), + 'builds JSONB object with numeric and boolean values' => \sprintf("SELECT JSONB_BUILD_OBJECT('numeric_key', '123', 'boolean_key', 'true') FROM %s e", ContainsJsons::class), + 'builds JSONB object with mixed field and literal values' => \sprintf("SELECT JSONB_BUILD_OBJECT('field_key', e.object1, 'literal_key', 'literal_value') FROM %s e", ContainsJsons::class), ]; } #[Test] - public function throws_exception_when_odd_number_of_arguments_given(): void + public function throws_exception_for_odd_number_of_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('jsonb_build_object() requires an even number of arguments'); $dql = \sprintf("SELECT JSONB_BUILD_OBJECT('key1', e.object1, 'key2') FROM %s e", ContainsJsons::class); - $this->assertSqlFromDql('', $dql); + $this->buildEntityManager()->createQuery($dql)->getSQL(); + } + + #[Test] + public function throws_exception_for_single_argument(): void + { + $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('jsonb_build_object() requires at least 2 arguments'); + + $dql = \sprintf("SELECT JSONB_BUILD_OBJECT('key1') FROM %s e", ContainsJsons::class); + $this->buildEntityManager()->createQuery($dql)->getSQL(); } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php index cb67a3b3..eccd47fb 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php @@ -36,7 +36,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_insert. Must be "true" or "false".'); @@ -46,7 +46,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_insert() requires at least 3 arguments'); @@ -56,7 +56,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_insert() requires between 3 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php index 6e88f696..4439ddaa 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php @@ -46,7 +46,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_path_exists. Must be "true" or "false".'); @@ -56,7 +56,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_exists() requires at least 2 arguments'); @@ -66,7 +66,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_exists() requires between 2 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php index 91ba190d..5c3e15f9 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php @@ -46,7 +46,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_path_match. Must be "true" or "false".'); @@ -56,7 +56,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_match() requires at least 2 arguments'); @@ -66,7 +66,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_match() requires between 2 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php index 009a5b8c..1b75ae97 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php @@ -46,7 +46,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_path_query_array. Must be "true" or "false".'); @@ -56,7 +56,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_query_array() requires at least 2 arguments'); @@ -66,7 +66,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_query_array() requires between 2 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php index fc70b0de..e4311d7c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php @@ -46,7 +46,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_path_query_first. Must be "true" or "false".'); @@ -56,7 +56,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_query_first() requires at least 2 arguments'); @@ -66,7 +66,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_query_first() requires between 2 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php index 6cb99489..dca52dc1 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php @@ -46,7 +46,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_path_query. Must be "true" or "false".'); @@ -56,7 +56,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_query() requires at least 2 arguments'); @@ -66,7 +66,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_path_query() requires between 2 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php index 270c7464..65ba36c2 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php @@ -42,7 +42,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for jsonb_set. Must be "true" or "false".'); @@ -52,7 +52,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_set() requires at least 3 arguments'); @@ -62,7 +62,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('jsonb_set() requires between 3 and 4 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/LeastTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/LeastTest.php index 89a5f0ea..9e974d09 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/LeastTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/LeastTest.php @@ -43,7 +43,7 @@ protected function getDqlStatements(): array } #[Test] - public function throws_exception_when_single_argument_given(): void + public function throws_exception_for_insufficient_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php index 72e05ef8..352d8d6c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.text1 !~* '.*Thomas.*') AS sclr_0 FROM ContainsTexts c0_", + 'case-insensitive regex pattern non-matching' => "SELECT (c0_.text1 !~* '.*Thomas.*') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT NOT_IREGEXP(e.text1, '.*Thomas.*') FROM %s e", ContainsTexts::class), + 'case-insensitive regex pattern non-matching' => \sprintf("SELECT NOT_IREGEXP(e.text1, '.*Thomas.*') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotRegexpTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotRegexpTest.php index 7ed7d50d..2db5f0df 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotRegexpTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotRegexpTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.text1 !~ '.*thomas.*') AS sclr_0 FROM ContainsTexts c0_", + 'case-sensitive regex pattern non-matching' => "SELECT (c0_.text1 !~ '.*thomas.*') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT NOT_REGEXP(e.text1, '.*thomas.*') FROM %s e", ContainsTexts::class), + 'case-sensitive regex pattern non-matching' => \sprintf("SELECT NOT_REGEXP(e.text1, '.*thomas.*') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotSimilarToTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotSimilarToTest.php index 8132113a..a78cd0db 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotSimilarToTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotSimilarToTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT c0_.text1 not similar to 'TEST' AS sclr_0 FROM ContainsTexts c0_", + 'SQL regex pattern non-matching' => "SELECT c0_.text1 not similar to 'TEST' AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT NOT_SIMILAR_TO(e.text1,'TEST') FROM %s e", ContainsTexts::class), + 'SQL regex pattern non-matching' => \sprintf("SELECT NOT_SIMILAR_TO(e.text1,'TEST') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/OverlapsTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/OverlapsTest.php index 0aa190df..b0af3a93 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/OverlapsTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/OverlapsTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.textArray && '{681,1185,1878}') AS sclr_0 FROM ContainsArrays c0_", + 'checks if arrays have overlapping elements' => "SELECT (c0_.textArray && '{681,1185,1878}') AS sclr_0 FROM ContainsArrays c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT OVERLAPS(e.textArray, '{681,1185,1878}') FROM %s e", ContainsArrays::class), + 'checks if arrays have overlapping elements' => \sprintf("SELECT OVERLAPS(e.textArray, '{681,1185,1878}') FROM %s e", ContainsArrays::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RandomTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RandomTest.php index 7f2f65ba..e94fff8c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RandomTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RandomTest.php @@ -19,16 +19,16 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT RANDOM() AS sclr_0 FROM ContainsDecimals c0_', - 'SELECT RANDOM() + c0_.decimal1 AS sclr_0 FROM ContainsDecimals c0_', + 'generates random number' => 'SELECT RANDOM() AS sclr_0 FROM ContainsDecimals c0_', + 'uses random in arithmetic expression' => 'SELECT RANDOM() + c0_.decimal1 AS sclr_0 FROM ContainsDecimals c0_', ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT RANDOM() FROM %s e', ContainsDecimals::class), - \sprintf('SELECT RANDOM() + e.decimal1 FROM %s e', ContainsDecimals::class), + 'generates random number' => \sprintf('SELECT RANDOM() FROM %s e', ContainsDecimals::class), + 'uses random in arithmetic expression' => \sprintf('SELECT RANDOM() + e.decimal1 FROM %s e', ContainsDecimals::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpCountTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpCountTest.php index 6eed6edb..0284c2d5 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpCountTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpCountTest.php @@ -8,6 +8,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpCount; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class RegexpCountTest extends BaseVariadicFunctionTestCase @@ -44,23 +45,30 @@ protected function getDqlStatements(): array ]; } + #[DataProvider('provideInvalidArgumentCountCases')] #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_invalid_argument_count(string $dql, string $expectedMessage): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_count() requires at least 2 arguments'); + $this->expectExceptionMessage($expectedMessage); - $dql = \sprintf('SELECT REGEXP_COUNT(e.text1) FROM %s e', ContainsTexts::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } - #[Test] - public function too_many_arguments_throws_exception(): void + /** + * @return array + */ + public static function provideInvalidArgumentCountCases(): array { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_count() requires between 2 and 4 arguments'); - - $dql = \sprintf("SELECT REGEXP_COUNT(e.text1, '\\d+', 1, 'i', 'extra_arg') FROM %s e", ContainsTexts::class); - $this->buildEntityManager()->createQuery($dql)->getSQL(); + return [ + 'too few arguments' => [ + \sprintf('SELECT REGEXP_COUNT(e.text1) FROM %s e', ContainsTexts::class), + 'regexp_count() requires at least 2 arguments', + ], + 'too many arguments' => [ + \sprintf("SELECT REGEXP_COUNT(e.text1, '\\d+', 1, 'i', 'extra_arg') FROM %s e", ContainsTexts::class), + 'regexp_count() requires between 2 and 4 arguments', + ], + ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php index 22a2b308..f64badc9 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php @@ -8,6 +8,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpInstr; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class RegexpInstrTest extends BaseVariadicFunctionTestCase @@ -50,23 +51,30 @@ protected function getDqlStatements(): array ]; } + #[DataProvider('provideInvalidArgumentCountCases')] #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_invalid_argument_count(string $dql, string $expectedMessage): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_instr() requires at least 2 arguments'); + $this->expectExceptionMessage($expectedMessage); - $dql = \sprintf('SELECT REGEXP_INSTR(e.text1) FROM %s e', ContainsTexts::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } - #[Test] - public function too_many_arguments_throws_exception(): void + /** + * @return array + */ + public static function provideInvalidArgumentCountCases(): array { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_instr() requires between 2 and 7 arguments'); - - $dql = \sprintf("SELECT REGEXP_INSTR(e.text1, 'c(.)(..)', 1, 1, 0, 'i', 2, 'extra_arg') FROM %s e", ContainsTexts::class); - $this->buildEntityManager()->createQuery($dql)->getSQL(); + return [ + 'too few arguments' => [ + \sprintf('SELECT REGEXP_INSTR(e.text1) FROM %s e', ContainsTexts::class), + 'regexp_instr() requires at least 2 arguments', + ], + 'too many arguments' => [ + \sprintf("SELECT REGEXP_INSTR(e.text1, 'c(.)(..)', 1, 1, 0, 'i', 2, 'extra_arg') FROM %s e", ContainsTexts::class), + 'regexp_instr() requires between 2 and 7 arguments', + ], + ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php index 1c64f5bf..44ba132f 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php @@ -41,7 +41,7 @@ protected function getDqlStatements(): array } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('regexp_like() requires at least 2 arguments'); @@ -51,7 +51,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('regexp_like() requires between 2 and 3 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php index d3b82dcb..cb17dbc2 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php @@ -41,7 +41,7 @@ protected function getDqlStatements(): array } #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_too_few_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('regexp_match() requires at least 2 arguments'); @@ -51,7 +51,7 @@ public function too_few_arguments_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('regexp_match() requires between 2 and 3 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php index ac37f9a8..3f7de205 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php @@ -8,6 +8,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpReplace; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class RegexpReplaceTest extends BaseVariadicFunctionTestCase @@ -46,23 +47,30 @@ protected function getDqlStatements(): array ]; } + #[DataProvider('provideInvalidArgumentCountCases')] #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_invalid_argument_count(string $dql, string $expectedMessage): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_replace() requires at least 3 arguments'); + $this->expectExceptionMessage($expectedMessage); - $dql = \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern') FROM %s e", ContainsTexts::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } - #[Test] - public function too_many_arguments_throws_exception(): void + /** + * @return array + */ + public static function provideInvalidArgumentCountCases(): array { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_replace() requires between 3 and 6 arguments'); - - $dql = \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 3, 2, 'i', 'extra_arg') FROM %s e", ContainsTexts::class); - $this->buildEntityManager()->createQuery($dql)->getSQL(); + return [ + 'too few arguments' => [ + \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern') FROM %s e", ContainsTexts::class), + 'regexp_replace() requires at least 3 arguments', + ], + 'too many arguments' => [ + \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 3, 2, 'i', 'extra_arg') FROM %s e", ContainsTexts::class), + 'regexp_replace() requires between 3 and 6 arguments', + ], + ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpSubstrTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpSubstrTest.php index fdc9f701..2ec8f325 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpSubstrTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpSubstrTest.php @@ -8,6 +8,7 @@ use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpSubstr; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; class RegexpSubstrTest extends BaseVariadicFunctionTestCase @@ -46,23 +47,30 @@ protected function getDqlStatements(): array ]; } + #[DataProvider('provideInvalidArgumentCountCases')] #[Test] - public function too_few_arguments_throws_exception(): void + public function throws_exception_for_invalid_argument_count(string $dql, string $expectedMessage): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_substr() requires at least 2 arguments'); + $this->expectExceptionMessage($expectedMessage); - $dql = \sprintf('SELECT REGEXP_SUBSTR(e.text1) FROM %s e', ContainsTexts::class); $this->buildEntityManager()->createQuery($dql)->getSQL(); } - #[Test] - public function too_many_arguments_throws_exception(): void + /** + * @return array + */ + public static function provideInvalidArgumentCountCases(): array { - $this->expectException(InvalidArgumentForVariadicFunctionException::class); - $this->expectExceptionMessage('regexp_substr() requires between 2 and 6 arguments'); - - $dql = \sprintf("SELECT REGEXP_SUBSTR(e.text1, 'c(.)(..)', 1, 1, 'i', 1, 'extra_arg') FROM %s e", ContainsTexts::class); - $this->buildEntityManager()->createQuery($dql)->getSQL(); + return [ + 'too few arguments' => [ + \sprintf('SELECT REGEXP_SUBSTR(e.text1) FROM %s e', ContainsTexts::class), + 'regexp_substr() requires at least 2 arguments', + ], + 'too many arguments' => [ + \sprintf("SELECT REGEXP_SUBSTR(e.text1, 'c(.)(..)', 1, 1, 'i', 1, 'extra_arg') FROM %s e", ContainsTexts::class), + 'regexp_substr() requires between 2 and 6 arguments', + ], + ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpTest.php index 7ecf7efe..67e8d618 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.text1 ~ '.*thomas.*') AS sclr_0 FROM ContainsTexts c0_", + 'matches text against regular expression pattern' => "SELECT (c0_.text1 ~ '.*thomas.*') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT REGEXP(e.text1, '.*thomas.*') FROM %s e", ContainsTexts::class), + 'matches text against regular expression pattern' => \sprintf("SELECT REGEXP(e.text1, '.*thomas.*') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ReturnsValueForJsonValueTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ReturnsValueForJsonValueTest.php index 9545c5ff..7649d44f 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ReturnsValueForJsonValueTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ReturnsValueForJsonValueTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.object1 @?? '$.test[*] ?? (@ > 2)') AS sclr_0 FROM ContainsJsons c0_", + 'checks if JSON path expression returns value' => "SELECT (c0_.object1 @?? '$.test[*] ?? (@ > 2)') AS sclr_0 FROM ContainsJsons c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT RETURNS_VALUE_FOR_JSON_VALUE(e.object1, '$.test[*] ?? (@ > 2)') FROM %s e", ContainsJsons::class), + 'checks if JSON path expression returns value' => \sprintf("SELECT RETURNS_VALUE_FOR_JSON_VALUE(e.object1, '$.test[*] ?? (@ > 2)') FROM %s e", ContainsJsons::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RowToJsonTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RowToJsonTest.php index e57ba503..c7f0a007 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RowToJsonTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RowToJsonTest.php @@ -44,7 +44,7 @@ protected function getDqlStatements(): array } #[Test] - public function invalid_boolean_throws_exception(): void + public function throws_exception_for_invalid_boolean(): void { $this->expectException(InvalidBooleanException::class); $this->expectExceptionMessage('Invalid boolean value "invalid" provided for row_to_json. Must be "true" or "false".'); @@ -54,7 +54,7 @@ public function invalid_boolean_throws_exception(): void } #[Test] - public function too_many_arguments_throws_exception(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); $this->expectExceptionMessage('row_to_json() requires between 1 and 2 arguments'); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SimilarToTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SimilarToTest.php index 47d19d8d..3f834ae6 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SimilarToTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SimilarToTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT c0_.text1 similar to 'TEST' AS sclr_0 FROM ContainsTexts c0_", + 'SQL regular expression pattern matching' => "SELECT c0_.text1 similar to 'TEST' AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT SIMILAR_TO(e.text1, 'TEST') FROM %s e", ContainsTexts::class), + 'SQL regular expression pattern matching' => \sprintf("SELECT SIMILAR_TO(e.text1, 'TEST') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SplitPartTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SplitPartTest.php index 53797b29..67e36c3e 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SplitPartTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SplitPartTest.php @@ -19,16 +19,24 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT split_part(c0_.text1, ',', 1) AS sclr_0 FROM ContainsTexts c0_", - "SELECT split_part(c0_.text2, '-', -2) AS sclr_0 FROM ContainsTexts c0_", + 'splits text and returns first part' => "SELECT split_part(c0_.text1, ',', 1) AS sclr_0 FROM ContainsTexts c0_", + 'splits text and returns part from end' => "SELECT split_part(c0_.text2, '-', -2) AS sclr_0 FROM ContainsTexts c0_", + 'splits with zero field number' => "SELECT split_part(c0_.text1, ',', 0) AS sclr_0 FROM ContainsTexts c0_", + 'splits with large field number' => "SELECT split_part(c0_.text1, ',', 999) AS sclr_0 FROM ContainsTexts c0_", + 'splits with single character delimiter' => "SELECT split_part(c0_.text1, '|', 2) AS sclr_0 FROM ContainsTexts c0_", + 'splits with multi-character delimiter' => "SELECT split_part(c0_.text1, ':::', 1) AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT SPLIT_PART(e.text1, ',', 1) FROM %s e", ContainsTexts::class), - \sprintf("SELECT SPLIT_PART(e.text2, '-', -2) FROM %s e", ContainsTexts::class), + 'splits text and returns first part' => \sprintf("SELECT SPLIT_PART(e.text1, ',', 1) FROM %s e", ContainsTexts::class), + 'splits text and returns part from end' => \sprintf("SELECT SPLIT_PART(e.text2, '-', -2) FROM %s e", ContainsTexts::class), + 'splits with zero field number' => \sprintf("SELECT SPLIT_PART(e.text1, ',', 0) FROM %s e", ContainsTexts::class), + 'splits with large field number' => \sprintf("SELECT SPLIT_PART(e.text1, ',', 999) FROM %s e", ContainsTexts::class), + 'splits with single character delimiter' => \sprintf("SELECT SPLIT_PART(e.text1, '|', 2) FROM %s e", ContainsTexts::class), + 'splits with multi-character delimiter' => \sprintf("SELECT SPLIT_PART(e.text1, ':::', 1) FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StartsWithTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StartsWithTest.php index 94f0dcbe..6b23850b 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StartsWithTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StartsWithTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (STARTS_WITH(c0_.text1, 'TEST')) AS sclr_0 FROM ContainsTexts c0_", + 'checks if text starts with prefix' => "SELECT (STARTS_WITH(c0_.text1, 'TEST')) AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT STARTS_WITH(e.text1,'TEST') FROM %s e", ContainsTexts::class), + 'checks if text starts with prefix' => \sprintf("SELECT STARTS_WITH(e.text1,'TEST') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StrConcatTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StrConcatTest.php index 737c0110..a7ffdacf 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StrConcatTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StrConcatTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.text1 || 'text2') AS sclr_0 FROM ContainsTexts c0_", + 'concatenates field with literal string' => "SELECT (c0_.text1 || 'text2') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT STRCONCAT(e.text1, 'text2') FROM %s e", ContainsTexts::class), + 'concatenates field with literal string' => \sprintf("SELECT STRCONCAT(e.text1, 'text2') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringToArrayTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringToArrayTest.php index 8fc77088..fd20d706 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringToArrayTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringToArrayTest.php @@ -19,14 +19,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT string_to_array(c0_.text1, ',') AS sclr_0 FROM ContainsTexts c0_", + 'splits text into array using comma delimiter' => "SELECT string_to_array(c0_.text1, ',') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT STRING_TO_ARRAY(e.text1, ',') FROM %s e", ContainsTexts::class), + 'splits text into array using comma delimiter' => \sprintf("SELECT STRING_TO_ARRAY(e.text1, ',') FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php index 30c7e145..daf7e0a6 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php @@ -21,14 +21,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (c0_.object1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_", + 'checks if right operand keys exist in left JSON object' => "SELECT (c0_.object1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.object1, ARRAY('test')) FROM %s e", ContainsJsons::class), + 'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.object1, ARRAY('test')) FROM %s e", ContainsJsons::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToCharTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToCharTest.php index 4d7b8870..3ee6872c 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToCharTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToCharTest.php @@ -22,23 +22,23 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT to_char(c0_.datetime1, 'HH12:MI:SS') AS sclr_0 FROM ContainsDates c0_", - "SELECT to_char(c0_.dateinterval1, 'HH24:MI:SS') AS sclr_0 FROM ContainsDates c0_", - "SELECT to_char(c0_.decimal1, '999D99S') AS sclr_0 FROM ContainsDecimals c0_", + 'formats datetime with 12-hour time' => "SELECT to_char(c0_.datetime1, 'HH12:MI:SS') AS sclr_0 FROM ContainsDates c0_", + 'formats interval with 24-hour time' => "SELECT to_char(c0_.dateinterval1, 'HH24:MI:SS') AS sclr_0 FROM ContainsDates c0_", + 'formats decimal with custom pattern' => "SELECT to_char(c0_.decimal1, '999D99S') AS sclr_0 FROM ContainsDecimals c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT TO_CHAR(e.datetime1, 'HH12:MI:SS') FROM %s e", ContainsDates::class), - \sprintf("SELECT TO_CHAR(e.dateinterval1, 'HH24:MI:SS') FROM %s e", ContainsDates::class), - \sprintf("SELECT TO_CHAR(e.decimal1, '999D99S') FROM %s e", ContainsDecimals::class), + 'formats datetime with 12-hour time' => \sprintf("SELECT TO_CHAR(e.datetime1, 'HH12:MI:SS') FROM %s e", ContainsDates::class), + 'formats interval with 24-hour time' => \sprintf("SELECT TO_CHAR(e.dateinterval1, 'HH24:MI:SS') FROM %s e", ContainsDates::class), + 'formats decimal with custom pattern' => \sprintf("SELECT TO_CHAR(e.decimal1, '999D99S') FROM %s e", ContainsDecimals::class), ]; } #[Test] - public function throws_exception_when_argument_is_missing(): void + public function throws_exception_for_missing_arguments(): void { $this->expectException(QueryException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php index ed837d2f..0381a4fd 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php @@ -21,19 +21,19 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT to_date(c0_.text1, 'DD Mon YYYY') AS sclr_0 FROM ContainsTexts c0_", + 'converts text to date using format pattern' => "SELECT to_date(c0_.text1, 'DD Mon YYYY') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT TO_DATE(e.text1, 'DD Mon YYYY') FROM %s e", ContainsTexts::class), + 'converts text to date using format pattern' => \sprintf("SELECT TO_DATE(e.text1, 'DD Mon YYYY') FROM %s e", ContainsTexts::class), ]; } #[Test] - public function throws_exception_when_argument_is_missing(): void + public function throws_exception_for_missing_arguments(): void { $this->expectException(QueryException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToJsonbTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToJsonbTest.php index dc4b2082..238fe511 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToJsonbTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToJsonbTest.php @@ -19,22 +19,22 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT to_jsonb(c0_.text1) AS sclr_0 FROM ContainsTexts c0_', - 'SELECT to_jsonb(UPPER(c0_.text1)) AS sclr_0 FROM ContainsTexts c0_', - 'SELECT to_jsonb(1 + 1) AS sclr_0 FROM ContainsTexts c0_', - 'SELECT to_jsonb(1) AS sclr_0 FROM ContainsTexts c0_', - 'SELECT to_jsonb(LENGTH(c0_.text1)) AS sclr_0 FROM ContainsTexts c0_', + 'converts text field to jsonb' => 'SELECT to_jsonb(c0_.text1) AS sclr_0 FROM ContainsTexts c0_', + 'converts function result to jsonb' => 'SELECT to_jsonb(UPPER(c0_.text1)) AS sclr_0 FROM ContainsTexts c0_', + 'converts arithmetic expression to jsonb' => 'SELECT to_jsonb(1 + 1) AS sclr_0 FROM ContainsTexts c0_', + 'converts literal number to jsonb' => 'SELECT to_jsonb(1) AS sclr_0 FROM ContainsTexts c0_', + 'converts length function to jsonb' => 'SELECT to_jsonb(LENGTH(c0_.text1)) AS sclr_0 FROM ContainsTexts c0_', ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT TO_JSONB(e.text1) FROM %s e', ContainsTexts::class), - \sprintf('SELECT TO_JSONB(UPPER(e.text1)) FROM %s e', ContainsTexts::class), - \sprintf('SELECT TO_JSONB(1+1) FROM %s e', ContainsTexts::class), - \sprintf('SELECT TO_JSONB(true) FROM %s e', ContainsTexts::class), - \sprintf('SELECT TO_JSONB(LENGTH(e.text1)) FROM %s e', ContainsTexts::class), + 'converts text field to jsonb' => \sprintf('SELECT TO_JSONB(e.text1) FROM %s e', ContainsTexts::class), + 'converts function result to jsonb' => \sprintf('SELECT TO_JSONB(UPPER(e.text1)) FROM %s e', ContainsTexts::class), + 'converts arithmetic expression to jsonb' => \sprintf('SELECT TO_JSONB(1+1) FROM %s e', ContainsTexts::class), + 'converts literal number to jsonb' => \sprintf('SELECT TO_JSONB(true) FROM %s e', ContainsTexts::class), + 'converts length function to jsonb' => \sprintf('SELECT TO_JSONB(LENGTH(e.text1)) FROM %s e', ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToNumberTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToNumberTest.php index c2e106d1..1e7ab224 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToNumberTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToNumberTest.php @@ -21,19 +21,19 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT to_number(c0_.text1, '99G999D9S') AS sclr_0 FROM ContainsTexts c0_", + 'converts text to number using format pattern' => "SELECT to_number(c0_.text1, '99G999D9S') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT TO_NUMBER(e.text1, '99G999D9S') FROM %s e", ContainsTexts::class), + 'converts text to number using format pattern' => \sprintf("SELECT TO_NUMBER(e.text1, '99G999D9S') FROM %s e", ContainsTexts::class), ]; } #[Test] - public function throws_exception_when_argument_is_missing(): void + public function throws_exception_for_missing_arguments(): void { $this->expectException(QueryException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTimestampTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTimestampTest.php index 5b54d880..204206d2 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTimestampTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTimestampTest.php @@ -21,19 +21,19 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT to_timestamp(c0_.text1, 'DD Mon YYYY') AS sclr_0 FROM ContainsTexts c0_", + 'converts text to timestamp using format pattern' => "SELECT to_timestamp(c0_.text1, 'DD Mon YYYY') AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT TO_TIMESTAMP(e.text1, 'DD Mon YYYY') FROM %s e", ContainsTexts::class), + 'converts text to timestamp using format pattern' => \sprintf("SELECT TO_TIMESTAMP(e.text1, 'DD Mon YYYY') FROM %s e", ContainsTexts::class), ]; } #[Test] - public function throws_exception_when_argument_is_missing(): void + public function throws_exception_for_missing_arguments(): void { $this->expectException(QueryException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsqueryTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsqueryTest.php index 7ea28e23..13dab2ae 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsqueryTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsqueryTest.php @@ -27,23 +27,23 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT to_tsquery(c0_.text1) AS sclr_0 FROM ContainsTexts c0_', - 'SELECT to_tsquery(UPPER(c0_.text1)) AS sclr_0 FROM ContainsTexts c0_', - "SELECT to_tsquery('english', c0_.text1) AS sclr_0 FROM ContainsTexts c0_", + 'converts text to tsquery with default config' => 'SELECT to_tsquery(c0_.text1) AS sclr_0 FROM ContainsTexts c0_', + 'converts function result to tsquery' => 'SELECT to_tsquery(UPPER(c0_.text1)) AS sclr_0 FROM ContainsTexts c0_', + 'converts text to tsquery with specified config' => "SELECT to_tsquery('english', c0_.text1) AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT TO_TSQUERY(e.text1) FROM %s e', ContainsTexts::class), - \sprintf('SELECT TO_TSQUERY(UPPER(e.text1)) FROM %s e', ContainsTexts::class), - \sprintf("SELECT TO_TSQUERY('english', e.text1) FROM %s e", ContainsTexts::class), + 'converts text to tsquery with default config' => \sprintf('SELECT TO_TSQUERY(e.text1) FROM %s e', ContainsTexts::class), + 'converts function result to tsquery' => \sprintf('SELECT TO_TSQUERY(UPPER(e.text1)) FROM %s e', ContainsTexts::class), + 'converts text to tsquery with specified config' => \sprintf("SELECT TO_TSQUERY('english', e.text1) FROM %s e", ContainsTexts::class), ]; } #[Test] - public function throws_exception_when_too_many_arguments_given(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsvectorTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsvectorTest.php index 32177a43..ee8310e8 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsvectorTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsvectorTest.php @@ -43,7 +43,7 @@ protected function getDqlStatements(): array } #[Test] - public function throws_exception_when_too_many_arguments_given(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php index 6e25568a..b1c1bc8d 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php @@ -23,14 +23,14 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - "SELECT (to_tsvector(c0_.text1) @@ to_tsquery('testing')) AS sclr_0 FROM ContainsTexts c0_", + 'matches tsvector against tsquery' => "SELECT (to_tsvector(c0_.text1) @@ to_tsquery('testing')) AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf("SELECT TSMATCH(TO_TSVECTOR(e.text1), TO_TSQUERY('testing')) FROM %s e", ContainsTexts::class), + 'matches tsvector against tsquery' => \sprintf("SELECT TSMATCH(TO_TSVECTOR(e.text1), TO_TSQUERY('testing')) FROM %s e", ContainsTexts::class), ]; } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/UnaccentTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/UnaccentTest.php index d61adb39..40cb1e17 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/UnaccentTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/UnaccentTest.php @@ -27,21 +27,21 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT unaccent(c0_.text1) AS sclr_0 FROM ContainsTexts c0_', - "SELECT unaccent('unaccent', c0_.text1) AS sclr_0 FROM ContainsTexts c0_", + 'removes accents with default dictionary' => 'SELECT unaccent(c0_.text1) AS sclr_0 FROM ContainsTexts c0_', + 'removes accents with specified dictionary' => "SELECT unaccent('unaccent', c0_.text1) AS sclr_0 FROM ContainsTexts c0_", ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT UNACCENT(e.text1) FROM %s e', ContainsTexts::class), - \sprintf("SELECT UNACCENT('unaccent', e.text1) FROM %s e", ContainsTexts::class), + 'removes accents with default dictionary' => \sprintf('SELECT UNACCENT(e.text1) FROM %s e', ContainsTexts::class), + 'removes accents with specified dictionary' => \sprintf("SELECT UNACCENT('unaccent', e.text1) FROM %s e", ContainsTexts::class), ]; } #[Test] - public function throws_exception_when_too_many_arguments_given(): void + public function throws_exception_for_too_many_arguments(): void { $this->expectException(InvalidArgumentForVariadicFunctionException::class); diff --git a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/WidthBucketTest.php b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/WidthBucketTest.php index 66b4c973..29b8b8d7 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/WidthBucketTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/WidthBucketTest.php @@ -5,7 +5,9 @@ namespace Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions; use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsDecimals; +use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException; use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\WidthBucket; +use PHPUnit\Framework\Attributes\Test; class WidthBucketTest extends TestCase { @@ -19,16 +21,36 @@ protected function getStringFunctions(): array protected function getExpectedSqlStatements(): array { return [ - 'SELECT WIDTH_BUCKET(c0_.decimal1, 0.0, 20.0, 4) AS sclr_0 FROM ContainsDecimals c0_', - 'SELECT WIDTH_BUCKET(15, 0.0, 20.0, 4) AS sclr_0 FROM ContainsDecimals c0_', + 'assigns field value to histogram bucket' => 'SELECT WIDTH_BUCKET(c0_.decimal1, 0.0, 20.0, 4) AS sclr_0 FROM ContainsDecimals c0_', + 'assigns literal value to histogram bucket' => 'SELECT WIDTH_BUCKET(15, 0.0, 20.0, 4) AS sclr_0 FROM ContainsDecimals c0_', ]; } protected function getDqlStatements(): array { return [ - \sprintf('SELECT WIDTH_BUCKET(e.decimal1, 0.0, 20.0, 4) FROM %s e', ContainsDecimals::class), - \sprintf('SELECT WIDTH_BUCKET(15, 0.0, 20.0, 4) FROM %s e', ContainsDecimals::class), + 'assigns field value to histogram bucket' => \sprintf('SELECT WIDTH_BUCKET(e.decimal1, 0.0, 20.0, 4) FROM %s e', ContainsDecimals::class), + 'assigns literal value to histogram bucket' => \sprintf('SELECT WIDTH_BUCKET(15, 0.0, 20.0, 4) FROM %s e', ContainsDecimals::class), ]; } + + #[Test] + public function throws_exception_for_too_few_arguments(): void + { + $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('WIDTH_BUCKET() requires exactly 4 arguments'); + + $dql = \sprintf('SELECT WIDTH_BUCKET(e.decimal1, 0.0, 20.0) FROM %s e', ContainsDecimals::class); + $this->buildEntityManager()->createQuery($dql)->getSQL(); + } + + #[Test] + public function throws_exception_for_too_many_arguments(): void + { + $this->expectException(InvalidArgumentForVariadicFunctionException::class); + $this->expectExceptionMessage('WIDTH_BUCKET() requires exactly 4 arguments'); + + $dql = \sprintf('SELECT WIDTH_BUCKET(e.decimal1, 0.0, 20.0, 4, 5) FROM %s e', ContainsDecimals::class); + $this->buildEntityManager()->createQuery($dql)->getSQL(); + } }