Use strict argument validation for collections

This resolves #106
This commit is contained in:
Ben Ramsey
2020-02-23 00:50:00 -06:00
parent a8f1692b7f
commit aaccc850a1
13 changed files with 111 additions and 87 deletions
+9
View File
@@ -10,8 +10,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
* Introduce `Builder\BuilderCollection` and `Provider\Node\NodeProviderCollection`.
### Changed
* `Builder\FallbackBuilder` now accepts only a `Builder\BuilderCollection` as
its constructor parameter.
* `Provider\Node\FallbackNodeProvider` now accepts only a `Provider\Node\NodeProviderCollection`
as its constructor parameter.
* `Provider\Time\FixedTimeProvider` no longer accepts an array but accepts only
`Type\Time` instances.
### Deprecated
### Removed
+1
View File
@@ -13,6 +13,7 @@
"php": "^7.2 | ^8",
"ext-json": "*",
"brick/math": "^0.8",
"ramsey/collection": "^1.0",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
+40
View File
@@ -0,0 +1,40 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Builder;
use Ramsey\Collection\AbstractCollection;
use Ramsey\Collection\CollectionInterface;
use Traversable;
/**
* A collection of UuidBuilderInterface objects
*/
class BuilderCollection extends AbstractCollection implements CollectionInterface
{
public function getType(): string
{
return UuidBuilderInterface::class;
}
/**
* @psalm-mutation-free
* @psalm-suppress ImpureMethodCall
* @psalm-suppress InvalidTemplateParam
*/
public function getIterator(): Traversable
{
return parent::getIterator();
}
}
+5 -4
View File
@@ -28,14 +28,14 @@ use Ramsey\Uuid\UuidInterface;
class FallbackBuilder implements UuidBuilderInterface
{
/**
* @var UuidBuilderInterface[]
* @var BuilderCollection
*/
private $builders = [];
private $builders;
/**
* @param UuidBuilderInterface[] $builders An array of UUID builders
* @param BuilderCollection $builders An array of UUID builders
*/
public function __construct(array $builders)
public function __construct(BuilderCollection $builders)
{
$this->builders = $builders;
}
@@ -53,6 +53,7 @@ class FallbackBuilder implements UuidBuilderInterface
{
$lastBuilderException = null;
/** @var UuidBuilderInterface $builder */
foreach ($this->builders as $builder) {
try {
return $builder->build($codec, $bytes);
+6 -4
View File
@@ -14,6 +14,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid;
use Ramsey\Uuid\Builder\BuilderCollection;
use Ramsey\Uuid\Builder\FallbackBuilder;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
@@ -42,6 +43,7 @@ use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Provider\Dce\SystemDceSecurityProvider;
use Ramsey\Uuid\Provider\DceSecurityProviderInterface;
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
use Ramsey\Uuid\Provider\Node\NodeProviderCollection;
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
use Ramsey\Uuid\Provider\Node\SystemNodeProvider;
use Ramsey\Uuid\Provider\NodeProviderInterface;
@@ -328,10 +330,10 @@ class FeatureSet
return new RandomNodeProvider();
}
return new FallbackNodeProvider([
return new FallbackNodeProvider(new NodeProviderCollection([
new SystemNodeProvider(),
new RandomNodeProvider(),
]);
]));
}
/**
@@ -410,10 +412,10 @@ class FeatureSet
return new GuidBuilder($this->numberConverter, $this->timeConverter);
}
return new FallbackBuilder([
return new FallbackBuilder(new BuilderCollection([
new Rfc4122UuidBuilder($this->numberConverter, $this->timeConverter),
new NonstandardUuidBuilder($this->numberConverter, $this->timeConverter),
]);
]));
}
/**
+4 -3
View File
@@ -23,14 +23,14 @@ use Ramsey\Uuid\Provider\NodeProviderInterface;
class FallbackNodeProvider implements NodeProviderInterface
{
/**
* @var NodeProviderInterface[]
* @var NodeProviderCollection
*/
private $nodeProviders;
/**
* @param NodeProviderInterface[] $providers Array of node providers
* @param NodeProviderCollection $providers Array of node providers
*/
public function __construct(array $providers)
public function __construct(NodeProviderCollection $providers)
{
$this->nodeProviders = $providers;
}
@@ -40,6 +40,7 @@ class FallbackNodeProvider implements NodeProviderInterface
*/
public function getNode()
{
/** @var NodeProviderInterface $provider */
foreach ($this->nodeProviders as $provider) {
if ($node = $provider->getNode()) {
return $node;
@@ -0,0 +1,30 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Node;
use Ramsey\Collection\AbstractCollection;
use Ramsey\Collection\CollectionInterface;
use Ramsey\Uuid\Provider\NodeProviderInterface;
/**
* A collection of NodeProviderInterface objects
*/
class NodeProviderCollection extends AbstractCollection implements CollectionInterface
{
public function getType(): string
{
return NodeProviderInterface::class;
}
}
+4 -1
View File
@@ -33,7 +33,10 @@ use const STR_PAD_LEFT;
*/
class RandomNodeProvider implements NodeProviderInterface
{
public function getNode(): string
/**
* @inheritDoc
*/
public function getNode()
{
try {
$nodeBytes = random_bytes(6);
+4 -34
View File
@@ -14,12 +14,10 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Time;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\Time;
use function array_key_exists;
/**
* FixedTimeProvider uses an known time to provide the time
*
@@ -33,26 +31,15 @@ class FixedTimeProvider implements TimeProviderInterface
*/
private $fixedTime;
/**
* @param int[]|string[]|Time $time An array containing 'sec' and
* 'usec' keys or a Time object
*
* @throws InvalidArgumentException if the `$time` does not contain
* `sec` or `usec` components
*/
public function __construct($time)
public function __construct(Time $time)
{
if (!$time instanceof Time) {
$time = $this->convertToTime($time);
}
$this->fixedTime = $time;
}
/**
* Sets the `usec` component of the time
*
* @param int|string|Time $value The `usec` value to set
* @param int|string|IntegerObject $value The `usec` value to set
*/
public function setUsec($value): void
{
@@ -62,7 +49,7 @@ class FixedTimeProvider implements TimeProviderInterface
/**
* Sets the `sec` component of the time
*
* @param int|string|Time $value The `sec` value to set
* @param int|string|IntegerObject $value The `sec` value to set
*/
public function setSec($value): void
{
@@ -86,21 +73,4 @@ class FixedTimeProvider implements TimeProviderInterface
{
return $this->fixedTime;
}
/**
* @param int[]|string[] $time
*
* @return Time A time created from the provided array
*
* @throws InvalidArgumentException if the `$time` does not contain
* `sec` or `usec` components
*/
private function convertToTime(array $time): Time
{
if (!array_key_exists('sec', $time) || !array_key_exists('usec', $time)) {
throw new InvalidArgumentException('Array must contain sec and usec keys.');
}
return new Time($time['sec'], $time['usec']);
}
}
-9
View File
@@ -21,15 +21,6 @@ use Ramsey\Uuid\Type\Time;
*/
interface TimeProviderInterface
{
/**
* Returns a timestamp array
*
* @deprecated Transition to {@see TimeProviderInterface::getTime()}.
*
* @return int[]|string[] Array containing `sec` and `usec` components of a timestamp
*/
public function currentTime(): array;
/**
* Returns a time object
*/
+2 -1
View File
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test\Builder;
use Mockery;
use Ramsey\Uuid\Builder\BuilderCollection;
use Ramsey\Uuid\Builder\FallbackBuilder;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
@@ -40,7 +41,7 @@ class FallbackBuilderTest extends TestCase
->with($codec, $bytes)
->andThrow(UnableToBuildUuidException::class);
$fallbackBuilder = new FallbackBuilder([$builder1, $builder2, $builder3]);
$fallbackBuilder = new FallbackBuilder(new BuilderCollection([$builder1, $builder2, $builder3]));
$this->expectException(BuilderNotFoundException::class);
$this->expectExceptionMessage(
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test\Provider\Node;
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
use Ramsey\Uuid\Provider\Node\NodeProviderCollection;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Test\TestCase;
@@ -21,7 +22,7 @@ class FallbackNodeProviderTest extends TestCase
->method('getNode')
->willReturn(null);
$provider = new FallbackNodeProvider([$providerWithoutNode, $providerWithNode]);
$provider = new FallbackNodeProvider(new NodeProviderCollection([$providerWithoutNode, $providerWithNode]));
$provider->getNode();
}
@@ -39,7 +40,9 @@ class FallbackNodeProviderTest extends TestCase
$anotherProviderWithoutNode->expects($this->never())
->method('getNode');
$provider = new FallbackNodeProvider([$providerWithoutNode, $providerWithNode, $anotherProviderWithoutNode]);
$provider = new FallbackNodeProvider(new NodeProviderCollection(
[$providerWithoutNode, $providerWithNode, $anotherProviderWithoutNode]
));
$node = $provider->getNode();
$this->assertEquals('57764a07f756', $node);
@@ -51,7 +54,7 @@ class FallbackNodeProviderTest extends TestCase
$providerWithoutNode->method('getNode')
->willReturn(null);
$provider = new FallbackNodeProvider([$providerWithoutNode]);
$provider = new FallbackNodeProvider(new NodeProviderCollection([$providerWithoutNode]));
$node = $provider->getNode();
$this->assertNull($node);
@@ -10,34 +10,6 @@ use Ramsey\Uuid\Type\Time;
class FixedTimeProviderTest extends TestCase
{
public function testConstructorRequiresSecAndUsec(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Array must contain sec and usec keys.');
new FixedTimeProvider([]);
}
public function testCurrentTimeReturnsTimestamp(): void
{
$timestamp = ['sec' => 1458844556, 'usec' => 200997];
$provider = new FixedTimeProvider($timestamp);
$this->assertEquals($timestamp, $provider->currentTime());
}
public function testCurrentTimeReturnsTimestampAfterChange(): void
{
$timestamp = ['sec' => 1458844556, 'usec' => 200997];
$provider = new FixedTimeProvider($timestamp);
$newTimestamp = ['sec' => 1050804050, 'usec' => 30192];
$provider->setSec($newTimestamp['sec']);
$provider->setUsec($newTimestamp['usec']);
$this->assertEquals($newTimestamp, $provider->currentTime());
}
public function testGetTimeReturnsTime(): void
{
$time = new Time(1458844556, 200997);