From 159e290a334aa93556584baaeeacf3920bd03c0d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 7 Aug 2026 08:33:24 +0200 Subject: [PATCH] Align tests with PHP 8.6 changes to ext/tidy and ext/intl php-src 4782ec55aae added ZEND_ACC_NOT_SERIALIZABLE to tidyNode, which ext/deepclone honours by refusing the class. Following the design principle that the deepclone polyfill mirrors the newest native state, tidyNode joins the classes it rejects on every version; the extension itself only rejects it on 8.6+, so the test keeps the round-trip expectation for that case. php-src 94e8c54ef27 removed the doubled article from the ValueError thrown by normalizer_normalize(), so the message is now conditional on the version. Also de-flake Php73Test::testHardwareTimeAsArrayNanos: it compared the two hrtime() components separately, which fails whenever the pair straddles a whole second. --- src/DeepClone/DeepClone.php | 1 + src/Intl/Normalizer/Normalizer.php | 3 ++- tests/DeepClone/DeepCloneTest.php | 25 ++++++++++++++++++------ tests/Intl/Normalizer/NormalizerTest.php | 2 +- tests/Php73/Php73Test.php | 7 +++++-- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/DeepClone/DeepClone.php b/src/DeepClone/DeepClone.php index 31421da7..082d1d8e 100644 --- a/src/DeepClone/DeepClone.php +++ b/src/DeepClone/DeepClone.php @@ -25,6 +25,7 @@ final class DeepClone 'XMLReader' => true, 'SNMP' => true, 'tidy' => true, + 'tidyNode' => true, ]; private static array $reflectors = []; diff --git a/src/Intl/Normalizer/Normalizer.php b/src/Intl/Normalizer/Normalizer.php index e43092dd..d8c71b87 100644 --- a/src/Intl/Normalizer/Normalizer.php +++ b/src/Intl/Normalizer/Normalizer.php @@ -129,7 +129,8 @@ public static function normalize(string $s, int $form = self::FORM_C) return false; } - throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); + // the doubled article was fixed in PHP 8.6 + throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a '.(80600 > \PHP_VERSION_ID ? 'a ' : '').'valid normalization form'); } if ('' === $s) { diff --git a/tests/DeepClone/DeepCloneTest.php b/tests/DeepClone/DeepCloneTest.php index 3997acd7..bbab37b7 100644 --- a/tests/DeepClone/DeepCloneTest.php +++ b/tests/DeepClone/DeepCloneTest.php @@ -1193,18 +1193,31 @@ public function testMongoDbBsonRoundTrip() /** * @requires extension tidy */ - public function testTidyNodeRoundTrip() + public function testTidyNodeIsNotInstantiable() { $tidy = new \tidy(); $tidy->parseString('

hello

', [], 'utf8'); $b = $tidy->body()->child[0]->child[0]; // node - $clone = deepclone_from_array(deepclone_to_array($b)); + if (\PHP_VERSION_ID < 80600 && \extension_loaded('deepclone') && !TestListenerTrait::$enabledPolyfills) { + // tidyNode is final and bare-instantiable there, so the extension + // still restores it property by property. + $clone = deepclone_from_array(deepclone_to_array($b)); - $this->assertInstanceOf(\tidyNode::class, $clone); - $this->assertNotSame($b, $clone); - $this->assertSame($b->name, $clone->name); - $this->assertSame($b->value, $clone->value); + $this->assertInstanceOf(\tidyNode::class, $clone); + $this->assertNotSame($b, $clone); + $this->assertSame($b->name, $clone->name); + $this->assertSame($b->value, $clone->value); + + return; + } + + // tidyNode wraps a libTidy handle that cannot survive serialization; PHP 8.6 + // marks it NOT_SERIALIZABLE, and the polyfill mirrors that on every version. + $this->expectException(\DeepClone\NotInstantiableException::class); + $this->expectExceptionMessage('Type "tidyNode" is not instantiable.'); + + deepclone_to_array($b); } public function testHydrateScopedInstantiate() diff --git a/tests/Intl/Normalizer/NormalizerTest.php b/tests/Intl/Normalizer/NormalizerTest.php index 40230437..e4cbbc72 100644 --- a/tests/Intl/Normalizer/NormalizerTest.php +++ b/tests/Intl/Normalizer/NormalizerTest.php @@ -97,7 +97,7 @@ public function testNormalizeWithInvalidForm() { if (80000 <= \PHP_VERSION_ID) { $this->expectException(\ValueError::class); - $this->expectExceptionMessage('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); + $this->expectExceptionMessage('normalizer_normalize(): Argument #2 ($form) must be a '.(80600 > \PHP_VERSION_ID ? 'a ' : '').'valid normalization form'); } $this->assertFalse(normalizer_normalize('foo', -1)); diff --git a/tests/Php73/Php73Test.php b/tests/Php73/Php73Test.php index e56b33e9..076c31ec 100644 --- a/tests/Php73/Php73Test.php +++ b/tests/Php73/Php73Test.php @@ -83,8 +83,11 @@ public function testHardwareTimeAsArrayNanos() usleep(1000); $hrtime2 = hrtime(); - $this->assertSame(0, $hrtime2[0] - $hrtime[0]); - $this->assertGreaterThanOrEqual(1000000, $hrtime2[1] - $hrtime[1]); + // don't compare the components separately: the pair can straddle a whole second + $elapsed = 1000000000 * ($hrtime2[0] - $hrtime[0]) + $hrtime2[1] - $hrtime[1]; + + $this->assertGreaterThanOrEqual(1000000, $elapsed); + $this->assertLessThan(1000000000, $hrtime2[1]); } public function testHardwareTimeAsArraySeconds()