From 02e1b7e49c1c4cb2bfe2007e41c14e997f3ddcf4 Mon Sep 17 00:00:00 2001 From: Alexandre Tranchant Date: Wed, 22 May 2024 21:05:09 +0200 Subject: [PATCH] #20 Range exception enhancement done --- .../Geo/String/Exception/RangeException.php | 27 +++++++++++++++++++ lib/LongitudeOne/Geo/String/Parser.php | 26 +++++++----------- .../Geo/String/Tests/ParserTest.php | 9 ++++--- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/LongitudeOne/Geo/String/Exception/RangeException.php b/lib/LongitudeOne/Geo/String/Exception/RangeException.php index 2292779..86516c4 100644 --- a/lib/LongitudeOne/Geo/String/Exception/RangeException.php +++ b/lib/LongitudeOne/Geo/String/Exception/RangeException.php @@ -17,4 +17,31 @@ */ class RangeException extends \RangeException implements ExceptionInterface { + public const DEFAULT_MESSAGE = 'Unknown range exception'; + public const LATITUDE_MESSAGE = 'Latitude must be between -90 and 90'; + public const LATITUDE_OUT_OF_RANGE = 90; + public const LONGITUDE_MESSAGE = 'Longitude must be between -180 and 180'; + public const LONGITUDE_OUT_OF_RANGE = 180; + public const MINUTES_MESSAGE = 'Minutes must be between 0 and 59'; + public const MINUTES_OUT_OF_RANGE = 3600; + public const SECONDS_MESSAGE = 'Seconds must be between 0 and 59'; + public const SECONDS_OUT_OF_RANGE = 60; + + public function __construct(string $value, int $code, ?\Throwable $previous = null) + { + $message = sprintf('[RangeException] %s, got "%s".', $this->setMessage($code), $value); + + parent::__construct($message, $code, $previous); + } + + private function setMessage(int $code): string + { + return match ($code) { + self::LATITUDE_OUT_OF_RANGE => self::LATITUDE_MESSAGE, + self::LONGITUDE_OUT_OF_RANGE => self::LONGITUDE_MESSAGE, + self::SECONDS_OUT_OF_RANGE => self::SECONDS_MESSAGE, + self::MINUTES_OUT_OF_RANGE => self::MINUTES_MESSAGE, + default => self::DEFAULT_MESSAGE, + }; + } } diff --git a/lib/LongitudeOne/Geo/String/Parser.php b/lib/LongitudeOne/Geo/String/Parser.php index 1f87438..bfb38fa 100644 --- a/lib/LongitudeOne/Geo/String/Parser.php +++ b/lib/LongitudeOne/Geo/String/Parser.php @@ -127,7 +127,12 @@ private function cardinal(int|float $value): int|float // Throw exception if value is out of range if ($value > $range) { - throw $this->rangeError('Degrees', $range, -1 * $range); + $code = RangeException::LATITUDE_OUT_OF_RANGE; + if (180 === $range) { + $code = RangeException::LONGITUDE_OUT_OF_RANGE; + } + + throw new RangeException($this->input, $code); } // Return value with sign @@ -248,7 +253,7 @@ private function minutes(): string|int // Throw exception if minutes are greater than 60 if ($readMinutes > 60) { - throw $this->rangeError('Minutes', 60); + throw new RangeException($this->input, RangeException::MINUTES_OUT_OF_RANGE); } // Get fractional minutes @@ -266,13 +271,13 @@ private function minutes(): string|int return (string) ((float) $minutes + (float) $this->seconds()); } - // If minutes is a float there will be no seconds + // If minutes is a float, there will be no seconds if ($this->lexer->isNextToken(Lexer::T_FLOAT)) { $minutes = $this->match(Lexer::T_FLOAT); // Throw exception if minutes are greater than 60 if ($minutes > 60) { - throw $this->rangeError('Minutes', 60); + throw new RangeException($this->input, RangeException::MINUTES_OUT_OF_RANGE); } // Get fractional minutes @@ -344,17 +349,6 @@ private function point(): float|int|array return [$x, $y]; } - /** - * Create out of range exception. - */ - private function rangeError(string $type, int $high, ?int $low = null): RangeException - { - $range = null === $low ? sprintf('greater than %d', $high) : sprintf('out of range %d to %d', $low, $high); - $message = sprintf('[Range Error] Error: %s %s in value "%s"', $type, $range, $this->input); - - return new RangeException($message); - } - /** * Match and return seconds value. * @@ -368,7 +362,7 @@ private function seconds(): int|string // Throw exception if seconds are greater than 60 if ($seconds > 60) { - throw $this->rangeError('Seconds', 60); + throw new RangeException($this->input, RangeException::SECONDS_OUT_OF_RANGE); } // Get fractional seconds diff --git a/tests/LongitudeOne/Geo/String/Tests/ParserTest.php b/tests/LongitudeOne/Geo/String/Tests/ParserTest.php index 5054c12..e94fec1 100644 --- a/tests/LongitudeOne/Geo/String/Tests/ParserTest.php +++ b/tests/LongitudeOne/Geo/String/Tests/ParserTest.php @@ -52,10 +52,11 @@ public static function dataSourceBad(): \Generator yield ['55:34:22°', UnexpectedValueException::class, '[Syntax Error] line 0, col 8: Error: Expected LongitudeOne\Geo\String\Lexer::T_INTEGER or LongitudeOne\Geo\String\Lexer::T_FLOAT, got "°" in value "55:34:22°"']; yield ['55:34.22', UnexpectedValueException::class, '[Syntax Error] line 0, col 3: Error: Expected LongitudeOne\Geo\String\Lexer::T_INTEGER, got "34.22" in value "55:34.22"']; yield ['55#34.22', UnexpectedValueException::class, '[Syntax Error] line 0, col 2: Error: Expected LongitudeOne\Geo\String\Lexer::T_INTEGER or LongitudeOne\Geo\String\Lexer::T_FLOAT, got "#" in value "55#34.22"']; - yield ['200N', RangeException::class, '[Range Error] Error: Degrees out of range -90 to 90 in value "200N"']; - yield ['55:200:32', RangeException::class, '[Range Error] Error: Minutes greater than 60 in value "55:200:32"']; - yield ['55:20:99', RangeException::class, '[Range Error] Error: Seconds greater than 60 in value "55:20:99"']; - yield ['55°70.99\'', RangeException::class, '[Range Error] Error: Minutes greater than 60 in value "55°70.99\'"']; + yield ['100N', RangeException::class, '[RangeException] Latitude must be between -90 and 90, got "100N".']; + yield ['190W', RangeException::class, '[RangeException] Longitude must be between -180 and 180, got "190W".']; + yield ['55:200:32', RangeException::class, '[RangeException] Minutes must be between 0 and 59, got "55:200:32".']; + yield ['55:20:99', RangeException::class, '[RangeException] Seconds must be between 0 and 59, got "55:20:99".']; + yield ['55°70.99\'', RangeException::class, '[RangeException] Minutes must be between 0 and 59, got "55°70.99\'".']; } /**