diff --git a/tests/Doctrine/Functions/AbstractDoctrineFunctionTestCase.php b/tests/Doctrine/Functions/AbstractDoctrineFunctionTestCase.php new file mode 100644 index 00000000..7bc3d628 --- /dev/null +++ b/tests/Doctrine/Functions/AbstractDoctrineFunctionTestCase.php @@ -0,0 +1,68 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Doctrine\Functions; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\ORM\Query\AST\Node; +use Doctrine\ORM\Query\SqlWalker; +use PHPUnit\Framework\TestCase; + +abstract class AbstractDoctrineFunctionTestCase extends TestCase +{ + protected function createSqlWalker(AbstractPlatform $platform, string $serverVersion = '11.0.0-MariaDB'): SqlWalker + { + $connection = $this->createMock(Connection::class); + $connection->method('getDatabasePlatform')->willReturn($platform); + $connection->method('getServerVersion')->willReturn($serverVersion); + + $sqlWalker = $this->getMockBuilder(SqlWalker::class) + ->disableOriginalConstructor() + ->onlyMethods(['getConnection']) + ->getMock(); + + $sqlWalker->method('getConnection')->willReturn($connection); + + return $sqlWalker; + } + + protected function createNode(string $sql): Node + { + $node = $this->createMock(Node::class); + $node->method('dispatch')->willReturn($sql); + + return $node; + } + + protected function setObjectProperty(object $object, string $property, mixed $value): void + { + $reflection = new \ReflectionProperty($object, $property); + $reflection->setValue($object, $value); + } + + protected function setStaticProperty(string $class, string $property, mixed $value): void + { + $reflection = new \ReflectionProperty($class, $property); + $reflection->setValue(null, $value); + } +} diff --git a/tests/Doctrine/Functions/ArrayPositionTest.php b/tests/Doctrine/Functions/ArrayPositionTest.php new file mode 100644 index 00000000..7fdff42d --- /dev/null +++ b/tests/Doctrine/Functions/ArrayPositionTest.php @@ -0,0 +1,42 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Tests\Doctrine\Functions; + +use App\Doctrine\Functions\ArrayPosition; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; + +final class ArrayPositionTest extends AbstractDoctrineFunctionTestCase +{ + public function testArrayPositionBuildsSql(): void + { + $function = new ArrayPosition('ARRAY_POSITION'); + $this->setObjectProperty($function, 'array', $this->createNode(':ids')); + $this->setObjectProperty($function, 'field', $this->createNode('p.id')); + + $sql = $function->getSql($this->createSqlWalker(new PostgreSQLPlatform())); + + $this->assertSame('ARRAY_POSITION(:ids, p.id)', $sql); + } +} + diff --git a/tests/Doctrine/Functions/Field2Test.php b/tests/Doctrine/Functions/Field2Test.php new file mode 100644 index 00000000..d25e511f --- /dev/null +++ b/tests/Doctrine/Functions/Field2Test.php @@ -0,0 +1,45 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Doctrine\Functions; + +use App\Doctrine\Functions\Field2; +use Doctrine\DBAL\Platforms\MySQLPlatform; + +final class Field2Test extends AbstractDoctrineFunctionTestCase +{ + public function testField2BuildsSql(): void + { + $function = new Field2('FIELD2'); + $this->setObjectProperty($function, 'field', $this->createNode('p.id')); + $this->setObjectProperty($function, 'values', [ + $this->createNode('1'), + $this->createNode('2'), + $this->createNode('3'), + ]); + + $sql = $function->getSql($this->createSqlWalker(new MySQLPlatform())); + + $this->assertSame('FIELD2(p.id, 1, 2, 3)', $sql); + } +} + diff --git a/tests/Doctrine/Functions/ILikeTest.php b/tests/Doctrine/Functions/ILikeTest.php new file mode 100644 index 00000000..4541e9c9 --- /dev/null +++ b/tests/Doctrine/Functions/ILikeTest.php @@ -0,0 +1,66 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Doctrine\Functions; + +use App\Doctrine\Functions\ILike; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Platforms\MySQLPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; +use Doctrine\DBAL\Platforms\SQLServerPlatform; +use PHPUnit\Framework\Attributes\DataProvider; + +final class ILikeTest extends AbstractDoctrineFunctionTestCase +{ + public static function iLikePlatformProvider(): \Generator + { + yield 'mysql' => [new MySQLPlatform(), '(part_name LIKE :pattern)']; + yield 'postgres' => [new PostgreSQLPlatform(), '(part_name ILIKE :pattern)']; + yield 'sqlite' => [new SQLitePlatform(), "(part_name LIKE :pattern ESCAPE '\\')"]; + } + + #[DataProvider('iLikePlatformProvider')] + public function testILikeUsesExpectedOperator(AbstractPlatform $platform, string $expectedSql): void + { + $function = new ILike('ILIKE'); + $function->value = $this->createNode('part_name'); + $function->expr = $this->createNode(':pattern'); + + $sql = $function->getSql($this->createSqlWalker($platform)); + + $this->assertSame($expectedSql, $sql); + } + + public function testILikeThrowsOnUnsupportedPlatform(): void + { + $function = new ILike('ILIKE'); + $function->value = $this->createNode('part_name'); + $function->expr = $this->createNode(':pattern'); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('does not support case insensitive like expressions'); + + $function->getSql($this->createSqlWalker(new SQLServerPlatform())); + } +} + diff --git a/tests/Doctrine/Functions/NatsortTest.php b/tests/Doctrine/Functions/NatsortTest.php new file mode 100644 index 00000000..fd10199f --- /dev/null +++ b/tests/Doctrine/Functions/NatsortTest.php @@ -0,0 +1,95 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Doctrine\Functions; + +use App\Doctrine\Functions\Natsort; +use Doctrine\DBAL\Platforms\MariaDBPlatform; +use Doctrine\DBAL\Platforms\MySQLPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; + +final class NatsortTest extends AbstractDoctrineFunctionTestCase +{ + protected function setUp(): void + { + parent::setUp(); + + Natsort::allowSlowNaturalSort(false); + $this->setStaticProperty(Natsort::class, 'supportsNaturalSort', null); + } + + public function testNatsortUsesPostgresCollation(): void + { + $function = new Natsort('NATSORT'); + $this->setObjectProperty($function, 'field', $this->createNode('part_name')); + + $sql = $function->getSql($this->createSqlWalker(new PostgreSQLPlatform())); + + $this->assertSame('part_name COLLATE numeric', $sql); + } + + public function testNatsortUsesMariaDbNativeFunctionOnSupportedVersion(): void + { + $function = new Natsort('NATSORT'); + $this->setObjectProperty($function, 'field', $this->createNode('part_name')); + + $sql = $function->getSql($this->createSqlWalker(new MariaDBPlatform(), '10.11.2-MariaDB')); + + $this->assertSame('NATURAL_SORT_KEY(part_name)', $sql); + } + + public function testNatsortFallsBackWithoutSlowSort(): void + { + $function = new Natsort('NATSORT'); + $this->setObjectProperty($function, 'field', $this->createNode('part_name')); + + $sql = $function->getSql($this->createSqlWalker(new MariaDBPlatform(), '10.6.10-MariaDB')); + + $this->assertSame('part_name', $sql); + } + + public function testNatsortUsesSlowSortFunctionOnMySqlWhenEnabled(): void + { + Natsort::allowSlowNaturalSort(); + + $function = new Natsort('NATSORT'); + $this->setObjectProperty($function, 'field', $this->createNode('part_name')); + + $sql = $function->getSql($this->createSqlWalker(new MySQLPlatform())); + + $this->assertSame('NatSortKey(part_name, 0)', $sql); + } + + public function testNatsortUsesSlowSortCollationOnSqliteWhenEnabled(): void + { + Natsort::allowSlowNaturalSort(); + + $function = new Natsort('NATSORT'); + $this->setObjectProperty($function, 'field', $this->createNode('part_name')); + + $sql = $function->getSql($this->createSqlWalker(new SQLitePlatform())); + + $this->assertSame('part_name COLLATE NATURAL_CMP', $sql); + } +} + diff --git a/tests/Doctrine/Functions/RegexpTest.php b/tests/Doctrine/Functions/RegexpTest.php new file mode 100644 index 00000000..d1866210 --- /dev/null +++ b/tests/Doctrine/Functions/RegexpTest.php @@ -0,0 +1,66 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Doctrine\Functions; + +use App\Doctrine\Functions\Regexp; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Platforms\MySQLPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; +use Doctrine\DBAL\Platforms\SQLServerPlatform; +use PHPUnit\Framework\Attributes\DataProvider; + +final class RegexpTest extends AbstractDoctrineFunctionTestCase +{ + public static function regexpPlatformProvider(): \Generator + { + yield 'mysql' => [new MySQLPlatform(), '(part_name REGEXP :regex)']; + yield 'sqlite' => [new SQLitePlatform(), '(part_name REGEXP :regex)']; + yield 'postgres' => [new PostgreSQLPlatform(), '(part_name ~* :regex)']; + } + + #[DataProvider('regexpPlatformProvider')] + public function testRegexpUsesExpectedOperator(AbstractPlatform $platform, string $expectedSql): void + { + $function = new Regexp('REGEXP'); + $this->setObjectProperty($function, 'value', $this->createNode('part_name')); + $this->setObjectProperty($function, 'regexp', $this->createNode(':regex')); + + $sql = $function->getSql($this->createSqlWalker($platform)); + + $this->assertSame($expectedSql, $sql); + } + + public function testRegexpThrowsOnUnsupportedPlatform(): void + { + $function = new Regexp('REGEXP'); + $this->setObjectProperty($function, 'value', $this->createNode('part_name')); + $this->setObjectProperty($function, 'regexp', $this->createNode(':regex')); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('does not support regular expressions'); + + $function->getSql($this->createSqlWalker(new SQLServerPlatform())); + } +} +