From 14926c4cc991c4d9bc9e39e00d97f7d5830baf79 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Jun 2026 11:06:38 +0200 Subject: [PATCH 1/8] HTML API: Limit leading newline serialization to HTML elements --- .../html-api/class-wp-html-processor.php | 6 +- .../html-api/wpHtmlProcessor-serialize.php | 82 +++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 35d91fad3129c..b0d3d53755da1 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1461,8 +1461,8 @@ public function serialize_token(): string { /* * The HTML parser strips a leading newline immediately after the start - * tag of TEXTAREA, PRE, and LISTING elements. When serializing, prepend - * a leading newline to ensure the semantic HTML content is preserved. + * tag of HTML TEXTAREA, PRE, and LISTING elements. When serializing, + * prepend a leading newline to ensure the semantic HTML content is preserved. * * For example, `
\n\nX
` must not become `
\nX
` because its content * has changed. However, `
X
` and `
\nX
` are _equivalent_. @@ -1481,7 +1481,7 @@ public function serialize_token(): string { * * @see https://html.spec.whatwg.org/multipage/parsing.html */ - if ( 'TEXTAREA' === $tag_name || 'PRE' === $tag_name || 'LISTING' === $tag_name ) { + if ( $in_html && ( 'TEXTAREA' === $tag_name || 'PRE' === $tag_name || 'LISTING' === $tag_name ) ) { $html .= "\n"; } diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index e516addb6c314..fb11e414b8201 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -340,6 +340,88 @@ public function test_normalize_special_leading_newline_handling( string $input, $this->assertEqualHTML( $expected, $normalized_twice ); } + /** + * Ensures that the special leading newline rule applies only in the HTML namespace. + * + * @ticket 64607 + * + * @dataProvider data_provider_special_leading_newline_namespace_serialization + * + * @param string $input HTML input containing a PRE, LISTING, or TEXTAREA element. + * @param string $expected Expected normalized output. + */ + public function test_special_leading_newline_rule_depends_on_namespace( string $input, string $expected ) { + $normalized = WP_HTML_Processor::normalize( $input ); + $this->assertSame( + $expected, + $normalized, + 'Should serialize special leading newlines according to the element namespace.' + ); + $this->assertSame( + $expected, + WP_HTML_Processor::normalize( $normalized ), + 'Normalizing already-normalized special leading newlines should not change them.' + ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_provider_special_leading_newline_namespace_serialization() { + return array( + 'MathML TEXTAREA' => array( + '', + '', + ), + 'MathML TEXTAREA with leading newline' => array( + "", + "", + ), + 'SVG TEXTAREA' => array( + '', + '', + ), + 'SVG TEXTAREA with leading newline' => array( + "", + "", + ), + 'HTML TEXTAREA inside SVG HTML integration point' => array( + '', + "", + ), + 'HTML TEXTAREA with leading newline inside SVG HTML integration point' => array( + "", + "", + ), + 'HTML TEXTAREA inside MathML text integration point' => array( + '', + "", + ), + 'HTML TEXTAREA with leading newline inside MathML text integration point' => array( + "", + "", + ), + 'HTML TEXTAREA inside MathML HTML integration point' => array( + '', + "", + ), + 'HTML TEXTAREA with leading newline inside MathML HTML integration point' => array( + "", + "", + ), + 'HTML PRE after exiting SVG foreign content' => array( + '
X
', + "
\nX
", + ), + 'HTML LISTING after exiting MathML foreign content' => array( + 'X', + "\nX", + ), + ); + } + /** * Ensures that fuzzer-discovered inputs do not emit native PHP errors. * From e7a6735b14a71992fa9497877492e3ffd9b0710f Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 15:49:13 +0200 Subject: [PATCH 2/8] Clairfy HTML content language --- src/wp-includes/html-api/class-wp-html-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 0124d8e357b9e..5f15da5383f34 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1468,7 +1468,7 @@ public function serialize_token(): string { /* * The HTML parser strips a leading newline immediately after the start - * tag of HTML TEXTAREA, PRE, and LISTING elements. When serializing, + * tag of TEXTAREA, PRE, and LISTING elements in HTML content. When serializing, * prepend a leading newline to ensure the semantic HTML content is preserved. * * For example, `
\n\nX
` must not become `
\nX
` because its content From ef43091ce87f152ca379c856e0f63ea8e54e51a3 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 16:17:23 +0200 Subject: [PATCH 3/8] HTML API: Consolidate leading newline namespace tests --- .../html-api/wpHtmlProcessor-serialize.php | 170 +++++++++--------- 1 file changed, 83 insertions(+), 87 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index 34193f098adc4..441dd2e6f9dbe 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -470,96 +470,32 @@ public static function data_provider_serialize_doctype() { * * @dataProvider data_provider_normalize_special_leading_newline_cases * - * @param string $input HTML input containing leading newlines in PRE, LISTING, or TEXTAREA elements. - * @param string $expected Expected output after normalization, which should preserve leading newlines. + * @param string $input HTML input containing leading newlines in PRE, LISTING, or TEXTAREA elements. + * @param string $expected Expected output after normalization, which should preserve leading newlines. + * @param bool $assert_exact Optional. Whether to compare the exact normalized output. */ - public function test_normalize_special_leading_newline_handling( string $input, string $expected ) { + public function test_normalize_special_leading_newline_handling( string $input, string $expected, bool $assert_exact = false ) { $normalized = WP_HTML_Processor::normalize( $input ); - $this->assertEqualHTML( $expected, $normalized ); - $normalized_twice = WP_HTML_Processor::normalize( $normalized ); - $this->assertEqualHTML( $expected, $normalized_twice ); - } - - /** - * Ensures that the special leading newline rule applies only in the HTML namespace. - * - * @ticket 64607 - * - * @dataProvider data_provider_special_leading_newline_namespace_serialization - * - * @param string $input HTML input containing a PRE, LISTING, or TEXTAREA element. - * @param string $expected Expected normalized output. - */ - public function test_special_leading_newline_rule_depends_on_namespace( string $input, string $expected ) { - $normalized = WP_HTML_Processor::normalize( $input ); - $this->assertSame( - $expected, - $normalized, - 'Should serialize special leading newlines according to the element namespace.' - ); - $this->assertSame( - $expected, - WP_HTML_Processor::normalize( $normalized ), - 'Normalizing already-normalized special leading newlines should not change them.' - ); - } + if ( $assert_exact ) { + $this->assertSame( + $expected, + $normalized, + 'Should serialize special leading newlines according to the element namespace.' + ); + } else { + $this->assertEqualHTML( $expected, $normalized ); + } - /** - * Data provider. - * - * @return array[] - */ - public static function data_provider_special_leading_newline_namespace_serialization() { - return array( - 'MathML TEXTAREA' => array( - '', - '', - ), - 'MathML TEXTAREA with leading newline' => array( - "", - "", - ), - 'SVG TEXTAREA' => array( - '', - '', - ), - 'SVG TEXTAREA with leading newline' => array( - "", - "", - ), - 'HTML TEXTAREA inside SVG HTML integration point' => array( - '', - "", - ), - 'HTML TEXTAREA with leading newline inside SVG HTML integration point' => array( - "", - "", - ), - 'HTML TEXTAREA inside MathML text integration point' => array( - '', - "", - ), - 'HTML TEXTAREA with leading newline inside MathML text integration point' => array( - "", - "", - ), - 'HTML TEXTAREA inside MathML HTML integration point' => array( - '', - "", - ), - 'HTML TEXTAREA with leading newline inside MathML HTML integration point' => array( - "", - "", - ), - 'HTML PRE after exiting SVG foreign content' => array( - '
X
', - "
\nX
", - ), - 'HTML LISTING after exiting MathML foreign content' => array( - 'X', - "\nX", - ), - ); + $normalized_twice = WP_HTML_Processor::normalize( $normalized ); + if ( $assert_exact ) { + $this->assertSame( + $expected, + $normalized_twice, + 'Normalizing already-normalized special leading newlines should not change them.' + ); + } else { + $this->assertEqualHTML( $expected, $normalized_twice ); + } } /** @@ -779,6 +715,66 @@ public static function data_provider_normalize_special_leading_newline_cases() { "", "", ), + 'MathML TEXTAREA does not receive leading newline' => array( + '', + '', + true, + ), + 'MathML TEXTAREA preserves leading newline' => array( + "", + "", + true, + ), + 'SVG TEXTAREA does not receive leading newline' => array( + '', + '', + true, + ), + 'SVG TEXTAREA preserves leading newline' => array( + "", + "", + true, + ), + 'HTML TEXTAREA inside SVG HTML integration point receives leading newline' => array( + '', + "", + true, + ), + 'HTML TEXTAREA inside SVG HTML integration point preserves leading newlines' => array( + "", + "", + true, + ), + 'HTML TEXTAREA inside MathML text integration point receives leading newline' => array( + '', + "", + true, + ), + 'HTML TEXTAREA inside MathML text integration point preserves leading newlines' => array( + "", + "", + true, + ), + 'HTML TEXTAREA inside MathML HTML integration point receives leading newline' => array( + '', + "", + true, + ), + 'HTML TEXTAREA inside MathML HTML integration point preserves leading newlines' => array( + "", + "", + true, + ), + 'HTML PRE after exiting SVG foreign content receives leading newline' => array( + '
X
', + "
\nX
", + true, + ), + 'HTML LISTING after exiting MathML foreign content receives leading newline' => array( + 'X', + "\nX", + true, + ), ); } } From 88b5dc0f464806bf3cf13bf43de5dc56feedf64b Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 18:10:15 +0200 Subject: [PATCH 4/8] Remove expect_exact test arg --- .../html-api/wpHtmlProcessor-serialize.php | 40 +++---------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index 441dd2e6f9dbe..651f5b61869d0 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -472,30 +472,12 @@ public static function data_provider_serialize_doctype() { * * @param string $input HTML input containing leading newlines in PRE, LISTING, or TEXTAREA elements. * @param string $expected Expected output after normalization, which should preserve leading newlines. - * @param bool $assert_exact Optional. Whether to compare the exact normalized output. */ - public function test_normalize_special_leading_newline_handling( string $input, string $expected, bool $assert_exact = false ) { + public function test_normalize_special_leading_newline_handling( string $input, string $expected ) { $normalized = WP_HTML_Processor::normalize( $input ); - if ( $assert_exact ) { - $this->assertSame( - $expected, - $normalized, - 'Should serialize special leading newlines according to the element namespace.' - ); - } else { - $this->assertEqualHTML( $expected, $normalized ); - } - + $this->assertEqualHTML( $expected, $normalized ); $normalized_twice = WP_HTML_Processor::normalize( $normalized ); - if ( $assert_exact ) { - $this->assertSame( - $expected, - $normalized_twice, - 'Normalizing already-normalized special leading newlines should not change them.' - ); - } else { - $this->assertEqualHTML( $expected, $normalized_twice ); - } + $this->assertEqualHTML( $expected, $normalized_twice ); } /** @@ -671,9 +653,9 @@ public static function data_provider_normalized_fuzzer_cases_that_should_be_idem /** * Data provider. * - * @return array[] + * @return array */ - public static function data_provider_normalize_special_leading_newline_cases() { + public static function data_provider_normalize_special_leading_newline_cases(): array { return array( 'Leading newline in PRE' => array( "
\nline 1\nline 2
", @@ -718,62 +700,50 @@ public static function data_provider_normalize_special_leading_newline_cases() { 'MathML TEXTAREA does not receive leading newline' => array( '', '', - true, ), 'MathML TEXTAREA preserves leading newline' => array( "", "", - true, ), 'SVG TEXTAREA does not receive leading newline' => array( '', '', - true, ), 'SVG TEXTAREA preserves leading newline' => array( "", "", - true, ), 'HTML TEXTAREA inside SVG HTML integration point receives leading newline' => array( '', "", - true, ), 'HTML TEXTAREA inside SVG HTML integration point preserves leading newlines' => array( "", "", - true, ), 'HTML TEXTAREA inside MathML text integration point receives leading newline' => array( '', "", - true, ), 'HTML TEXTAREA inside MathML text integration point preserves leading newlines' => array( "", "", - true, ), 'HTML TEXTAREA inside MathML HTML integration point receives leading newline' => array( '', "", - true, ), 'HTML TEXTAREA inside MathML HTML integration point preserves leading newlines' => array( "", "", - true, ), 'HTML PRE after exiting SVG foreign content receives leading newline' => array( '
X
', "
\nX
", - true, ), 'HTML LISTING after exiting MathML foreign content receives leading newline' => array( 'X', "\nX", - true, ), ); } From a4788b3561ac149b731990f0a9fd5645c62f9521 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 18:23:51 +0200 Subject: [PATCH 5/8] HTML API: Focus leading newline normalization tests --- .../html-api/wpHtmlProcessor-serialize.php | 62 +++++-------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index 651f5b61869d0..b2af09684ebcf 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -463,21 +463,21 @@ public static function data_provider_serialize_doctype() { } /** - * Ensures that leading newlines in PRE, LISTING, and TEXTAREA elements are preserved upon normalization, - * and that normalization is idempotent in these cases. + * Ensures that leading newlines in PRE, LISTING, and TEXTAREA elements are normalized + * according to their parsing namespace, and that normalization is idempotent in these cases. * * @ticket 64607 * * @dataProvider data_provider_normalize_special_leading_newline_cases * - * @param string $input HTML input containing leading newlines in PRE, LISTING, or TEXTAREA elements. - * @param string $expected Expected output after normalization, which should preserve leading newlines. + * @param string $input HTML input containing leading newlines in PRE, LISTING, or TEXTAREA elements. + * @param string $expected Expected exact output after normalization. */ public function test_normalize_special_leading_newline_handling( string $input, string $expected ) { $normalized = WP_HTML_Processor::normalize( $input ); - $this->assertEqualHTML( $expected, $normalized ); + $this->assertSame( $expected, $normalized ); $normalized_twice = WP_HTML_Processor::normalize( $normalized ); - $this->assertEqualHTML( $expected, $normalized_twice ); + $this->assertSame( $expected, $normalized_twice ); } /** @@ -659,7 +659,7 @@ public static function data_provider_normalize_special_leading_newline_cases(): return array( 'Leading newline in PRE' => array( "
\nline 1\nline 2
", - "
line 1\nline 2
", + "
\nline 1\nline 2
", ), 'Double leading newline in PRE' => array( "
\n\nline 2\nline 3
", @@ -667,7 +667,7 @@ public static function data_provider_normalize_special_leading_newline_cases(): ), 'Multiple text nodes inside PRE' => array( "
\nline 1 still line 1
", - '
line 1 still line 1
', + "
\nline 1 still line 1
", ), 'Multiple text nodes inside PRE with leading newlines' => array( "
\n\nline 2 still line 2
", @@ -675,7 +675,7 @@ public static function data_provider_normalize_special_leading_newline_cases(): ), 'Leading newline in LISTING' => array( "\nline 1\nline 2", - "line 1\nline 2", + "\nline 1\nline 2", ), 'Double leading newline in LISTING' => array( "\n\nline 2\nline 3", @@ -683,7 +683,7 @@ public static function data_provider_normalize_special_leading_newline_cases(): ), 'Multiple text nodes inside LISTING' => array( "\nline 1 still line 1", - 'line 1 still line 1', + "\nline 1 still line 1", ), 'Multiple text nodes inside LISTING with leading newlines' => array( "\n\nline 2 still line 2", @@ -691,60 +691,28 @@ public static function data_provider_normalize_special_leading_newline_cases(): ), 'Leading newline in TEXTAREA' => array( "", - "", + "", ), 'Double leading newline in TEXTAREA' => array( "", "", ), - 'MathML TEXTAREA does not receive leading newline' => array( + 'Foreign MathML TEXTAREA does not ignore leading newlines' => array( '', '', ), - 'MathML TEXTAREA preserves leading newline' => array( + 'Foreign MathML TEXTAREA preserves leading newline' => array( "", "", ), - 'SVG TEXTAREA does not receive leading newline' => array( + 'Foreign SVG TEXTAREA does not ignore leading newlines' => array( '', '', ), - 'SVG TEXTAREA preserves leading newline' => array( + 'Foreign SVG TEXTAREA preserves leading newline' => array( "", "", ), - 'HTML TEXTAREA inside SVG HTML integration point receives leading newline' => array( - '', - "", - ), - 'HTML TEXTAREA inside SVG HTML integration point preserves leading newlines' => array( - "", - "", - ), - 'HTML TEXTAREA inside MathML text integration point receives leading newline' => array( - '', - "", - ), - 'HTML TEXTAREA inside MathML text integration point preserves leading newlines' => array( - "", - "", - ), - 'HTML TEXTAREA inside MathML HTML integration point receives leading newline' => array( - '', - "", - ), - 'HTML TEXTAREA inside MathML HTML integration point preserves leading newlines' => array( - "", - "", - ), - 'HTML PRE after exiting SVG foreign content receives leading newline' => array( - '
X
', - "
\nX
", - ), - 'HTML LISTING after exiting MathML foreign content receives leading newline' => array( - 'X', - "\nX", - ), ); } } From 5261d501a98a0a3fcae036d807f27da5d3e0fc65 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 18:25:57 +0200 Subject: [PATCH 6/8] HTML API: Document exact newline normalization assertions --- tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index b2af09684ebcf..94051ff3cab48 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -475,6 +475,13 @@ public static function data_provider_serialize_doctype() { */ public function test_normalize_special_leading_newline_handling( string $input, string $expected ) { $normalized = WP_HTML_Processor::normalize( $input ); + + /* + * Do not use assertEqualHTML() here. A leading newline after the start tag + * in HTML PRE, LISTING, and TEXTAREA elements is ignored when parsed, so + * `` and `` are equivalent + * HTML. This test asserts the exact normalized serialization. + */ $this->assertSame( $expected, $normalized ); $normalized_twice = WP_HTML_Processor::normalize( $normalized ); $this->assertSame( $expected, $normalized_twice ); From 4ad0bdd410ad1dec415cd4dd9af41857af170acc Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 18:31:49 +0200 Subject: [PATCH 7/8] HTML API: Assert semantic newline normalization --- .../tests/html-api/wpHtmlProcessor-serialize.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index 94051ff3cab48..b5f024c4c2d38 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -474,17 +474,18 @@ public static function data_provider_serialize_doctype() { * @param string $expected Expected exact output after normalization. */ public function test_normalize_special_leading_newline_handling( string $input, string $expected ) { - $normalized = WP_HTML_Processor::normalize( $input ); + $normalized = WP_HTML_Processor::normalize( $input ); + $normalized_twice = WP_HTML_Processor::normalize( $normalized ); /* - * Do not use assertEqualHTML() here. A leading newline after the start tag - * in HTML PRE, LISTING, and TEXTAREA elements is ignored when parsed, so - * `` and `` are equivalent - * HTML. This test asserts the exact normalized serialization. + * Byte equality pins normalize()'s serialized form; HTML equality verifies + * semantic equivalence. This distinction matters because HTML parsing ignores + * one leading LF after PRE, LISTING, and TEXTAREA start tags. */ $this->assertSame( $expected, $normalized ); - $normalized_twice = WP_HTML_Processor::normalize( $normalized ); $this->assertSame( $expected, $normalized_twice ); + $this->assertEqualHTML( $input, $normalized ); + $this->assertEqualHTML( $normalized, $normalized_twice ); } /** From a0e82e066ab23ef0623d9e6b56e7a028db3d2bd6 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 25 Jun 2026 18:34:18 +0200 Subject: [PATCH 8/8] Normalize twice after once is OK --- tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index b5f024c4c2d38..e332ec12a0a91 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -474,8 +474,7 @@ public static function data_provider_serialize_doctype() { * @param string $expected Expected exact output after normalization. */ public function test_normalize_special_leading_newline_handling( string $input, string $expected ) { - $normalized = WP_HTML_Processor::normalize( $input ); - $normalized_twice = WP_HTML_Processor::normalize( $normalized ); + $normalized = WP_HTML_Processor::normalize( $input ); /* * Byte equality pins normalize()'s serialized form; HTML equality verifies @@ -483,8 +482,10 @@ public function test_normalize_special_leading_newline_handling( string $input, * one leading LF after PRE, LISTING, and TEXTAREA start tags. */ $this->assertSame( $expected, $normalized ); - $this->assertSame( $expected, $normalized_twice ); $this->assertEqualHTML( $input, $normalized ); + + $normalized_twice = WP_HTML_Processor::normalize( $normalized ); + $this->assertSame( $expected, $normalized_twice ); $this->assertEqualHTML( $normalized, $normalized_twice ); }