From db738bba999a13313c09dbb893a3f6939d1e8826 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 15 Oct 2020 12:34:03 -0400 Subject: [PATCH] Encoder for x-user-defined --- lib/Encoding/XUserDefined.php | 15 ++++- tests/cases/Encoding/TestXUserDefined.php | 74 ++++++++++++++++------- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/lib/Encoding/XUserDefined.php b/lib/Encoding/XUserDefined.php index 8266a35..081948e 100644 --- a/lib/Encoding/XUserDefined.php +++ b/lib/Encoding/XUserDefined.php @@ -6,7 +6,7 @@ declare(strict_types=1); namespace MensBeam\Intl\Encoding; -class XUserDefined extends AbstractEncoding implements Encoding { +class XUserDefined extends AbstractEncoding implements StatelessEncoding { const NAME = "x-user-defined"; const LABELS = ["x-user-defined"]; @@ -76,7 +76,18 @@ class XUserDefined extends AbstractEncoding implements Encoding { return 0; } } - + + public static function encode(int $codePoint, bool $fatal = true): string { + if ($codePoint < 0 || $codePoint > 0x10FFFF) { + throw new EncoderException("Encountered code point outside Unicode range ($codePoint)", self::E_INVALID_CODE_POINT); + } elseif ($codePoint < 0x80) { + return chr($codePoint); + } elseif ($codePoint >= 0xF780 && $codePoint <= 0xF7FF) { + return chr($codePoint - 0xF780 + 0x80); + } else { + return self::errEnc(!$fatal, $codePoint); + } + } /** @codeCoverageIgnore */ protected function seekBack(int $distance): int { diff --git a/tests/cases/Encoding/TestXUserDefined.php b/tests/cases/Encoding/TestXUserDefined.php index 83205e8..e9fb74c 100644 --- a/tests/cases/Encoding/TestXUserDefined.php +++ b/tests/cases/Encoding/TestXUserDefined.php @@ -7,8 +7,10 @@ declare(strict_types=1); namespace MensBeam\Intl\TestCase\Encoding; use MensBeam\Intl\Encoding\XUserDefined; +use MensBeam\Intl\Encoding\Encoding; +use MensBeam\Intl\Encoding\EncoderException; -class TestXUserDefined extends \MensBeam\Intl\Test\DecoderTest { +class TestXUserDefined extends \MensBeam\Intl\Test\CoderDecoderTest { protected $testedClass = XUserDefined::class; /* X-user-defined doesn't have complex seeking, so this string is generic */ protected $seekString = "30 31 32 33 34 35 36"; @@ -17,6 +19,54 @@ class TestXUserDefined extends \MensBeam\Intl\Test\DecoderTest { /* This string is supposed to contain an invalid character sequence sandwiched between two null characters, but x-user-defined has no invalid characters */ protected $brokenChar = ""; + public function provideCodePoints() { + return [ + 'U+0064 (HTML)' => [false, 0x64, "64"], + 'U+0064 (fatal)' => [true, 0x64, "64"], + 'U+F780 (HTML)' => [false, 0xF780, "80"], + 'U+F780 (fatal)' => [true, 0xF780, "80"], + 'U+F7FF (HTML)' => [false, 0xF7FF, "FF"], + 'U+F7FF (fatal)' => [true, 0xF7FF, "FF"], + 'U+00CA (HTML)' => [false, 0xCA, bin2hex("Ê")], + 'U+00CA (fatal)' => [true, 0xCA, new EncoderException("", Encoding::E_UNAVAILABLE_CODE_POINT)], + '-1 (HTML)' => [false, -1, new EncoderException("", Encoding::E_INVALID_CODE_POINT)], + '-1 (fatal)' => [true, -1, new EncoderException("", Encoding::E_INVALID_CODE_POINT)], + '0x110000 (HTML)' => [false, 0x110000, new EncoderException("", Encoding::E_INVALID_CODE_POINT)], + '0x110000 (fatal)' => [true, 0x110000, new EncoderException("", Encoding::E_INVALID_CODE_POINT)], + ]; + } + + public function provideStrings() { + $a_bytes = []; + $a_codes = []; + for ($a = 0; $a < 0x80; $a++) { + $a_bytes[] = strtoupper(bin2hex(chr($a))); + $a_codes[] = $a; + } + $p_bytes = []; + $p_codes = []; + for ($a = 0; $a < 0x80; $a++) { + $p_bytes[] = strtoupper(bin2hex(chr(0x80 + $a))); + $p_codes[] = 0xF780 + $a; + } + $a_bytes = implode(" ", $a_bytes); + $p_bytes = implode(" ", $p_bytes); + return [ + 'empty string' => ["", []], + 'ASCI bytes' => [$a_bytes, $a_codes], + 'private-use bytes' => [$p_bytes, $p_codes], + ]; + } + + /** + * @dataProvider provideCodePoints + * @covers MensBeam\Intl\Encoding\XUserDefined::encode + * @covers MensBeam\Intl\Encoding\XUserDefined::errEnc + */ + public function testEncodeCodePoints(bool $fatal, $input, $exp) { + return parent::testEncodeCodePoints($fatal, $input, $exp); + } + /** * @dataProvider provideStrings * @covers MensBeam\Intl\Encoding\XUserDefined::__construct @@ -123,26 +173,4 @@ class TestXUserDefined extends \MensBeam\Intl\Test\DecoderTest { public function testSeekBackOverRandomData() { return parent::testSeekBackOverRandomData(); } - - public function provideStrings() { - $a_bytes = []; - $a_codes = []; - for ($a = 0; $a < 0x80; $a++) { - $a_bytes[] = strtoupper(bin2hex(chr($a))); - $a_codes[] = $a; - } - $p_bytes = []; - $p_codes = []; - for ($a = 0; $a < 0x80; $a++) { - $p_bytes[] = strtoupper(bin2hex(chr(0x80 + $a))); - $p_codes[] = 0xF780 + $a; - } - $a_bytes = implode(" ", $a_bytes); - $p_bytes = implode(" ", $p_bytes); - return [ - 'empty string' => ["", []], - 'ASCI bytes' => [$a_bytes, $a_codes], - 'private-use bytes' => [$p_bytes, $p_codes], - ]; - } }