From 3598c8cfd039d1ff2710d6f987c34db797370b99 Mon Sep 17 00:00:00 2001 From: Spomky Date: Tue, 28 Sep 2021 21:27:48 +0200 Subject: [PATCH] New interface Normalizable --- phpstan.neon | 2 +- src/ByteStringObject.php | 11 +- src/CBORObject.php | 2 +- src/IndefiniteLengthByteStringObject.php | 17 +- src/IndefiniteLengthListObject.php | 18 +- src/IndefiniteLengthMapObject.php | 24 +- src/IndefiniteLengthTextStringObject.php | 17 +- src/ListObject.php | 15 +- src/MapObject.php | 26 +- src/NegativeIntegerObject.php | 11 +- src/Normalizable.php | 22 ++ src/OtherObject/BreakObject.php | 2 +- .../DoublePrecisionFloatObject.php | 27 +- src/OtherObject/FalseObject.php | 12 +- src/OtherObject/GenericObject.php | 2 +- src/OtherObject/HalfPrecisionFloatObject.php | 29 +- src/OtherObject/NullObject.php | 10 +- src/OtherObject/SimpleObject.php | 35 +- .../SinglePrecisionFloatObject.php | 26 +- src/OtherObject/TrueObject.php | 12 +- src/OtherObject/UndefinedObject.php | 4 +- src/Tag/Base16EncodingTag.php | 2 +- src/Tag/Base64EncodingTag.php | 2 +- src/Tag/Base64Tag.php | 2 +- src/Tag/Base64UrlEncodingTag.php | 2 +- src/Tag/Base64UrlTag.php | 2 +- src/Tag/BigFloatTag.php | 42 +-- src/Tag/CBOREncodingTag.php | 2 +- src/Tag/CBORTag.php | 13 +- src/Tag/DatetimeTag.php | 23 +- src/Tag/DecimalFractionTag.php | 33 +- src/Tag/GenericTag.php | 2 +- src/Tag/MimeTag.php | 10 +- src/Tag/NegativeBigIntegerTag.php | 13 +- src/Tag/TimestampTag.php | 36 +- src/Tag/UnsignedBigIntegerTag.php | 10 +- src/Tag/UriTag.php | 12 +- src/TextStringObject.php | 9 +- src/UnsignedIntegerObject.php | 11 +- tests/Type/InvalidTypeTest.php | 8 +- tests/Type/OtherObject/AllTest.php | 347 ++++++++++++++++++ tests/Type/Tag/DatetimeTagTest.php | 18 +- tests/Type/Tag/MimeTagTest.php | 65 ++++ 43 files changed, 823 insertions(+), 165 deletions(-) create mode 100644 src/Normalizable.php create mode 100644 tests/Type/Tag/MimeTagTest.php diff --git a/phpstan.neon b/phpstan.neon index bf84d79..419943c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -32,6 +32,6 @@ parameters: count: 1 path: src/Tag/TimestampTag.php - - message: '#Method CBOR\\OtherObject\\NullObject\:\:getNormalizedData\(\) should return mixed but return statement is missing\.#' + message: '#Method CBOR\\OtherObject\\NullObject\:\:normalize\(\) should return mixed but return statement is missing\.#' count: 1 path: src/OtherObject/NullObject.php diff --git a/src/ByteStringObject.php b/src/ByteStringObject.php index ccc0323..d7ae82b 100644 --- a/src/ByteStringObject.php +++ b/src/ByteStringObject.php @@ -13,7 +13,7 @@ namespace CBOR; -final class ByteStringObject extends AbstractCBORObject +final class ByteStringObject extends AbstractCBORObject implements Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_BYTE_STRING; @@ -62,11 +62,16 @@ public function getLength(): int return mb_strlen($this->value, '8bit'); } + public function normalize(): string + { + return $this->value; + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false): string { - return $this->value; + return $this->normalize(); } } diff --git a/src/CBORObject.php b/src/CBORObject.php index 876bfc6..9224733 100644 --- a/src/CBORObject.php +++ b/src/CBORObject.php @@ -67,7 +67,7 @@ public function getMajorType(): int; public function getAdditionalInformation(): int; /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface * * @return mixed|null */ diff --git a/src/IndefiniteLengthByteStringObject.php b/src/IndefiniteLengthByteStringObject.php index 474baa3..58bc770 100644 --- a/src/IndefiniteLengthByteStringObject.php +++ b/src/IndefiniteLengthByteStringObject.php @@ -16,7 +16,7 @@ /** * @final */ -class IndefiniteLengthByteStringObject extends AbstractCBORObject +class IndefiniteLengthByteStringObject extends AbstractCBORObject implements Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_BYTE_STRING; private const ADDITIONAL_INFORMATION = self::LENGTH_INDEFINITE; @@ -81,16 +81,21 @@ public function getLength(): int return $length; } - /** - * @deprecated The method will be removed on v3.0. No replacement - */ - public function getNormalizedData(bool $ignoreTags = false): string + public function normalize(): string { $result = ''; foreach ($this->chunks as $chunk) { - $result .= $chunk->getNormalizedData($ignoreTags); + $result .= $chunk->normalize(); } return $result; } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + */ + public function getNormalizedData(bool $ignoreTags = false): string + { + return $this->normalize(); + } } diff --git a/src/IndefiniteLengthListObject.php b/src/IndefiniteLengthListObject.php index ba6a654..ada20e1 100644 --- a/src/IndefiniteLengthListObject.php +++ b/src/IndefiniteLengthListObject.php @@ -23,7 +23,7 @@ * @phpstan-implements IteratorAggregate * @final */ -class IndefiniteLengthListObject extends AbstractCBORObject implements Countable, IteratorAggregate +class IndefiniteLengthListObject extends AbstractCBORObject implements Countable, IteratorAggregate, Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_LIST; private const ADDITIONAL_INFORMATION = self::LENGTH_INDEFINITE; @@ -55,15 +55,23 @@ public function __toString(): string } /** - * @deprecated The method will be removed on v3.0. No replacement + * @return mixed[] + */ + public function normalize(): array + { + return array_map(static function (CBORObject $object) { + return $object instanceof Normalizable ? $object->normalize() : $object; + }, $this->data); + } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface * * @return mixed[] */ public function getNormalizedData(bool $ignoreTags = false): array { - return array_map(static function (CBORObject $item) use ($ignoreTags) { - return $item->getNormalizedData($ignoreTags); - }, $this->data); + return $this->normalize(); } public function add(CBORObject $item): self diff --git a/src/IndefiniteLengthMapObject.php b/src/IndefiniteLengthMapObject.php index aa7a19d..25946d5 100644 --- a/src/IndefiniteLengthMapObject.php +++ b/src/IndefiniteLengthMapObject.php @@ -16,6 +16,7 @@ use ArrayIterator; use function count; use Countable; +use InvalidArgumentException; use Iterator; use IteratorAggregate; @@ -23,7 +24,7 @@ * @phpstan-implements IteratorAggregate * @final */ -class IndefiniteLengthMapObject extends AbstractCBORObject implements Countable, IteratorAggregate +class IndefiniteLengthMapObject extends AbstractCBORObject implements Countable, IteratorAggregate, Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_MAP; private const ADDITIONAL_INFORMATION = self::LENGTH_INDEFINITE; @@ -79,17 +80,30 @@ public function getIterator(): Iterator } /** - * @deprecated The method will be removed on v3.0. No replacement - * * @return mixed[] */ - public function getNormalizedData(bool $ignoreTags = false): array + public function normalize(): array { $result = []; foreach ($this->data as $object) { - $result[$object->getKey()->getNormalizedData($ignoreTags)] = $object->getValue()->getNormalizedData($ignoreTags); + $keyObject = $object->getKey(); + if (!$keyObject instanceof Normalizable) { + throw new InvalidArgumentException('Invalid key. Shall be normalizable'); + } + $valueObject = $object->getValue(); + $result[$keyObject->normalize()] = $valueObject instanceof Normalizable ? $valueObject->normalize() : $object; } return $result; } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + * + * @return mixed[] + */ + public function getNormalizedData(bool $ignoreTags = false): array + { + return $this->normalize(); + } } diff --git a/src/IndefiniteLengthTextStringObject.php b/src/IndefiniteLengthTextStringObject.php index a5c10b9..e3afa9d 100644 --- a/src/IndefiniteLengthTextStringObject.php +++ b/src/IndefiniteLengthTextStringObject.php @@ -16,7 +16,7 @@ /** * @final */ -class IndefiniteLengthTextStringObject extends AbstractCBORObject +class IndefiniteLengthTextStringObject extends AbstractCBORObject implements Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_TEXT_STRING; private const ADDITIONAL_INFORMATION = self::LENGTH_INDEFINITE; @@ -81,16 +81,21 @@ public function getLength(): int return $length; } - /** - * @deprecated The method will be removed on v3.0. No replacement - */ - public function getNormalizedData(bool $ignoreTags = false): string + public function normalize(): string { $result = ''; foreach ($this->data as $object) { - $result .= $object->getNormalizedData($ignoreTags); + $result .= $object->normalize(); } return $result; } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + */ + public function getNormalizedData(bool $ignoreTags = false): string + { + return $this->normalize(); + } } diff --git a/src/ListObject.php b/src/ListObject.php index 109d371..bbe1655 100644 --- a/src/ListObject.php +++ b/src/ListObject.php @@ -24,7 +24,7 @@ /** * @phpstan-implements IteratorAggregate */ -class ListObject extends AbstractCBORObject implements Countable, IteratorAggregate +class ListObject extends AbstractCBORObject implements Countable, IteratorAggregate, Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_LIST; @@ -93,16 +93,21 @@ public function get(int $index): CBORObject return $this->data[$index]; } + public function normalize(): array + { + return array_map(static function (CBORObject $object) { + return $object instanceof Normalizable ? $object->normalize() : $object; + }, $this->data); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface * * @return array */ public function getNormalizedData(bool $ignoreTags = false): array { - return array_map(static function (CBORObject $item) use ($ignoreTags) { - return $item->getNormalizedData($ignoreTags); - }, $this->data); + return $this->normalize(); } public function count(): int diff --git a/src/MapObject.php b/src/MapObject.php index ff5ecbb..c697eea 100644 --- a/src/MapObject.php +++ b/src/MapObject.php @@ -23,7 +23,7 @@ /** * @phpstan-implements IteratorAggregate */ -final class MapObject extends AbstractCBORObject implements Countable, IteratorAggregate +final class MapObject extends AbstractCBORObject implements Countable, IteratorAggregate, Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_MAP; @@ -97,18 +97,28 @@ public function getIterator(): Iterator return new ArrayIterator($this->data); } - /** - * @deprecated The method will be removed on v3.0. No replacement - * - * @return array - */ - public function getNormalizedData(bool $ignoreTags = false): array + public function normalize(): array { $result = []; foreach ($this->data as $object) { - $result[$object->getKey()->getNormalizedData($ignoreTags)] = $object->getValue()->getNormalizedData($ignoreTags); + $keyObject = $object->getKey(); + if (!$keyObject instanceof Normalizable) { + throw new InvalidArgumentException('Invalid key. Shall be normalizable'); + } + $valueObject = $object->getValue(); + $result[$keyObject->normalize()] = $valueObject instanceof Normalizable ? $valueObject->normalize() : $object; } return $result; } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + * + * @return array + */ + public function getNormalizedData(bool $ignoreTags = false): array + { + return $this->normalize(); + } } diff --git a/src/NegativeIntegerObject.php b/src/NegativeIntegerObject.php index 8cee945..513dfd7 100644 --- a/src/NegativeIntegerObject.php +++ b/src/NegativeIntegerObject.php @@ -19,7 +19,7 @@ /** * @final */ -class NegativeIntegerObject extends AbstractCBORObject +class NegativeIntegerObject extends AbstractCBORObject implements Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_NEGATIVE_INTEGER; @@ -73,12 +73,17 @@ public function getValue(): string return $minusOne->minus($result)->toBase(10); } + public function normalize(): string + { + return $this->getValue(); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false): string { - return $this->getValue(); + return $this->normalize(); } private static function createBigInteger(BigInteger $integer): self diff --git a/src/Normalizable.php b/src/Normalizable.php new file mode 100644 index 0000000..3b77662 --- /dev/null +++ b/src/Normalizable.php @@ -0,0 +1,22 @@ +getExponent(); - $mant = $this->getMantissa(); + return $this->normalize(); + } + + /** + * @return float|int + */ + public function normalize() + { + $exponent = $this->getExponent(); + $mantissa = $this->getMantissa(); $sign = $this->getSign(); - if (0 === $exp) { - $val = $mant * 2 ** (-(1022 + 52)); - } elseif (0b11111111111 !== $exp) { - $val = ($mant + (1 << 52)) * 2 ** ($exp - (1023 + 52)); + if (0 === $exponent) { + $val = $mantissa * 2 ** (-(1022 + 52)); + } elseif (0b11111111111 !== $exponent) { + $val = ($mantissa + (1 << 52)) * 2 ** ($exponent - (1023 + 52)); } else { - $val = 0 === $mant ? INF : NAN; + $val = 0 === $mantissa ? INF : NAN; } return $sign * $val; diff --git a/src/OtherObject/FalseObject.php b/src/OtherObject/FalseObject.php index 127fd96..f08adb2 100644 --- a/src/OtherObject/FalseObject.php +++ b/src/OtherObject/FalseObject.php @@ -13,9 +13,10 @@ namespace CBOR\OtherObject; +use CBOR\Normalizable; use CBOR\OtherObject as Base; -final class FalseObject extends Base +final class FalseObject extends Base implements Normalizable { public function __construct() { @@ -37,11 +38,16 @@ public static function createFromLoadedData(int $additionalInformation, ?string return new self(); } + public function normalize(): bool + { + return false; + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false): bool { - return false; + return $this->normalize(); } } diff --git a/src/OtherObject/GenericObject.php b/src/OtherObject/GenericObject.php index 6c9d62f..33ce776 100644 --- a/src/OtherObject/GenericObject.php +++ b/src/OtherObject/GenericObject.php @@ -34,7 +34,7 @@ public static function createFromLoadedData(int $additionalInformation, ?string } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/OtherObject/HalfPrecisionFloatObject.php b/src/OtherObject/HalfPrecisionFloatObject.php index 0501069..f081c6c 100644 --- a/src/OtherObject/HalfPrecisionFloatObject.php +++ b/src/OtherObject/HalfPrecisionFloatObject.php @@ -14,11 +14,12 @@ namespace CBOR\OtherObject; use Brick\Math\BigInteger; +use CBOR\Normalizable; use CBOR\OtherObject as Base; use CBOR\Utils; use InvalidArgumentException; -final class HalfPrecisionFloatObject extends Base +final class HalfPrecisionFloatObject extends Base implements Normalizable { public static function supportedAdditionalInformation(): array { @@ -35,7 +36,7 @@ public static function createFromLoadedData(int $additionalInformation, ?string */ public static function create(string $value): self { - if (4 !== mb_strlen($value, '8bit')) { + if (2 !== mb_strlen($value, '8bit')) { throw new InvalidArgumentException('The value is not a valid half precision floating point'); } @@ -43,20 +44,28 @@ public static function create(string $value): self } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { - $exp = $this->getExponent(); - $mant = $this->getMantissa(); + return $this->normalize(); + } + + /** + * @return float|int + */ + public function normalize() + { + $exponent = $this->getExponent(); + $mantissa = $this->getMantissa(); $sign = $this->getSign(); - if (0 === $exp) { - $val = $mant * 2 ** (-24); - } elseif (0b11111 !== $exp) { - $val = ($mant + (1 << 10)) * 2 ** ($exp - 25); + if (0 === $exponent) { + $val = $mantissa * 2 ** (-24); + } elseif (0b11111 !== $exponent) { + $val = ($mantissa + (1 << 10)) * 2 ** ($exponent - 25); } else { - $val = 0 === $mant ? INF : NAN; + $val = 0 === $mantissa ? INF : NAN; } return $sign * $val; diff --git a/src/OtherObject/NullObject.php b/src/OtherObject/NullObject.php index d1634a2..9ab68d6 100644 --- a/src/OtherObject/NullObject.php +++ b/src/OtherObject/NullObject.php @@ -13,9 +13,10 @@ namespace CBOR\OtherObject; +use CBOR\Normalizable; use CBOR\OtherObject as Base; -final class NullObject extends Base +final class NullObject extends Base implements Normalizable { public function __construct() { @@ -37,10 +38,15 @@ public static function createFromLoadedData(int $additionalInformation, ?string return new self(); } + public function normalize() + { + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { + return $this->normalize(); } } diff --git a/src/OtherObject/SimpleObject.php b/src/OtherObject/SimpleObject.php index 75b18a2..e26f015 100644 --- a/src/OtherObject/SimpleObject.php +++ b/src/OtherObject/SimpleObject.php @@ -13,31 +13,42 @@ namespace CBOR\OtherObject; +use CBOR\Normalizable; use CBOR\OtherObject as Base; use CBOR\Utils; use function chr; use InvalidArgumentException; +use function ord; -final class SimpleObject extends Base +final class SimpleObject extends Base implements Normalizable { public static function supportedAdditionalInformation(): array { - return range(0, 19); + return array_merge(range(0, 19), [24]); } public static function createFromLoadedData(int $additionalInformation, ?string $data): Base { - if (null !== $data && $additionalInformation < 32) { - throw new InvalidArgumentException('Invalid simple value. Content data should not be present.'); + if (24 === $additionalInformation) { + if (null === $data) { + throw new InvalidArgumentException('Invalid simple value. Content data is missing.'); + } + if (1 !== mb_strlen($data, '8bit')) { + throw new InvalidArgumentException('Invalid simple value. Content data is too long.'); + } + if (ord($data) < 32) { + throw new InvalidArgumentException('Invalid simple value. Content data must be between 32 and 255.'); + } + } elseif ($additionalInformation < 20) { + if (null !== $data) { + throw new InvalidArgumentException('Invalid simple value. Content data should not be present.'); + } } return new self($additionalInformation, $data); } - /** - * @deprecated The method will be removed on v3.0. No replacement - */ - public function getNormalizedData(bool $ignoreTags = false) + public function normalize(): int { if (null === $this->data) { return $this->getAdditionalInformation(); @@ -46,6 +57,14 @@ public function getNormalizedData(bool $ignoreTags = false) return Utils::binToInt($this->data); } + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + */ + public function getNormalizedData(bool $ignoreTags = false): int + { + return $this->normalize(); + } + /** * @return SimpleObject */ diff --git a/src/OtherObject/SinglePrecisionFloatObject.php b/src/OtherObject/SinglePrecisionFloatObject.php index 694f911..ac22020 100644 --- a/src/OtherObject/SinglePrecisionFloatObject.php +++ b/src/OtherObject/SinglePrecisionFloatObject.php @@ -43,20 +43,28 @@ public static function create(string $value): self } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { - $exp = $this->getExponent(); - $mant = $this->getMantissa(); + return $this->normalize(); + } + + /** + * @return float|int + */ + public function normalize() + { + $exponent = $this->getExponent(); + $mantissa = $this->getMantissa(); $sign = $this->getSign(); - if (0 === $exp) { - $val = $mant * 2 ** (-(126 + 23)); - } elseif (0b11111111 !== $exp) { - $val = ($mant + (1 << 23)) * 2 ** ($exp - (127 + 23)); + if (0 === $exponent) { + $val = $mantissa * 2 ** (-(126 + 23)); + } elseif (0b11111111 !== $exponent) { + $val = ($mantissa + (1 << 23)) * 2 ** ($exponent - (127 + 23)); } else { - $val = 0 === $mant ? INF : NAN; + $val = 0 === $mantissa ? INF : NAN; } return $sign * $val; @@ -82,7 +90,7 @@ public function getSign(): int { $data = $this->data; Utils::assertString($data, 'Invalid data'); - $sign = Utils::binToBigInteger($data)->shiftedRight(32); + $sign = Utils::binToBigInteger($data)->shiftedRight(31); return $sign->isEqualTo(BigInteger::one()) ? -1 : 1; } diff --git a/src/OtherObject/TrueObject.php b/src/OtherObject/TrueObject.php index cf15093..e6f1591 100644 --- a/src/OtherObject/TrueObject.php +++ b/src/OtherObject/TrueObject.php @@ -13,9 +13,10 @@ namespace CBOR\OtherObject; +use CBOR\Normalizable; use CBOR\OtherObject as Base; -final class TrueObject extends Base +final class TrueObject extends Base implements Normalizable { public function __construct() { @@ -37,11 +38,16 @@ public static function createFromLoadedData(int $additionalInformation, ?string return new self(); } + public function normalize(): bool + { + return true; + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false): bool { - return true; + return $this->normalize(); } } diff --git a/src/OtherObject/UndefinedObject.php b/src/OtherObject/UndefinedObject.php index 22dc2fc..3743afe 100644 --- a/src/OtherObject/UndefinedObject.php +++ b/src/OtherObject/UndefinedObject.php @@ -38,7 +38,9 @@ public static function createFromLoadedData(int $additionalInformation, ?string } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + * + * @return string */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/Base16EncodingTag.php b/src/Tag/Base16EncodingTag.php index 3c4a738..1e75ae8 100644 --- a/src/Tag/Base16EncodingTag.php +++ b/src/Tag/Base16EncodingTag.php @@ -40,7 +40,7 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/Base64EncodingTag.php b/src/Tag/Base64EncodingTag.php index 7e8c902..a689700 100644 --- a/src/Tag/Base64EncodingTag.php +++ b/src/Tag/Base64EncodingTag.php @@ -41,7 +41,7 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/Base64Tag.php b/src/Tag/Base64Tag.php index eb03926..fc8178c 100644 --- a/src/Tag/Base64Tag.php +++ b/src/Tag/Base64Tag.php @@ -48,7 +48,7 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/Base64UrlEncodingTag.php b/src/Tag/Base64UrlEncodingTag.php index 2192f29..48fa74f 100644 --- a/src/Tag/Base64UrlEncodingTag.php +++ b/src/Tag/Base64UrlEncodingTag.php @@ -41,7 +41,7 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/Base64UrlTag.php b/src/Tag/Base64UrlTag.php index de48a90..20e66a6 100644 --- a/src/Tag/Base64UrlTag.php +++ b/src/Tag/Base64UrlTag.php @@ -48,7 +48,7 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/BigFloatTag.php b/src/Tag/BigFloatTag.php index b55f1e7..a2320f2 100644 --- a/src/Tag/BigFloatTag.php +++ b/src/Tag/BigFloatTag.php @@ -16,6 +16,7 @@ use CBOR\CBORObject; use CBOR\ListObject; use CBOR\NegativeIntegerObject; +use CBOR\Normalizable; use CBOR\Tag; use CBOR\UnsignedIntegerObject; use function count; @@ -23,7 +24,7 @@ use InvalidArgumentException; use RuntimeException; -final class BigFloatTag extends Tag +final class BigFloatTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -73,37 +74,36 @@ public static function createFromExponentAndMantissa(CBORObject $e, CBORObject $ return self::create($object); } - /** - * @deprecated The method will be removed on v3.0. No replacement - */ - public function getNormalizedData(bool $ignoreTags = false) + public function normalize() { - if ($ignoreTags) { - return $this->object->getNormalizedData($ignoreTags); - } - - if (!$this->object instanceof ListObject || 2 !== count($this->object)) { - return $this->object->getNormalizedData($ignoreTags); - } $e = $this->object->get(0); $m = $this->object->get(1); - if (!$e instanceof UnsignedIntegerObject && !$e instanceof NegativeIntegerObject) { - return $this->object->getNormalizedData($ignoreTags); - } - if (!$m instanceof UnsignedIntegerObject && !$m instanceof NegativeIntegerObject && !$m instanceof NegativeBigIntegerTag && !$m instanceof UnsignedBigIntegerTag) { - return $this->object->getNormalizedData($ignoreTags); - } - return rtrim( bcmul( - $m->getNormalizedData($ignoreTags), + $m->normalize(), bcpow( '2', - $e->getNormalizedData($ignoreTags), + $e->normalize(), 100), 100), '0' ); } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface + */ + public function getNormalizedData(bool $ignoreTags = false) + { + if ($ignoreTags) { + return $this->object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ListObject || 2 !== count($this->object)) { + return $this->object->getNormalizedData($ignoreTags); + } + + return $this->normalize(); + } } diff --git a/src/Tag/CBOREncodingTag.php b/src/Tag/CBOREncodingTag.php index 8369a24..e9b7fc5 100644 --- a/src/Tag/CBOREncodingTag.php +++ b/src/Tag/CBOREncodingTag.php @@ -48,7 +48,7 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/CBORTag.php b/src/Tag/CBORTag.php index 91b4401..2ab74fe 100644 --- a/src/Tag/CBORTag.php +++ b/src/Tag/CBORTag.php @@ -14,9 +14,10 @@ namespace CBOR\Tag; use CBOR\CBORObject; +use CBOR\Normalizable; use CBOR\Tag; -final class CBORTag extends Tag +final class CBORTag extends Tag implements Normalizable { public static function getTagId(): int { @@ -36,7 +37,15 @@ public static function create(CBORObject $object): Tag } /** - * @deprecated The method will be removed on v3.0. No replacement + * @return mixed|CBORObject|null + */ + public function normalize() + { + return $this->object instanceof Normalizable ? $this->object->normalize() : $this->object; + } + + /** + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/DatetimeTag.php b/src/Tag/DatetimeTag.php index 16b4497..7740961 100644 --- a/src/Tag/DatetimeTag.php +++ b/src/Tag/DatetimeTag.php @@ -15,15 +15,17 @@ use CBOR\CBORObject; use CBOR\IndefiniteLengthTextStringObject; +use CBOR\Normalizable; use CBOR\Tag; use CBOR\TextStringObject; use DateTimeImmutable; +use DateTimeInterface; use InvalidArgumentException; /** * @final */ -class DatetimeTag extends Tag +class DatetimeTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -50,8 +52,18 @@ public static function create(CBORObject $object): Tag return new self($ai, $data, $object); } + public function normalize(): DateTimeInterface + { + $result = DateTimeImmutable::createFromFormat(DATE_RFC3339, $this->object->normalize()); + if (false !== $result) { + return $result; + } + + return DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s.uP', $this->object->normalize()); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { @@ -59,11 +71,6 @@ public function getNormalizedData(bool $ignoreTags = false) return $this->object->getNormalizedData($ignoreTags); } - $result = DateTimeImmutable::createFromFormat(DATE_RFC3339, $this->object->getNormalizedData($ignoreTags)); - if (false !== $result) { - return $result; - } - - return DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s.uP', $this->object->getNormalizedData($ignoreTags)); + return $this->normalize(); } } diff --git a/src/Tag/DecimalFractionTag.php b/src/Tag/DecimalFractionTag.php index 1a3c611..fa6f91f 100644 --- a/src/Tag/DecimalFractionTag.php +++ b/src/Tag/DecimalFractionTag.php @@ -16,6 +16,7 @@ use CBOR\CBORObject; use CBOR\ListObject; use CBOR\NegativeIntegerObject; +use CBOR\Normalizable; use CBOR\Tag; use CBOR\UnsignedIntegerObject; use function count; @@ -23,7 +24,7 @@ use InvalidArgumentException; use RuntimeException; -final class DecimalFractionTag extends Tag +final class DecimalFractionTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -72,8 +73,25 @@ public static function createFromExponentAndMantissa(CBORObject $e, CBORObject $ return self::create($object); } + public function normalize() + { + $e = $this->object->get(0); + $m = $this->object->get(1); + + return rtrim( + bcmul( + $m->normalize(), + bcpow( + '10', + $e->normalize(), + 100), + 100), + '0' + ); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { @@ -94,15 +112,6 @@ public function getNormalizedData(bool $ignoreTags = false) return $this->object->getNormalizedData($ignoreTags); } - return rtrim( - bcmul( - $m->getNormalizedData($ignoreTags), - bcpow( - '10', - $e->getNormalizedData($ignoreTags), - 100), - 100), - '0' - ); + return $this->normalize(); } } diff --git a/src/Tag/GenericTag.php b/src/Tag/GenericTag.php index e0a763d..8239e9c 100644 --- a/src/Tag/GenericTag.php +++ b/src/Tag/GenericTag.php @@ -29,7 +29,7 @@ public static function createFromLoadedData(int $additionalInformation, ?string } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/MimeTag.php b/src/Tag/MimeTag.php index 3b55dd8..967b0cd 100644 --- a/src/Tag/MimeTag.php +++ b/src/Tag/MimeTag.php @@ -15,11 +15,12 @@ use CBOR\CBORObject; use CBOR\IndefiniteLengthTextStringObject; +use CBOR\Normalizable; use CBOR\Tag; use CBOR\TextStringObject; use InvalidArgumentException; -final class MimeTag extends Tag +final class MimeTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -47,8 +48,13 @@ public static function create(CBORObject $object): Tag return new self($ai, $data, $object); } + public function normalize(): string + { + return $this->object->normalize(); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/NegativeBigIntegerTag.php b/src/Tag/NegativeBigIntegerTag.php index bb8907f..0e1267e 100644 --- a/src/Tag/NegativeBigIntegerTag.php +++ b/src/Tag/NegativeBigIntegerTag.php @@ -17,10 +17,11 @@ use CBOR\ByteStringObject; use CBOR\CBORObject; use CBOR\IndefiniteLengthByteStringObject; +use CBOR\Normalizable; use CBOR\Tag; use InvalidArgumentException; -final class NegativeBigIntegerTag extends Tag +final class NegativeBigIntegerTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -48,8 +49,16 @@ public static function create(CBORObject $object): Tag return new self($ai, $data, $object); } + public function normalize(): string + { + $integer = BigInteger::fromBase(bin2hex($this->object->getValue()), 16); + $minusOne = BigInteger::of(-1); + + return $minusOne->minus($integer)->toBase(10); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/TimestampTag.php b/src/Tag/TimestampTag.php index 230a72f..534fd14 100644 --- a/src/Tag/TimestampTag.php +++ b/src/Tag/TimestampTag.php @@ -15,15 +15,17 @@ use CBOR\CBORObject; use CBOR\NegativeIntegerObject; +use CBOR\Normalizable; use CBOR\OtherObject\DoublePrecisionFloatObject; use CBOR\OtherObject\HalfPrecisionFloatObject; use CBOR\OtherObject\SinglePrecisionFloatObject; use CBOR\Tag; use CBOR\UnsignedIntegerObject; use DateTimeImmutable; +use DateTimeInterface; use InvalidArgumentException; -final class TimestampTag extends Tag +final class TimestampTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -50,8 +52,35 @@ public static function create(CBORObject $object): Tag return new self($ai, $data, $object); } + public function normalize(): DateTimeInterface + { + $object = $this->object; + + switch (true) { + case $object instanceof UnsignedIntegerObject: + case $object instanceof NegativeIntegerObject: + return DateTimeImmutable::createFromFormat('U', (string) $object->normalize()); + case $object instanceof HalfPrecisionFloatObject: + case $object instanceof SinglePrecisionFloatObject: + case $object instanceof DoublePrecisionFloatObject: + $value = (string) $object->normalize(); + $parts = explode('.', $value); + if (isset($parts[1])) { + if (mb_strlen($parts[1], '8bit') > 6) { + $parts[1] = mb_substr($parts[1], 0, 6, '8bit'); + } else { + $parts[1] = str_pad($parts[1], 6, '0', STR_PAD_RIGHT); + } + } + + return DateTimeImmutable::createFromFormat('U.u', implode('.', $parts)); + default: + throw new InvalidArgumentException('Unable to normalize the object'); + } + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { @@ -61,11 +90,10 @@ public function getNormalizedData(bool $ignoreTags = false) switch (true) { case $this->object instanceof UnsignedIntegerObject: case $this->object instanceof NegativeIntegerObject: - return DateTimeImmutable::createFromFormat('U', (string) $this->object->getNormalizedData($ignoreTags)); case $this->object instanceof HalfPrecisionFloatObject: case $this->object instanceof SinglePrecisionFloatObject: case $this->object instanceof DoublePrecisionFloatObject: - return DateTimeImmutable::createFromFormat('U.u', (string) $this->object->getNormalizedData($ignoreTags)); + return $this->normalize(); default: return $this->object->getNormalizedData($ignoreTags); } diff --git a/src/Tag/UnsignedBigIntegerTag.php b/src/Tag/UnsignedBigIntegerTag.php index e187d9a..35786d8 100644 --- a/src/Tag/UnsignedBigIntegerTag.php +++ b/src/Tag/UnsignedBigIntegerTag.php @@ -16,6 +16,7 @@ use CBOR\ByteStringObject; use CBOR\CBORObject; use CBOR\IndefiniteLengthByteStringObject; +use CBOR\Normalizable; use CBOR\Tag; use CBOR\Utils; use InvalidArgumentException; @@ -23,7 +24,7 @@ /** * @final */ -class UnsignedBigIntegerTag extends Tag +class UnsignedBigIntegerTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -51,8 +52,13 @@ public static function create(CBORObject $object): Tag return new self($ai, $data, $object); } + public function normalize(): string + { + return Utils::hexToString($this->object->normalize()); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { diff --git a/src/Tag/UriTag.php b/src/Tag/UriTag.php index ca53bad..3234e1d 100644 --- a/src/Tag/UriTag.php +++ b/src/Tag/UriTag.php @@ -15,11 +15,12 @@ use CBOR\CBORObject; use CBOR\IndefiniteLengthTextStringObject; +use CBOR\Normalizable; use CBOR\Tag; use CBOR\TextStringObject; use InvalidArgumentException; -final class UriTag extends Tag +final class UriTag extends Tag implements Normalizable { public function __construct(int $additionalInformation, ?string $data, CBORObject $object) { @@ -47,11 +48,16 @@ public static function create(CBORObject $object): Tag return new self($ai, $data, $object); } + public function normalize(): string + { + return $this->object->normalize(); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false) { - return $this->object->getNormalizedData($ignoreTags); + return $this->normalize(); } } diff --git a/src/TextStringObject.php b/src/TextStringObject.php index 11d9584..9de2430 100644 --- a/src/TextStringObject.php +++ b/src/TextStringObject.php @@ -13,7 +13,7 @@ namespace CBOR; -final class TextStringObject extends AbstractCBORObject +final class TextStringObject extends AbstractCBORObject implements Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_TEXT_STRING; @@ -63,9 +63,14 @@ public function getLength(): int } /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false): string + { + return $this->normalize(); + } + + public function normalize() { return $this->data; } diff --git a/src/UnsignedIntegerObject.php b/src/UnsignedIntegerObject.php index 3f02e85..750e2ab 100644 --- a/src/UnsignedIntegerObject.php +++ b/src/UnsignedIntegerObject.php @@ -16,7 +16,7 @@ use Brick\Math\BigInteger; use InvalidArgumentException; -final class UnsignedIntegerObject extends AbstractCBORObject +final class UnsignedIntegerObject extends AbstractCBORObject implements Normalizable { private const MAJOR_TYPE = self::MAJOR_TYPE_UNSIGNED_INTEGER; @@ -81,12 +81,17 @@ public function getValue(): string return $integer->toBase(10); } + public function normalize(): string + { + return $this->getValue(); + } + /** - * @deprecated The method will be removed on v3.0. No replacement + * @deprecated The method will be removed on v3.0. Please use CBOR\Normalizable interface */ public function getNormalizedData(bool $ignoreTags = false): string { - return $this->getValue(); + return $this->normalize(); } private static function createBigInteger(BigInteger $integer): self diff --git a/tests/Type/InvalidTypeTest.php b/tests/Type/InvalidTypeTest.php index 2a0a883..df4893e 100644 --- a/tests/Type/InvalidTypeTest.php +++ b/tests/Type/InvalidTypeTest.php @@ -111,10 +111,10 @@ public function getInvalidDataItems(): array ['fc', InvalidArgumentException::class, 'Cannot parse the data. Found invalid Additional Information "00011100" (28).'], ['fd', InvalidArgumentException::class, 'Cannot parse the data. Found invalid Additional Information "00011101" (29).'], ['fe', InvalidArgumentException::class, 'Cannot parse the data. Found invalid Additional Information "00011110" (30).'], - ['f800', InvalidArgumentException::class, 'Invalid simple value. Content data should not be present.'], - ['f801', InvalidArgumentException::class, 'Invalid simple value. Content data should not be present.'], - ['f818', InvalidArgumentException::class, 'Invalid simple value. Content data should not be present.'], - ['f81f', InvalidArgumentException::class, 'Invalid simple value. Content data should not be present.'], + ['f800', InvalidArgumentException::class, 'Invalid simple value. Content data must be between 32 and 255.'], + ['f801', InvalidArgumentException::class, 'Invalid simple value. Content data must be between 32 and 255.'], + ['f818', InvalidArgumentException::class, 'Invalid simple value. Content data must be between 32 and 255.'], + ['f81f', InvalidArgumentException::class, 'Invalid simple value. Content data must be between 32 and 255.'], ['5f00ff', RuntimeException::class, 'Unable to parse the data. Infinite Byte String object can only get Byte String objects.'], ['5f21ff', RuntimeException::class, 'Unable to parse the data. Infinite Byte String object can only get Byte String objects.'], ['5f6100ff', RuntimeException::class, 'Unable to parse the data. Infinite Byte String object can only get Byte String objects.'], diff --git a/tests/Type/OtherObject/AllTest.php b/tests/Type/OtherObject/AllTest.php index 15107ac..fbd3234 100644 --- a/tests/Type/OtherObject/AllTest.php +++ b/tests/Type/OtherObject/AllTest.php @@ -14,10 +14,14 @@ namespace CBOR\Test\Type\OtherObject; use CBOR\CBORObject; +use CBOR\Normalizable; use CBOR\OtherObject\BreakObject; +use CBOR\OtherObject\DoublePrecisionFloatObject; use CBOR\OtherObject\FalseObject; +use CBOR\OtherObject\HalfPrecisionFloatObject; use CBOR\OtherObject\NullObject; use CBOR\OtherObject\SimpleObject; +use CBOR\OtherObject\SinglePrecisionFloatObject; use CBOR\OtherObject\TrueObject; use CBOR\OtherObject\UndefinedObject; use CBOR\StringStream; @@ -47,6 +51,7 @@ public function createValidFalseObject(): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $decoded->getMajorType()); static::assertEquals(CBORObject::OBJECT_FALSE, $decoded->getAdditionalInformation()); static::assertNull($decoded->getContent()); + static::assertFalse($decoded->normalize()); } /** @@ -65,6 +70,7 @@ public function createValidTrueObject(): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $decoded->getMajorType()); static::assertEquals(CBORObject::OBJECT_TRUE, $decoded->getAdditionalInformation()); static::assertNull($decoded->getContent()); + static::assertTrue($decoded->normalize()); } /** @@ -83,6 +89,7 @@ public function createValidNullObject(): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $decoded->getMajorType()); static::assertEquals(CBORObject::OBJECT_NULL, $decoded->getAdditionalInformation()); static::assertNull($decoded->getContent()); + static::assertNull($decoded->normalize()); } /** @@ -101,6 +108,7 @@ public function createValidUndefinedObject(): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $decoded->getMajorType()); static::assertEquals(CBORObject::OBJECT_UNDEFINED, $decoded->getAdditionalInformation()); static::assertNull($decoded->getContent()); + static::assertNotInstanceOf(Normalizable::class, $decoded); } /** @@ -112,6 +120,7 @@ public function createValidBreakObject(): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $object->getMajorType()); static::assertEquals(CBORObject::OBJECT_BREAK, $object->getAdditionalInformation()); + static::assertNotInstanceOf(Normalizable::class, $object); } /** @@ -132,6 +141,58 @@ public function createValidSimpleObjectWithoutContent(int $value): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $decoded->getMajorType()); static::assertEquals($value, $decoded->getAdditionalInformation()); static::assertNull($decoded->getContent()); + //static::assertEquals($value, $decoded->normalize()); + } + + /** + * @test + * @dataProvider getHalfPrecisionFloatObject + */ + public function createValidHalfPrecisionFloatObject(string $value, float $expected, float $delta): void + { + $object = HalfPrecisionFloatObject::create($value); + + static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $object->getMajorType()); + static::assertEquals(CBORObject::OBJECT_HALF_PRECISION_FLOAT, $object->getAdditionalInformation()); + if (INF === $expected || $expected === -INF) { + static::assertInfinite($object->normalize()); + } else { + static::assertEqualsWithDelta($expected, $object->normalize(), $delta); + } + } + + /** + * @test + * @dataProvider getSinglePrecisionFloatObject + */ + public function createValidSinglePrecisionFloatObject(string $value, float $expected, float $delta): void + { + $object = SinglePrecisionFloatObject::create($value); + + static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $object->getMajorType()); + static::assertEquals(CBORObject::OBJECT_SINGLE_PRECISION_FLOAT, $object->getAdditionalInformation()); + if (INF === $expected || $expected === -INF) { + static::assertInfinite($object->normalize()); + } else { + static::assertEqualsWithDelta($expected, $object->normalize(), $delta); + } + } + + /** + * @test + * @dataProvider getDoublePrecisionFloatObject + */ + public function createValidDoublePrecisionFloatObject(string $value, float $expected, float $delta): void + { + $object = DoublePrecisionFloatObject::create($value); + + static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $object->getMajorType()); + static::assertEquals(CBORObject::OBJECT_DOUBLE_PRECISION_FLOAT, $object->getAdditionalInformation()); + if (INF === $expected || $expected === -INF) { + static::assertInfinite($object->normalize()); + } else { + static::assertEqualsWithDelta($expected, $object->normalize(), $delta); + } } /** @@ -145,6 +206,7 @@ public function createValidSimpleObjectWithContent(int $value): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $object->getMajorType()); static::assertEquals(CBORObject::OBJECT_SIMPLE_VALUE, $object->getAdditionalInformation()); static::assertEquals(chr($value), $object->getContent()); + //static::assertEquals($value, $object->normalize()); $stream = StringStream::create($object->__toString()); $decoded = $this->getDecoder()->decode($stream); @@ -152,6 +214,7 @@ public function createValidSimpleObjectWithContent(int $value): void static::assertEquals(CBORObject::MAJOR_TYPE_OTHER_TYPE, $decoded->getMajorType()); static::assertEquals(CBORObject::OBJECT_SIMPLE_VALUE, $decoded->getAdditionalInformation()); static::assertEquals(chr($value), $decoded->getContent()); + //static::assertEquals($value, $decoded->normalize()); } /** @@ -192,4 +255,288 @@ public function getSimpleObjectWithContent(): array [255], ]; } + + /** + * @see https://en.wikipedia.org/wiki/Half-precision_floating-point_format + */ + public function getHalfPrecisionFloatObject(): array + { + return [ + [ + $this->bin('0000000000000001', 2), + 0.000000059604645, + 0.000000000000001, + ], + [ + $this->bin('0000001111111111', 2), + 0.000060975552, + 0.000000000001, + ], + [ + $this->bin('0000010000000000', 2), + 0.00006103515625, + 0.00000000000001, + ], + [ + $this->bin('0111101111111111', 2), + 65504, + 1, + ], + [ + $this->bin('0011101111111111', 2), + 0.99951172, + 0.00000001, + ], + [ + $this->bin('0011110000000000', 2), + 1, + 1, + ], + [ + $this->bin('0011110000000001', 2), + 1.00097656, + 0.00000001, + ], + [ + $this->bin('0011010101010101', 2), + 0.333251953125, + 0.000000000001, + ], + [ + $this->bin('1100000000000000', 2), + -1, + 1, + ], + [ + $this->bin('0000000000000000', 2), + 0, + 1, + ], + [ + $this->bin('1000000000000000', 2), + -0, + 1, + ], + [ + $this->bin('0111110000000000', 2), + INF, + 1, + ], + [ + $this->bin('1111110000000000', 2), + -INF, + 1, + ], + ]; + } + + /** + * @see https://en.wikipedia.org/wiki/Single-precision_floating-point_format + */ + public function getSinglePrecisionFloatObject(): array + { + return [ + [ + $this->bin('00000000000000000000000000000001', 4), + 2 ** -149, + 10 ** -149, + ], + [ + $this->bin('00000000011111111111111111111111', 4), + 1.1754942107 * 10 ** -38, + 10 ** -38, + ], + [ + $this->bin('00000000100000000000000000000000', 4), + 1.1754943508 * 10 ** -38, + 10 ** -38, + ], + [ + $this->bin('01111111011111111111111111111111', 4), + 3.4028234664 * 10 ** 38, + 10 ** 38, + ], + [ + $this->bin('00111111011111111111111111111111', 4), + 0.999999940395355225, + 0.000000000000000001, + ], + [ + $this->bin('00111111100000000000000000000000', 4), + 1, + 1, + ], + [ + $this->bin('00111111100000000000000000000001', 4), + 1.00000011920928955, + 0.00000000000000001, + ], + [ + $this->bin('11000000000000000000000000000000', 4), + -2, + 1, + ], + [ + $this->bin('00000000000000000000000000000000', 4), + 0, + 0, + ], + [ + $this->bin('10000000000000000000000000000000', 4), + -0, + 0, + ], + [ + $this->bin('01111111100000000000000000000000', 4), + INF, + 0, + ], + [ + $this->bin('11111111100000000000000000000000', 4), + -INF, + 0, + ], + [ + $this->bin('01000000010010010000111111011011', 4), + 3.14159274101257324, + 0.00000000000000001, + ], + [ + $this->bin('00111110101010101010101010101011', 4), + 0.333333343267440796, + 0.000000000000000001, + ], + ]; + } + + /** + * @see https://en.wikipedia.org/wiki/Double-precision_floating-point_format + */ + public function getDoublePrecisionFloatObject(): array + { + return [ + [ + $this->bin('0011111111110000000000000000000000000000000000000000000000000000', 8), + 1, + 1, + ], + [ + $this->bin('0011111111110000000000000000000000000000000000000000000000000001', 8), + 1.0000000000000002, + 0.0000000000000001, + ], + [ + $this->bin('0011111111110000000000000000000000000000000000000000000000000010', 8), + 1.0000000000000004, + 0.0000000000000001, + ], + [ + $this->bin('0100000000000000000000000000000000000000000000000000000000000000', 8), + 2, + 0.0000000000000001, + ], + [ + $this->bin('1100000000000000000000000000000000000000000000000000000000000000', 8), + -2, + 0.0000000000000001, + ], + [ + $this->bin('0100000000001000000000000000000000000000000000000000000000000000', 8), + 3, + 0.0000000000000001, + ], + [ + $this->bin('0100000000010000000000000000000000000000000000000000000000000000', 8), + 4, + 0.0000000000000001, + ], + [ + $this->bin('0100000000010100000000000000000000000000000000000000000000000000', 8), + 5, + 0.0000000000000001, + ], + [ + $this->bin('0100000000011000000000000000000000000000000000000000000000000000', 8), + 6, + 0.0000000000000001, + ], + [ + $this->bin('0100000000110111000000000000000000000000000000000000000000000000', 8), + 23, + 0.0000000000000001, + ], + [ + $this->bin('0011111110001000000000000000000000000000000000000000000000000000', 8), + 0.01171875, + 0.00000001, + ], + [ + $this->bin('0000000000000000000000000000000000000000000000000000000000000001', 8), + 4.9406564584124654 * 10 ** -324, + 10 ** -324, + ], + [ + $this->bin('0000000000001111111111111111111111111111111111111111111111111111', 8), + 2.2250738585072009 * 10 ** -308, + 10 ** -308, + ], + [ + $this->bin('0000000000010000000000000000000000000000000000000000000000000000', 8), + 2.2250738585072014 * 10 ** -308, + 10 ** -308, + ], + [ + $this->bin('0111111111101111111111111111111111111111111111111111111111111111', 8), + 1.7976931348623157 * 10 ** 308, + 1, + ], + [ + $this->bin('0000000000000000000000000000000000000000000000000000000000000000', 8), + 0, + 0.0000000000000001, + ], + [ + $this->bin('1000000000000000000000000000000000000000000000000000000000000000', 8), + -0, + 0.0000000000000001, + ], + [ + $this->bin('0111111111110000000000000000000000000000000000000000000000000000', 8), + INF, + 1, + ], + [ + $this->bin('1111111111110000000000000000000000000000000000000000000000000000', 8), + -INF, + 1, + ], + [ + $this->bin('0011111111010101010101010101010101010101010101010101010101010101', 8), + 1 / 3, + 0.0000000000000001, + ], + [ + $this->bin('0100000000001001001000011111101101010100010001000010110100011000', 8), + pi(), + 0.0000000000000001, + ], + ]; + } + + private function bin(string $binary, int $length): string + { + return str_pad( + hex2bin( + str_pad( + base_convert($binary, 2, 16), + $length * 2, + '0', + STR_PAD_LEFT + ) + ), + $length, + '0', + STR_PAD_LEFT + ); + } } diff --git a/tests/Type/Tag/DatetimeTagTest.php b/tests/Type/Tag/DatetimeTagTest.php index e8ae61a..9ee9551 100644 --- a/tests/Type/Tag/DatetimeTagTest.php +++ b/tests/Type/Tag/DatetimeTagTest.php @@ -16,6 +16,9 @@ use CBOR\ByteStringObject; use CBOR\CBORObject; use CBOR\NegativeIntegerObject; +use CBOR\OtherObject\DoublePrecisionFloatObject; +use CBOR\OtherObject\HalfPrecisionFloatObject; +use CBOR\OtherObject\SinglePrecisionFloatObject; use CBOR\Tag\DatetimeTag; use CBOR\Tag\TimestampTag; use CBOR\TextStringObject; @@ -78,7 +81,10 @@ public function createValidTimestampTagWithNegativeInteger(): void */ public function createValidTimestampTagWithHalfPrecisionFloat(): void { - static::markTestSkipped('To be done'); + $tag = TimestampTag::create( + HalfPrecisionFloatObject::create(hex2bin(base_convert('0011010101010101', 2, 16))) + ); + static::assertEquals('0.333251', $tag->normalize()->format('U.u')); } /** @@ -86,7 +92,10 @@ public function createValidTimestampTagWithHalfPrecisionFloat(): void */ public function createValidTimestampTagWithSinglePrecisionFloat(): void { - static::markTestSkipped('To be done'); + $tag = TimestampTag::create( + SinglePrecisionFloatObject::create(hex2bin(base_convert('00111111011111111111111111111111', 2, 16))) + ); + static::assertEquals('0.999999', $tag->normalize()->format('U.u')); } /** @@ -94,7 +103,10 @@ public function createValidTimestampTagWithSinglePrecisionFloat(): void */ public function createValidTimestampTagWithDoublePrecisionFloat(): void { - static::markTestSkipped('To be done'); + $tag = TimestampTag::create( + DoublePrecisionFloatObject::create(hex2bin(base_convert('0100000000001001001000011111101101010100010001000010110100011000', 2, 16))) + ); + static::assertEquals('3.141592', $tag->normalize()->format('U.u')); } public function getDatetimes(): array diff --git a/tests/Type/Tag/MimeTagTest.php b/tests/Type/Tag/MimeTagTest.php new file mode 100644 index 0000000..04b188a --- /dev/null +++ b/tests/Type/Tag/MimeTagTest.php @@ -0,0 +1,65 @@ +normalize()); + } + + /** + * @test + */ + public function createValidTagFromTIndefiniteLengthTextStringObject(): void + { + $tag = MimeTag::create( + IndefiniteLengthTextStringObject::create() + ->append('text') + ->append('/') + ->append('plain') + ); + static::assertEquals('text/plain', $tag->normalize()); + } + + /** + * @test + */ + public function createInvalidTag(): void + { + static::expectException(InvalidArgumentException::class); + static::expectExceptionMessage('This tag only accepts a Byte String object.'); + + MimeTag::create( + BreakObject::create() + ); + } +}