diff --git a/.gitattributes b/.gitattributes index bc2c43f..60c2a77 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ /.travis.yml export-ignore /tests export-ignore /phpunit.xml.dist export-ignore +/phpcs.xml export-ignore /apigen.neon export-ignore diff --git a/.travis.yml b/.travis.yml index 4ec0096..7dba238 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ before_script: - composer self-update - composer install --dev --prefer-source -script: ./vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml +script: + - ./vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml + - ./vendor/bin/phpcs --standard=phpcs.xml ./ after_script: php vendor/bin/coveralls diff --git a/composer.json b/composer.json index 41c32a4..c8737ec 100644 --- a/composer.json +++ b/composer.json @@ -24,14 +24,17 @@ }, "require-dev": { "moontoast/math": "~1.1", + "ircmaxell/random-lib": "~1.0", "symfony/console": "~2.3", "doctrine/dbal": ">=2.3", "phpunit/phpunit": "~4.1", + "squizlabs/php_codesniffer": "2.0.0RC4", "satooshi/php-coveralls": "~0.6" }, "bin": ["bin/uuid"], "suggest": { "moontoast/math": "Support for converting UUID to 128-bit integer (in string form).", + "ircmaxell/random-lib": "Provides RandomLib to use with the RandomLibAdapter", "symfony/console": "Support for use of the bin/uuid command line tool.", "doctrine/dbal": "Allow the use of a UUID as doctrine field type." }, diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..6aa2b59 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,15 @@ + + + + Coding standard rules for Rhumsaa\Uuid + + */build/* + */tests/* + */vendor/* + + + + + + + diff --git a/src/Builder/DefaultUuidBuilder.php b/src/Builder/DefaultUuidBuilder.php new file mode 100644 index 0000000..0cf6720 --- /dev/null +++ b/src/Builder/DefaultUuidBuilder.php @@ -0,0 +1,24 @@ +converter = $converter; + } + + public function build(CodecInterface $codec, array $fields) + { + return new Uuid($fields, $this->converter, $codec); + } +} diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php new file mode 100644 index 0000000..21751ab --- /dev/null +++ b/src/Builder/DegradedUuidBuilder.php @@ -0,0 +1,24 @@ +converter = $converter; + } + + public function build(CodecInterface $codec, array $fields) + { + return new DegradedUuid($fields, $this->converter, $codec); + } +} diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php new file mode 100644 index 0000000..023a896 --- /dev/null +++ b/src/Codec/GuidStringCodec.php @@ -0,0 +1,55 @@ +getFieldsHex()); + + // Swap byte-order on the first three fields + $this->swapFields($components); + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $components + ); + } + + public function encodeBinary(UuidInterface $uuid) + { + $components = array_values($uuid->getFieldsHex()); + + return hex2bin(implode('', $components)); + } + + public function decode($encodedUuid) + { + $components = $this->extractComponents($encodedUuid); + + $this->swapFields($components); + + return $this->getBuilder()->build($this, $this->getFields($components)); + } + + public function decodeBytes($bytes) + { + return parent::decode(bin2hex($bytes)); + } + + protected function swapFields(array & $components) + { + $hex = unpack('H*', pack('V', hexdec($components[0]))); + $components[0] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[1]))); + $components[1] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[2]))); + $components[2] = $hex[1]; + } +} diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php new file mode 100644 index 0000000..d9eb62d --- /dev/null +++ b/src/Codec/StringCodec.php @@ -0,0 +1,101 @@ +builder = $builder; + } + + public function encode(UuidInterface $uuid) + { + $fields = array_values($uuid->getFieldsHex()); + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $fields + ); + } + + public function encodeBinary(UuidInterface $uuid) + { + return hex2bin($uuid->getHex()); + } + + public function decode($encodedUuid) + { + $components = $this->extractComponents($encodedUuid); + $fields = $this->getFields($components); + + return $this->builder->build($this, $fields); + } + + public function decodeBytes($bytes) + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + } + + $hexUuid = unpack('H*', $bytes); + + return $this->decode($hexUuid[1]); + } + + protected function getBuilder() + { + return $this->builder; + } + + protected function extractComponents($encodedUuid) + { + $nameParsed = str_replace(array( + 'urn:', + 'uuid:', + '{', + '}', + '-' + ), '', $encodedUuid); + + // We have stripped out the dashes and are breaking up the string using + // substr(). In this way, we can accept a full hex value that doesn't + // contain dashes. + $components = array( + substr($nameParsed, 0, 8), + substr($nameParsed, 8, 4), + substr($nameParsed, 12, 4), + substr($nameParsed, 16, 4), + substr($nameParsed, 20) + ); + + $nameParsed = implode('-', $components); + + if (! Uuid::isValid($nameParsed)) { + throw new InvalidArgumentException('Invalid UUID string: ' . $encodedUuid); + } + + return $components; + } + + protected function getFields(array $components) + { + return array( + 'time_low' => sprintf('%08s', $components[0]), + 'time_mid' => sprintf('%04s', $components[1]), + 'time_hi_and_version' => sprintf('%04s', $components[2]), + 'clock_seq_hi_and_reserved' => sprintf('%02s', substr($components[3], 0, 2)), + 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), + 'node' => sprintf('%012s', $components[4]) + ); + } +} diff --git a/src/CodecInterface.php b/src/CodecInterface.php new file mode 100644 index 0000000..cb934ec --- /dev/null +++ b/src/CodecInterface.php @@ -0,0 +1,27 @@ +getHelperSet()->get('table'); $table->setLayout(TableHelper::LAYOUT_BORDERLESS); - $table->addRows(array( - array('encode:', 'STR:', (string) $uuid), - array('', 'INT:', (string) $uuid->getInteger()), - )); - - if ($uuid->getVariant() != Uuid::RFC_4122) { - - $table->addRows(array( - array('decode:', 'variant:', 'Not an RFC 4122 UUID'), - )); - - $table->render($output); - - return; - } - - switch ($uuid->getVersion()) { - case 1: - $version = '1 (time and node based)'; - break; - case 2: - $version = '2 (DCE security based)'; - break; - case 3: - $version = '3 (name based, MD5)'; - break; - case 4: - $version = '4 (random data based)'; - break; - case 5: - $version = '5 (name based, SHA-1)'; - break; - } - - $table->addRows(array( - array('decode:', 'variant:', 'RFC 4122'), - array('', 'version:', $version), - )); - - if ($uuid->getVersion() == 1) { - $table->addRows(array( - array('', 'content:', 'time: ' . $uuid->getDateTime()->format('c')), - array('', '', 'clock: ' . $uuid->getClockSequence() . ' (usually random)'), - array('', '', 'node: ' . substr(chunk_split($uuid->getNodeHex(), 2, ':'), 0, -1)), - )); - } - - if ($uuid->getVersion() == 4) { - $table->addRows(array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(no semantics: random data only)'), - )); - } - - if ($uuid->getVersion() == 3 || $uuid->getVersion() == 5) { - $table->addRows(array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(not decipherable: MD5 message digest only)'), - )); - } + (new UuidFormatter())->write($table, $uuid); $table->render($output); } diff --git a/src/Console/Command/GenerateCommand.php b/src/Console/Command/GenerateCommand.php index 4dc20a9..78a1669 100644 --- a/src/Console/Command/GenerateCommand.php +++ b/src/Console/Command/GenerateCommand.php @@ -159,9 +159,11 @@ class GenerateCommand extends Command return $namespace; } - throw new Exception('Invalid namespace. ' + throw new Exception( + 'Invalid namespace. ' . 'May be either a UUID in string representation or an identifier ' . 'for internally pre-defined namespace UUIDs (currently known ' - . 'are "ns:DNS", "ns:URL", "ns:OID", and "ns:X500").'); + . 'are "ns:DNS", "ns:URL", "ns:OID", and "ns:X500").' + ); } } diff --git a/src/Console/Util/Formatter/V1Formatter.php b/src/Console/Util/Formatter/V1Formatter.php new file mode 100644 index 0000000..4c27c00 --- /dev/null +++ b/src/Console/Util/Formatter/V1Formatter.php @@ -0,0 +1,19 @@ +getDateTime()->format('c')), + array('', '', 'clock: ' . $uuid->getClockSequence() . ' (usually random)'), + array('', '', 'node: ' . substr(chunk_split($uuid->getNodeHex(), 2, ':'), 0, -1)), + ); + } +} diff --git a/src/Console/Util/Formatter/V2Formatter.php b/src/Console/Util/Formatter/V2Formatter.php new file mode 100644 index 0000000..3362028 --- /dev/null +++ b/src/Console/Util/Formatter/V2Formatter.php @@ -0,0 +1,15 @@ +getHex(), 2, ':'), 0, -1)), + array('', '', '(not decipherable: MD5 message digest only)'), + ); + } +} diff --git a/src/Console/Util/Formatter/V4Formatter.php b/src/Console/Util/Formatter/V4Formatter.php new file mode 100644 index 0000000..4bce8ca --- /dev/null +++ b/src/Console/Util/Formatter/V4Formatter.php @@ -0,0 +1,18 @@ +getHex(), 2, ':'), 0, -1)), + array('', '', '(no semantics: random data only)'), + ); + } +} diff --git a/src/Console/Util/Formatter/V5Formatter.php b/src/Console/Util/Formatter/V5Formatter.php new file mode 100644 index 0000000..bf99c78 --- /dev/null +++ b/src/Console/Util/Formatter/V5Formatter.php @@ -0,0 +1,18 @@ +getHex(), 2, ':'), 0, -1)), + array('', '', '(not decipherable: SHA1 message digest only)'), + ); + } +} diff --git a/src/Console/Util/UuidContentFormatterInterface.php b/src/Console/Util/UuidContentFormatterInterface.php new file mode 100644 index 0000000..ae74ca6 --- /dev/null +++ b/src/Console/Util/UuidContentFormatterInterface.php @@ -0,0 +1,10 @@ + '1 (time and node based)', + 2 => '2 (DCE security based)', + 3 => '3 (name based, MD5)', + 4 => '4 (random data based)', + 5 => '5 (name based, SHA-1)' + ]; + + private static $variantMap = [ + Uuid::RESERVED_NCS => 'Reserved', + Uuid::RFC_4122 => 'RFC 4122', + Uuid::RESERVED_MICROSOFT => 'Reserved for Microsoft use.', + Uuid::RESERVED_FUTURE => 'Reserved for future use.' + ]; + + private static $formatters; + + public function __construct() + { + if (self::$formatters == null) { + self::$formatters = [ + 1 => new V1Formatter(), + 2 => new V2Formatter(), + 3 => new V3Formatter(), + 4 => new V4Formatter(), + 5 => new V5Formatter() + ]; + } + } + + public function write(TableHelper $table, UuidInterface $uuid) + { + $table->addRows(array( + array('encode:', 'STR:', (string) $uuid), + array('', 'INT:', (string) $uuid->getInteger()), + )); + + if ($uuid->getVariant() == Uuid::RFC_4122) { + $table->addRows(array( + array('decode:', 'variant:',$this->getFormattedVariant($uuid)), + array('', 'version:', $this->getFormattedVersion($uuid)), + )); + + $table->addRows($this->getContent($uuid)); + } else { + $table->addRows(array( + array('decode:', 'variant:', 'Not an RFC 4122 UUID'), + )); + } + } + + public function getFormattedVersion(UuidInterface $uuid) + { + return self::$versionMap[$uuid->getVersion()]; + } + + public function getFormattedVariant(UuidInterface $uuid) + { + return self::$variantMap[$uuid->getVariant()]; + } + + /** + * Returns content as an array of rows, each row being an array containing column values. + */ + public function getContent(UuidInterface $uuid) + { + $formatter = self::$formatters[$uuid->getVersion()]; + + return $formatter->getContent($uuid); + } +} diff --git a/src/Converter/Number/BigNumberConverter.php b/src/Converter/Number/BigNumberConverter.php new file mode 100644 index 0000000..31189be --- /dev/null +++ b/src/Converter/Number/BigNumberConverter.php @@ -0,0 +1,27 @@ +multiply('10000000'); + + $usec = new \Moontoast\Math\BigNumber($microSeconds); + $usec->multiply('10'); + + $uuidTime->add($sec) + ->add($usec) + ->add('122192928000000000'); + + $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); + + return array( + 'low' => substr($uuidTimeHex, 8), + 'mid' => substr($uuidTimeHex, 4, 4), + 'hi' => substr($uuidTimeHex, 0, 4), + ); + } +} diff --git a/src/Converter/Time/DegradedTimeConverter.php b/src/Converter/Time/DegradedTimeConverter.php new file mode 100644 index 0000000..c482ee4 --- /dev/null +++ b/src/Converter/Time/DegradedTimeConverter.php @@ -0,0 +1,18 @@ + sprintf('%08x', $uuidTime & 0xffffffff), + 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), + 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), + ); + } +} diff --git a/src/Converter/TimeConverterInterface.php b/src/Converter/TimeConverterInterface.php new file mode 100644 index 0000000..2f4c397 --- /dev/null +++ b/src/Converter/TimeConverterInterface.php @@ -0,0 +1,16 @@ +getVersion() != 1) { + throw new Exception\UnsupportedOperationException('Not a time-based UUID'); + } + + $time = $this->converter->fromHex($this->getTimestampHex()); + + $ts = new \Moontoast\Math\BigNumber($time, 20); + $ts->subtract('122192928000000000'); + $ts->divide('10000000.0'); + $ts->round(); + $unixTime = $ts->getValue(); + + return new \DateTime("@{$unixTime}"); + } + + /** + * Returns an array of the fields of this UUID, with keys named according + * to the RFC 4122 names for the fields. + * + * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer + * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer + * * **time_hi_and_version**: The high field of the timestamp multiplexed with + * the version number, an unsigned 16-bit integer + * * **clock_seq_hi_and_reserved**: The high field of the clock sequence + * multiplexed with the variant, an unsigned 8-bit integer + * * **clock_seq_low**: The low field of the clock sequence, an unsigned + * 8-bit integer + * * **node**: The spatially unique node identifier, an unsigned 48-bit + * integer + * + * @return array The UUID fields represented as integer values + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + * @link http://tools.ietf.org/html/rfc4122#section-4.1.2 + */ + public function getFields() + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' + . 'values overflow the system max integer value' + . '; consider calling getFieldsHex instead' + ); + } + + /** + * Returns the node value associated with this UUID + * + * For UUID version 1, the node field consists of an IEEE 802 MAC + * address, usually the host address. For systems with multiple IEEE + * 802 addresses, any available one can be used. The lowest addressed + * octet (octet number 10) contains the global/local bit and the + * unicast/multicast bit, and is the first octet of the address + * transmitted on an 802.3 LAN. + * + * For systems with no IEEE address, a randomly or pseudo-randomly + * generated value may be used; see RFC 4122, Section 4.5. The + * multicast bit must be set in such addresses, in order that they + * will never conflict with addresses obtained from network cards. + * + * For UUID version 3 or 5, the node field is a 48-bit value constructed + * from a name as described in RFC 4122, Section 4.3. + * + * For UUID version 4, the node field is a randomly or pseudo-randomly + * generated 48-bit value as described in RFC 4122, Section 4.4. + * + * @return int Unsigned 48-bit integer value of node + * @link http://tools.ietf.org/html/rfc4122#section-4.1.6 + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getNode() + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node ' + . 'is an unsigned 48-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getNodeHex instead' + ); + } + + /** + * Returns the low field of the timestamp (the first 32 bits of the UUID). + * + * @return int Unsigned 32-bit integer value of time_low + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getTimeLow() + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low ' + . 'is an unsigned 32-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getTimeLowHex instead' + ); + } + + /** + * The timestamp value associated with this UUID + * + * The 60 bit timestamp value is constructed from the time_low, + * time_mid, and time_hi fields of this UUID. The resulting + * timestamp is measured in 100-nanosecond units since midnight, + * October 15, 1582 UTC. + * + * The timestamp value is only meaningful in a time-based UUID, which + * has version type 1. If this UUID is not a time-based UUID then + * this method throws UnsupportedOperationException. + * + * @return int Unsigned 60-bit integer value of the timestamp + * @throws Exception\UnsupportedOperationException If this UUID is not a version 1 UUID + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + * @link http://tools.ietf.org/html/rfc4122#section-4.1.4 + */ + public function getTimestamp() + { + if ($this->getVersion() != 1) { + throw new Exception\UnsupportedOperationException('Not a time-based UUID'); + } + + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp ' + . 'is an unsigned 60-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getTimestampHex instead' + ); + } +} diff --git a/src/FeatureSet.php b/src/FeatureSet.php new file mode 100644 index 0000000..50f855d --- /dev/null +++ b/src/FeatureSet.php @@ -0,0 +1,176 @@ +disableBigNumber = $forceNoBigNumber; + $this->disable64Bit = $force32Bit; + $this->ignoreSystemNode = $ignoreSystemNode; + + $this->numberConverter = $this->buildNumberConverter(); + $this->builder = $this->buildUuidBuilder(); + $this->codec = $this->buildCodec($useGuids); + $this->nodeProvider = $this->buildNodeProvider(); + $this->randomGenerator = $this->buildRandomGenerator(); + $this->timeConverter = $this->buildTimeConverter(); + $this->timeProvider = new SystemTimeProvider(); + } + + public function getBuilder() + { + return $this->builder; + } + + public function getCodec() + { + return $this->codec; + } + + public function getNodeProvider() + { + return $this->nodeProvider; + } + + public function getNumberConverter() + { + return $this->numberConverter; + } + + public function getRandomGenerator() + { + return $this->randomGenerator; + } + + public function getTimeConverter() + { + return $this->timeConverter; + } + + public function getTimeProvider() + { + return $this->timeProvider; + } + + protected function buildCodec($useGuids = false) + { + if ($useGuids) { + return new GuidStringCodec($this->builder); + } + + return new StringCodec($this->builder); + } + + protected function buildNodeProvider() + { + if ($this->ignoreSystemNode) { + return new RandomNodeProvider(); + } + + return new FallbackNodeProvider([ + new SystemNodeProvider(), + new RandomNodeProvider() + ]); + } + + protected function buildNumberConverter() + { + if ($this->hasBigNumber()) { + return new BigNumberConverter(); + } + + return new DegradedNumberConverter(); + } + + protected function buildRandomGenerator() + { + return (new RandomGeneratorFactory())->getGenerator(); + } + + protected function buildTimeConverter() + { + if ($this->is64BitSystem()) { + return new PhpTimeConverter(); + } elseif ($this->hasBigNumber()) { + return new BigNumberTimeConverter(); + } + + return new DegradedTimeConverter(); + } + + protected function buildUuidBuilder() + { + if ($this->is64BitSystem()) { + return new DefaultUuidBuilder($this->numberConverter); + } + + return new DegradedUuidBuilder($this->numberConverter); + } + + /** + * Returns true if the system has Moontoast\Math\BigNumber + * + * @return bool + */ + protected function hasBigNumber() + { + return class_exists('Moontoast\Math\BigNumber') && ! $this->disableBigNumber; + } + + /** + * Returns true if the system is 64-bit, false otherwise + * + * @return bool + */ + protected function is64BitSystem() + { + return PHP_INT_SIZE == 8 && ! $this->disable64Bit; + } +} diff --git a/src/Generator/MtRandGenerator.php b/src/Generator/MtRandGenerator.php new file mode 100644 index 0000000..c5e7c03 --- /dev/null +++ b/src/Generator/MtRandGenerator.php @@ -0,0 +1,19 @@ +generator = $generator; + + if ($this->generator == null) { + $factory = new Factory(); + + $this->generator = $factory->getLowStrengthGenerator(); + } + } + + public function generate($length) + { + return $this->generator->generate($length); + } +} diff --git a/src/Provider/Node/FallbackNodeProvider.php b/src/Provider/Node/FallbackNodeProvider.php new file mode 100644 index 0000000..1d854c7 --- /dev/null +++ b/src/Provider/Node/FallbackNodeProvider.php @@ -0,0 +1,26 @@ +nodeProviders = $providers; + } + + public function getNode() + { + foreach ($this->nodeProviders as $provider) { + if ($node = $provider->getNode()) { + return $node; + } + } + + return null; + } +} diff --git a/src/Provider/Node/RandomNodeProvider.php b/src/Provider/Node/RandomNodeProvider.php new file mode 100644 index 0000000..5850d93 --- /dev/null +++ b/src/Provider/Node/RandomNodeProvider.php @@ -0,0 +1,15 @@ +getIfconfig(), $matches, PREG_PATTERN_ORDER)) { + $node = $matches[1][0]; + $node = str_replace(':', '', $node); + $node = str_replace('-', '', $node); + } + + return $node; + } + + /** + * Returns the network interface configuration for the system + * + * @todo Needs evaluation and possibly modification to ensure this works + * well across multiple platforms. + * @codeCoverageIgnore + * @return string + */ + protected function getIfconfig() + { + switch (strtoupper(substr(php_uname('a'), 0, 3))) { + case 'WIN': + $ifconfig = `ipconfig /all 2>&1`; + break; + case 'DAR': + $ifconfig = `ifconfig 2>&1`; + break; + case 'LIN': + default: + $ifconfig = `netstat -ie 2>&1`; + break; + } + + return $ifconfig; + } +} diff --git a/src/Provider/NodeProviderInterface.php b/src/Provider/NodeProviderInterface.php new file mode 100644 index 0000000..d3540c4 --- /dev/null +++ b/src/Provider/NodeProviderInterface.php @@ -0,0 +1,8 @@ +fixedTime = $timestamp; + } + + public function setUsec($value) + { + $this->fixedTime['usec'] = $value; + } + + public function setSec($value) + { + $this->fixedTime['sec'] = $value; + } + + public function currentTime() + { + return $this->fixedTime; + } +} diff --git a/src/Provider/Time/SystemTimeProvider.php b/src/Provider/Time/SystemTimeProvider.php new file mode 100644 index 0000000..816d606 --- /dev/null +++ b/src/Provider/Time/SystemTimeProvider.php @@ -0,0 +1,13 @@ + '000000000000', ); + protected $converter; + /** * Creates a universally unique identifier (UUID) from an array of fields. * @@ -156,11 +135,14 @@ class Uuid implements \JsonSerializable * UUIDs. * * @param array $fields + * @param CodecInterface $codec String codec * @link Rhumsaa.Uuid.Uuid.html#method_getFields */ - protected function __construct(array $fields) + public function __construct(array $fields, NumberConverterInterface $converter, CodecInterface $codec) { $this->fields = $fields; + $this->codec = $codec; + $this->converter = $converter; } /** @@ -201,9 +183,9 @@ class Uuid implements \JsonSerializable * @param Uuid $uuid UUID to which this UUID is to be compared * @return int -1, 0 or 1 as this UUID is less than, equal to, or greater than $uuid */ - public function compareTo(Uuid $uuid) + public function compareTo(UuidInterface $uuid) { - $comparison = null; + $comparison = 0; if ($this->getMostSignificantBitsHex() < $uuid->getMostSignificantBitsHex()) { $comparison = -1; @@ -213,8 +195,6 @@ class Uuid implements \JsonSerializable $comparison = -1; } elseif ($this->getLeastSignificantBitsHex() > $uuid->getLeastSignificantBitsHex()) { $comparison = 1; - } else { - $comparison = 0; } return $comparison; @@ -247,13 +227,7 @@ class Uuid implements \JsonSerializable */ public function getBytes() { - $bytes = ''; - - foreach (range(-2, -32, 2) as $step) { - $bytes = chr(hexdec(substr($this->getHex(), $step, 2))) . $bytes; - } - - return $bytes; + return $this->codec->encodeBinary($this); } /** @@ -330,6 +304,11 @@ class Uuid implements \JsonSerializable return sprintf('%04x', $this->getClockSequence()); } + public function getNumberConverter() + { + return $this->converter; + } + /** * Returns a PHP DateTime object representing the timestamp associated * with this UUID. @@ -340,7 +319,8 @@ class Uuid implements \JsonSerializable * * @return \DateTime A PHP DateTime representation of the date * @throws Exception\UnsupportedOperationException If this UUID is not a version 1 UUID - * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and Moontoast\Math\BigNumber is not present + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * Moontoast\Math\BigNumber is not present */ public function getDateTime() { @@ -348,31 +328,8 @@ class Uuid implements \JsonSerializable throw new Exception\UnsupportedOperationException('Not a time-based UUID'); } - - if (self::is64BitSystem()) { - - $unixTime = ($this->getTimestamp() - 0x01b21dd213814000) / 1e7; - $unixTime = number_format($unixTime, 0, '', ''); - - } elseif (self::hasBigNumber()) { - - $time = \Moontoast\Math\BigNumber::baseConvert($this->getTimestampHex(), 16, 10); - - $ts = new \Moontoast\Math\BigNumber($time, 20); - $ts->subtract('122192928000000000'); - $ts->divide('10000000.0'); - $ts->round(); - $unixTime = $ts->getValue(); - - } else { - - throw new Exception\UnsatisfiedDependencyException( - 'When calling ' . __METHOD__ . ' on a 32-bit system, ' - . 'Moontoast\Math\BigNumber must be present in order ' - . 'to extract DateTime from version 1 UUIDs' - ); - - } + $unixTime = ($this->getTimestamp() - 0x01b21dd213814000) / 1e7; + $unixTime = number_format($unixTime, 0, '', ''); return new \DateTime("@{$unixTime}"); } @@ -398,14 +355,6 @@ class Uuid implements \JsonSerializable */ public function getFields() { - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' - . 'values overflow the system max integer value' - . '; consider calling getFieldsHex instead' - ); - } - return array( 'time_low' => $this->getTimeLow(), 'time_mid' => $this->getTimeMid(), @@ -456,22 +405,7 @@ class Uuid implements \JsonSerializable */ public function getInteger() { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since integer is an unsigned ' - . '128-bit integer; Moontoast\Math\BigNumber is required' - . '; consider calling getMostSignificantBitsHex instead' - ); - } - - $number = \Moontoast\Math\BigNumber::baseConvert( - $this->getHex(), - 16, - 10 - ); - - return new \Moontoast\Math\BigNumber($number); + return $this->converter->fromHex($this->getHex()); } /** @@ -482,22 +416,7 @@ class Uuid implements \JsonSerializable */ public function getLeastSignificantBits() { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since least significant bits is an unsigned ' - . '64-bit integer; Moontoast\Math\BigNumber is required' - . '; consider calling getLeastSignificantBitsHex instead' - ); - } - - $number = \Moontoast\Math\BigNumber::baseConvert( - $this->getLeastSignificantBitsHex(), - 16, - 10 - ); - - return new \Moontoast\Math\BigNumber($number); + return $this->converter->fromHex($this->getLeastSignificantBitsHex()); } /** @@ -523,22 +442,7 @@ class Uuid implements \JsonSerializable */ public function getMostSignificantBits() { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since most significant bits is an unsigned ' - . '64-bit integer; Moontoast\Math\BigNumber is required' - . '; consider calling getMostSignificantBitsHex instead' - ); - } - - $number = \Moontoast\Math\BigNumber::baseConvert( - $this->getMostSignificantBitsHex(), - 16, - 10 - ); - - return new \Moontoast\Math\BigNumber($number); + return $this->converter->fromHex($this->getMostSignificantBitsHex()); } /** @@ -583,15 +487,6 @@ class Uuid implements \JsonSerializable */ public function getNode() { - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node ' - . 'is an unsigned 48-bit integer and can overflow the system ' - . 'max integer value' - . '; consider calling getNodeHex instead' - ); - } - return hexdec($this->getNodeHex()); } @@ -654,15 +549,6 @@ class Uuid implements \JsonSerializable */ public function getTimeLow() { - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low ' - . 'is an unsigned 32-bit integer and can overflow the system ' - . 'max integer value' - . '; consider calling getTimeLowHex instead' - ); - } - return hexdec($this->getTimeLowHex()); } @@ -719,15 +605,6 @@ class Uuid implements \JsonSerializable throw new Exception\UnsupportedOperationException('Not a time-based UUID'); } - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp ' - . 'is an unsigned 60-bit integer and can overflow the system ' - . 'max integer value' - . '; consider calling getTimestampHex instead' - ); - } - return hexdec($this->getTimestampHex()); } @@ -836,10 +713,21 @@ class Uuid implements \JsonSerializable */ public function toString() { - return vsprintf( - '%08s-%04s-%04s-%02s%02s-%012s', - $this->fields - ); + return $this->codec->encode($this); + } + + public static function getFactory() + { + if (! self::$factory) { + self::$factory = new UuidFactory(); + } + + return self::$factory; + } + + public static function setFactory(UuidFactory $factory) + { + self::$factory = $factory; } /** @@ -851,20 +739,7 @@ class Uuid implements \JsonSerializable */ public static function fromBytes($bytes) { - if (strlen($bytes) !== 16) { - throw new InvalidArgumentException('$bytes string should contain 16 characters.'); - } - - $uuid = ''; - foreach (range(0, 15) as $step) { - $uuid .= sprintf('%02x', ord($bytes[$step])); - - if (in_array($step, array(3, 5, 7, 9))) { - $uuid .= '-'; - } - } - - return Uuid::fromString($uuid); + return self::getFactory()->fromBytes($bytes); } /** @@ -877,34 +752,7 @@ class Uuid implements \JsonSerializable */ public static function fromString($name) { - $nameParsed = str_replace(array('urn:', 'uuid:', '{', '}', '-'), '', $name); - - // We have stripped out the dashes and are breaking up the string using - // substr(). In this way, we can accept a full hex value that doesn't - // contain dashes. - $components = array( - substr($nameParsed, 0, 8), - substr($nameParsed, 8, 4), - substr($nameParsed, 12, 4), - substr($nameParsed, 16, 4), - substr($nameParsed, 20), - ); - $nameParsed = implode('-', $components); - - if (!self::isValid($nameParsed)) { - throw new InvalidArgumentException('Invalid UUID string: ' . $name); - } - - $fields = array( - 'time_low' => sprintf('%08s', $components[0]), - 'time_mid' => sprintf('%04s', $components[1]), - 'time_hi_and_version' => sprintf('%04s', $components[2]), - 'clock_seq_hi_and_reserved' => sprintf('%02s', substr($components[3], 0, 2)), - 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), - 'node' => sprintf('%012s', $components[4]), - ); - - return new self($fields); + return self::getFactory()->fromString($name); } /** @@ -916,22 +764,7 @@ class Uuid implements \JsonSerializable */ public static function fromInteger($integer) { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since integer is an unsigned ' - . '128-bit integer; Moontoast\Math\BigNumber is required. ' - ); - } - - if (!$integer instanceof \Moontoast\Math\BigNumber) { - $integer = new \Moontoast\Math\BigNumber($integer); - } - - $hex = \Moontoast\Math\BigNumber::baseConvert($integer, 10, 16); - $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); - - return self::fromString($hex); + return self::getFactory()->fromInteger($integer); } /** @@ -951,6 +784,7 @@ class Uuid implements \JsonSerializable if (!preg_match('/' . self::VALID_PATTERN . '/', $uuid)) { return false; } + return true; } @@ -971,80 +805,20 @@ class Uuid implements \JsonSerializable */ public static function uuid1($node = null, $clockSeq = null) { - if ($node === null && !self::$ignoreSystemNode) { - $node = self::getNodeFromSystem(); - } - - // if $node is still null (couldn't get from system), randomly generate - // a node value, according to RFC 4122, Section 4.5 - if ($node === null) { - $node = sprintf('%06x%06x', mt_rand(0, 1 << 24), mt_rand(0, 1 << 24)); - } - - // Convert the node to hex, if it is still an integer - if (is_int($node)) { - $node = sprintf('%012x', $node); - } - - if (ctype_xdigit($node) && strlen($node) <= 12) { - $node = strtolower(sprintf('%012s', $node)); - } else { - throw new InvalidArgumentException('Invalid node value'); - } - - if ($clockSeq === null) { - // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 - $clockSeq = mt_rand(0, 1 << 14); - } - - // Create a 60-bit time value as a count of 100-nanosecond intervals - // since 00:00:00.00, 15 October 1582 - if (self::$timeOfDayTest === null) { - $timeOfDay = gettimeofday(); - } else { - $timeOfDay = self::$timeOfDayTest; - } - $uuidTime = self::calculateUuidTime($timeOfDay['sec'], $timeOfDay['usec']); - - // Set the version number to 1 - $timeHi = hexdec($uuidTime['hi']) & 0x0fff; - $timeHi &= ~(0xf000); - $timeHi |= 1 << 12; - - // Set the variant to RFC 4122 - $clockSeqHi = ($clockSeq >> 8) & 0x3f; - $clockSeqHi &= ~(0xc0); - $clockSeqHi |= 0x80; - - $fields = array( - 'time_low' => $uuidTime['low'], - 'time_mid' => $uuidTime['mid'], - 'time_hi_and_version' => sprintf('%04x', $timeHi), - 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), - 'clock_seq_low' => sprintf('%02x', $clockSeq & 0xff), - 'node' => $node, - ); - - return new self($fields); + return self::getFactory()->uuid1($node, $clockSeq); } /** * Generate a version 3 UUID based on the MD5 hash of a namespace identifier (which * is a UUID) and a name (which is a string). * - * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $ns The UUID namespace in which to create the named UUID * @param string $name The name to create a UUID for * @return Uuid */ public static function uuid3($ns, $name) { - if (!($ns instanceof Uuid)) { - $ns = self::fromString($ns); - } - - $hash = md5($ns->getBytes() . $name); - - return self::uuidFromHashedName($hash, 3); + return self::getFactory()->uuid3($ns, $name); } /** @@ -1054,221 +828,19 @@ class Uuid implements \JsonSerializable */ public static function uuid4() { - $bytes = self::generateBytes(16); - - // When converting the bytes to hex, it turns into a 32-character - // hexadecimal string that looks a lot like an MD5 hash, so at this - // point, we can just pass it to uuidFromHashedName. - $hex = bin2hex($bytes); - return self::uuidFromHashedName($hex, 4); + return self::getFactory()->uuid4(); } /** * Generate a version 5 UUID based on the SHA-1 hash of a namespace identifier (which * is a UUID) and a name (which is a string). * - * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $ns The UUID namespace in which to create the named UUID * @param string $name The name to create a UUID for * @return Uuid */ public static function uuid5($ns, $name) { - if (!($ns instanceof Uuid)) { - $ns = self::fromString($ns); - } - - $hash = sha1($ns->getBytes() . $name); - - return self::uuidFromHashedName($hash, 5); - } - - /** - * Calculates the UUID time fields from a UNIX timestamp - * - * UUID time is a 60-bit time value as a count of 100-nanosecond intervals - * since 00:00:00.00, 15 October 1582. - * - * @param int $sec Seconds since the Unix Epoch - * @param int $usec Microseconds - * @return array - * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and Moontoast\Math\BigNumber is not present - */ - protected static function calculateUuidTime($sec, $usec) - { - if (self::is64BitSystem()) { - - // 0x01b21dd213814000 is the number of 100-ns intervals between the - // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - $uuidTime = ($sec * 10000000) + ($usec * 10) + 0x01b21dd213814000; - - return array( - 'low' => sprintf('%08x', $uuidTime & 0xffffffff), - 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), - 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), - ); - } - - if (self::hasBigNumber()) { - - $uuidTime = new \Moontoast\Math\BigNumber('0'); - - $sec = new \Moontoast\Math\BigNumber($sec); - $sec->multiply('10000000'); - - $usec = new \Moontoast\Math\BigNumber($usec); - $usec->multiply('10'); - - $uuidTime->add($sec) - ->add($usec) - ->add('122192928000000000'); - - $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); - - return array( - 'low' => substr($uuidTimeHex, 8), - 'mid' => substr($uuidTimeHex, 4, 4), - 'hi' => substr($uuidTimeHex, 0, 4), - ); - } - - throw new Exception\UnsatisfiedDependencyException( - 'When calling ' . __METHOD__ . ' on a 32-bit system, ' - . 'Moontoast\Math\BigNumber must be present in order ' - . 'to generate version 1 UUIDs' - ); - } - - /** - * Returns the network interface configuration for the system - * - * @todo Needs evaluation and possibly modification to ensure this works - * well across multiple platforms. - * @codeCoverageIgnore - */ - protected static function getIfconfig() - { - switch (strtoupper(substr(php_uname('a'), 0, 3))) { - case 'WIN': - $ifconfig = `ipconfig /all 2>&1`; - break; - case 'DAR': - $ifconfig = `ifconfig 2>&1`; - break; - case 'LIN': - default: - $ifconfig = `netstat -ie 2>&1`; - break; - } - - return $ifconfig; - } - - /** - * Get the hardware address as a 48-bit positive integer. If all attempts to - * obtain the hardware address fail, we choose a random 48-bit number with - * its eighth bit set to 1 as recommended in RFC 4122. "Hardware address" - * means the MAC address of a network interface, and on a machine with - * multiple network interfaces the MAC address of any one of them may be - * returned. - * - * @return string - */ - protected static function getNodeFromSystem() - { - $node = null; - $pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/'; - $matches = array(); - - // Search the ifconfig output for all MAC addresses and return - // the first one found - if (preg_match_all($pattern, self::getIfconfig(), $matches, PREG_PATTERN_ORDER)) { - $node = $matches[1][0]; - $node = str_replace(':', '', $node); - $node = str_replace('-', '', $node); - } - - return $node; - } - - /** - * Returns true if the system has Moontoast\Math\BigNumber - * - * @return bool - */ - protected static function hasBigNumber() - { - return (class_exists('Moontoast\Math\BigNumber') && !self::$forceNoBigNumber); - } - - /** - * Returns true if the system has openssl_random_pseudo_bytes() - * - * @return bool - */ - protected static function hasOpensslRandomPseudoBytes() - { - return (function_exists('openssl_random_pseudo_bytes') && !self::$forceNoOpensslRandomPseudoBytes); - } - - /** - * Returns true if the system is 64-bit, false otherwise - * - * @return bool - */ - protected static function is64BitSystem() - { - return (PHP_INT_SIZE == 8 && !self::$force32Bit); - } - - /** - * Returns a version 3 or 5 UUID based on the hash (md5 or sha1) of a - * namespace identifier (which is a UUID) and a name (which is a string) - * - * @param string $hash The hash to use when creating the UUID - * @param int $version The UUID version to be generated - * @return Uuid - */ - protected static function uuidFromHashedName($hash, $version) - { - // Set the version number - $timeHi = hexdec(substr($hash, 12, 4)) & 0x0fff; - $timeHi &= ~(0xf000); - $timeHi |= $version << 12; - - // Set the variant to RFC 4122 - $clockSeqHi = hexdec(substr($hash, 16, 2)) & 0x3f; - $clockSeqHi &= ~(0xc0); - $clockSeqHi |= 0x80; - - $fields = array( - 'time_low' => substr($hash, 0, 8), - 'time_mid' => substr($hash, 8, 4), - 'time_hi_and_version' => sprintf('%04x', $timeHi), - 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), - 'clock_seq_low' => substr($hash, 18, 2), - 'node' => substr($hash, 20, 12), - ); - - return new self($fields); - } - - /** - * Generates random bytes for use in version 4 UUIDs - * - * @param int $length - * @return string - */ - private static function generateBytes($length) - { - if (self::hasOpensslRandomPseudoBytes()) { - return openssl_random_pseudo_bytes($length); - } - - $bytes = ''; - for ($i = 1; $i <= $length; $i++) { - $bytes = chr(mt_rand(0, 255)) . $bytes; - } - - return $bytes; + return self::getFactory()->uuid5($ns, $name); } } diff --git a/src/UuidBuilder.php b/src/UuidBuilder.php new file mode 100644 index 0000000..29b253b --- /dev/null +++ b/src/UuidBuilder.php @@ -0,0 +1,11 @@ +codec = $features->getCodec(); + $this->nodeProvider = $features->getNodeProvider(); + $this->numberConverter = $features->getNumberConverter(); + $this->randomGenerator = $features->getRandomGenerator(); + $this->timeConverter = $features->getTimeConverter(); + $this->timeProvider = $features->getTimeProvider(); + $this->uuidBuilder = $features->getBuilder(); + } + + public function getCodec() + { + return $this->codec; + } + + public function setTimeConverter(TimeConverterInterface $converter) + { + $this->timeConverter = $converter; + } + + public function setTimeProvider(TimeProviderInterface $provider) + { + $this->timeProvider = $provider; + } + + public function setRandomGenerator(RandomGeneratorInterface $generator) + { + $this->randomGenerator = $generator; + } + + public function setNodeProvider(NodeProviderInterface $provider) + { + $this->nodeProvider = $provider; + } + + public function setNumberConverter(NumberConverterInterface $converter) + { + $this->numberConverter = $converter; + } + + public function setUuidBuilder(UuidBuilder $builder) + { + $this->uuidBuilder = $builder; + } + + /** + * Creates a UUID from a byte string. + * + * @param string $bytes + * @return Uuid + * @throws InvalidArgumentException If the $bytes string does not contain 16 characters + */ + public function fromBytes($bytes) + { + return $this->codec->decodeBytes($bytes); + } + + /** + * Creates a UUID from the string standard representation as described + * in the toString() method. + * + * @param string $name A string that specifies a UUID + * @return Uuid + * @throws InvalidArgumentException If the $name isn't a valid UUID + */ + public function fromString($name) + { + return $this->codec->decode($name); + } + + public function fromInteger($integer) + { + $hex = $this->numberConverter->toHex($integer); + $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); + + return $this->fromString($hex); + } + + /** + * Generate a version 1 UUID from a host ID, sequence number, and the current time. + * If $node is not given, we will attempt to obtain the local hardware + * address. If $clockSeq is given, it is used as the sequence number; + * otherwise a random 14-bit sequence number is chosen. + * + * @param int|string $node A 48-bit number representing the hardware + * address. This number may be represented as + * an integer or a hexadecimal string. + * @param int $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time + * or if the node ID changes. + * @return Uuid + * @throws InvalidArgumentException if the $node is invalid + */ + public function uuid1($node = null, $clockSeq = null) + { + $node = $this->getValidNode($node); + + if ($clockSeq === null) { + // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 + $clockSeq = mt_rand(0, 1 << 14); + } + + // Create a 60-bit time value as a count of 100-nanosecond intervals + // since 00:00:00.00, 15 October 1582 + $timeOfDay = $this->timeProvider->currentTime(); + $uuidTime = $this->timeConverter->calculateTime($timeOfDay['sec'], $timeOfDay['usec']); + + $timeHi = $this->applyVersion($uuidTime['hi'], 1); + $clockSeqHi = $this->applyVariant($clockSeq >> 8); + + $fields = array( + 'time_low' => $uuidTime['low'], + 'time_mid' => $uuidTime['mid'], + 'time_hi_and_version' => sprintf('%04x', $timeHi), + 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), + 'clock_seq_low' => sprintf('%02x', $clockSeq & 0xff), + 'node' => $node, + ); + + return $this->uuid($fields); + } + + + /** + * Generate a version 3 UUID based on the MD5 hash of a namespace identifier (which + * is a UUID) and a name (which is a string). + * + * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return Uuid + */ + public function uuid3($ns, $name) + { + return $this->uuidFromNsAndName($ns, $name, 3, 'md5'); + } + + /** + * Generate a version 4 (random) UUID. + * + * @return Uuid + */ + public function uuid4() + { + $bytes = $this->randomGenerator->generate(16); + + // When converting the bytes to hex, it turns into a 32-character + // hexadecimal string that looks a lot like an MD5 hash, so at this + // point, we can just pass it to uuidFromHashedName. + $hex = bin2hex($bytes); + + return $this->uuidFromHashedName($hex, 4); + } + + /** + * Generate a version 5 UUID based on the SHA-1 hash of a namespace identifier (which + * is a UUID) and a name (which is a string). + * + * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return Uuid + */ + public function uuid5($ns, $name) + { + return $this->uuidFromNsAndName($ns, $name, 5, 'sha1'); + } + + public function uuid(array $fields) + { + return $this->uuidBuilder->build($this->codec, $fields); + } + + protected function applyVariant($clockSeqHi) + { + // Set the variant to RFC 4122 + $clockSeqHi = $clockSeqHi & 0x3f; + $clockSeqHi &= ~(0xc0); + $clockSeqHi |= 0x80; + + return $clockSeqHi; + } + + /** + * @param string $timeHi + * @param integer $version + */ + protected function applyVersion($timeHi, $version) + { + $timeHi = hexdec($timeHi) & 0x0fff; + $timeHi &= ~(0xf000); + $timeHi |= $version << 12; + + return $timeHi; + } + + /** + * @param string $name + * @param integer $version + * @param string $hashFunction + */ + protected function uuidFromNsAndName($ns, $name, $version, $hashFunction) + { + if (!($ns instanceof Uuid)) { + $ns = $this->codec->decode($ns); + } + + $hash = call_user_func($hashFunction, ($ns->getBytes() . $name)); + + return $this->uuidFromHashedName($hash, $version); + } + + /** + * Returns a version 3 or 5 UUID based on the hash (md5 or sha1) of a + * namespace identifier (which is a UUID) and a name (which is a string) + * + * @param string $hash The hash to use when creating the UUID + * @param int $version The UUID version to be generated + * @return Uuid + */ + protected function uuidFromHashedName($hash, $version) + { + $timeHi = $this->applyVersion(substr($hash, 12, 4), $version); + $clockSeqHi = $this->applyVariant(hexdec(substr($hash, 16, 2))); + + $fields = array( + 'time_low' => substr($hash, 0, 8), + 'time_mid' => substr($hash, 8, 4), + 'time_hi_and_version' => sprintf('%04x', $timeHi), + 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), + 'clock_seq_low' => substr($hash, 18, 2), + 'node' => substr($hash, 20, 12), + ); + + return $this->uuid($fields); + } + + protected function getValidNode($node) + { + if ($node === null) { + $node = $this->nodeProvider->getNode(); + } + + // Convert the node to hex, if it is still an integer + if (is_int($node)) { + $node = sprintf('%012x', $node); + } + + if (! ctype_xdigit($node) || strlen($node) > 12) { + throw new \InvalidArgumentException('Invalid node value'); + } + + return strtolower(sprintf('%012s', $node)); + } +} diff --git a/src/UuidInterface.php b/src/UuidInterface.php new file mode 100644 index 0000000..4670e7e --- /dev/null +++ b/src/UuidInterface.php @@ -0,0 +1,111 @@ +fromHex('ffff'); + } + + /** + * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException + */ + public function testConvertingToHexThrowsException() + { + $converter = new DegradedNumberConverter(); + + $converter->toHex(0); + } +} diff --git a/tests/RandomGeneratorFactoryTest.php b/tests/RandomGeneratorFactoryTest.php new file mode 100644 index 0000000..130b7eb --- /dev/null +++ b/tests/RandomGeneratorFactoryTest.php @@ -0,0 +1,24 @@ +assertNotInstanceOf('\Rhumsaa\Uuid\Generator\OpenSslGenerator', $generator); + } + + public function testFactoryReturnsOpenSslGeneratorIfAvailable() + { + RandomGeneratorFactory::$forceNoOpensslRandomPseudoBytes = false; + + $generator = RandomGeneratorFactory::getGenerator(); + + $this->assertInstanceOf('\Rhumsaa\Uuid\Generator\OpenSslGenerator', $generator); + } +} diff --git a/tests/UuidBcTag1_1_2Test.php b/tests/UuidBcTag1_1_2Test.php index 1cd789f..60966f1 100644 --- a/tests/UuidBcTag1_1_2Test.php +++ b/tests/UuidBcTag1_1_2Test.php @@ -12,6 +12,8 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase { protected function setUp() { + Uuid::setFactory(new UuidFactory()); + // Skip these tests if run on a 32-bit build of PHP if (PHP_INT_SIZE == 4) { $this->markTestSkipped( @@ -21,8 +23,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString - * @covers Rhumsaa\Uuid\Uuid::__construct */ public function testFromString() { @@ -32,7 +32,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString */ public function testFromStringWithCurlyBraces() { @@ -42,7 +41,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid UUID string: */ @@ -52,7 +50,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString */ public function testFromStringWithUrn() { @@ -62,7 +59,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getBytes */ public function testGetBytes() { @@ -71,7 +67,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqHiAndReserved */ public function testGetClockSeqHiAndReserved() { @@ -80,7 +75,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqLow */ public function testGetClockSeqLow() { @@ -89,7 +83,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSequence */ public function testGetClockSequence() { @@ -98,7 +91,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime */ public function testGetDateTime() { @@ -114,8 +106,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -127,7 +117,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getFields */ public function testGetFields() { @@ -141,7 +130,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBits */ public function testGetLeastSignificantBits() { @@ -158,7 +146,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBits */ public function testGetMostSignificantBits() { @@ -175,7 +162,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getNode */ public function testGetNode() { @@ -184,7 +170,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersion */ public function testGetTimeHiAndVersion() { @@ -193,7 +178,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLow */ public function testGetTimeLow() { @@ -202,7 +186,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeMid */ public function testGetTimeMid() { @@ -211,7 +194,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp */ public function testGetTimestamp() { @@ -225,8 +207,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -238,7 +218,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getUrn */ public function testGetUrn() { @@ -247,7 +226,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedNcs() { @@ -277,7 +255,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForRfc4122() { @@ -295,7 +272,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedMicrosoft() { @@ -307,7 +283,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedFuture() { @@ -319,7 +294,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion1() { @@ -328,7 +302,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion2() { @@ -337,7 +310,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion3() { @@ -346,7 +318,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion4() { @@ -355,7 +326,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion5() { @@ -364,8 +334,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::toString - * @covers Rhumsaa\Uuid\Uuid::__toString */ public function testToString() { @@ -381,8 +349,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::getNodeFromSystem */ public function testUuid1() { @@ -394,7 +360,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithNodeAndClockSequence() { @@ -409,11 +374,10 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithRandomNode() { - Uuid::$ignoreSystemNode = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, false, true))); $uuid = Uuid::uuid1(); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); @@ -427,8 +391,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidObject() { @@ -444,8 +406,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidString() { @@ -456,8 +416,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid4 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid4() { @@ -472,8 +430,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidObject() { @@ -489,8 +445,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidString() { @@ -501,7 +455,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::compareTo */ public function testCompareTo() { @@ -530,7 +483,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::equals */ public function testEquals() { diff --git a/tests/UuidFactoryTest.php b/tests/UuidFactoryTest.php new file mode 100644 index 0000000..b5ca218 --- /dev/null +++ b/tests/UuidFactoryTest.php @@ -0,0 +1,24 @@ +fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); + } + + public function testParsesGuidCorrectly() + { + $factory = new UuidFactory(new FeatureSet(true)); + + $uuid = $factory->fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); + } +} diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 8be8b26..8d609fe 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -1,20 +1,20 @@ assertInstanceOf('\Rhumsaa\Uuid\Uuid', $guid); + // UUID's and GUID's share the same textual representation + $this->assertEquals($uuid->toString(), $guid->toString()); + // But not the same binary representation + $this->assertNotEquals(bin2hex($uuid->getBytes()), bin2hex($guid->getBytes())); + } + + /** */ public function testFromStringWithCurlyBraces() { @@ -34,7 +50,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid UUID string: */ @@ -44,7 +59,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString */ public function testFromStringWithUrn() { @@ -54,7 +68,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getBytes */ public function testGetBytes() { @@ -64,7 +77,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqHiAndReserved */ public function testGetClockSeqHiAndReserved() { @@ -73,7 +85,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqHiAndReservedHex */ public function testGetClockSeqHiAndReservedHex() { @@ -82,7 +93,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqLow */ public function testGetClockSeqLow() { @@ -91,7 +101,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqLowHex */ public function testGetClockSeqLowHex() { @@ -100,7 +109,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSequence */ public function testGetClockSequence() { @@ -109,7 +117,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSequenceHex */ public function testGetClockSequenceHex() { @@ -118,7 +125,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime */ public function testGetDateTime() { @@ -144,12 +150,11 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime */ public function testGetDateTime32Bit() { $this->skipIfNoMoontoastMath(); - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); // Check a recent date $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); @@ -173,21 +178,21 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetDateTimeThrownException() { - Uuid::$force32Bit = true; - Uuid::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true, true))); $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertInstanceOf('Rhumsaa\Uuid\DegradedUuid', $uuid); + $this->assertInstanceOf('Rhumsaa\Uuid\Converter\Number\DegradedNumberConverter', $uuid->getNumberConverter()); + $date = $uuid->getDateTime(); } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -199,7 +204,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getFields */ public function testGetFields() { @@ -220,18 +224,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getFields * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetFields32Bit() { - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $fields = $uuid->getFields(); } /** - * @covers Rhumsaa\Uuid\Uuid::getFieldsHex */ public function testGetFieldsHex() { @@ -250,7 +253,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBits */ public function testGetLeastSignificantBits() { @@ -262,18 +264,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBits * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetLeastSignificantBitsException() { - Uuid::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bn = $uuid->getLeastSignificantBits(); } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBitsHex */ public function testGetLeastSignificantBitsHex() { @@ -282,7 +283,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBits */ public function testGetMostSignificantBits() { @@ -294,18 +294,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBits * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetMostSignificantBitsException() { - Uuid::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bn = $uuid->getMostSignificantBits(); } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBitsHex */ public function testGetMostSignificantBitsHex() { @@ -314,7 +313,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getNode */ public function testGetNode() { @@ -325,18 +323,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getNode * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetNode32Bit() { - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $node = $uuid->getNode(); } /** - * @covers Rhumsaa\Uuid\Uuid::getNodeHex */ public function testGetNodeHex() { @@ -345,7 +342,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersion */ public function testGetTimeHiAndVersion() { @@ -354,7 +350,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersionHex */ public function testGetTimeHiAndVersionHex() { @@ -363,7 +358,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLow */ public function testGetTimeLow() { @@ -374,18 +368,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLow * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetTimeLow32Bit() { - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $timeLow = $uuid->getTimeLow(); } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLowHex */ public function testGetTimeLowHex() { @@ -394,7 +387,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeMid */ public function testGetTimeMid() { @@ -403,7 +395,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeMidHex */ public function testGetTimeMidHex() { @@ -412,7 +403,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp */ public function testGetTimestamp() { @@ -428,7 +418,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestampHex */ public function testGetTimestampHex() { @@ -442,8 +431,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -455,8 +442,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestampHex - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -468,18 +453,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetTimestamp32Bit() { - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $ts = $uuid->getTimestamp(); } /** - * @covers Rhumsaa\Uuid\Uuid::getUrn */ public function testGetUrn() { @@ -488,7 +472,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedNcs() { @@ -518,7 +501,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForRfc4122() { @@ -536,7 +518,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedMicrosoft() { @@ -548,7 +529,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedFuture() { @@ -560,7 +540,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion1() { @@ -569,7 +548,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion2() { @@ -578,7 +556,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion3() { @@ -587,7 +564,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion4() { @@ -596,7 +572,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion5() { @@ -605,8 +580,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::toString - * @covers Rhumsaa\Uuid\Uuid::__toString */ public function testToString() { @@ -622,8 +595,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::getNodeFromSystem */ public function testUuid1() { @@ -635,7 +606,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithNodeAndClockSequence() { @@ -652,7 +622,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithHexadecimalNode() { @@ -670,7 +639,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithMixedCaseHexadecimalNode() { @@ -688,7 +656,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithNodeAndClockSequence32Bit() { @@ -707,7 +674,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid node value */ @@ -717,7 +683,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid node value */ @@ -727,7 +692,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid node value */ @@ -736,12 +700,9 @@ class UuidTest extends TestCase $uuid = Uuid::uuid1('db77e160355ef'); } - /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - */ public function testUuid1WithRandomNode() { - Uuid::$ignoreSystemNode = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, false, true))); $uuid = Uuid::uuid1(); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); @@ -755,8 +716,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidObject() { @@ -772,8 +731,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidString() { @@ -789,7 +746,6 @@ class UuidTest extends TestCase * Taken from the Python UUID tests in * http://hg.python.org/cpython/file/2f4c4db9aee5/Lib/test/test_uuid.py * - * @covers Rhumsaa\Uuid\Uuid::uuid3 */ public function testUuid3WithKnownUuids() { @@ -809,9 +765,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid4 - * @covers Rhumsaa\Uuid\Uuid::generateBytes - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid4() { @@ -822,13 +775,10 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid4 - * @covers Rhumsaa\Uuid\Uuid::generateBytes - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid4WithoutOpensslRandomPseudoBytes() { - Uuid::$forceNoOpensslRandomPseudoBytes = true; + RandomGeneratorFactory::$forceNoOpensslRandomPseudoBytes = true; $uuid = Uuid::uuid4(); $this->assertInstanceOf('Rhumsaa\Uuid\Uuid', $uuid); $this->assertEquals(2, $uuid->getVariant()); @@ -840,8 +790,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidObject() { @@ -857,8 +805,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidString() { @@ -874,7 +820,6 @@ class UuidTest extends TestCase * Taken from the Python UUID tests in * http://hg.python.org/cpython/file/2f4c4db9aee5/Lib/test/test_uuid.py * - * @covers Rhumsaa\Uuid\Uuid::uuid5 */ public function testUuid5WithKnownUuids() { @@ -894,7 +839,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::compareTo */ public function testCompareTo() { @@ -923,7 +867,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::equals */ public function testEquals() { @@ -938,20 +881,18 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTime() { - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 1348845514, 'usec' => 277885, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); // For usec = 277885 - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4dbe7e2-097f-11e2-9669-00007ffffffe', (string) $uuidA); @@ -960,7 +901,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidA->getTimeHiAndVersionHex()); // For usec = 0 - Uuid::$timeOfDayTest['usec'] = 0; + $timeOfDay->setUsec(0); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4b18100-097f-11e2-9669-00007ffffffe', (string) $uuidB); @@ -969,7 +910,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidB->getTimeHiAndVersionHex()); // For usec = 999999 - Uuid::$timeOfDayTest['usec'] = 999999; + $timeOfDay->setUsec(999999); $uuidC = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c54a1776-097f-11e2-9669-00007ffffffe', (string) $uuidC); @@ -979,23 +920,21 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeForce32BitPath() { $this->skipIfNoMoontoastMath(); - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 1348845514, 'usec' => 277885, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); // For usec = 277885 - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4dbe7e2-097f-11e2-9669-00007ffffffe', (string) $uuidA); @@ -1004,7 +943,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidA->getTimeHiAndVersionHex()); // For usec = 0 - Uuid::$timeOfDayTest['usec'] = 0; + $timeOfDay->setUsec(0); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4b18100-097f-11e2-9669-00007ffffffe', (string) $uuidB); @@ -1013,7 +952,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidB->getTimeHiAndVersionHex()); // For usec = 999999 - Uuid::$timeOfDayTest['usec'] = 999999; + $timeOfDay->setUsec(999999); $uuidC = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c54a1776-097f-11e2-9669-00007ffffffe', (string) $uuidC); @@ -1023,22 +962,20 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds64Bit() { $this->skip64BitTest(); // 5235-03-31T21:20:59+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 103072857659, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('ff9785f6-ffff-1fff-9669-00007ffffffe', (string) $uuidA); @@ -1047,14 +984,14 @@ class UuidTest extends TestCase $this->assertEquals('1fff', $uuidA->getTimeHiAndVersionHex()); // 1582-10-15T00:00:00+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -12219292800, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('00000000-0000-1000-9669-00007ffffffe', (string) $uuidB); @@ -1067,25 +1004,23 @@ class UuidTest extends TestCase * This test ensures that the UUIDs generated by the 32-bit path match * those generated by the 64-bit path, given the same 64-bit time values. * - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds64BitThrough32BitPath() { $this->skipIfNoMoontoastMath(); $this->skip64BitTest(); - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); // 5235-03-31T21:20:59+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 103072857659, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('ff9785f6-ffff-1fff-9669-00007ffffffe', (string) $uuidA); @@ -1094,14 +1029,14 @@ class UuidTest extends TestCase $this->assertEquals('1fff', $uuidA->getTimeHiAndVersionHex()); // 1582-10-15T00:00:00+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -12219292800, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('00000000-0000-1000-9669-00007ffffffe', (string) $uuidB); @@ -1111,23 +1046,21 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds32Bit() { $this->skipIfNoMoontoastMath(); - Uuid::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); // 2038-01-19T03:14:07+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 2147483647, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('13813ff6-6912-11fe-9669-00007ffffffe', (string) $uuidA); @@ -1136,14 +1069,14 @@ class UuidTest extends TestCase $this->assertEquals('11fe', $uuidA->getTimeHiAndVersionHex()); // 1901-12-13T20:45:53+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -2147483647, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('1419d680-d292-1165-9669-00007ffffffe', (string) $uuidB); @@ -1156,22 +1089,20 @@ class UuidTest extends TestCase * This test ensures that the UUIDs generated by the 64-bit path match * those generated by the 32-bit path, given the same 32-bit time values. * - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds32BitThrough64BitPath() { $this->skip64BitTest(); // 2038-01-19T03:14:07+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 2147483647, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('13813ff6-6912-11fe-9669-00007ffffffe', (string) $uuidA); @@ -1180,14 +1111,14 @@ class UuidTest extends TestCase $this->assertEquals('11fe', $uuidA->getTimeHiAndVersionHex()); // 1901-12-13T20:45:53+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -2147483647, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - Uuid::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('1419d680-d292-1165-9669-00007ffffffe', (string) $uuidB); @@ -1208,24 +1139,27 @@ class UuidTest extends TestCase $currentTime = strtotime('2012-12-11T00:00:00+00:00'); $endTime = $currentTime + 3600; + $factory = new UuidFactory(); + $smallIntFactory = new UuidFactory(new FeatureSet(false, true)); + + $timeOfDay = new FixedTimeProvider(array( + 'sec' => $currentTime, + 'usec' => $usec, + 'minuteswest' => 0, + 'dsttime' => 0, + )); + + $factory->setTimeProvider($timeOfDay); + $smallIntFactory->setTimeProvider($timeOfDay); + while ($currentTime <= $endTime) { foreach (array(0, 50000, 250000, 500000, 750000, 999999) as $usec) { + $timeOfDay->setSec($currentTime); + $timeOfDay->setUsec($usec); - $timeOfDay = array( - 'sec' => $currentTime, - 'usec' => $usec, - 'minuteswest' => 0, - 'dsttime' => 0, - ); - - Uuid::$timeOfDayTest = $timeOfDay; - - Uuid::$force32Bit = true; - $uuid32 = Uuid::uuid1(0x00007ffffffe, 0x1669); - - Uuid::$force32Bit = false; - $uuid64 = Uuid::uuid1(0x00007ffffffe, 0x1669); + $uuid32 = $smallIntFactory->uuid1(0x00007ffffffe, 0x1669); + $uuid64 = $factory->uuid1(0x00007ffffffe, 0x1669); $this->assertTrue( $uuid32->equals($uuid64), @@ -1243,79 +1177,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testCalculateUuidTimeThrownException() { - Uuid::$force32Bit = true; - Uuid::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true, true))); $uuid = Uuid::uuid1(0x00007ffffffe, 0x1669); } /** - * @covers Rhumsaa\Uuid\Uuid::hasBigNumber - */ - public function testHasBigNumber() - { - $this->skipIfNoMoontoastMath(); - - $hasBigNumber = new \ReflectionMethod( - 'Rhumsaa\Uuid\Uuid', 'hasBigNumber' - ); - $hasBigNumber->setAccessible(true); - - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - $this->assertTrue($hasBigNumber->invoke($uuid)); - - Uuid::$forceNoBigNumber = true; - $this->assertFalse($hasBigNumber->invoke($uuid)); - } - - /** - * @covers Rhumsaa\Uuid\Uuid::hasOpensslRandomPseudoBytes - */ - public function testHasOpensslRandomPseudoBytes() - { - $hasOpensslRandomPseudoBytes = new \ReflectionMethod( - 'Rhumsaa\Uuid\Uuid', 'hasOpensslRandomPseudoBytes' - ); - $hasOpensslRandomPseudoBytes->setAccessible(true); - - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - $this->assertTrue($hasOpensslRandomPseudoBytes->invoke($uuid)); - - Uuid::$forceNoOpensslRandomPseudoBytes = true; - $this->assertFalse($hasOpensslRandomPseudoBytes->invoke($uuid)); - } - - /** - * @covers Rhumsaa\Uuid\Uuid::is64BitSystem - */ - public function testIs64BitSystem() - { - $is64BitSystem = new \ReflectionMethod( - 'Rhumsaa\Uuid\Uuid', 'is64BitSystem' - ); - $is64BitSystem->setAccessible(true); - - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - if (PHP_INT_SIZE == 8) { - $this->assertTrue($is64BitSystem->invoke($uuid)); - } else { - $this->assertFalse($is64BitSystem->invoke($uuid)); - } - - Uuid::$force32Bit = true; - $this->assertFalse($is64BitSystem->invoke($uuid)); - } - - /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion1() { @@ -1324,7 +1195,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion2() { @@ -1333,7 +1203,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion3() { @@ -1342,7 +1211,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion4() { @@ -1351,7 +1219,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion5() { @@ -1360,7 +1227,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodUpperCase() { @@ -1369,7 +1235,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidBadHex() { @@ -1378,7 +1243,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidTooShort1() { @@ -1387,7 +1251,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidTooShort2() { @@ -1396,7 +1259,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidNoDashes() { @@ -1405,7 +1267,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidTooLong() { @@ -1414,7 +1275,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testUsingNilAsValidUuid() { @@ -1423,7 +1283,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromBytes */ public function testFromBytes() { @@ -1435,8 +1294,30 @@ class UuidTest extends TestCase $this->assertTrue($uuid->equals($fromBytesUuid)); } + public function testFromLittleEndianBytes() + { + $uuidFactory = new UuidFactory(new FeatureSet(false)); + $guidFactory = new UuidFactory(new FeatureSet(true)); + + // Check that parsing BE bytes as LE reverses fields + $uuid = $uuidFactory->fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $bytes = $uuid->getBytes(); + + $guid = $guidFactory->fromBytes($bytes); + + // First three fields should be reversed + $this->assertEquals('b08c6fff-7dc5-e111-9b21-0800200c9a66', $guid->toString()); + + // Check that parsing LE bytes as LE preserves fields + $guid = $guidFactory->fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $bytes = $guid->getBytes(); + + $parsedGuid = $guidFactory->fromBytes($bytes); + + $this->assertEquals($guid->toString(), $parsedGuid->toString()); + } + /** - * @covers Rhumsaa\Uuid\Uuid::fromBytes * @expectedException InvalidArgumentException */ public function testFromBytesArgumentTooShort() @@ -1445,7 +1326,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromBytes * @expectedException InvalidArgumentException */ public function testFromBytesArgumentTooLong() @@ -1454,7 +1334,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromInteger */ public function testFromIntegerBigNumber() { @@ -1467,7 +1346,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromInteger */ public function testFromIntegerString() { @@ -1479,7 +1357,6 @@ class UuidTest extends TestCase $this->assertTrue($uuid->equals($fromIntegerUuid)); } - /** * This test ensures that Rhumsaa\Uuid passes the same test cases * as the Python UUID library. @@ -1487,25 +1364,6 @@ class UuidTest extends TestCase * Taken from the Python UUID tests in * http://hg.python.org/cpython/file/2f4c4db9aee5/Lib/test/test_uuid.py * - * @covers Rhumsaa\Uuid\Uuid::fromString - * @covers Rhumsaa\Uuid\Uuid::fromBytes - * @covers Rhumsaa\Uuid\Uuid::fromInteger - * @covers Rhumsaa\Uuid\Uuid::toString - * @covers Rhumsaa\Uuid\Uuid::getBytes - * @covers Rhumsaa\Uuid\Uuid::getFieldsHex - * @covers Rhumsaa\Uuid\Uuid::getHex - * @covers Rhumsaa\Uuid\Uuid::getInteger - * @covers Rhumsaa\Uuid\Uuid::getTimeLowHex - * @covers Rhumsaa\Uuid\Uuid::getTimeMidHex - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersionHex - * @covers Rhumsaa\Uuid\Uuid::getClockSeqHiAndReservedHex - * @covers Rhumsaa\Uuid\Uuid::getClockSeqLowHex - * @covers Rhumsaa\Uuid\Uuid::getNodeHex - * @covers Rhumsaa\Uuid\Uuid::getUrn - * @covers Rhumsaa\Uuid\Uuid::getTimestampHex - * @covers Rhumsaa\Uuid\Uuid::getClockSequenceHex - * @covers Rhumsaa\Uuid\Uuid::getVariant - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testUuidPassesPythonTests() { @@ -1828,13 +1686,12 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getInteger * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException - * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\Uuid::getInteger without support for large integers + * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\Converter\Number\DegradedNumberConverter::fromHex without support for large integers */ public function testGetInteger() { - Uuid::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true))); $uuid = Uuid::uuid1(); $uuid->getInteger(); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 786bef2..50e981f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -9,6 +9,9 @@ if (!file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { . "See http://getcomposer.org for help with installing composer\n"); } +// Set a default timezone for HHVM tests +date_default_timezone_set('UTC'); + // Include the Composer autoloader $loader = include realpath(dirname(__FILE__) . '/../vendor/autoload.php'); diff --git a/tests/console-mocks/testExecuteForVersion5Uuid.txt b/tests/console-mocks/testExecuteForVersion5Uuid.txt index e564146..2498622 100644 --- a/tests/console-mocks/testExecuteForVersion5Uuid.txt +++ b/tests/console-mocks/testExecuteForVersion5Uuid.txt @@ -4,5 +4,5 @@ decode: variant: RFC 4122 version: 5 (name based, SHA-1) content: 88:63:13:e1:3b:8a:53:72:9b:90:0c:9a:ee:19:9e:5d - (not decipherable: MD5 message digest only) + (not decipherable: SHA1 message digest only) ========= ========== =================================================