From 3d09d4d75b29b866911501256d848f7a23243bcd Mon Sep 17 00:00:00 2001 From: Laurent Lyaudet Date: Tue, 16 Jun 2026 17:13:23 +0200 Subject: [PATCH 1/2] LL: tests/Utf8ValidatorTest.php split the "mega test" into tests for each error type. --- tests/Utf8ValidatorTest.php | 120 ++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) diff --git a/tests/Utf8ValidatorTest.php b/tests/Utf8ValidatorTest.php index ed432a8..373fb36 100644 --- a/tests/Utf8ValidatorTest.php +++ b/tests/Utf8ValidatorTest.php @@ -32,7 +32,7 @@ public function testValidUtf8() } } - public function testAllErrorTypes() + public function testNotAContinuationOctet() { try { Utf8Validator::validate('"abcd'.chr(233).'"'); @@ -41,6 +41,19 @@ public function testAllErrorTypes() $this->assertContains('Non-UTF8 character found', $e->getMessage()); $this->assertContains(' which is not a continuation octet.', $e->getMessage()); } + for ($i = 246; $i < 255; ++$i) { // 245 and 255 already forbidden + try { + Utf8Validator::validate('"abcd'.chr(195).chr($i).'"'); + $this->fail('"abcd\d195\d'.$i.'" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains(' which is not a continuation octet.', $e->getMessage()); + } + } + } + + public function testAllErrorTypes() + { try { Utf8Validator::validate('"abcd'.chr(233)); $this->fail('ISO 8859-15 "abcdé should not pass validation.'); @@ -126,12 +139,111 @@ public function testAllErrorTypes() $this->assertContains('Non-UTF8 character found', $e->getMessage()); $this->assertContains(' which is invalid.', $e->getMessage()); } + } + } + + public function testPrematureEndOfString() + { + try { + Utf8Validator::validate('"abcd'.chr(233)); + $this->fail('ISO 8859-15 "abcdé should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains( + ', end of string was found instead of a continuation octet.', + $e->getMessage() + ); + } + } + + public function testForbiddenOctets() + { + $forbiddenOctets = array( + 192, + 193, + 245, + 255 + ); + foreach ($forbiddenOctets as $forbiddenOctet) { try { - Utf8Validator::validate('"abcd'.chr(195).chr($i).'"'); - $this->fail('"abcd\d195\d'.$i.'" should not pass validation.'); + Utf8Validator::validate('"abcd'.chr(233).chr($forbiddenOctet).'"'); + $this->fail('"abcd\d233\d'.$forbiddenOctet.'" should not pass validation.'); } catch (InvalidEncodingException $e) { $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains(' which is not a continuation octet.', $e->getMessage()); + $this->assertContains( + ' which is one of the four forbidden values (C0, C1, F5, FF).', + $e->getMessage() + ); + } + try { + Utf8Validator::validate('"abcd'.chr($forbiddenOctet).'"'); + $this->fail('"abcd\d'.$forbiddenOctet.'" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains( + ' which is one of the four forbidden values (C0, C1, F5, FF).', + $e->getMessage() + ); + } + } + } + + public function testUnwantedContinuationOctet() + { + try { + Utf8Validator::validate('"abcd'.chr(129).'"'); + $this->fail('"abcd\d129" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains( + ' which is a continuation octet.', + $e->getMessage() + ); + } + } + + public function testForbiddenSurrogatePairs() + { + for ($i = 160; $i <= 191; ++$i) { + try { + Utf8Validator::validate('"abcd'.chr(237).chr($i).chr(129).'"'); + $this->fail('"abcd\d237\d'.$i.'\d129" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains( + ' which is into the forbidden range of surrogate pairs.', + $e->getMessage() + ); + } + try { + Utf8Validator::validate('"abcd'.chr(237).chr($i).'"'); + $this->fail('"abcd\d237\d'.$i.'" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains( + ' which is into the forbidden range of surrogate pairs.', + $e->getMessage() + ); + } + } + } + + public function testOtherInvalidOctetSequences() + { + for ($i = 246; $i < 255; ++$i) { // 245 and 255 already forbidden + try { + Utf8Validator::validate('"abcd'.chr($i).chr(129).chr(129).chr(129).'"'); + $this->fail('"abcd\d'.$i.'\d129\d129\d129" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains(' which is invalid.', $e->getMessage()); + } + try { + Utf8Validator::validate('"abcd'.chr($i).'"'); + $this->fail('"abcd\d'.$i.'" should not pass validation.'); + } catch (InvalidEncodingException $e) { + $this->assertContains('Non-UTF8 character found', $e->getMessage()); + $this->assertContains(' which is invalid.', $e->getMessage()); } } } From 68dd8ecfe9abe88fb648343552a849a884dadf9c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 17 Jun 2026 11:28:25 +0200 Subject: [PATCH 2/2] Remove outdated method --- tests/Utf8ValidatorTest.php | 90 ------------------------------------- 1 file changed, 90 deletions(-) diff --git a/tests/Utf8ValidatorTest.php b/tests/Utf8ValidatorTest.php index 373fb36..9b4cad4 100644 --- a/tests/Utf8ValidatorTest.php +++ b/tests/Utf8ValidatorTest.php @@ -52,96 +52,6 @@ public function testNotAContinuationOctet() } } - public function testAllErrorTypes() - { - try { - Utf8Validator::validate('"abcd'.chr(233)); - $this->fail('ISO 8859-15 "abcdé should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains( - ', end of string was found instead of a continuation octet.', - $e->getMessage() - ); - } - $forbiddenOctets = array( - 192, - 193, - 245, - 255 - ); - foreach ($forbiddenOctets as $forbiddenOctet) { - try { - Utf8Validator::validate('"abcd'.chr(233).chr($forbiddenOctet).'"'); - $this->fail('"abcd\d233\d'.$forbiddenOctet.'" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains( - ' which is one of the four forbidden values (C0, C1, F5, FF).', - $e->getMessage() - ); - } - try { - Utf8Validator::validate('"abcd'.chr($forbiddenOctet).'"'); - $this->fail('"abcd\d'.$forbiddenOctet.'" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains( - ' which is one of the four forbidden values (C0, C1, F5, FF).', - $e->getMessage() - ); - } - } - try { - Utf8Validator::validate('"abcd'.chr(129).'"'); - $this->fail('"abcd\d129" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains( - ' which is a continuation octet.', - $e->getMessage() - ); - } - for ($i = 160; $i <= 191; ++$i) { - try { - Utf8Validator::validate('"abcd'.chr(237).chr($i).chr(129).'"'); - $this->fail('"abcd\d237\d'.$i.'\d129" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains( - ' which is into the forbidden range of surrogate pairs.', - $e->getMessage() - ); - } - try { - Utf8Validator::validate('"abcd'.chr(237).chr($i).'"'); - $this->fail('"abcd\d237\d'.$i.'" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains( - ' which is into the forbidden range of surrogate pairs.', - $e->getMessage() - ); - } - } - for ($i = 246; $i < 255; ++$i) { // 245 and 255 already forbidden - try { - Utf8Validator::validate('"abcd'.chr($i).chr(129).chr(129).chr(129).'"'); - $this->fail('"abcd\d'.$i.'\d129\d129\d129" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains(' which is invalid.', $e->getMessage()); - } - try { - Utf8Validator::validate('"abcd'.chr($i).'"'); - $this->fail('"abcd\d'.$i.'" should not pass validation.'); - } catch (InvalidEncodingException $e) { - $this->assertContains('Non-UTF8 character found', $e->getMessage()); - $this->assertContains(' which is invalid.', $e->getMessage()); - } - } - } - public function testPrematureEndOfString() { try {