From 64988126f3b1a4d5450457d8f6a32d233f75ae89 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Thu, 19 Dec 2019 12:20:53 -0600 Subject: [PATCH] Use internal exceptions Fixes #254 --- CHANGELOG.md | 13 +++++ src/Codec/GuidStringCodec.php | 2 +- src/Codec/OrderedTimeCodec.php | 2 +- src/Codec/StringCodec.php | 2 +- src/Codec/TimestampFirstCombCodec.php | 2 +- src/Converter/Number/BigNumberConverter.php | 2 +- src/Converter/Number/GmpConverter.php | 2 +- src/Converter/NumberStringTrait.php | 2 +- src/Converter/Time/BigNumberTimeConverter.php | 2 +- src/Converter/Time/GmpTimeConverter.php | 2 +- src/Converter/Time/PhpTimeConverter.php | 2 +- src/DegradedUuid.php | 21 ++++++-- src/Exception/DateTimeException.php | 24 +++++++++ src/Exception/InvalidArgumentException.php | 24 +++++++++ src/Exception/InvalidUuidStringException.php | 7 +-- src/Exception/RandomSourceException.php | 27 ++++++++++ .../UnsatisfiedDependencyException.php | 6 +-- .../UnsupportedOperationException.php | 6 +-- src/Generator/CombGenerator.php | 2 +- src/Generator/DefaultTimeGenerator.php | 16 ++++-- src/Generator/RandomBytesGenerator.php | 17 ++++++- src/Provider/Node/RandomNodeProvider.php | 11 +++- src/Provider/Time/FixedTimeProvider.php | 2 +- src/Uuid.php | 17 ++++++- .../Number/BigNumberConverterTest.php | 2 +- tests/Converter/Number/GmpConverterTest.php | 2 +- .../Time/BigNumberTimeConverterTest.php | 2 +- tests/Converter/Time/GmpTimeConverterTest.php | 2 +- tests/Converter/Time/PhpTimeConverterTest.php | 2 +- tests/DegradedUuidTest.php | 51 +++++++++++++++++++ tests/Generator/CombGeneratorTest.php | 2 +- tests/Generator/DefaultTimeGeneratorTest.php | 24 +++++++++ tests/Generator/RandomBytesGeneratorTest.php | 19 +++++++ .../Provider/Node/RandomNodeProviderTest.php | 20 ++++++++ .../Provider/Node/SystemNodeProviderTest.php | 2 +- tests/UuidTest.php | 35 ++++++++++++- 36 files changed, 336 insertions(+), 40 deletions(-) create mode 100644 src/Exception/DateTimeException.php create mode 100644 src/Exception/InvalidArgumentException.php create mode 100644 src/Exception/RandomSourceException.php create mode 100644 tests/DegradedUuidTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c963333..efa05a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Allow use of the [GMP extension](https://www.php.net/gmp) for number and time conversion through the addition of `Converter\Number\GmpConverter` and `Converter\Time\GmpTimeConverter`. +* Add an internal `InvalidArgumentException` that descends from the built-in + PHP `\InvalidArgumentException`. All places that used to throw + `\InvalidArgumentException` now throw `Ramsey\Uuid\Exception\InvalidArgumentException`. + This should not cause any BC breaks, however. +* Add an internal `DateTimeException` that descends from the built-in PHP + `\RuntimeException`. `Uuid::getDateTime()` and `DegradedUuid::getDateTime()` + may throw this exception if `\DateTimeImmutable` throws an error or exception. +* Add `RandomSourceException` that descends from the built-in PHP + `\RuntimeException`. DefaultTimeGenerator, RandomBytesGenerator, and + RandomNodeProvider may throw this exception if `random_bytes()` or + `random_int()` throw an error or exception. ### Changed @@ -37,6 +48,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * `NumberConverterInterface::toHex(string $number): string` * `TimeConverterInterface::calculateTime(string $seconds, string $microSeconds): array` * `TimeConverterInterface::convertTime(string $timestamp): string` +* `UnsatisfiedDependencyException` and `UnsupportedOperationException` are now + descended from `\LogicException`. Previously, they descended from `\RuntimeException`. ### Deprecated diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index 4328a1d9..8dea903e 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -14,7 +14,7 @@ namespace Ramsey\Uuid\Codec; -use InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\UuidInterface; diff --git a/src/Codec/OrderedTimeCodec.php b/src/Codec/OrderedTimeCodec.php index d5316fea..ea26fac3 100644 --- a/src/Codec/OrderedTimeCodec.php +++ b/src/Codec/OrderedTimeCodec.php @@ -14,7 +14,7 @@ namespace Ramsey\Uuid\Codec; -use InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\UuidInterface; /** diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index 75e98fa8..2b45a723 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -14,8 +14,8 @@ namespace Ramsey\Uuid\Codec; -use InvalidArgumentException; use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; diff --git a/src/Codec/TimestampFirstCombCodec.php b/src/Codec/TimestampFirstCombCodec.php index 997146d9..13fab58d 100644 --- a/src/Codec/TimestampFirstCombCodec.php +++ b/src/Codec/TimestampFirstCombCodec.php @@ -14,7 +14,7 @@ namespace Ramsey\Uuid\Codec; -use InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\UuidInterface; diff --git a/src/Converter/Number/BigNumberConverter.php b/src/Converter/Number/BigNumberConverter.php index 419ef19c..b0491998 100644 --- a/src/Converter/Number/BigNumberConverter.php +++ b/src/Converter/Number/BigNumberConverter.php @@ -14,11 +14,11 @@ namespace Ramsey\Uuid\Converter\Number; -use InvalidArgumentException; use Moontoast\Math\BigNumber; use Ramsey\Uuid\Converter\DependencyCheckTrait; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Converter\NumberStringTrait; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; /** diff --git a/src/Converter/Number/GmpConverter.php b/src/Converter/Number/GmpConverter.php index 7c444b7b..2c95a273 100644 --- a/src/Converter/Number/GmpConverter.php +++ b/src/Converter/Number/GmpConverter.php @@ -14,10 +14,10 @@ namespace Ramsey\Uuid\Converter\Number; -use InvalidArgumentException; use Ramsey\Uuid\Converter\DependencyCheckTrait; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Converter\NumberStringTrait; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; /** diff --git a/src/Converter/NumberStringTrait.php b/src/Converter/NumberStringTrait.php index bc8c56cc..faf92178 100644 --- a/src/Converter/NumberStringTrait.php +++ b/src/Converter/NumberStringTrait.php @@ -14,7 +14,7 @@ namespace Ramsey\Uuid\Converter; -use InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidArgumentException; /** * Provides shared functionality to check the values of string numbers for diff --git a/src/Converter/Time/BigNumberTimeConverter.php b/src/Converter/Time/BigNumberTimeConverter.php index dfc7c269..9b153ee8 100644 --- a/src/Converter/Time/BigNumberTimeConverter.php +++ b/src/Converter/Time/BigNumberTimeConverter.php @@ -14,11 +14,11 @@ namespace Ramsey\Uuid\Converter\Time; -use InvalidArgumentException; use Moontoast\Math\BigNumber; use Ramsey\Uuid\Converter\DependencyCheckTrait; use Ramsey\Uuid\Converter\NumberStringTrait; use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; /** diff --git a/src/Converter/Time/GmpTimeConverter.php b/src/Converter/Time/GmpTimeConverter.php index b5fbe109..1224c0aa 100644 --- a/src/Converter/Time/GmpTimeConverter.php +++ b/src/Converter/Time/GmpTimeConverter.php @@ -14,10 +14,10 @@ namespace Ramsey\Uuid\Converter\Time; -use InvalidArgumentException; use Ramsey\Uuid\Converter\DependencyCheckTrait; use Ramsey\Uuid\Converter\NumberStringTrait; use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; /** diff --git a/src/Converter/Time/PhpTimeConverter.php b/src/Converter/Time/PhpTimeConverter.php index 7f621a34..4b7bfb49 100644 --- a/src/Converter/Time/PhpTimeConverter.php +++ b/src/Converter/Time/PhpTimeConverter.php @@ -14,10 +14,10 @@ namespace Ramsey\Uuid\Converter\Time; -use InvalidArgumentException; use Ramsey\Uuid\Converter\DependencyCheckTrait; use Ramsey\Uuid\Converter\NumberStringTrait; use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; /** diff --git a/src/DegradedUuid.php b/src/DegradedUuid.php index 5810f360..4a66431f 100644 --- a/src/DegradedUuid.php +++ b/src/DegradedUuid.php @@ -16,6 +16,7 @@ use DateTimeImmutable; use DateTimeInterface; +use Ramsey\Uuid\Exception\DateTimeException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Exception\UnsupportedOperationException; @@ -31,6 +32,8 @@ class DegradedUuid extends Uuid /** * @return DateTimeImmutable An immutable instance of DateTimeInterface * + * @throws DateTimeException if DateTime throws an exception/error + * @throws UnsatisfiedDependencyException if large integer support is not available * @throws UnsupportedOperationException if UUID is not time-based */ public function getDateTime(): DateTimeInterface @@ -42,11 +45,19 @@ public function getDateTime(): DateTimeInterface $time = $this->numberConverter->fromHex($this->getTimestampHex()); $unixTime = $this->timeConverter->convertTime($time); - return new DateTimeImmutable("@{$unixTime}"); + try { + return new DateTimeImmutable("@{$unixTime}"); + } catch (\Throwable $exception) { + throw new DateTimeException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } } /** - * @throws UnsatisfiedDependencyException if called on a 32-bit system + * @throws UnsatisfiedDependencyException if large integer support is not available * * @inheritDoc */ @@ -60,7 +71,7 @@ public function getFields(): array } /** - * @throws UnsatisfiedDependencyException if called on a 32-bit system + * @throws UnsatisfiedDependencyException if large integer support is not available */ public function getNode(): int { @@ -73,7 +84,7 @@ public function getNode(): int } /** - * @throws UnsatisfiedDependencyException if called on a 32-bit system + * @throws UnsatisfiedDependencyException if large integer support is not available */ public function getTimeLow(): int { @@ -86,7 +97,7 @@ public function getTimeLow(): int } /** - * @throws UnsatisfiedDependencyException if called on a 32-bit system + * @throws UnsatisfiedDependencyException if large integer support is not available * @throws UnsupportedOperationException if UUID is not time-based */ public function getTimestamp(): int diff --git a/src/Exception/DateTimeException.php b/src/Exception/DateTimeException.php new file mode 100644 index 00000000..dbc48404 --- /dev/null +++ b/src/Exception/DateTimeException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Exception; + +use RuntimeException as PhpRuntimeException; + +/** + * Thrown to indicate that the PHP DateTime extension encountered an exception/error + */ +class DateTimeException extends PhpRuntimeException +{ +} diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php new file mode 100644 index 00000000..08bbb802 --- /dev/null +++ b/src/Exception/InvalidArgumentException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Exception; + +use InvalidArgumentException as PhpInvalidArgumentException; + +/** + * Thrown to indicate that the argument received is not valid + */ +class InvalidArgumentException extends PhpInvalidArgumentException +{ +} diff --git a/src/Exception/InvalidUuidStringException.php b/src/Exception/InvalidUuidStringException.php index 2f981818..24f42c64 100644 --- a/src/Exception/InvalidUuidStringException.php +++ b/src/Exception/InvalidUuidStringException.php @@ -14,10 +14,11 @@ namespace Ramsey\Uuid\Exception; -use InvalidArgumentException; - /** - * Thrown to indicate that the parsed UUID string is invalid. + * Thrown to indicate that the string received is not a valid UUID + * + * The InvalidArgumentException that this extends is the ramsey/uuid version + * of this exception. It exists in the same namespace as this class. */ class InvalidUuidStringException extends InvalidArgumentException { diff --git a/src/Exception/RandomSourceException.php b/src/Exception/RandomSourceException.php new file mode 100644 index 00000000..0c3e4f52 --- /dev/null +++ b/src/Exception/RandomSourceException.php @@ -0,0 +1,27 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Exception; + +use RuntimeException as PhpRuntimeException; + +/** + * Thrown to indicate that the source of random data encountered an error + * + * This exception is used mostly to indicate that random_bytes() or random_int() + * threw an exception. However, it may be used for other sources of random data. + */ +class RandomSourceException extends PhpRuntimeException +{ +} diff --git a/src/Exception/UnsatisfiedDependencyException.php b/src/Exception/UnsatisfiedDependencyException.php index 7a3657da..4ac49584 100644 --- a/src/Exception/UnsatisfiedDependencyException.php +++ b/src/Exception/UnsatisfiedDependencyException.php @@ -14,12 +14,12 @@ namespace Ramsey\Uuid\Exception; -use RuntimeException; +use LogicException as PhpLogicException; /** * Thrown to indicate that the requested operation has dependencies that have not - * been satisfied. + * been satisfied */ -class UnsatisfiedDependencyException extends RuntimeException +class UnsatisfiedDependencyException extends PhpLogicException { } diff --git a/src/Exception/UnsupportedOperationException.php b/src/Exception/UnsupportedOperationException.php index 09ed1c5d..e6391b03 100644 --- a/src/Exception/UnsupportedOperationException.php +++ b/src/Exception/UnsupportedOperationException.php @@ -14,11 +14,11 @@ namespace Ramsey\Uuid\Exception; -use RuntimeException; +use LogicException as PhpLogicException; /** - * Thrown to indicate that the requested operation is not supported. + * Thrown to indicate that the requested operation is not supported */ -class UnsupportedOperationException extends RuntimeException +class UnsupportedOperationException extends PhpLogicException { } diff --git a/src/Generator/CombGenerator.php b/src/Generator/CombGenerator.php index 303f2a57..cd94503c 100644 --- a/src/Generator/CombGenerator.php +++ b/src/Generator/CombGenerator.php @@ -14,8 +14,8 @@ namespace Ramsey\Uuid\Generator; -use InvalidArgumentException; use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; /** * CombGenerator generates COMBs (combined UUID/timestamp) diff --git a/src/Generator/DefaultTimeGenerator.php b/src/Generator/DefaultTimeGenerator.php index c7e36b69..f8e1bc00 100644 --- a/src/Generator/DefaultTimeGenerator.php +++ b/src/Generator/DefaultTimeGenerator.php @@ -14,9 +14,10 @@ namespace Ramsey\Uuid\Generator; -use InvalidArgumentException; use Ramsey\Uuid\BinaryUtils; use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Exception\RandomSourceException; use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Provider\TimeProviderInterface; @@ -53,6 +54,7 @@ public function __construct( /** * @throws InvalidArgumentException if the parameters contain invalid values + * @throws RandomSourceException if random_int() throws an exception/error * * @inheritDoc */ @@ -61,8 +63,16 @@ public function generate($node = null, ?int $clockSeq = null): string $node = $this->getValidNode($node); if ($clockSeq === null) { - // This does not use "stable storage"; see RFC 4122, Section 4.2.1.1. - $clockSeq = random_int(0, 0x3fff); + try { + // This does not use "stable storage"; see RFC 4122, Section 4.2.1.1. + $clockSeq = random_int(0, 0x3fff); + } catch (\Throwable $exception) { + throw new RandomSourceException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } } // Create a 60-bit time value as a count of 100-nanosecond intervals diff --git a/src/Generator/RandomBytesGenerator.php b/src/Generator/RandomBytesGenerator.php index 23cf0428..888199a5 100644 --- a/src/Generator/RandomBytesGenerator.php +++ b/src/Generator/RandomBytesGenerator.php @@ -14,6 +14,8 @@ namespace Ramsey\Uuid\Generator; +use Ramsey\Uuid\Exception\RandomSourceException; + /** * RandomBytesGenerator generates strings of random binary data using the * built-in `random_bytes()` PHP function @@ -22,8 +24,21 @@ */ class RandomBytesGenerator implements RandomGeneratorInterface { + /** + * @throws RandomSourceException if random_bytes() throws an exception/error + * + * @inheritDoc + */ public function generate(int $length): string { - return random_bytes($length); + try { + return random_bytes($length); + } catch (\Throwable $exception) { + throw new RandomSourceException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } } } diff --git a/src/Provider/Node/RandomNodeProvider.php b/src/Provider/Node/RandomNodeProvider.php index 830113c2..309f1fdf 100644 --- a/src/Provider/Node/RandomNodeProvider.php +++ b/src/Provider/Node/RandomNodeProvider.php @@ -14,6 +14,7 @@ namespace Ramsey\Uuid\Provider\Node; +use Ramsey\Uuid\Exception\RandomSourceException; use Ramsey\Uuid\Provider\NodeProviderInterface; /** @@ -28,7 +29,15 @@ class RandomNodeProvider implements NodeProviderInterface */ public function getNode() { - $nodeBytes = random_bytes(6); + try { + $nodeBytes = random_bytes(6); + } catch (\Throwable $exception) { + throw new RandomSourceException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } // Split the node bytes for math on 32-bit systems. $nodeMsb = substr($nodeBytes, 0, 3); diff --git a/src/Provider/Time/FixedTimeProvider.php b/src/Provider/Time/FixedTimeProvider.php index b9e24e40..81369317 100644 --- a/src/Provider/Time/FixedTimeProvider.php +++ b/src/Provider/Time/FixedTimeProvider.php @@ -14,7 +14,7 @@ namespace Ramsey\Uuid\Provider\Time; -use InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Provider\TimeProviderInterface; /** diff --git a/src/Uuid.php b/src/Uuid.php index 9c4a0840..db31f426 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -19,6 +19,7 @@ use Ramsey\Uuid\Codec\CodecInterface; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\DateTimeException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Exception\UnsupportedOperationException; @@ -346,6 +347,7 @@ public function getNumberConverter(): NumberConverterInterface * @return DateTimeImmutable An immutable instance of DateTimeInterface * * @throws UnsupportedOperationException if UUID is not time-based + * @throws DateTimeException if DateTime throws an exception/error */ public function getDateTime(): DateTimeInterface { @@ -355,7 +357,15 @@ public function getDateTime(): DateTimeInterface $unixTime = $this->timeConverter->convertTime((string) $this->getTimestamp()); - return new DateTimeImmutable("@{$unixTime}"); + try { + return new DateTimeImmutable("@{$unixTime}"); + } catch (\Throwable $exception) { + throw new DateTimeException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); + } } /** @@ -403,6 +413,8 @@ public function getHex(): string } /** + * @throws UnsatisfiedDependencyException if large integer support is not available + * * @inheritDoc */ public function getInteger() @@ -478,6 +490,8 @@ public function getMostSignificantBitsHex(): string * @link http://tools.ietf.org/html/rfc4122#section-4.1.6 RFC 4122, § 4.1.6: Node * * @return int Unsigned 48-bit integer value of node + * + * @throws UnsatisfiedDependencyException if large integer support is not available */ public function getNode(): int { @@ -541,6 +555,7 @@ public function getTimeMidHex(): string * * @link http://tools.ietf.org/html/rfc4122#section-4.1.4 RFC 4122, § 4.1.4: Timestamp * + * @throws UnsatisfiedDependencyException if large integer support is not available * @throws UnsupportedOperationException if UUID is not time-based */ public function getTimestamp(): int diff --git a/tests/Converter/Number/BigNumberConverterTest.php b/tests/Converter/Number/BigNumberConverterTest.php index 877df985..f96a56af 100644 --- a/tests/Converter/Number/BigNumberConverterTest.php +++ b/tests/Converter/Number/BigNumberConverterTest.php @@ -5,8 +5,8 @@ namespace Ramsey\Uuid\Test\Converter\Number; use AspectMock\Test as AspectMock; -use InvalidArgumentException; use Ramsey\Uuid\Converter\Number\BigNumberConverter; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/Converter/Number/GmpConverterTest.php b/tests/Converter/Number/GmpConverterTest.php index 22bf9c8b..bcc4f541 100644 --- a/tests/Converter/Number/GmpConverterTest.php +++ b/tests/Converter/Number/GmpConverterTest.php @@ -5,8 +5,8 @@ namespace Ramsey\Uuid\Test\Converter\Number; use AspectMock\Test as AspectMock; -use InvalidArgumentException; use Ramsey\Uuid\Converter\Number\GmpConverter; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/Converter/Time/BigNumberTimeConverterTest.php b/tests/Converter/Time/BigNumberTimeConverterTest.php index 6a2032a9..356c05db 100644 --- a/tests/Converter/Time/BigNumberTimeConverterTest.php +++ b/tests/Converter/Time/BigNumberTimeConverterTest.php @@ -5,8 +5,8 @@ namespace Ramsey\Uuid\Test\Converter\Time; use AspectMock\Test as AspectMock; -use InvalidArgumentException; use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/Converter/Time/GmpTimeConverterTest.php b/tests/Converter/Time/GmpTimeConverterTest.php index 3edeb98a..f449ab2f 100644 --- a/tests/Converter/Time/GmpTimeConverterTest.php +++ b/tests/Converter/Time/GmpTimeConverterTest.php @@ -5,8 +5,8 @@ namespace Ramsey\Uuid\Test\Converter\Time; use AspectMock\Test as AspectMock; -use InvalidArgumentException; use Ramsey\Uuid\Converter\Time\GmpTimeConverter; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/Converter/Time/PhpTimeConverterTest.php b/tests/Converter/Time/PhpTimeConverterTest.php index c30c6547..f6a9f996 100644 --- a/tests/Converter/Time/PhpTimeConverterTest.php +++ b/tests/Converter/Time/PhpTimeConverterTest.php @@ -4,9 +4,9 @@ namespace Ramsey\Uuid\Test\Converter\Time; -use InvalidArgumentException; use Mockery; use Ramsey\Uuid\Converter\Time\PhpTimeConverter; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/DegradedUuidTest.php b/tests/DegradedUuidTest.php new file mode 100644 index 00000000..86301c11 --- /dev/null +++ b/tests/DegradedUuidTest.php @@ -0,0 +1,51 @@ +shouldReceive('fromHex') + ->once() + ->andReturn('aFromHexValue'); + + $timeConverter = Mockery::mock(TimeConverterInterface::class); + $timeConverter + ->shouldReceive('convertTime') + ->once() + ->with('aFromHexValue') + ->andReturn('foobar'); + + $builder = new DegradedUuidBuilder($numberConverter, $timeConverter); + $codec = new StringCodec($builder); + + $factory = new UuidFactory(); + $factory->setCodec($codec); + + $uuid = $factory->fromString('b1484596-25dc-11ea-978f-2e728ce88125'); + + $this->assertInstanceOf(DegradedUuid::class, $uuid); + + $this->expectException(DateTimeException::class); + $this->expectExceptionMessage( + 'DateTimeImmutable::__construct(): Failed to parse time string ' + . '(@foobar) at position 0 (@): Unexpected character' + ); + + $uuid->getDateTime(); + } +} diff --git a/tests/Generator/CombGeneratorTest.php b/tests/Generator/CombGeneratorTest.php index c21f8a0c..2f9655c3 100644 --- a/tests/Generator/CombGeneratorTest.php +++ b/tests/Generator/CombGeneratorTest.php @@ -5,10 +5,10 @@ namespace Ramsey\Uuid\Test\Generator; use Exception; -use InvalidArgumentException; use PHPUnit\Framework\Error\Error as PHPUnitError; use PHPUnit\Framework\MockObject\MockObject; use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Generator\CombGenerator; use Ramsey\Uuid\Generator\RandomGeneratorInterface; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/Generator/DefaultTimeGeneratorTest.php b/tests/Generator/DefaultTimeGeneratorTest.php index e3e90a0e..f283c0d2 100644 --- a/tests/Generator/DefaultTimeGeneratorTest.php +++ b/tests/Generator/DefaultTimeGeneratorTest.php @@ -5,10 +5,12 @@ namespace Ramsey\Uuid\Test\Generator; use AspectMock\Test as AspectMock; +use Exception; use Mockery; use PHPUnit\Framework\MockObject\MockObject; use Ramsey\Uuid\BinaryUtils; use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\RandomSourceException; use Ramsey\Uuid\Generator\DefaultTimeGenerator; use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Provider\TimeProviderInterface; @@ -217,4 +219,26 @@ public function testGenerateUsesRandomSequenceWhenClockSeqNull(): void $defaultTimeGenerator->generate($this->nodeId); $randomInt->verifyInvokedOnce([0, 0x3fff]); } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testGenerateThrowsExceptionWhenExceptionThrownByRandomint(): void + { + AspectMock::func('Ramsey\Uuid\Generator', 'random_int', function (): void { + throw new Exception('Could not gather sufficient random data'); + }); + + $defaultTimeGenerator = new DefaultTimeGenerator( + $this->nodeProvider, + $this->timeConverter, + $this->timeProvider + ); + + $this->expectException(RandomSourceException::class); + $this->expectExceptionMessage('Could not gather sufficient random data'); + + $defaultTimeGenerator->generate($this->nodeId); + } } diff --git a/tests/Generator/RandomBytesGeneratorTest.php b/tests/Generator/RandomBytesGeneratorTest.php index c1f48755..32b6d8b9 100644 --- a/tests/Generator/RandomBytesGeneratorTest.php +++ b/tests/Generator/RandomBytesGeneratorTest.php @@ -6,6 +6,7 @@ use AspectMock\Test as AspectMock; use Exception; +use Ramsey\Uuid\Exception\RandomSourceException; use Ramsey\Uuid\Generator\RandomBytesGenerator; use Ramsey\Uuid\Test\TestCase; @@ -54,4 +55,22 @@ public function testGenerateReturnsRandomBytes(int $length, string $hex): void $generator = new RandomBytesGenerator(); $this->assertEquals($bytes, $generator->generate($length)); } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testGenerateThrowsExceptionWhenExceptionThrownByRandombytes(): void + { + AspectMock::func('Ramsey\Uuid\Generator', 'random_bytes', function (): void { + throw new Exception('Could not gather sufficient random data'); + }); + + $generator = new RandomBytesGenerator(); + + $this->expectException(RandomSourceException::class); + $this->expectExceptionMessage('Could not gather sufficient random data'); + + $generator->generate(16); + } } diff --git a/tests/Provider/Node/RandomNodeProviderTest.php b/tests/Provider/Node/RandomNodeProviderTest.php index 9aa1b08d..5d02785c 100644 --- a/tests/Provider/Node/RandomNodeProviderTest.php +++ b/tests/Provider/Node/RandomNodeProviderTest.php @@ -5,6 +5,8 @@ namespace Ramsey\Uuid\Test\Provider\Node; use AspectMock\Test as AspectMock; +use Exception; +use Ramsey\Uuid\Exception\RandomSourceException; use Ramsey\Uuid\Provider\Node\RandomNodeProvider; use Ramsey\Uuid\Test\TestCase; @@ -110,4 +112,22 @@ public function testGetNodeAlwaysSetsMulticastBit(): void $this->assertSame('010000000000', $node); } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testGetNodeThrowsExceptionWhenExceptionThrownByRandombytes(): void + { + AspectMock::func('Ramsey\Uuid\Provider\Node', 'random_bytes', function (): void { + throw new Exception('Could not gather sufficient random data'); + }); + + $provider = new RandomNodeProvider(); + + $this->expectException(RandomSourceException::class); + $this->expectExceptionMessage('Could not gather sufficient random data'); + + $provider->getNode(); + } } diff --git a/tests/Provider/Node/SystemNodeProviderTest.php b/tests/Provider/Node/SystemNodeProviderTest.php index 80e085cd..0fb52496 100644 --- a/tests/Provider/Node/SystemNodeProviderTest.php +++ b/tests/Provider/Node/SystemNodeProviderTest.php @@ -6,7 +6,7 @@ use AspectMock\Proxy\FuncProxy; use AspectMock\Test as AspectMock; -use InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Provider\Node\SystemNodeProvider; use Ramsey\Uuid\Test\TestCase; diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 5bbc4819..6f25a80b 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -5,12 +5,18 @@ namespace Ramsey\Uuid\Test; use DateTimeInterface; -use InvalidArgumentException; +use Mockery; use PHPUnit\Framework\MockObject\MockObject; +use Ramsey\Uuid\Builder\DefaultUuidBuilder; +use Ramsey\Uuid\Codec\StringCodec; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; use Ramsey\Uuid\Codec\TimestampLastCombCodec; use Ramsey\Uuid\Converter\Number\DegradedNumberConverter; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; use Ramsey\Uuid\DegradedUuid; +use Ramsey\Uuid\Exception\DateTimeException; +use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Exception\UnsupportedOperationException; @@ -2111,4 +2117,31 @@ public function testUuidVersionConstantForVersion5(): void $uuid = Uuid::fromString('886313e1-3b8a-5372-9b90-0c9aee199e5d'); $this->assertEquals($uuid->getVersion(), Uuid::UUID_TYPE_HASH_SHA1); } + + public function testGetDateTimeThrowsExceptionWhenDateTimeCannotParseString(): void + { + $numberConverter = Mockery::mock(NumberConverterInterface::class); + $timeConverter = Mockery::mock(TimeConverterInterface::class); + + $timeConverter + ->shouldReceive('convertTime') + ->once() + ->andReturn('foobar'); + + $builder = new DefaultUuidBuilder($numberConverter, $timeConverter); + $codec = new StringCodec($builder); + + $factory = new UuidFactory(); + $factory->setCodec($codec); + + $uuid = $factory->fromString('b1484596-25dc-11ea-978f-2e728ce88125'); + + $this->expectException(DateTimeException::class); + $this->expectExceptionMessage( + 'DateTimeImmutable::__construct(): Failed to parse time string ' + . '(@foobar) at position 0 (@): Unexpected character' + ); + + $uuid->getDateTime(); + } }