diff --git a/.github/workflows/full.yaml b/.github/workflows/full.yaml index 7eefcc84..e9464c84 100644 --- a/.github/workflows/full.yaml +++ b/.github/workflows/full.yaml @@ -1,8 +1,21 @@ name: Full tests on: + schedule: + - cron: '0 17 * * 4' push: + branches: + - main + - dev + paths-ignore: + - '**.md' + - 'LICENSE' pull_request: - branches: [ dev, main ] + branches: + - main + - dev + paths-ignore: + - '**.md' + - 'LICENSE' permissions: contents: read @@ -90,7 +103,7 @@ jobs: - name: Run test suite and with coverage for codeclimate for PHP 8.3 and doctrine/orm ^3.1 only if: ${{ env.HAS_CC_SECRET == 'true' }} - uses: paambaati/codeclimate-action@v5.0.0 + uses: paambaati/codeclimate-action@v6.0.0 env: CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} with: diff --git a/composer.json b/composer.json index 7c69e721..0b9fee41 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "php": "^8.1", "ext-json": "*", "ext-mbstring": "*", - "longitude-one/geo-parser": "^3.0.0", + "longitude-one/geo-parser": "^3.0.1", "longitude-one/wkt-parser": "^3.0.0", "longitude-one/wkb-parser": "^3.0.0", "doctrine/orm": "^2.19|^3.1" diff --git a/lib/LongitudeOne/Spatial/Exception/InvalidValueException.php b/lib/LongitudeOne/Spatial/Exception/InvalidValueException.php index f4ae3002..b99a2189 100644 --- a/lib/LongitudeOne/Spatial/Exception/InvalidValueException.php +++ b/lib/LongitudeOne/Spatial/Exception/InvalidValueException.php @@ -25,4 +25,8 @@ */ class InvalidValueException extends \Exception implements ExceptionInterface { + public const OUT_OF_RANGE_LATITUDE = 'Out of range latitude value, latitude must be between -90 and 90, got "%s".'; + public const OUT_OF_RANGE_LONGITUDE = 'Out of range longitude value, longitude must be between -180 and 180, got "%s".'; + public const OUT_OF_RANGE_MINUTE = 'Out of range minute value, minute must be between 0 and 59, got "%s".'; + public const OUT_OF_RANGE_SECOND = 'Out of range second value, second must be between 0 and 59, got "%s".'; } diff --git a/lib/LongitudeOne/Spatial/Exception/RangeException.php b/lib/LongitudeOne/Spatial/Exception/RangeException.php new file mode 100644 index 00000000..fd45d9ab --- /dev/null +++ b/lib/LongitudeOne/Spatial/Exception/RangeException.php @@ -0,0 +1,30 @@ + 2017-2024 + * Copyright Longitude One 2020-2024 + * Copyright 2015 Derek J. Lambert + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +declare(strict_types=1); + +namespace LongitudeOne\Spatial\Exception; + +/** + * Range Exception class. + * + * This exception is thrown when a geodesic coordinate is out of range. + * + * @internal the library uses this exception internally and is always caught to throw a more explicit InvalidValueException + */ +final class RangeException extends \Exception implements ExceptionInterface +{ +} diff --git a/lib/LongitudeOne/Spatial/PHP/Types/AbstractPoint.php b/lib/LongitudeOne/Spatial/PHP/Types/AbstractPoint.php index 4b45f876..1937d81d 100644 --- a/lib/LongitudeOne/Spatial/PHP/Types/AbstractPoint.php +++ b/lib/LongitudeOne/Spatial/PHP/Types/AbstractPoint.php @@ -18,10 +18,11 @@ namespace LongitudeOne\Spatial\PHP\Types; -use LongitudeOne\Geo\String\Exception\RangeException; +use LongitudeOne\Geo\String\Exception\RangeException as GeoParserRangeException; use LongitudeOne\Geo\String\Exception\UnexpectedValueException; use LongitudeOne\Geo\String\Parser; use LongitudeOne\Spatial\Exception\InvalidValueException; +use LongitudeOne\Spatial\Exception\RangeException; /** * Abstract point object for POINT spatial types. @@ -29,7 +30,7 @@ * @see https://stackoverflow.com/questions/7309121/preferred-order-of-writing-latitude-longitude-tuples * @see https://docs.geotools.org/latest/userguide/library/referencing/order.html */ -abstract class AbstractPoint extends AbstractGeometry +abstract class AbstractPoint extends AbstractGeometry implements PointInterface { /** * The X coordinate or the longitude. @@ -96,51 +97,53 @@ public function getY(): float|int /** * Latitude fluent setter. * - * @param string $latitude the new latitude of point + * @param float|int|string $latitude the new latitude of point * * @throws InvalidValueException when latitude is not valid */ - public function setLatitude(string $latitude): self + public function setLatitude(float|int|string $latitude): static { - return $this->setY($latitude); + try { + $geodesicCoordinate = $this->setGeodesicCoordinate($latitude, -90, 90); + } catch (RangeException $e) { + throw new InvalidValueException(sprintf(InvalidValueException::OUT_OF_RANGE_LATITUDE, $latitude), $e->getCode(), $e); + } + + $this->y = $geodesicCoordinate; + + return $this; } /** * Longitude setter. * - * @param string $longitude the new longitude + * @param float|int|string $longitude the new longitude * * @throws InvalidValueException when longitude is not valid */ - public function setLongitude(string $longitude): self + public function setLongitude(float|int|string $longitude): static { - return $this->setX($longitude); + try { + $geodesicCoordinate = $this->setGeodesicCoordinate($longitude, -180, 180); + } catch (RangeException $e) { + throw new InvalidValueException(sprintf(InvalidValueException::OUT_OF_RANGE_LONGITUDE, $longitude), $e->getCode(), $e); + } + + $this->x = $geodesicCoordinate; + + return $this; } /** * X setter. (Latitude setter). * - * @param string $x the new X + * @param float|int|string $x the new X * * @throws InvalidValueException when x is not valid */ - public function setX(string $x): self + public function setX(float|int|string $x): static { - $parser = new Parser($x); - - try { - $x = $parser->parse(); - } catch (RangeException $e) { - throw new InvalidValueException($e->getMessage(), $e->getCode(), $e); - } catch (UnexpectedValueException $e) { - throw new InvalidValueException(sprintf('Invalid coordinate value, got "%s".', $x), $e->getCode(), $e); - } - - if (is_array($x)) { - throw new InvalidValueException('Invalid coordinate value, coordinate cannot be an array.'); - } - - $this->x = $x; + $this->x = $this->setCartesianCoordinate($x); return $this; } @@ -148,27 +151,13 @@ public function setX(string $x): self /** * Y setter. Longitude Setter. * - * @param string $y the new Y value + * @param float|int|string $y the new Y value * * @throws InvalidValueException when Y is invalid, not in valid range */ - public function setY(string $y): self + public function setY(float|int|string $y): static { - $parser = new Parser($y); - - try { - $y = $parser->parse(); - } catch (RangeException $e) { - throw new InvalidValueException($e->getMessage(), $e->getCode(), $e); - } catch (UnexpectedValueException $e) { - throw new InvalidValueException(sprintf('Invalid coordinate value, got "%s".', $y), $e->getCode(), $e); - } - - if (is_array($y)) { - throw new InvalidValueException('Invalid coordinate value, coordinate cannot be an array.'); - } - - $this->y = $y; + $this->y = $this->setCartesianCoordinate($y); return $this; } @@ -184,23 +173,6 @@ public function toArray(): array return [$this->x, $this->y]; } - /** - * Abstract point internal constructor. - * - * @param string $x X, longitude - * @param string $y Y, latitude - * @param null|int $srid Spatial Reference System Identifier - * - * @throws InvalidValueException if x or y are invalid - */ - protected function construct(string $x, string $y, ?int $srid = null): void - { - $this->setX($x) - ->setY($y) - ->setSrid($srid) - ; - } - /** * Validate arguments. * @@ -216,6 +188,11 @@ protected function validateArguments(array $argv, string $caller): array $argc = count($argv); if (1 == $argc && is_array($argv[0])) { + $count = count($argv[0]); + if ($count < 2 || $count > 3) { + throw $this->createException($argv[0], $caller, true); + } + foreach ($argv[0] as $value) { if (is_numeric($value) || is_string($value)) { continue; @@ -251,13 +228,34 @@ protected function validateArguments(array $argv, string $caller): array throw $this->createException($argv, $caller); } + /** + * Check the range of a coordinate. + * + * @param float|int $coordinate the coordinate to check + * @param int $min the minimum accepted value + * @param int $max the maximum accepted value + * + * @return float|int $coordinate or throw a RangeException + * + * @throws RangeException when coordinate is out of range fixed by min and max + */ + private function checkRange(float|int $coordinate, int $min, int $max): float|int + { + if ($coordinate < $min || $coordinate > $max) { + throw new RangeException(sprintf('Coordinate must be comprised between %d and %d, got "%s".', $min, $max, $coordinate)); + } + + return $coordinate; + } + /** * Create a fluent message for InvalidException. * - * @param mixed[] $argv the arguments - * @param string $caller the method calling the method calling exception :) + * @param mixed[] $argv the arguments + * @param string $caller the method calling the method calling exception :) + * @param bool $subArray when the first argument was a subarray converted into an array */ - private function createException(array $argv, string $caller): InvalidValueException + private function createException(array $argv, string $caller, bool $subArray = false): InvalidValueException { array_walk($argv, function (&$value) { if (is_numeric($value) || is_string($value)) { @@ -267,11 +265,107 @@ private function createException(array $argv, string $caller): InvalidValueExcep $value = gettype($value); }); + $message = 'Invalid parameters passed to %s::%s: %s'; + if ($subArray) { + $message = 'Invalid parameters passed to %s::%s: array(%s)'; + } + return new InvalidValueException(sprintf( - 'Invalid parameters passed to %s::%s: %s', - $this::class, + $message, + static::class, $caller, implode(', ', $argv) )); } + + /** + * Use the longitude-one/geo-parser to parse a coordinate. + * + * @param string $coordinate the coordinate to parse + * + * @throws InvalidValueException when coordinate is invalid + */ + private function geoParse(string $coordinate): float|int + { + try { + $parser = new Parser($coordinate); + + $parsedCoordinate = $parser->parse(); + } catch (GeoParserRangeException $e) { + $message = match ($e->getCode()) { + GeoParserRangeException::LATITUDE_OUT_OF_RANGE => sprintf(InvalidValueException::OUT_OF_RANGE_LATITUDE, $coordinate), + GeoParserRangeException::LONGITUDE_OUT_OF_RANGE => sprintf(InvalidValueException::OUT_OF_RANGE_LONGITUDE, $coordinate), + GeoParserRangeException::MINUTES_OUT_OF_RANGE => sprintf(InvalidValueException::OUT_OF_RANGE_MINUTE, $coordinate), + GeoParserRangeException::SECONDS_OUT_OF_RANGE => sprintf(InvalidValueException::OUT_OF_RANGE_SECOND, $coordinate), + default => $e->getMessage(), + }; + + throw new InvalidValueException($message, $e->getCode(), $e); + } catch (UnexpectedValueException $e) { + throw new InvalidValueException(sprintf('Invalid coordinate value, got "%s".', $coordinate), $e->getCode(), $e); + } + + if (is_array($parsedCoordinate)) { + throw new InvalidValueException('Invalid coordinate value, coordinate cannot be an array.'); + } + + return $parsedCoordinate; + } + + /** + * Set a cartesian coordinate. + * Abscissa or ordinate. + * + * @param float|int|string $coordinate the coordinate to set + * + * @throws InvalidValueException when coordinate is invalid, RangeException is never thrown + */ + private function setCartesianCoordinate(float|int|string $coordinate): float|int + { + if (is_integer($coordinate) || is_float($coordinate)) { + // We don't check the range of the value. + return $coordinate; + } + + // $y is a string, let's use the geo-parser. + return $this->geoParse($coordinate); + } + + /** + * Set a geodesic coordinate. + * Latitude or longitude. + * + * @param float|int|string $coordinate the coordinate to set + * @param int $min the minimum value + * @param int $max the maximum value + * + * @throws InvalidValueException|RangeException when coordinate is invalid or out of range + */ + private function setGeodesicCoordinate(float|int|string $coordinate, int $min, int $max): float|int + { + if (is_integer($coordinate) || is_float($coordinate)) { + // We check the range of the value. + return $this->checkRange($coordinate, $min, $max); + } + + // $y is a string, let's use the geo-parser. + $parsedCoordinate = $this->geoParse($coordinate); + + if ($parsedCoordinate < $min || $parsedCoordinate > $max) { + throw new RangeException(sprintf('Coordinate must be comprised between %d and %d, got "%s".', $min, $max, $coordinate)); + } + + return $parsedCoordinate; + } + + /** + * Abstract point internal constructor. + * + * @param string $x X, longitude + * @param string $y Y, latitude + * @param null|int $srid Spatial Reference System Identifier + * + * @throws InvalidValueException if x or y are invalid + */ + abstract protected function construct(string $x, string $y, ?int $srid = null): void; } diff --git a/lib/LongitudeOne/Spatial/PHP/Types/CartesianInterface.php b/lib/LongitudeOne/Spatial/PHP/Types/CartesianInterface.php new file mode 100644 index 00000000..86188ab5 --- /dev/null +++ b/lib/LongitudeOne/Spatial/PHP/Types/CartesianInterface.php @@ -0,0 +1,57 @@ + 2017-2024 + * Copyright Longitude One 2020-2024 + * Copyright 2015 Derek J. Lambert + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +declare(strict_types=1); + +namespace LongitudeOne\Spatial\PHP\Types; + +/** + * Cartesian coordinates are planar coordinates expressed in linear units (meters). + * It includes projected coordinates, map projection coordinates, grid coordinates. + * Coordinates are x and y. + * + * Be aware that the setters of this interface don't throw exceptions when coordinates are out of range of the selected SRID. + */ +interface CartesianInterface +{ + /** + * @return float|int the abscissa coordinate + */ + public function getX(): float|int; + + /** + * @return float|int the ordinate coordinate + */ + public function getY(): float|int; + + /** + * The interface doesn't fix the return type. + * Usually, fluent setters return "self". + * Cartesian interfaces are used in AbstractPoint. It can return a geometry interface or a geographic one. + * + * @param float|int|string $x the abscissa coordinate + */ + public function setX(float|int|string $x): CartesianInterface|PointInterface; + + /** + * The interface doesn't fix the return type. + * Usually, fluent setters return "self". + * Cartesian interfaces are used in AbstractPoint. It can return a geometry interface or a geographic one. + * + * @param float|int|string $y the ordinate coordinate + */ + public function setY(float|int|string $y): CartesianInterface|PointInterface; +} diff --git a/lib/LongitudeOne/Spatial/PHP/Types/GeodeticInterface.php b/lib/LongitudeOne/Spatial/PHP/Types/GeodeticInterface.php new file mode 100644 index 00000000..56974b4b --- /dev/null +++ b/lib/LongitudeOne/Spatial/PHP/Types/GeodeticInterface.php @@ -0,0 +1,60 @@ + 2017-2024 + * Copyright Longitude One 2020-2024 + * Copyright 2015 Derek J. Lambert + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +declare(strict_types=1); + +namespace LongitudeOne\Spatial\PHP\Types; + +use LongitudeOne\Spatial\Exception\InvalidValueException; + +/** + * Geodetic (or geographic) coordinates are spherical coordinates expressed in angular units (degrees). + * Coordinates are longitude and latitude. + */ +interface GeodeticInterface +{ + /** + * @return float|int the converted latitude coordinate + */ + public function getLatitude(): float|int; + + /** + * @return float|int the converted longitude coordinate + */ + public function getLongitude(): float|int; + + /** + * The interface doesn't fix the return type. + * Usually, fluent setters return "self". + * Geodetic interfaces are used in AbstractPoint. It can return a geometry interface or a geographic one. + * + * @param float|int|string $latitude latitude to set. Out of range values are not allowed. + * + * @throws InvalidValueException when latitude is out of range + */ + public function setLatitude(float|int|string $latitude): GeodeticInterface|PointInterface; + + /** + * The interface doesn't fix the return type. + * Usually, fluent setters return "self". + * Geodetic interfaces are used in AbstractPoint. It can return a geometry interface or a geographic one. + * + * @param float|int|string $longitude longitude to set. Out of range values are not allowed. + * + * @throws InvalidValueException when longitude is out of range + */ + public function setLongitude(float|int|string $longitude): GeodeticInterface|PointInterface; +} diff --git a/lib/LongitudeOne/Spatial/PHP/Types/Geography/Point.php b/lib/LongitudeOne/Spatial/PHP/Types/Geography/Point.php index d67b382f..f0739c01 100644 --- a/lib/LongitudeOne/Spatial/PHP/Types/Geography/Point.php +++ b/lib/LongitudeOne/Spatial/PHP/Types/Geography/Point.php @@ -18,79 +18,58 @@ namespace LongitudeOne\Spatial\PHP\Types\Geography; -use LongitudeOne\Geo\String\Exception\RangeException; -use LongitudeOne\Geo\String\Exception\UnexpectedValueException; -use LongitudeOne\Geo\String\Parser; use LongitudeOne\Spatial\Exception\InvalidValueException; use LongitudeOne\Spatial\PHP\Types\AbstractPoint; +use LongitudeOne\Spatial\PHP\Types\GeodeticInterface; use LongitudeOne\Spatial\PHP\Types\PointInterface; /** * Point object for the POINT geography type. */ -class Point extends AbstractPoint implements GeographyInterface, PointInterface +class Point extends AbstractPoint implements GeodeticInterface, GeographyInterface, PointInterface { /** * X setter. * - * @param string $x X coordinate + * @param float|int|string $x X coordinate * * @throws InvalidValueException when y is not in range of accepted value, or is totally invalid */ - public function setX(string $x): self + public function setX(float|int|string $x): static { - $parser = new Parser($x); - - try { - $x = $parser->parse(); - } catch (RangeException $e) { - throw new InvalidValueException($e->getMessage(), $e->getCode(), $e); - } catch (UnexpectedValueException $e) { - throw new InvalidValueException(sprintf('Invalid longitude value, got "%s".', $x), $e->getCode(), $e); - } - - if (is_array($x)) { - throw new InvalidValueException('Invalid longitude value, longitude cannot be an array.'); - } - - if ($x < -180 || $x > 180) { - throw new InvalidValueException(sprintf('Invalid longitude value "%s", must be in range -180 to 180.', $x)); - } - - $this->x = $x; - - return $this; + // TODO #67 - Trigger a deprecation notice when using this method. Advice to use setLongitude instead. + return parent::setLongitude($x); } /** * Y setter. * - * @param string $y the Y coordinate + * @param float|int|string $y the Y coordinate * * @throws InvalidValueException when y is not in range of accepted value, or is totally invalid */ - public function setY(string $y): self + public function setY(float|int|string $y): static { - $parser = new Parser($y); - - try { - $y = $parser->parse(); - } catch (RangeException $e) { - throw new InvalidValueException($e->getMessage(), $e->getCode(), $e); - } catch (UnexpectedValueException $e) { - throw new InvalidValueException(sprintf('Invalid latitude value, got "%s".', $y), $e->getCode(), $e); - } - - if (is_array($y)) { - throw new InvalidValueException('Invalid latitude value, latitude cannot be an array.'); - } - - if ($y < -90 || $y > 90) { - throw new InvalidValueException(sprintf('Invalid latitude value "%s", must be in range -90 to 90.', $y)); - } - - $this->y = $y; + // TODO #67 - Trigger a deprecation notice when using this method. Advice to use setLongitude instead. + return parent::setLatitude($y); + } - return $this; + /** + * Point internal constructor. + * + * It uses Longitude and Latitude setters. + * + * @param string $x X, longitude + * @param string $y Y, latitude + * @param null|int $srid Spatial Reference System Identifier + * + * @throws InvalidValueException if x or y are invalid + */ + protected function construct(string $x, string $y, ?int $srid = null): void + { + $this->setLongitude($x) + ->setLatitude($y) + ->setSrid($srid) + ; } } diff --git a/lib/LongitudeOne/Spatial/PHP/Types/Geometry/Point.php b/lib/LongitudeOne/Spatial/PHP/Types/Geometry/Point.php index 0751f2ba..d7cd30af 100644 --- a/lib/LongitudeOne/Spatial/PHP/Types/Geometry/Point.php +++ b/lib/LongitudeOne/Spatial/PHP/Types/Geometry/Point.php @@ -18,12 +18,32 @@ namespace LongitudeOne\Spatial\PHP\Types\Geometry; +use LongitudeOne\Spatial\Exception\InvalidValueException; use LongitudeOne\Spatial\PHP\Types\AbstractPoint; +use LongitudeOne\Spatial\PHP\Types\CartesianInterface; use LongitudeOne\Spatial\PHP\Types\PointInterface; /** * Point object for the POINT geometry type. */ -class Point extends AbstractPoint implements GeometryInterface, PointInterface +class Point extends AbstractPoint implements CartesianInterface, GeometryInterface, PointInterface { + /** + * Point internal constructor. + * + * It uses X and Y setters. + * + * @param string $x X, longitude + * @param string $y Y, latitude + * @param null|int $srid Spatial Reference System Identifier + * + * @throws InvalidValueException if x or y are invalid + */ + protected function construct(string $x, string $y, ?int $srid = null): void + { + $this->setX($x) + ->setY($y) + ->setSrid($srid) + ; + } } diff --git a/quality/php-mess-detector/ruleset.xml b/quality/php-mess-detector/ruleset.xml index 34a4bdc4..ae16f2f0 100644 --- a/quality/php-mess-detector/ruleset.xml +++ b/quality/php-mess-detector/ruleset.xml @@ -6,9 +6,12 @@ http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> Alexandre Tranchant rule set. - + + + + diff --git a/tests/LongitudeOne/Spatial/Tests/DataProvider.php b/tests/LongitudeOne/Spatial/Tests/DataProvider.php new file mode 100644 index 00000000..c0489f17 --- /dev/null +++ b/tests/LongitudeOne/Spatial/Tests/DataProvider.php @@ -0,0 +1,115 @@ + 2017-2024 + * Copyright Longitude One 2020-2024 + * Copyright 2015 Derek J. Lambert + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +declare(strict_types=1); + +namespace LongitudeOne\Spatial\Tests; + +class DataProvider +{ + /** + * @return \Generator + */ + public static function outOfRangeLatitudeProvider(): \Generator + { + yield 'int(-100)' => [-100]; + + yield 'float(-90.01)' => [-90.01]; + + yield 'string(-100)' => ['-100']; + + yield 'string(-100°)' => ['-100°']; + + yield 'int(100)' => [100]; + + yield 'float(90.01)' => [90.01]; + + yield 'string(100°)' => ['100°']; + } + + /** + * @return \Generator + */ + public static function outOfRangeLongitudeProvider(): \Generator + { + yield 'int(-190)' => [-190]; + + yield 'float(-180.01)' => [-180.01]; + + yield 'string(-190)' => ['-190']; + + yield 'string(-190°)' => ['-190°']; + + yield 'int(190)' => [190]; + + yield 'float(180.01)' => [180.01]; + + yield 'string(190)' => ['190']; + + yield 'string(190°)' => ['190°']; + } + + /** + * @return \Generator + */ + public static function validGeodesicCoordinateProvider(): \Generator + { + // Integers + yield 'int(42), int(42)' => [42, 42, 42, 42]; + + yield 'int(-42), int(-42)' => [-42, -42, -42, -42]; + + yield 'int(180), int(90)' => [180, 90, 180, 90]; + + yield 'int(-180), int(-90)' => [-180, -90, -180, -90]; + + // Floats + yield 'float(42.42), float(42.42)' => [42.42, 42.42, 42.42, 42.42]; + + yield 'float(-42.42), float(-42.42)' => [-42.42, -42.42, -42.42, -42.42]; + + yield 'float(180.0), float(90.0)' => [180.0, 90.0, 180.0, 90.0]; + + yield 'float(-180.0), float(-90.0)' => [-180.0, -90.0, -180.0, -90.0]; + + // Strings + yield 'string(42), string(42)' => ['42', '42', 42, 42]; + + yield 'string(-42), string(-42)' => ['-42', '-42', -42, -42]; + + yield 'string(180), string(90)' => ['180', '90', 180, 90]; + + yield 'string(-180), string(-90)' => ['-180', '-90', -180, -90]; + + // Strings with degrees + yield 'string(42°), string(42°)' => ['42°', '42°', 42.0, 42.0]; + + yield 'string(-42°), string(-42°)' => ['-42°', '-42°', -42.0, -42.0]; + + yield 'string(180°), string(90°)' => ['180°', '90°', 180.0, 90.0]; + + yield 'string(-180°), string(-90°)' => ['-180°', '-90°', -180.0, -90.0]; + + // Strings with degrees and minutes + yield "string(42°42'), string(42°42')" => ["42°42'", "42°42'", 42.7, 42.7]; + + yield "string(-42°42'), string(-42°42')" => ["-42°42'", "-42°42'", -42.7, -42.7]; + + yield "string(180°0'), string(90°0')" => ["180°0'", "90°0'", 180.0, 90.0]; + + yield "string(-180°0'), string(-90°0')" => ["-180°0'", "-90°0'", -180.0, -90.0]; + } +} diff --git a/tests/LongitudeOne/Spatial/Tests/PHP/Types/AbstractPointTest.php b/tests/LongitudeOne/Spatial/Tests/PHP/Types/AbstractPointTest.php new file mode 100644 index 00000000..7f44ea79 --- /dev/null +++ b/tests/LongitudeOne/Spatial/Tests/PHP/Types/AbstractPointTest.php @@ -0,0 +1,551 @@ + 2017-2024 + * Copyright Longitude One 2020-2024 + * Copyright 2015 Derek J. Lambert + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ + +declare(strict_types=1); + +namespace LongitudeOne\Spatial\Tests\PHP\Types; + +use LongitudeOne\Spatial\Exception\InvalidValueException; +use LongitudeOne\Spatial\PHP\Types\AbstractPoint; +use LongitudeOne\Spatial\PHP\Types\Geography\Point as GeographicPoint; +use LongitudeOne\Spatial\PHP\Types\Geometry\Point as GeometricPoint; +use LongitudeOne\Spatial\Tests\DataProvider as LoDataProvider; +use LongitudeOne\Spatial\Tests\Helper\PointHelperTrait; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +/** + * Geometric and geographic points tests. + * These methods involve tests launched on both Geometric and Geographic points. + * + * @group php + * + * @internal + * + * @covers \LongitudeOne\Spatial\PHP\Types\AbstractPoint + * @covers \LongitudeOne\Spatial\PHP\Types\Geography\Point + * @covers \LongitudeOne\Spatial\PHP\Types\Geometry\Point + */ +class AbstractPointTest extends TestCase +{ + // phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint + + use PointHelperTrait; + + private const DELTA = 0.000000000001; + + /** + * @return \Generator + */ + public static function easyValuesProvider(): \Generator + { + $points = [ + 'GeometricPoint' => GeometricPoint::class, + 'GeographicPoint' => GeographicPoint::class, + ]; + + $methods = [ + 'setX' => ['getX', 'getLongitude'], + 'setY' => ['getY', 'getLatitude'], + 'setLongitude' => ['getX', 'getLongitude'], + 'setLatitude' => ['getY', 'getLatitude'], + ]; + + $values = [ + 'int(20)' => ['actual' => 20, 'expected' => 20], + 'float(20.0)' => ['actual' => 20.0, 'expected' => 20.0], + 'string(20)' => ['actual' => '20', 'expected' => 20], + 'string(20.0)' => ['actual' => '20.0', 'expected' => 20], + ]; + + foreach ($points as $className => $class) { + foreach ($methods as $setter => $getters) { + foreach ($values as $valueName => $value) { + yield sprintf('%s with %s and %s', $className, $setter, $valueName) => [$class, $setter, $getters, $value['actual'], $value['expected']]; + } + } + } + } + + /** + * @return \Generator + */ + public static function mixedGeodesicCoordinateProvider(): \Generator + { + $points = [ + 'GeometricPoint' => GeometricPoint::class, + 'GeographicPoint' => GeographicPoint::class, + ]; + + /** @var array $geodesicCoordinates */ + $geodesicCoordinates = [ + '79:56:55W, 40:26:46N' => [-79.9486111111111, 40.44611111111111], + '79° 56\' 55" W, 40° 26\' 46" N' => [-79.9486111111111, 40.44611111111111], + '79°56′55″W, 40°26′46″N' => [-79.9486111111111, 40.44611111111111], + '79° 56′ 55″ W, 40° 26′ 46″ N' => [-79.9486111111111, 40.44611111111111], + '79:56:55.832W, 40:26:46.543N' => [-79.94884222222223, 40.446261944444444], + '112:4:0W, 33:27:0N' => [-112.066666666666, 33.45], + ]; + + foreach ($points as $className => $class) { + foreach ($geodesicCoordinates as $coordinatesString => $expected) { + $coordinates = explode(', ', $coordinatesString); + + yield sprintf('%s(%s, %s)', $className, $coordinates[0], $coordinates[1]) => [$class, $coordinates[0], $coordinates[1], $expected[0], $expected[1]]; + } + } + } + + /** + * @return \Generator}, null, void> + */ + public static function pointTypeProvider(): \Generator + { + yield 'GeometricPoint' => [GeometricPoint::class]; + + yield 'GeographicPoint' => [GeographicPoint::class]; + } + + /** + * @return \Generator, 1: string, 2: string, 3: string}, null, void> + */ + public static function rangeExceptionProvider(): \Generator + { + $points = [ + 'GeometricPoint' => GeometricPoint::class, + 'GeographicPoint' => GeographicPoint::class, + ]; + + $exceptions = [ + 'Out of range latitude' => [ + '79:56:55W', '92:26:46N', + 'Out of range latitude value, latitude must be between -90 and 90, got "92:26:46N".', + ], + 'Out of range longitude' => [ + '190:56:55W', '84:26:46N', + 'Out of range longitude value, longitude must be between -180 and 180, got "190:56:55W".', + ], + 'Invalid latitude direction' => [ + '100:56:55W', '84:26:46Q', + 'Invalid coordinate value, got "84:26:46Q".', + ], + 'Latitude minutes greater than 59' => [ + '108:42:55W', '84:64:46N', + 'Out of range minute value, minute must be between 0 and 59, got "84:64:46N".', + ], + 'Latitude seconds greater than 59' => [ + '108:42:55W', '84:23:75N', + 'Out of range second value, second must be between 0 and 59, got "84:23:75N".', + ], + 'Longitude degrees greater than 180' => [ + '190:56:55W', '84:26:46N', + 'Out of range longitude value, longitude must be between -180 and 180, got "190:56:55W".', + ], + 'Invalid longitude direction' => [ + '100:56:55P', '84:26:46N', + 'Invalid coordinate value, got "100:56:55P".', + ], + 'Longitude minutes greater than 59' => [ + '108:62:55W', '84:26:46N', + 'Out of range minute value, minute must be between 0 and 59, got "108:62:55W".', + ], + 'Longitude seconds greater than 59' => [ + '108:53:94W', '84:26:46N', + 'Out of range second value, second must be between 0 and 59, got "108:53:94W".', + ], + ]; + + foreach ($points as $className => $class) { + foreach ($exceptions as $dataTestName => $dataTest) { + yield sprintf('%s with a %s', $dataTestName, $className) => [$class, $dataTest[0], $dataTest[1], $dataTest[2]]; + } + } + } + + /** + * @return \Generator, 1: string}, null, void> + */ + public static function setterProvider(): \Generator + { + $points = [ + 'GeometricPoint' => GeometricPoint::class, + 'GeographicPoint' => GeographicPoint::class, + ]; + $methods = [ + 'setX', + 'setY', + 'setLongitude', + 'setLatitude', + ]; + foreach ($points as $className => $class) { + foreach ($methods as $method) { + yield sprintf('%s with %s', $className, $method) => [$class, $method]; + } + } + } + + /** + * @return \Generator, 1: float|int|string, 2: float|int|string, 3: float|int, 4: float|int}, null, void> + */ + public static function validGeodesicCoordinateProvider(): \Generator + { + $points = [ + 'GeometricPoint' => GeometricPoint::class, + 'GeographicPoint' => GeographicPoint::class, + ]; + foreach ($points as $point) { + foreach (LoDataProvider::validGeodesicCoordinateProvider() as $key => $value) { + yield sprintf('%s(%s)', $point, $key) => array_merge([$point], $value); + } + } + } + + /** + * Assert that the object has the method. + * + * @param object $object object to test + * @param string $method the method to test + */ + private static function assertObjectHasMethod(object $object, string $method): void + { + static::assertTrue(method_exists($object, $method), sprintf('Method "%s":"%s" does not exist.', $object::class, $method)); + } + + /** + * Test getType method. + * + * @param class-string $class the classname to test, Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testGetType(string $class): void + { + $point = new $class(0, 0); + static::assertEquals('Point', $point->getType()); + } + + /** + * Test geodesic setters. + * + * @param class-string $pointType Geometric or geographic point + * @param float|int|string $longitude the actual longitude + * @param float|int|string $latitude the actual latitude + * @param float|int $expectedLongitude the expected longitude + * @param float|int $expectedLatitude the expected latitude + */ + #[DataProvider('validGeodesicCoordinateProvider')] + public function testGoodGeodesicCoordinate(string $pointType, float|int|string $longitude, float|int|string $latitude, float|int $expectedLongitude, float|int $expectedLatitude): void + { + $geographicPoint = new $pointType(0, 0); + $geographicPoint->setLongitude($longitude); + $geographicPoint->setLatitude($latitude); + + static::assertSame($expectedLongitude, $geographicPoint->getLongitude()); + static::assertSame($expectedLatitude, $geographicPoint->getLatitude()); + } + + /** + * Test valid string points. + * + * @param class-string $abstractPoint Geometric point and geographic point + * @param float|int|string $longitude the longitude to test + * @param float|int|string $latitude the latitude to test + * @param float|int $expectedLongitude the expected longitude + * @param float|int $expectedLatitude the expected latitude + */ + #[DataProvider('mixedGeodesicCoordinateProvider')] + public function testGoodStringPoints(string $abstractPoint, float|int|string $longitude, float|int|string $latitude, float|int $expectedLongitude, float|int $expectedLatitude): void + { + $point = new $abstractPoint($longitude, $latitude); + static::assertEqualsWithDelta($expectedLongitude, $point->getLongitude(), self::DELTA); + static::assertEqualsWithDelta($expectedLatitude, $point->getLatitude(), self::DELTA); + + $point = new $abstractPoint(0, 0, 4326); + $point->setLongitude($longitude); + $point->setLatitude($latitude); + static::assertEqualsWithDelta($expectedLongitude, $point->getLongitude(), self::DELTA); + static::assertEqualsWithDelta($expectedLatitude, $point->getLatitude(), self::DELTA); + } + + /** + * Test argument 1 with too few values - Two invalid parameters. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testInvalidArrayWithTooFewValues(string $abstractPoint): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct: array(1)', $abstractPoint)); + + new $abstractPoint([1]); + } + + /** + * Test argument 1 with too many values - Two invalid parameters. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testInvalidArrayWithTooManyValues(string $abstractPoint): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct: array(1, 2, 3, 4)', $abstractPoint)); + + new $abstractPoint([1, 2, 3, 4]); + } + + /** + * Test to convert point to json. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testJson(string $abstractPoint): void + { + $expected = '{"type":"Point","coordinates":[5,5],"srid":null}'; + $point = new $abstractPoint(5, 5); + + static::assertEquals($expected, $point->toJson()); + static::assertEquals($expected, json_encode($point)); + + $point->setSrid(4326); + $expected = '{"type":"Point","coordinates":[5,5],"srid":4326}'; + static::assertEquals($expected, $point->toJson()); + static::assertEquals($expected, json_encode($point)); + } + + /** + * Test bad string parameters - No parameters. + * + * @param class-string $pointType Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testMissingArguments(string $pointType): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct:', $pointType)); + + new $pointType(); + } + + /** + * Test a point created with an array. + * + * @param class-string $pointType Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testPointFromArrayToString(string $pointType): void + { + $point = new $pointType([5, 5]); + + static::assertSame('5 5', (string) $point); + } + + /** + * Test error when point is created with too many arguments. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testPointTooManyArguments(string $abstractPoint): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct: 5, 5, 5, 5', $abstractPoint)); + + new $abstractPoint(5, 5, 5, 5); + } + + /** + * Test point with srid. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testPointWithSrid(string $abstractPoint): void + { + $point = new $abstractPoint(5, 5, 2154); + $actual = $point->getSrid(); + static::assertSame(2154, $actual); + + $point->setSrid(4326); + $actual = $point->getSrid(); + static::assertSame(4326, $actual); + } + + /** + * Test error when point was created with the wrong arguments type. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testPointWrongArgumentTypes(string $abstractPoint): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct: array, array, 1234', $abstractPoint)); + + new $abstractPoint([], [], '1234'); + } + + /** + * This test checks that the geo-parser range exceptions are caught and "converted" to InvalidValueException. + * This test focuses on constructor. + * + * @param class-string $abstractPoint Geometric point and geographic point + * @param string $firstCoordinate the first coordinate to test + * @param string $secondCoordinate the second coordinate to test + * @param string $expectedMessage the expected message + */ + #[DataProvider('rangeExceptionProvider')] + public function testRangeExceptionAreCaughtWithConstructor(string $abstractPoint, string $firstCoordinate, string $secondCoordinate, string $expectedMessage): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage($expectedMessage); + + new $abstractPoint($firstCoordinate, $secondCoordinate); + } + + /** + * This test checks that the geo-parser range exceptions are caught and "converted" to InvalidValueException. + * This test focuses on X and Y setters. + * + * @param class-string $abstractPoint Geometric point and geographic point + * @param string $firstCoordinate the first coordinate to test + * @param string $secondCoordinate the second coordinate to test + * @param string $expectedMessage the expected message + */ + #[DataProvider('rangeExceptionProvider')] + public function testRangeExceptionAreCaughtWithNonExpectedSetters(string $abstractPoint, string $firstCoordinate, string $secondCoordinate, string $expectedMessage): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage($expectedMessage); + + $point = new $abstractPoint(0, 0); + $point->setX($firstCoordinate); + $point->setY($secondCoordinate); + } + + /** + * This test checks that the geo-parser range exceptions are caught and "converted" to InvalidValueException. + * This test focuses on longitude and latitude setters. + * + * @param class-string $abstractPoint Geometric point and geographic point + * @param string $firstCoordinate the first coordinate to test + * @param string $secondCoordinate the second coordinate to test + * @param string $expectedMessage the expected message + */ + #[DataProvider('rangeExceptionProvider')] + public function testRangeExceptionAreCaughtWithSetters(string $abstractPoint, string $firstCoordinate, string $secondCoordinate, string $expectedMessage): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage($expectedMessage); + + $point = new $abstractPoint(0, 0); + $point->setLongitude($firstCoordinate); + $point->setLatitude($secondCoordinate); + } + + /** + * Test setX method. + * + * @param class-string $abstractPoint Geometric point and geographic point + * @param string $setter the setter to test + * @param array{0: string, 1: string} $getters the getters to test + * @param float|int|string $actual the actual value to set + * @param float|int $expected the expected value + * + * @throws InvalidValueException it should NOT happen + */ + #[DataProvider('easyValuesProvider')] + public function testSetters(string $abstractPoint, string $setter, array $getters, float|int|string $actual, float|int $expected): void + { + $firstGetter = $getters[0]; + $secondGetter = $getters[1]; + + $point = new $abstractPoint(10, 10); + self::assertObjectHasMethod($point, $setter); + self::assertObjectHasMethod($point, $firstGetter); + self::assertObjectHasMethod($point, $secondGetter); + + $point->{$setter}($actual); + static::assertSame($expected, $point->{$firstGetter}()); + static::assertSame($expected, $point->{$secondGetter}()); + } + + /** + * This test checks that an exception is thrown when passing two coordinates separated by a space. + * This test checks all setters. + * + * @param class-string $abstractPoint Geometric point and geographic point + * @param string $method the method to test + */ + #[DataProvider('setterProvider')] + public function testSettersWithAnArray(string $abstractPoint, string $method): void + { + $point = new $abstractPoint(10, 10); + + self::expectException(InvalidValueException::class); + self::expectExceptionMessage('Invalid coordinate value, coordinate cannot be an array.'); + static::assertTrue(method_exists($point, $method), sprintf('Method "%s":"%s" does not exist.', $abstractPoint, $method)); + $point->{$method}('10 20'); + } + + /** + * Test to convert point to array. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testToArray(string $abstractPoint): void + { + $expected = [-10, 11]; + $point = new $abstractPoint(-10, 11); + $actual = $point->toArray(); + static::assertEquals($expected, $actual); + + $expected = [-42.42, 42.43]; + $point = new $abstractPoint(-42.42, 42.43); + $actual = $point->toArray(); + static::assertEquals($expected, $actual); + } + + /** + * Test bad string parameters - Two invalid parameters. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testTwoInvalidArguments(string $abstractPoint): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct: NULL, NULL', $abstractPoint)); + + new $abstractPoint(null, null); + } + + /** + * Test bad string parameters - More than 3 parameters. + * + * @param class-string $abstractPoint Geometric point and geographic point + */ + #[DataProvider('pointTypeProvider')] + public function testUnusedArguments(string $abstractPoint): void + { + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Invalid parameters passed to %s::__construct: 1, 2, 3, 4, NULL, 5', $abstractPoint)); + + new $abstractPoint(1, 2, 3, 4, null, 5); + } +} diff --git a/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geography/PointTest.php b/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geography/PointTest.php index 7f88fed9..759a583a 100644 --- a/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geography/PointTest.php +++ b/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geography/PointTest.php @@ -20,6 +20,8 @@ use LongitudeOne\Spatial\Exception\InvalidValueException; use LongitudeOne\Spatial\PHP\Types\Geography\Point; +use LongitudeOne\Spatial\Tests\DataProvider as LoDataProvider; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -34,104 +36,23 @@ class PointTest extends TestCase { /** - * Test bad string parameters - latitude degrees greater than 90. + * @return \Generator */ - public function testBadLatitudeDegrees(): void + public static function outOfRangeLatitudeProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Degrees out of range -90 to 90 in value "92:26:46N"'); - - new Point('79:56:55W', '92:26:46N'); - } - - /** - * Test bad string parameters - invalid latitude direction. - */ - public function testBadLatitudeDirection(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid latitude value, got "84:26:46Q"'); - - new Point('100:56:55W', '84:26:46Q'); - } - - /** - * Test bad string parameters - latitude minutes greater than 59. - */ - public function testBadLatitudeMinutes(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Minutes greater than 60 in value "84:64:46N"'); - - new Point('108:42:55W', '84:64:46N'); - } - - /** - * Test bad string parameters - latitude seconds greater than 59. - */ - public function testBadLatitudeSeconds(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Seconds greater than 60 in value "84:23:75N"'); - - new Point('108:42:55W', '84:23:75N'); - } - - /** - * Test bad string parameters - longitude degrees greater than 180. - */ - public function testBadLongitudeDegrees(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Degrees out of range -180 to 180 in value "190:56:55W"'); - - new Point('190:56:55W', '84:26:46N'); - } - - /** - * Test bad string parameters - invalid longitude direction. - */ - public function testBadLongitudeDirection(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid longitude value, got "100:56:55P"'); - - new Point('100:56:55P', '84:26:46N'); - } - - /** - * Test bad string parameters - longitude minutes greater than 59. - */ - public function testBadLongitudeMinutes(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Minutes greater than 60 in value "108:62:55W"'); - - new Point('108:62:55W', '84:26:46N'); - } - - /** - * Test bad string parameters - longitude seconds greater than 59. - */ - public function testBadLongitudeSeconds(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Seconds greater than 60 in value "108:53:94W"'); - - new Point('108:53:94W', '84:26:46N'); + foreach (LoDataProvider::outOfRangeLatitudeProvider() as $key => $value) { + yield $key => $value; + } } /** - * Test bad numeric parameters - latitude greater than 90. - * - * @throws InvalidValueException it should happen + * @return \Generator */ - public function testBadNumericGreaterThanLatitude(): void + public static function outOfRangeLongitudeProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid latitude value "190", must be in range -90 to 90.'); - - new Point(55, 190); + foreach (LoDataProvider::outOfRangeLongitudeProvider() as $key => $value) { + yield $key => $value; + } } /** @@ -142,7 +63,7 @@ public function testBadNumericGreaterThanLatitude(): void public function testBadNumericGreaterThanLongitude(): void { $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid longitude value "180.134", must be in range -180 to 180.'); + $this->expectExceptionMessage('Out of range longitude value, longitude must be between -180 and 180, got "180.134".'); new Point(180.134, 54); } @@ -155,7 +76,7 @@ public function testBadNumericGreaterThanLongitude(): void public function testBadNumericLessThanLatitude(): void { $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid latitude value "-90.00001", must be in range -90 to 90.'); + $this->expectExceptionMessage('Out of range latitude value, latitude must be between -90 and 90, got "-90.00001".'); new Point(55, -90.00001); } @@ -168,7 +89,7 @@ public function testBadNumericLessThanLatitude(): void public function testBadNumericLessThanLongitude(): void { $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid longitude value "-230", must be in range -180 to 180.'); + $this->expectExceptionMessage('Out of range longitude value, longitude must be between -180 and 180, got "-230".'); new Point(-230, 54); } @@ -262,136 +183,94 @@ public function testGoodStringPoints(): void } /** - * Test a point created with an array and converts to string. + * Test out-of-range latitude with constructor. * - * @throws InvalidValueException it should NOT happen + * @param float|int|string $latitude the out-of-range latitude */ - public function testPointFromArrayToString(): void + #[DataProvider('outOfRangeLatitudeProvider')] + public function testOutOfRangeLatitudeConstructor(float|int|string $latitude): void { - $expected = '5 5'; - $point = new Point([5, 5]); - - static::assertEquals($expected, (string) $point); + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Out of range latitude value, latitude must be between -90 and 90, got "%s".', $latitude)); + new Point(0, $latitude); } /** - * Test error when point created with too many arguments. + * Test out of range longitude with constructor. * - * @throws InvalidValueException it should happen + * @param float|int|string $longitude the out-of-range longitude + * + * @throws InvalidValueException the expected exception */ - public function testPointTooManyArguments(): void + #[DataProvider('outOfRangeLongitudeProvider')] + public function testOutOfRangeLongitudeConstructor(float|int|string $longitude): void { $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geography\\Point::__construct: 5, 5, 5, 5'); - - new Point(5, 5, 5, 5); + $this->expectExceptionMessage(sprintf('Out of range longitude value, longitude must be between -180 and 180, got "%s".', $longitude)); + new Point($longitude, 0); } /** - * Test a point with SRID. + * Test out of range latitude with latitude setters. * - * @throws InvalidValueException it should not happen - */ - public function testPointWithSrid(): void - { - $point = new Point(10, 10, 4326); - $result = $point->getSrid(); - - static::assertEquals(4326, $result); - - // Lambert - $point = new Point(10, 10, 2154); - $result = $point->getSrid(); - - static::assertEquals(2154, $result); - } - - /** - * Test error when point is created with wrong arguments. + * @param float|int|string $latitude the out-of-range latitude * - * @throws InvalidValueException it should happen + * @throws InvalidValueException the expected exception */ - public function testPointWrongArgumentTypes(): void + #[DataProvider('outOfRangeLatitudeProvider')] + public function testOutOfRangeSetLatitude(float|int|string $latitude): void { + $point = new Point(0, 0); $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geography\\Point::__construct: array, array, 1234'); - - new Point([], [], '1234'); + $this->expectExceptionMessage(sprintf('Out of range latitude value, latitude must be between -90 and 90, got "%s".', $latitude)); + $point->setLatitude($latitude); } /** - * Test setX method with an array. + * Test out of range longitude with longitude setters. * - * @throws InvalidValueException it should NOT happen - */ - public function testSetFirstCoordinateWithAnArray(): void - { - $point = new Point(10, 10); - - self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid longitude value, longitude cannot be an array.'); - $point->setX('10 20'); - } - - /** - * Test setY method with an array. + * @param float|int|string $longitude the out-of-range longitude * - * @throws InvalidValueException it should NOT happen + * @throws InvalidValueException the expected exception */ - public function testSetSecondCoordinateWithAnArray(): void + #[DataProvider('outOfRangeLongitudeProvider')] + public function testOutOfRangeSetLongitude(float|int|string $longitude): void { - $point = new Point(10, 10); - - self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid latitude value, latitude cannot be an array.'); - $point->setY('10 20'); + $point = new Point(0, 0); + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Out of range longitude value, longitude must be between -180 and 180, got "%s".', $longitude)); + $point->setLongitude($longitude); } /** - * Test setX method. + * Test out of range longitude. * - * @throws InvalidValueException it should NOT happen - */ - public function testSetX(): void - { - $point = new Point(10, 10); - $point->setX('20'); - static::assertSame(20, $point->getLongitude()); - static::assertSame(20, $point->getX()); - - self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid longitude value, got "foo".'); - $point->setX('foo'); - } - - /** - * Test setY method. + * @param float|int|string $longitude the out-of-range longitude * - * @throws InvalidValueException it should NOT happen + * @throws InvalidValueException the expected exception */ - public function testSetY(): void + #[DataProvider('outOfRangeLongitudeProvider')] + public function testOutOfRangeSetX(float|int|string $longitude): void { - $point = new Point(10, 10); - $point->setY('20'); - static::assertSame(20, $point->getLatitude()); - static::assertSame(20, $point->getY()); - - self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid latitude value, got "foo".'); - $point->setY('foo'); + $point = new Point(0, 0); + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Out of range longitude value, longitude must be between -180 and 180, got "%s".', $longitude)); + $point->setX($longitude); } /** - * Test to convert point to array. + * Test out of range latitude. * - * @throws InvalidValueException it should happen + * @param float|int|string $latitude the out-of-range latitude + * + * @throws InvalidValueException the expected exception */ - public function testToArray(): void + #[DataProvider('outOfRangeLatitudeProvider')] + public function testOutOfRangeSetY(float|int|string $latitude): void { - $expected = [10, 10]; - $point = new Point(10, 10); - $result = $point->toArray(); - - static::assertEquals($expected, $result); + $point = new Point(0, 0); + $this->expectException(InvalidValueException::class); + $this->expectExceptionMessage(sprintf('Out of range latitude value, latitude must be between -90 and 90, got "%s".', $latitude)); + $point->setY($latitude); } } diff --git a/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geometry/PointTest.php b/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geometry/PointTest.php index 20ce7528..70cecd6c 100644 --- a/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geometry/PointTest.php +++ b/tests/LongitudeOne/Spatial/Tests/PHP/Types/Geometry/PointTest.php @@ -19,8 +19,10 @@ namespace LongitudeOne\Spatial\Tests\PHP\Types\Geometry; use LongitudeOne\Spatial\Exception\InvalidValueException; -use LongitudeOne\Spatial\PHP\Types\Geometry\Point; +use LongitudeOne\Spatial\PHP\Types\Geometry\Point as GeometricPoint; +use LongitudeOne\Spatial\Tests\DataProvider as LoDataProvider; use LongitudeOne\Spatial\Tests\Helper\PointHelperTrait; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -37,91 +39,65 @@ class PointTest extends TestCase use PointHelperTrait; /** - * Test bad string parameters - latitude degrees greater than 90. + * @return \Generator */ - public function testBadLatitudeDegrees(): void + public static function goodGeodesicCoordinateProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Degrees out of range -90 to 90 in value "92:26:46N"'); - - new Point('79:56:55W', '92:26:46N'); + foreach (LoDataProvider::validGeodesicCoordinateProvider() as $key => $value) { + yield $key => $value; + } } /** - * Test bad string parameters - invalid latitude direction. + * @return \Generator */ - public function testBadLatitudeDirection(): void + public static function outOfRangeLatitudeProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid coordinate value, got "84:26:46Q".'); - - new Point('100:56:55W', '84:26:46Q'); + foreach (LoDataProvider::outOfRangeLatitudeProvider() as $key => $value) { + yield $key => $value; + } } /** - * Test bad string parameters - latitude minutes greater than 59. + * @return \Generator */ - public function testBadLatitudeMinutes(): void + public static function outOfRangeLongitudeProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Minutes greater than 60 in value "84:64:46N"'); - - new Point('108:42:55W', '84:64:46N'); + foreach (LoDataProvider::outOfRangeLongitudeProvider() as $key => $value) { + yield $key => $value; + } } /** - * Test bad string parameters - latitude seconds greater than 59. + * @return \Generator */ - public function testBadLatitudeSeconds(): void + public static function tooBigLatitudeProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Seconds greater than 60 in value "84:23:75N"'); - - new Point('108:42:55W', '84:23:75N'); + foreach (LoDataProvider::outOfRangeLatitudeProvider() as $key => $value) { + yield $key => $value; + } } /** - * Test bad string parameters - longitude degrees greater than 180. + * @return \Generator */ - public function testBadLongitudeDegrees(): void + public static function tooBigLongitudeProvider(): \Generator { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Degrees out of range -180 to 180 in value "190:56:55W"'); + yield 'int(-190)' => [-190]; - new Point('190:56:55W', '84:26:46N'); - } + yield 'float(-180.01)' => [-180.01]; - /** - * Test bad string parameters - invalid longitude direction. - */ - public function testBadLongitudeDirection(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid coordinate value, got "100:56:55P".'); + yield 'string(-190)' => ['-190']; - new Point('100:56:55P', '84:26:46N'); - } + yield 'string(-190°)' => ['-190°']; - /** - * Test bad string parameters - longitude minutes greater than 59. - */ - public function testBadLongitudeMinutes(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Minutes greater than 60 in value "108:62:55W"'); + yield 'int(190)' => [190]; - new Point('108:62:55W', '84:26:46N'); - } + yield 'float(180.01)' => [180.01]; - /** - * Test bad string parameters - longitude seconds greater than 59. - */ - public function testBadLongitudeSeconds(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('[Range Error] Error: Seconds greater than 60 in value "108:53:94W"'); + yield 'string(190)' => ['190']; - new Point('108:53:94W', '84:26:46N'); + yield 'string(190°)' => ['190°']; } /** @@ -134,7 +110,7 @@ public function testEmbeddedArrays(): void $this->expectException(InvalidValueException::class); $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geometry\\Point::__construct: array'); - new Point([[3, []]]); + new GeometricPoint([[3, []]]); } /** @@ -142,10 +118,30 @@ public function testEmbeddedArrays(): void */ public function testGetType(): void { - $point = static::createPointOrigin(); - $result = $point->getType(); + $geometricPoint = new GeometricPoint(0, 0); + + static::assertEquals('Point', $geometricPoint->getType()); + } + + /** + * Test to set geodesic coordinates. + * + * @param float|int|string $longitude longitude to set + * @param float|int|string $latitude latitude to set + * @param float|int $expectedLongitude expected longitude + * @param float|int $expectedLatitude expected latitude + * + * @throws InvalidValueException It shall NOT happen + */ + #[DataProvider('goodGeodesicCoordinateProvider')] + public function testGoodGeodesicCoordinate(float|int|string $longitude, float|int|string $latitude, float|int $expectedLongitude, float|int $expectedLatitude): void + { + $geographicPoint = new GeometricPoint(0, 0); + $geographicPoint->setLongitude($longitude); + $geographicPoint->setLatitude($latitude); - static::assertEquals('Point', $result); + static::assertSame($expectedLongitude, $geographicPoint->getLongitude()); + static::assertSame($expectedLatitude, $geographicPoint->getLatitude()); } /** @@ -172,216 +168,119 @@ public function testGoodNumericPoint(): void } /** - * Test valid string points. + * Test out of range latitude constructor. + * + * @param float|int|string $latitude out-of-range value + * + * @throws InvalidValueException It shall NOT happen */ - public function testGoodStringPoints(): void + #[DataProvider('outOfRangeLatitudeProvider')] + public function testOutOfRangeLatitudeConstructor(float|int|string $latitude): void { - $point = new Point('79:56:55W', '40:26:46N'); - - static::assertEqualsWithDelta(40.44611111111111, $point->getLatitude(), 0.000000000001); - static::assertEqualsWithDelta(-79.9486111111111, $point->getLongitude(), 0.000000000001); - - $point = new Point('79°56\'55"W', '40°26\'46"N'); - - static::assertEqualsWithDelta(40.44611111111111, $point->getLatitude(), 0.000000000001); - static::assertEqualsWithDelta(-79.9486111111111, $point->getLongitude(), 0.000000000001); - - $point = new Point('79° 56\' 55" W', '40° 26\' 46" N'); - - static::assertEqualsWithDelta(40.44611111111111, $point->getLatitude(), 0.000000000001); - static::assertEqualsWithDelta(-79.9486111111111, $point->getLongitude(), 0.000000000001); - - $point = new Point('79°56′55″W', '40°26′46″N'); - - static::assertEqualsWithDelta(40.44611111111111, $point->getLatitude(), 0.000000000001); - static::assertEqualsWithDelta(-79.9486111111111, $point->getLongitude(), 0.000000000001); - - $point = new Point('79° 56′ 55″ W', '40° 26′ 46″ N'); - - static::assertEqualsWithDelta(40.44611111111111, $point->getLatitude(), 0.000000000001); - static::assertEqualsWithDelta(-79.9486111111111, $point->getLongitude(), 0.000000000001); - - $point = new Point('79:56:55.832W', '40:26:46.543N'); - - static::assertEqualsWithDelta(40.446261944444444, $point->getLatitude(), 0.000000000001); - static::assertEqualsWithDelta(-79.94884222222223, $point->getLongitude(), 0.000000000001); - - $point = new Point('112:4:0W', '33:27:0N'); - - static::assertEquals(33.45, $point->getLatitude()); - static::assertEqualsWithDelta(-112.06666666666, $point->getLongitude(), 0.0000000001); + $geometricPoint = new GeometricPoint(0, $latitude); + static::assertIsNumeric($geometricPoint->getLatitude()); + static::assertNotEmpty($geometricPoint->getLatitude()); } /** - * Test to convert point to json. + * Test out of range longitude constructor. + * + * @param float|int|string $longitude out-of-range value + * + * @throws InvalidValueException It shall NOT happen */ - public function testJson(): void + #[DataProvider('outOfRangeLongitudeProvider')] + public function testOutOfRangeLongitudeConstructor(float|int|string $longitude): void { - $expected = '{"type":"Point","coordinates":[5,5],"srid":null}'; - $point = static::createPointE(); - - static::assertEquals($expected, $point->toJson()); - static::assertEquals($expected, json_encode($point)); - - $point->setSrid(4326); - $expected = '{"type":"Point","coordinates":[5,5],"srid":4326}'; - static::assertEquals($expected, $point->toJson()); - static::assertEquals($expected, json_encode($point)); + $geometricPoint = new GeometricPoint($longitude, 0); + static::assertIsNumeric($geometricPoint->getLongitude()); + static::assertNotEmpty($geometricPoint->getLongitude()); } /** - * Test bad string parameters - No parameters. + * Test setLatitude with out-of-range values. + * + * @param float|int|string $latitude out-of-range value + * + * @throws InvalidValueException exception is expected */ - public function testMissingArguments(): void + #[DataProvider('outOfRangeLatitudeProvider')] + public function testOutOfRangeSetLatitude(float|int|string $latitude): void { + $point = new GeometricPoint(0, 0); $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geometry\\Point::__construct:'); - - new Point(); - } - - /** - * Test a point created with an array. - */ - public function testPointFromArrayToString(): void - { - $expected = '5 5'; - $point = static::createPointE(); - - static::assertSame($expected, (string) $point); + $this->expectExceptionMessage(sprintf('Out of range latitude value, latitude must be between -90 and 90, got "%s".', $latitude)); + $point->setLatitude($latitude); } /** - * Test error when point is created with too many arguments. + * Test setLongitude with out-of-range values. + * + * @param float|int|string $longitude out-of-range value + * + * @throws InvalidValueException expected exception */ - public function testPointTooManyArguments(): void + #[DataProvider('outOfRangeLongitudeProvider')] + public function testOutOfRangeSetLongitude(float|int|string $longitude): void { + $point = new GeometricPoint(0, 0); $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geometry\\Point::__construct: 5, 5, 5, 5'); - - new Point(5, 5, 5, 5); + $this->expectExceptionMessage(sprintf('Out of range longitude value, longitude must be between -180 and 180, got "%s".', $longitude)); + $point->setLongitude($longitude); } /** - * Test point with srid. + * Test setCoordinates with big integer. */ - public function testPointWithSrid(): void + public function testSetCoordinatesWithBigInteger(): void { - $point = static::createPointWithSrid(2154); - $result = $point->getSrid(); + $point = new GeometricPoint(10, 10); + $point->setX('200'); + static::assertSame(200, $point->getX()); - static::assertSame(2154, $result); - } + $point->setY('100'); + static::assertSame(100, $point->getY()); - /** - * Test error when point was created with wrong arguments type. - */ - public function testPointWrongArgumentTypes(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geometry\\Point::__construct: array, array, 1234'); + $point->setX('-180.3'); + static::assertSame(-180.3, $point->getX()); - new Point([], [], '1234'); + $point->setY('-190.3'); + static::assertSame(-190.3, $point->getY()); } /** - * Test setX method with an array. + * Test setLatitude with out-of-range values. * - * @throws InvalidValueException it should NOT happen - */ - public function testSetFirstCoordinateWithAnArray(): void - { - $point = new Point(10, 10); - - self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid coordinate value, coordinate cannot be an array.'); - $point->setX('10 20'); - } - - /** - * Test setY method with an array. + * @param float|int|string $latitude the out-of-range value * - * @throws InvalidValueException it should NOT happen + * @throws InvalidValueException it SHALL happen */ - public function testSetSecondCoordinateWithAnArray(): void + #[DataProvider('tooBigLatitudeProvider')] + public function testSetLatitudeWithBigInteger(float|int|string $latitude): void { - $point = new Point(10, 10); + $point = new GeometricPoint(10, 10); self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid coordinate value, coordinate cannot be an array.'); - $point->setY('10 20'); - } - - /** - * Test setX method. - * - * @throws InvalidValueException it should NOT happen - */ - public function testSetX(): void - { - $point = new Point(10, 10); - $point->setX('20'); - static::assertSame(20, $point->getX()); + self::expectExceptionMessage(sprintf('Out of range latitude value, latitude must be between -90 and 90, got "%s".', $latitude)); - self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid coordinate value, got "foo".'); - $point->setX('foo'); + $point->setLatitude($latitude); } /** - * Test setY method. + * Test setLongitude with out-of-range values. + * + * @param float|int|string $longitude the out-of-range value * - * @throws InvalidValueException it should NOT happen + * @throws InvalidValueException it SHALL happen */ - public function testSetY(): void + #[DataProvider('tooBigLongitudeProvider')] + public function testSetLongitudeWithBigInteger(float|int|string $longitude): void { - $point = new Point(10, 10); - $point->setY('20'); - static::assertSame(20, $point->getLatitude()); - static::assertSame(20, $point->getY()); + $point = new GeometricPoint(10, 10); self::expectException(InvalidValueException::class); - self::expectExceptionMessage('Invalid coordinate value, got "foo".'); - $point->setY('foo'); - } - - /** - * Test to convert a point to an array. - */ - public function testToArray(): void - { - $expected = [0, 0]; - $point = static::createPointOrigin(); - $result = $point->toArray(); - - static::assertSame($expected, $result); - - $expected = [-118.243, 34.0522]; - $point = static::createLosAngelesGeometry(); - $result = $point->toArray(); - - static::assertSame($expected, $result); - } - - /** - * Test bad string parameters - Two invalid parameters. - */ - public function testTwoInvalidArguments(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geometry\\Point::__construct: NULL, NULL'); - - new Point(null, null); - } - - /** - * Test bad string parameters - More than 3 parameters. - */ - public function testUnusedArguments(): void - { - $this->expectException(InvalidValueException::class); - $this->expectExceptionMessage('Invalid parameters passed to LongitudeOne\\Spatial\\PHP\\Types\\Geometry\\Point::__construct: 1, 2, 3, 4, NULL, 5'); + self::expectExceptionMessage(sprintf('Out of range longitude value, longitude must be between -180 and 180, got "%s".', $longitude)); - new Point(1, 2, 3, 4, null, 5); + $point->setLongitude($longitude); } } diff --git a/tests/LongitudeOne/Spatial/Tests/PHP/Types/InterfaceTest.php b/tests/LongitudeOne/Spatial/Tests/PHP/Types/InterfaceTest.php index 98a7ea63..363862c7 100644 --- a/tests/LongitudeOne/Spatial/Tests/PHP/Types/InterfaceTest.php +++ b/tests/LongitudeOne/Spatial/Tests/PHP/Types/InterfaceTest.php @@ -19,6 +19,8 @@ namespace LongitudeOne\Spatial\Tests\PHP\Types; use LongitudeOne\Spatial\Exception\InvalidValueException; +use LongitudeOne\Spatial\PHP\Types\CartesianInterface; +use LongitudeOne\Spatial\PHP\Types\GeodeticInterface; use LongitudeOne\Spatial\PHP\Types\Geography\GeographyInterface; use LongitudeOne\Spatial\PHP\Types\Geography\LineString as GeographyLineString; use LongitudeOne\Spatial\PHP\Types\Geography\Point as GeographyPoint; @@ -65,6 +67,8 @@ public function testGeographyLineStringInterface(): void static::assertInstanceOf(GeographyInterface::class, $lineString); static::assertInstanceOf(LineStringInterface::class, $lineString); static::assertNotInstanceOf(PointInterface::class, $lineString); + static::assertNotInstanceOf(GeodeticInterface::class, $lineString); + static::assertNotInstanceOf(CartesianInterface::class, $lineString); static::assertNotInstanceOf(PolygonInterface::class, $lineString); static::assertNotInstanceOf(MultiPointInterface::class, $lineString); static::assertNotInstanceOf(MultiLineStringInterface::class, $lineString); @@ -82,6 +86,8 @@ public function testGeographyPointInterface(): void static::assertInstanceOf(SpatialInterface::class, $point); static::assertInstanceOf(GeographyInterface::class, $point); static::assertInstanceOf(PointInterface::class, $point); + static::assertInstanceOf(GeodeticInterface::class, $point); + static::assertNotInstanceOf(CartesianInterface::class, $point); static::assertNotInstanceOf(LineStringInterface::class, $point); static::assertNotInstanceOf(PolygonInterface::class, $point); static::assertNotInstanceOf(MultiPointInterface::class, $point); @@ -122,6 +128,8 @@ public function testGeometryLineStringInterface(): void static::assertInstanceOf(SpatialInterface::class, $lineString); static::assertInstanceOf(GeometryInterface::class, $lineString); static::assertInstanceOf(LineStringInterface::class, $lineString); + static::assertNotInstanceOf(GeodeticInterface::class, $lineString); + static::assertNotInstanceOf(CartesianInterface::class, $lineString); static::assertNotInstanceOf(PointInterface::class, $lineString); static::assertNotInstanceOf(PolygonInterface::class, $lineString); static::assertNotInstanceOf(MultiPointInterface::class, $lineString); @@ -142,6 +150,8 @@ public function testGeometryPointInterface(): void static::assertInstanceOf(SpatialInterface::class, $point); static::assertInstanceOf(GeometryInterface::class, $point); static::assertInstanceOf(PointInterface::class, $point); + static::assertInstanceOf(CartesianInterface::class, $point); + static::assertNotInstanceOf(GeodeticInterface::class, $point); static::assertNotInstanceOf(LineStringInterface::class, $point); static::assertNotInstanceOf(PolygonInterface::class, $point); static::assertNotInstanceOf(MultiPointInterface::class, $point);