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);