Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Point.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
*/
final class Point implements \Stringable
{
private const POINT_REGEX = '/\((-?\d+(?:\.\d{1,6})?),\s*(-?\d+(?:\.\d{1,6})?)\)/';
private const COORDINATE_PATTERN = '-?\d+(?:\.\d{1,6})?';

private const POINT_REGEX = '/\(('.self::COORDINATE_PATTERN.'),\s*('.self::COORDINATE_PATTERN.')\)/';

public function __construct(
private readonly float $x,
Expand Down Expand Up @@ -51,7 +53,8 @@ private function validateCoordinate(float $value, string $name): void
{
$stringValue = (string) $value;

if (!\preg_match('/^-?\d+(\.\d{1,6})?$/', $stringValue)) {
$floatRegex = '/^'.self::COORDINATE_PATTERN.'$/';
if (!\preg_match($floatRegex, $stringValue)) {
throw new \InvalidArgumentException(
\sprintf('Invalid %s coordinate format: %s', $name, $stringValue)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Tests\Unit\MartinGeorgiev\Doctrine\DBAL\Types;

use Doctrine\DBAL\Types\ConversionException;
use MartinGeorgiev\Doctrine\DBAL\Types\BaseFloatArray;
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidFloatArrayItemForPHPException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -64,7 +64,7 @@ abstract public static function provideValidTransformations(): array;
#[Test]
public function throws_domain_exception_when_invalid_array_item_value(): void
{
$this->expectException(ConversionException::class);
$this->expectException(InvalidFloatArrayItemForPHPException::class);
$this->expectExceptionMessage('cannot be transformed to valid PHP float');

$this->fixture->transformArrayItemForPHP('1.e234');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Doctrine\DBAL\Platforms\AbstractPlatform;
use MartinGeorgiev\Doctrine\DBAL\Types\BaseNetworkTypeArray;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -55,24 +56,28 @@ public function has_name(): void
}

#[Test]
public function can_convert_null_to_database_value(): void
#[DataProvider('provideValidTransformations')]
public function can_convert_to_php_value(?array $phpValue, ?string $postgresValue): void
{
self::assertNull($this->fixture->convertToDatabaseValue(null, $this->platform));
self::assertEquals($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
}

#[Test]
public function can_convert_empty_array_to_database_value(): void
public static function provideValidTransformations(): array
{
self::assertEquals('{}', $this->fixture->convertToDatabaseValue([], $this->platform));
}

#[Test]
public function can_convert_valid_array_to_database_value(): void
{
self::assertEquals(
'{"valid_address","valid_address"}',
$this->fixture->convertToDatabaseValue(['valid_address', 'valid_address'], $this->platform)
);
return [
'null' => [
'phpValue' => null,
'postgresValue' => null,
],
'empty array' => [
'phpValue' => [],
'postgresValue' => '{}',
],
'valid array' => [
'phpValue' => ['valid_address', 'valid_address'],
'postgresValue' => '{"valid_address","valid_address"}',
],
];
}

#[Test]
Expand All @@ -84,23 +89,31 @@ public function throws_exception_for_invalid_type(): void
}

#[Test]
public function can_convert_null_to_php_value(): void
#[DataProvider('provideInvalidValues')]
public function throws_exception_for_invalid_values(mixed $arrayItem, string $exceptionMessage): void
{
self::assertNull($this->fixture->convertToPHPValue(null, $this->platform));
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage($exceptionMessage);
$this->fixture->transformArrayItemForPHP($arrayItem);
}

#[Test]
public function can_convert_empty_array_to_php_value(): void
public static function provideInvalidValues(): array
{
self::assertEquals([], $this->fixture->convertToPHPValue('{}', $this->platform));
return [
'invalid type' => [
'arrayItem' => [],
'exceptionMessage' => 'Invalid type',
],
'invalid format' => [
'arrayItem' => '"invalid_address"',
'exceptionMessage' => 'Invalid format',
],
];
}

#[Test]
public function can_convert_valid_string_to_php_value(): void
public function transform_array_item_for_php_handles_valid_string(): void
{
self::assertEquals(
['valid_address', 'valid_address'],
$this->fixture->convertToPHPValue('{"valid_address","valid_address"}', $this->platform)
);
$this->assertSame('valid_address', $this->fixture->transformArrayItemForPHP('"valid_address"'));
}
}
33 changes: 33 additions & 0 deletions tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/PointArrayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,37 @@ public function returns_empty_array_for_non_standard_postgres_array_format(): vo
self::assertEquals([], $result1);
self::assertEquals([], $result2);
}

#[Test]
public function transform_array_item_for_php_returns_null_for_null(): void
{
$this->assertNull($this->fixture->transformArrayItemForPHP(null));
}

#[Test]
#[DataProvider('provideInvalidTypes')]
public function transform_array_item_for_php_throws_for_invalid_type(mixed $value): void
{
$this->expectException(InvalidPointArrayItemForPHPException::class);
$this->fixture->transformArrayItemForPHP($value);
}

#[Test]
#[DataProvider('provideInvalidTypes')]
public function transform_postgres_array_to_php_array_returns_empty_for_invalid_format(mixed $value): void
{
$reflectionObject = new \ReflectionObject($this->fixture);
$reflectionMethod = $reflectionObject->getMethod('transformPostgresArrayToPHPArray');
$reflectionMethod->setAccessible(true);
$this->assertSame([], $reflectionMethod->invoke($this->fixture, $value));
}

public static function provideInvalidTypes(): array
{
return [
[123],
['not-a-point-instance'],
['{invalid}'],
];
}
}
15 changes: 15 additions & 0 deletions tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/PointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,19 @@ public static function provideInvalidDatabaseValues(): array
'float precision is too granular' => ['(1.23456789,7.89)'],
];
}

#[Test]
public function allows_coordinate_with_exactly_6_decimal_places(): void
{
$point = new PointValueObject(1.123456, 2.654321);
$this->assertSame(1.123456, $point->getX());
$this->assertSame(2.654321, $point->getY());
}

#[Test]
public function throws_for_coordinate_with_more_than_6_decimal_places(): void
{
$this->expectException(\InvalidArgumentException::class);
new PointValueObject(1.1234567, 2.0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\ParserException;
use PHPUnit\Framework\Attributes\Test;

Expand Down Expand Up @@ -38,4 +40,70 @@ public function throws_an_exception_when_lexer_is_not_populated_with_a_lookahead
$reflectionMethod->setAccessible(true);
$reflectionMethod->invoke($baseVariadicFunction, $parser, 'ArithmeticPrimary');
}

#[Test]
public function throws_exception_when_argument_count_is_too_low(): void
{
$function = new class('TEST') extends BaseVariadicFunction {
protected function getFunctionName(): string
{
return 'TEST';
}

protected function getNodeMappingPattern(): array
{
return ['StringPrimary'];
}

protected function getMinArgumentCount(): int
{
return 2;
}

protected function getMaxArgumentCount(): int
{
return 3;
}
};
$this->expectException(InvalidArgumentForVariadicFunctionException::class);
$reflectionClass = new \ReflectionClass($function);
$reflectionMethod = $reflectionClass->getMethod('validateArguments');
$reflectionMethod->setAccessible(true);

$node = $this->createMock(Node::class);
$reflectionMethod->invoke($function, $node); // 1 argument when min 2 are required
}

#[Test]
public function throws_exception_when_argument_count_is_too_high(): void
{
$function = new class('TEST') extends BaseVariadicFunction {
protected function getFunctionName(): string
{
return 'TEST';
}

protected function getNodeMappingPattern(): array
{
return ['StringPrimary'];
}

protected function getMinArgumentCount(): int
{
return 1;
}

protected function getMaxArgumentCount(): int
{
return 2;
}
};
$this->expectException(InvalidArgumentForVariadicFunctionException::class);
$reflectionClass = new \ReflectionClass($function);
$reflectionMethod = $reflectionClass->getMethod('validateArguments');
$reflectionMethod->setAccessible(true);

$node = $this->createMock(Node::class);
$reflectionMethod->invoke($function, $node, $node, $node); // 3 arguments when max 2 are required
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ public static function provideValidTransformations(): array
'phpValue' => ['Hello 世界', '🌍 Earth'],
'postgresValue' => '{"Hello 世界","🌍 Earth"}',
],
'with only nulls' => [
'phpValue' => [null, null],
'postgresValue' => '{NULL,NULL}',
],
'with only booleans' => [
'phpValue' => [true, false, true],
'postgresValue' => '{true,false,true}',
],
'with empty empty strings' => [
'phpValue' => ['', ''],
'postgresValue' => '{"",""}',
],
];
}

Expand Down Expand Up @@ -237,4 +249,17 @@ public static function provideMultiDimensionalArrays(): array
],
];
}

#[Test]
public function can_transform_array_with_gd_resource(): void
{
if (!\function_exists('imagecreatetruecolor')) {
$this->markTestSkipped('GD extension not available');
}

$resource = \imagecreatetruecolor(1, 1);
$result = PHPArrayToPostgresValueTransformer::transformToPostgresTextArray([$resource]);
$this->assertStringContainsString('GdImage', $result);
\imagedestroy($resource);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,26 @@ public static function provideValidTransformations(): array
'phpValue' => ['quoted', 'unquoted'],
'postgresValue' => '{"quoted",unquoted}',
],
'only whitespace' => [
'phpValue' => [],
'postgresValue' => ' ',
],
'with trailing comma' => [
'phpValue' => ['a'],
'postgresValue' => '{a,}}',
],
'with only backslashes' => [
'phpValue' => ['\\'],
'postgresValue' => '{\}',
],
'with only double quotes' => [
'phpValue' => ['"'],
'postgresValue' => '{"\""}',
],
'with empty quoted strings' => [
'phpValue' => ['', ''],
'postgresValue' => '{"",""}',
],
];
}

Expand Down
Loading