Browse Source

Start overhauling error handling; adjust coverage annotations

multi-byte
J. King 4 years ago
parent
commit
6417e8f0be
  1. 49
      lib/Encoding/AbstractEncoding.php
  2. 4
      tests/cases/Encoding/TestBig5.php
  3. 4
      tests/cases/Encoding/TestEUCKR.php
  4. 6
      tests/cases/Encoding/TestGB18030.php
  5. 4
      tests/cases/Encoding/TestSingleByte.php
  6. 2
      tests/cases/Encoding/TestUTF16LE.php
  7. 4
      tests/cases/Encoding/TestUTF8.php
  8. 2
      tests/cases/Encoding/TestXUserDefined.php

49
lib/Encoding/AbstractEncoding.php

@ -7,15 +7,32 @@ declare(strict_types=1);
namespace MensBeam\Intl\Encoding; namespace MensBeam\Intl\Encoding;
abstract class AbstractEncoding implements Encoding { abstract class AbstractEncoding implements Encoding {
/** @var string $string The string being decoded */
protected $string; protected $string;
/** @var int $posByte The current byte position in the string */
protected $posByte = 0; protected $posByte = 0;
/** @var int $posChar The current character (code point) position in the string */
protected $posChar = 0; protected $posChar = 0;
/** @var int $lenByte The length of the string, in bytes */
protected $lenByte = null; protected $lenByte = null;
/** @var int $lenChar The length of the string in characters, if known */
protected $lenChar = null; protected $lenChar = null;
/** To be removed */
protected $dirtyEOF = 0; protected $dirtyEOF = 0;
/** @var array $errStack A list of error data to aid in backwards seeking; the most recent error is kept off the stack */
protected $errStack = [];
/** @var int $errMark The byte position marking the most recent error. The one or more bytes previous to this position constitute an invalid character */
protected $errMark = -1;
/** @var int $errSync The byte position to which to move to skip over the most recent erroneous character */
protected $errSync = -2;
/** @var int $errMode The selected error mode (fatal or replace) */
protected $errMode = self::MODE_REPLACE; protected $errMode = self::MODE_REPLACE;
/** @var bool $allowSurrogates Whether surrogates in encodings other than UTF-16 should be passed through */
protected $allowSurrogates = false; protected $allowSurrogates = false;
/** @var bool $selfSynchronizing Whether the concrete class represents a self-synchronizing decoder. Such decoders do not use the error stack */
protected $selfSynchronizing = false; protected $selfSynchronizing = false;
/** @var string[] $stateProps The list of properties which constitutee state which must be saved when peeking/seeking; some encodings may add to this last for their own purposes */
protected $stateProps = ["posChar", "posByte", "posErr", "errStack", "errMark", "errSync"];
public $posErr = 0; public $posErr = 0;
@ -147,11 +164,11 @@ abstract class AbstractEncoding implements Encoding {
/** Returns a copy of the decoder's state to keep in memory */ /** Returns a copy of the decoder's state to keep in memory */
protected function stateSave(): array { protected function stateSave(): array {
return [ $out = [];
'posChar' => $this->posChar, foreach ($this->stateProps as $prop) {
'posByte' => $this->posByte, $out[$prop] = $this->$prop;
'posErr' => $this->posErr, }
]; return $out;
} }
/** Sets the decoder's state to the values specified */ /** Sets the decoder's state to the values specified */
@ -164,16 +181,22 @@ abstract class AbstractEncoding implements Encoding {
/** Handles decoding errors */ /** Handles decoding errors */
protected function errDec(int $mode, int $charOffset, int $byteOffset) { protected function errDec(int $mode, int $charOffset, int $byteOffset) {
assert(in_array($mode, [self::MODE_NULL, self::MODE_REPLACE, self::MODE_FATAL]), "Invalid error mode $mode"); assert(in_array($mode, [self::MODE_NULL, self::MODE_REPLACE, self::MODE_FATAL]), "Invalid error mode $mode");
$this->posErr = $this->posChar; if ($mode !== self::MODE_NULL) {
switch ($mode) { // expose the error to the user; this disambiguates a literal replacement character
case self::MODE_NULL: $this->posErr = $this->posChar;
// used internally during backward seeking for some encodings // unless the decoder is self-synchronizing, mark the error so that it can be skipped when seeking back
return null; // @codeCoverageIgnore if (!$this->selfSynchronizing) {
case self::MODE_REPLACE: $this->errStack[] = [$this->errMark, $this->errSync];
return 0xFFFD; $this->errMark = $this->posByte;
case self::MODE_FATAL: $this->errSync = $byteOffset;
}
if ($mode === self::MODE_FATAL) {
throw new DecoderException("Invalid code sequence at character offset $charOffset (byte offset $byteOffset)", self::E_INVALID_BYTE); throw new DecoderException("Invalid code sequence at character offset $charOffset (byte offset $byteOffset)", self::E_INVALID_BYTE);
} else {
return 0xFFFD;
}
} }
return null;
} }
/** Handles encoding errors */ /** Handles encoding errors */

4
tests/cases/Encoding/TestBig5.php

@ -31,7 +31,7 @@ class TestBig5 extends \MensBeam\Intl\Test\CoderDecoderTest {
/** /**
* @dataProvider provideCodePoints * @dataProvider provideCodePoints
* @covers MensBeam\Intl\Encoding\Big5::encode * @covers MensBeam\Intl\Encoding\Big5::encode
* @covers MensBeam\Intl\Encoding\Big5::err * @covers MensBeam\Intl\Encoding\Big5::errEnc
*/ */
public function testEncodeCodePoints(bool $fatal, $input, $exp) { public function testEncodeCodePoints(bool $fatal, $input, $exp) {
return parent::testEncodeCodePoints($fatal, $input, $exp); return parent::testEncodeCodePoints($fatal, $input, $exp);
@ -112,7 +112,7 @@ class TestBig5 extends \MensBeam\Intl\Test\CoderDecoderTest {
} }
/** /**
* @covers MensBeam\Intl\Encoding\Big5::err * @covers MensBeam\Intl\Encoding\Big5::errDec
*/ */
public function testReplacementModes() { public function testReplacementModes() {
return parent::testReplacementModes(); return parent::testReplacementModes();

4
tests/cases/Encoding/TestEUCKR.php

@ -31,7 +31,7 @@ class TestEUCKR extends \MensBeam\Intl\Test\CoderDecoderTest {
/** /**
* @dataProvider provideCodePoints * @dataProvider provideCodePoints
* @covers MensBeam\Intl\Encoding\EUCKR::encode * @covers MensBeam\Intl\Encoding\EUCKR::encode
* @covers MensBeam\Intl\Encoding\EUCKR::err * @covers MensBeam\Intl\Encoding\EUCKR::errEnc
*/ */
public function testEncodeCodePoints(bool $fatal, $input, $exp) { public function testEncodeCodePoints(bool $fatal, $input, $exp) {
return parent::testEncodeCodePoints($fatal, $input, $exp); return parent::testEncodeCodePoints($fatal, $input, $exp);
@ -112,7 +112,7 @@ class TestEUCKR extends \MensBeam\Intl\Test\CoderDecoderTest {
} }
/** /**
* @covers MensBeam\Intl\Encoding\EUCKR::err * @covers MensBeam\Intl\Encoding\EUCKR::errDec
*/ */
public function testReplacementModes() { public function testReplacementModes() {
return parent::testReplacementModes(); return parent::testReplacementModes();

6
tests/cases/Encoding/TestGB18030.php

@ -36,9 +36,9 @@ class TestGB18030 extends \MensBeam\Intl\Test\CoderDecoderTest {
/** /**
* @dataProvider provideCodePoints * @dataProvider provideCodePoints
* @covers MensBeam\Intl\Encoding\GB18030::encode * @covers MensBeam\Intl\Encoding\GB18030::encode
* @covers MensBeam\Intl\Encoding\GB18030::err * @covers MensBeam\Intl\Encoding\GB18030::errEnc
* @covers MensBeam\Intl\Encoding\GBK::encode * @covers MensBeam\Intl\Encoding\GBK::encode
* @covers MensBeam\Intl\Encoding\GBK::err * @covers MensBeam\Intl\Encoding\GBK::errEnc
*/ */
public function testEncodeCodePoints(bool $fatal, $input, $exp, $class = self::class) { public function testEncodeCodePoints(bool $fatal, $input, $exp, $class = self::class) {
$this->testedClass = $class; $this->testedClass = $class;
@ -120,7 +120,7 @@ class TestGB18030 extends \MensBeam\Intl\Test\CoderDecoderTest {
} }
/** /**
* @covers MensBeam\Intl\Encoding\GB18030::err * @covers MensBeam\Intl\Encoding\GB18030::errDec
*/ */
public function testReplacementModes() { public function testReplacementModes() {
return parent::testReplacementModes(); return parent::testReplacementModes();

4
tests/cases/Encoding/TestSingleByte.php

@ -186,7 +186,7 @@ class TestSingleByte extends \MensBeam\Intl\Test\CoderDecoderTest {
/** /**
* @dataProvider provideBrokenStrings * @dataProvider provideBrokenStrings
* @covers MensBeam\Intl\Encoding\SingleByteEncoding::err * @covers MensBeam\Intl\Encoding\SingleByteEncoding::errDec
*/ */
public function testReplacementModes(string $input = "", string $class = SingleByteEncoding::class) { public function testReplacementModes(string $input = "", string $class = SingleByteEncoding::class) {
$this->testedClass = $class; $this->testedClass = $class;
@ -286,7 +286,7 @@ class TestSingleByte extends \MensBeam\Intl\Test\CoderDecoderTest {
/** /**
* @dataProvider provideInvalids * @dataProvider provideInvalids
* @covers MensBeam\Intl\Encoding\SingleByteEncoding::encode * @covers MensBeam\Intl\Encoding\SingleByteEncoding::encode
* @covers MensBeam\Intl\Encoding\SingleByteEncoding::err * @covers MensBeam\Intl\Encoding\SingleByteEncoding::errEnc
*/ */
public function testEncodeInvalidCodePoints(string $class, bool $mode, int $input, $exp) { public function testEncodeInvalidCodePoints(string $class, bool $mode, int $input, $exp) {
if ($exp instanceof \Throwable) { if ($exp instanceof \Throwable) {

2
tests/cases/Encoding/TestUTF16LE.php

@ -102,7 +102,7 @@ class TestUTF16LE extends \MensBeam\Intl\Test\DecoderTest {
} }
/** /**
* @covers MensBeam\Intl\Encoding\UTF16::err * @covers MensBeam\Intl\Encoding\UTF16::errDec
*/ */
public function testReplacementModes() { public function testReplacementModes() {
return parent::testReplacementModes(); return parent::testReplacementModes();

4
tests/cases/Encoding/TestUTF8.php

@ -31,7 +31,7 @@ class TestUTF8 extends \MensBeam\Intl\Test\CoderDecoderTest {
/** /**
* @dataProvider provideCodePoints * @dataProvider provideCodePoints
* @covers MensBeam\Intl\Encoding\UTF8::encode * @covers MensBeam\Intl\Encoding\UTF8::encode
* @covers MensBeam\Intl\Encoding\UTF8::err * @covers MensBeam\Intl\Encoding\UTF8::errEnc
*/ */
public function testEncodeCodePoints(bool $fatal, $input, $exp) { public function testEncodeCodePoints(bool $fatal, $input, $exp) {
return parent::testEncodeCodePoints($fatal, $input, $exp); return parent::testEncodeCodePoints($fatal, $input, $exp);
@ -112,7 +112,7 @@ class TestUTF8 extends \MensBeam\Intl\Test\CoderDecoderTest {
} }
/** /**
* @covers MensBeam\Intl\Encoding\UTF8::err * @covers MensBeam\Intl\Encoding\UTF8::errDec
*/ */
public function testReplacementModes() { public function testReplacementModes() {
return parent::testReplacementModes(); return parent::testReplacementModes();

2
tests/cases/Encoding/TestXUserDefined.php

@ -93,7 +93,7 @@ class TestXUserDefined extends \MensBeam\Intl\Test\DecoderTest {
} }
/** /**
* @covers MensBeam\Intl\Encoding\XUserDefined::err * @covers MensBeam\Intl\Encoding\XUserDefined::errDec
*/ */
public function testReplacementModes() { public function testReplacementModes() {
return parent::testReplacementModes(); return parent::testReplacementModes();

Loading…
Cancel
Save