Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tag Processor: Fix a problem backing up too far after updating HTML #46598

Merged
merged 1 commit into from
Dec 20, 2022

Conversation

dmsnell
Copy link
Contributor

@dmsnell dmsnell commented Dec 15, 2022

What

Fixes a bug in the HTML Tag Processor when updating a document when the internal pointer is at the first tag in the document.

Why?

The Tag Processor shouldn't break code relying on it.

How?

A defect introduced in #46018 led to the tag processor backing up one index too far after flushing its queued changes on a document.

For most operations this didn't cause any harm because when immediately moving forward after an update, the next_tag() returned to the same spot: it was backing up to one position before the current tag instead of at the start of the current tag.

Unfortunately, when the current tag was the first in the document this would lead the processor to rewind to position -1, right before the start of the document, and lead to errors with strpos() when it received out-of-bounds indices.

In this fix we're correcting the adjustment for the HTML tag's < and documenting the math in the file so that it's clearer why it's there and providing guidance should another fix be necessary.

Props to @anton-vlasenko for finding this bug.

Testing Instructions

Run the PHP unit test suite with PHP <= 7.0.
Tests should start failing in trunk but should pass in this branch.

Temporarily merging in fix/parity-with-cores-php-ci-jobs in this PR to run such tests in CI.

Copy link
Contributor

@anton-vlasenko anton-vlasenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, @dmsnell!
It fixes lots of the tests.
But some PHP 5.6 tests still don't pass.
E.g.:

WP_HTML_Tag_Processor_Test::test_updating_attributes_works_even_in_malformed_html_2 with data set "Invalid entity inside attribute value" ('<img src="https://s0.wp.com/i.../span>', '<img foo="bar" class="firstTa.../span>')
[66](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:67)
Failed asserting that two strings are identical.
[67](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:68)
--- Expected
[68](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:69)
+++ Actual
[69](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:70)
@@ @@
[70](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:71)
-<img foo="bar" class="firstTag" src="https://s0.wp.com/i/atat.png" title="&; First &lt;title&gt; is &notit;" TITLE="second title" title="An Imperial &imperial; AT-AT"><span class="secondTag">test</span>
[71](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:72)
+<img class="firstTag" foo="bar" src="https://s0.wp.com/i/atat.png" title="&; First &lt;title&gt; is &notit;" TITLE="second title" title="An Imperial &imperial; AT-AT"><span class="secondTag">test</span>
[72](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:73)

[73](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:74)
/var/www/html/wp-content/plugins/gutenberg/phpunit/html/wp-html-tag-processor-test.php:1117
[74](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:75)
phpvfscomposer:///var/www/html/wp-content/plugins/gutenberg/vendor/phpunit/phpunit/phpunit:51
[75](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:76)

[76](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:77)
2) WP_HTML_Tag_Processor_Test::test_updating_attributes_works_even_in_malformed_html_2 with data set "Single and double quotes in attribute value" ('<p title="Demonstrating how t.../span>', '<p foo="bar" class="firstTag".../span>')
[77](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:78)
Failed asserting that two strings are identical.
[78](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:79)
--- Expected
[79](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:80)
+++ Actual
[80](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:81)
@@ @@
[81](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:82)
-<p foo="bar" class="firstTag" title="Demonstrating how to use single quote (') and double quote (&quot;)"><span class="secondTag">test</span>
[82](https://github.com/WordPress/gutenberg/actions/runs/3711263900/jobs/6291503554#step:14:83)
+<p class="firstTag" foo="bar" title="Demonstrating how to use single quote (') and double quote (&quot;)"><span class="secondTag">test</span>

@anton-vlasenko
Copy link
Contributor

I had to rebase this PR, because Github started to display incorrect "changed files" when I rebased https://github.com/WordPress/gutenberg/tree/fix/parity-with-cores-php-ci-jobs to the latest trunk.
Should this PR be converted to a draft to not accidentally merge it to trunk?

@adamziel
Copy link
Contributor

adamziel commented Dec 16, 2022

PHP 5.6 tests do not indicate a real problem – they just complain about the order of the generated attributes:

-<hr foo="bar" class="firstTag" id a  =5><span class="secondTag">test</span>
+<hr class="firstTag" foo="bar" id a  =5><span class="secondTag">test</span>

These updates are sorted as follows:

	private function apply_attributes_updates() {
		// ...
		usort( $this->attribute_updates, array( self::class, 'sort_start_ascending' ) );

		foreach ( $this->attribute_updates as $diff ) {
			// ...
		}
		// ...
	}

	private static function sort_start_ascending( $a, $b ) {
		return $a->start - $b->start;
	}

In the failed tests $a->start === $b->start – PHP 5.6 just has a different opinion on what to do with that than PHP 7+.

Ideally the tests wouldn't fail in this scenario. How about we provide an alternative acceptable output string where these attributes are listed in PHP 5.6 order @dmsnell ?

@anton-vlasenko
Copy link
Contributor

anton-vlasenko commented Dec 16, 2022

In the failed tests $a->start === $b->start – PHP 5.6 just has a different opinion on what to do with that than PHP 7+.

Ideally the tests wouldn't fail in this scenario. How about we provide an alternative acceptable output string where these attributes are listed in PHP 5.6 order @dmsnell ?

@adamziel
If you run the PHP 5.6 tests using the version of WP_HTML_Tag_Processor that was in use before #46018, the tests will pass.

I wonder why it passes the tests then?

The code responsible for attributes' sorting hasn't changed since then.

How about we provide an alternative acceptable output string where these attributes are listed in PHP 5.6 order @dmsnell ?

Doing so would make the tests pass, but it doesn't explain why the sorting doesn't work as it used to.
@dmsnell @adamziel

@anton-vlasenko
Copy link
Contributor

anton-vlasenko commented Dec 16, 2022

Doing so would make the tests pass, but it doesn't explain why the sorting doesn't work as it used to.

Ah, I get it. We didn't compare similar values in the callback function before #46018.
That's why the comparison logic didn't change, but we started to get failing tests.
This snippet illustrates the issue: https://3v4l.org/JO7urg
You were right about the root cause of the issue, @adamziel.

How about we provide an alternative acceptable output string where these attributes are listed in PHP 5.6 order

Yes. We also have to ensure that these alternative strings are only used when running the tests on PHP 5.x.

@dmsnell
Copy link
Contributor Author

dmsnell commented Dec 16, 2022

Thanks for working on this, both of you.

Should this PR be converted to a draft to not accidentally merge it to trunk?

This PR won't merge to trunk because it's based off of fix/parity-with-cores-php-ci-jobs. If the button is pressed then it will merge into that branch, and that's not much of a problem because we could undo it.

alternative strings

If I'm reading this right we're talking about providing alternative strings against which to compare the results based on differences in the sort algorithm across PHP versions. That's something that would quiet the tests but definitely increase the maintenance burden and confuse the people who come after us, so I'd rather we either fix the tests so that they aren't clamping down on behaviors we don't care to assert (for example, we don't care where the attributes appear) or we take the same "avoid the problem" approach but do it inside the tag processor.

I'll propose an update soon which does one of these.

It's noteworthy that PHP 8.0 changes the default behavior of the sort functions by making them stable, whereas in previous versions the sort is unstable. Simply changing the comparison string is not only risky, but it's only going to move us a couple steps forward before we would run into this same problem.

I'm thinking we could sort the updates by start and then by alphabetical order of the replacement. That shouldn't product a conflict because we shouldn't have multiple copies of the same attribute. This is all adjusting runtime behavior in order to appease deficient tests, and while I hate doing that, as a practical thing we discussed using DOMDocument in the tests and had a set of issues with doing that as well.

@dmsnell dmsnell changed the base branch from fix/parity-with-cores-php-ci-jobs to trunk December 16, 2022 20:59
@dmsnell dmsnell force-pushed the fix/tag-processor-back-too-far branch from f180522 to f138315 Compare December 16, 2022 20:59
@dmsnell
Copy link
Contributor Author

dmsnell commented Dec 16, 2022

Everything was passing in the tests in fix/parity-with-cores-php-ci-jobs, @anton-vlasenko, so I've rebased against trunk and I think this is ready to go.

It's a good update for trunk too so as soon as we're happy with it I'd like to merge it in.

dmsnell added a commit that referenced this pull request Dec 16, 2022
…46598)

A defect introduced in #46018 led to the tag processor backing up
one index too far after flushing its queued changes on a document.

For most operations this didn't cause any harm because when immediately
moving forward after an update, the `next_tag()` returned to the same
spot: it was backing up to one position before the current tag instead
of at the start of the current tag.

Unfortunately, when the current tag was the first in the document this
would lead the processor to rewind to position `-1`, right before the
start of the document, and lead to errors with `strpos()` when it
received out-of-bounds indices.

In this fix we're correcting the adjustment for the HTML tag's `<` and
documenting the math in the file so that it's clearer why it's there
and providing guidance should another fix be necessary.

As supporting work to this patch we're making the text replacement sort
stable, inside the tag processor, for when determining the order in which
to apply text replacements. This isn't necessary for the runtime but is
a nuissance for testing because different PHP versions produce different
unstable sort orderings and this prevents that from causing the unit
tests to fail in one version but pass in another.

Props to @anton-vlasenko for finding this bug.

Enforce sort stability when flushing out text replacements
@dmsnell dmsnell force-pushed the fix/tag-processor-back-too-far branch from f138315 to 5b7ef38 Compare December 16, 2022 21:02
Copy link
Contributor

@anton-vlasenko anton-vlasenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmsnell
When I run the tests locally (PHP 8.1), I get these errors (please see below).
Maybe it makes sense to add alternative strings, just as @adamziel proposed.
I'm not sure why Github's CI jobs don't fail. I'm investigating it.
P.S. I'm going to reinstall my local WP copy to see if it's somehow related.

I've asked around and it seems that this issue sometimes happens: sort works differently on different PHP installations.
So if the tests pass here, I guess that is fine.
Please disregard this message, @dmsnell

1) Block_Fixture_Test::test_kses_doesnt_change_fixtures with data set #69 ('<!-- wp:file {"href":"http://... -->\n', 'core__file__pdf-preview.seria...d.html')
Failed to match core__file__pdf-preview.serialized.html
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
 '<!-- wp:file {"href":"http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf","displayPreview":true,"previewHeight":370} -->
-<div class="wp-block-file"><object class="wp-block-file__embed" data="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf" type="application/pdf" style="width:100%;height:370px" aria-label="yolo"></object><a id="wp-block-file--media-_clientId_0" href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf">yolo</a><a href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-_clientId_0">Download</a></div>
+<div class="wp-block-file"><object></object><a id="wp-block-file--media-_clientId_0" href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf">yolo</a><a href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-_clientId_0">Download</a></div>
 <!-- /wp:file -->
 '

/Users/anton/html/wordpress.test/src/wp-content/plugins/gutenberg/phpunit/class-block-fixture-test.php:31

2) Block_Fixture_Test::test_kses_doesnt_change_fixtures with data set #70 ('<!-- wp:file {"href":"http://... -->\n', 'core__file__pdf-preview__depr...d.html')
Failed to match core__file__pdf-preview__deprecated-1.serialized.html
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
 '<!-- wp:file {"href":"http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf","displayPreview":true,"previewHeight":370} -->
-<div class="wp-block-file"><object class="wp-block-file__embed" data="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf" type="application/pdf" style="width:100%;height:370px" aria-label="yolo"></object><a href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf">yolo</a><a href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf" class="wp-block-file__button wp-element-button" download>Download</a></div>
+<div class="wp-block-file"><object></object><a href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf">yolo</a><a href="http://localhost:8889/wp-content/uploads/2021/04/yolo.pdf" class="wp-block-file__button wp-element-button" download>Download</a></div>
 <!-- /wp:file -->
 '

/Users/anton/html/wordpress.test/src/wp-content/plugins/gutenberg/phpunit/class-block-fixture-test.php:31

3) Gutenberg_REST_Global_Styles_Controller_Test::test_get_theme_items
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
-Array &0 ()
+Array &0 (
+    0 => Array &1 (
+        'version' => 2
+        'settings' => Array &2 (
+            'color' => Array &3 (
+                'palette' => Array &4 (
+                    'theme' => Array &5 (
+                        0 => Array &6 (
+                            'slug' => 'foreground'
+                            'color' => '#3F67C6'
+                            'name' => 'Foreground'
+                        )
+                    )
+                )
+            )
+        )
+        'styles' => Array &7 (
+            'blocks' => Array &8 (
+                'core/post-title' => Array &9 (
+                    'typography' => Array &10 (
+                        'fontWeight' => '700'
+                    )
+                )
+            )
+        )
+        'title' => 'variation'
+    )
+)

/Users/anton/html/wordpress.test/tests/phpunit/includes/abstract-testcase.php:987
/Users/anton/html/wordpress.test/src/wp-content/plugins/gutenberg/phpunit/class-gutenberg-rest-global-styles-controller-test.php:116

4) WP_Webfonts_Provider_Local_Test::test_get_css with data set "truetype format" (array(array('local', 'Open Sans', 'italic', 'bold', 'http://example.org/assets/fon...ht.ttf')), '@font-face{font-family:"Open ...pe');}')
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'@font-face{font-family:"Open Sans";font-style:italic;font-weight:bold;src:local("Open Sans"), url('http://example.org/assets/fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype');}'
+'@font-face{font-family:"Open Sans";font-style:italic;font-weight:bold;src:local("Open Sans"), url('/assets/fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype');}'

/Users/anton/html/wordpress.test/src/wp-content/plugins/gutenberg/phpunit/class-wp-webfonts-local-provider-test.php:91

5) WP_Webfonts_Provider_Local_Test::test_get_css with data set "woff2 format" (array(array('local', 'Source Serif Pro', 'normal', '200 900', 'normal', 'http://example.org/assets/fon....woff2'), array('local', 'Source Serif Pro', 'italic', '200 900', 'normal', 'http://example.org/assets/fon....woff2')), '@font-face{font-family:"Sourc...f2');}')
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');}@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');}'
+'@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');}@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');}'

/Users/anton/html/wordpress.test/src/wp-content/plugins/gutenberg/phpunit/class-wp-webfonts-local-provider-test.php:91

6) WP_Style_Engine_Test::test_wp_style_engine_get_styles with data set "inline_valid_typography_style" (array(array('clamp(2em, 2vw, 4em)', 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', 'italic', '800', '1.3', '2', 'underline', 'uppercase', '2')), null, array('font-size:clamp(2em, 2vw, 4em...ing:2;', array('clamp(2em, 2vw, 4em)', 'Roboto,Oxygen-Sans,Ubuntu,sans-serif', 'italic', '800', '1.3', '2', 'underline', 'uppercase', '2')))
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
 Array &0 (
-    'css' => 'font-size:clamp(2em, 2vw, 4em);font-family:Roboto,Oxygen-Sans,Ubuntu,sans-serif;font-style:italic;font-weight:800;line-height:1.3;column-count:2;text-decoration:underline;text-transform:uppercase;letter-spacing:2;'
+    'css' => 'font-size:clamp(2em, 2vw, 4em);font-family:Roboto,Oxygen-Sans,Ubuntu,sans-serif;font-style:italic;font-weight:800;line-height:1.3;text-decoration:underline;text-transform:uppercase;letter-spacing:2;'
     'declarations' => Array &1 (
         'font-size' => 'clamp(2em, 2vw, 4em)'
         'font-family' => 'Roboto,Oxygen-Sans,Ubuntu,sans-serif'
@@ @@
         'font-style' => 'italic'
         'font-weight' => '800'
         'line-height' => '1.3'
-        'column-count' => '2'
         'text-decoration' => 'underline'
         'text-transform' => 'uppercase'
         'letter-spacing' => '2'
     )
 )

/Users/anton/html/wordpress.test/src/wp-content/plugins/gutenberg/phpunit/style-engine/style-engine-test.php:47

* @return integer
*/
private static function sort_start_ascending( $a, $b ) {
return $a->start - $b->start;
$by_start = $a->start - $b->start;
if ( $by_start !== 0 ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ( $by_start !== 0 ) {
if ( 0 !== $by_start ) {

https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#yoda-conditions

}

$by_text = isset( $a->text, $b->text ) ? strcmp( $a->text, $b->text ) : 0;
if ( $by_text !== 0 ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ( $by_text !== 0 ) {
if ( 0 !== $by_text ) {

https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#yoda-conditions

@dmsnell
Copy link
Contributor Author

dmsnell commented Dec 19, 2022

Rebasing this against trunk@{9.hours.ago} to start investigating performance test suite failures. Will likely rewrite the branch a few times.

@github-actions
Copy link

github-actions bot commented Dec 20, 2022

Size Change: +35 B (0%)

Total Size: 1.32 MB

Filename Size Change
build/edit-site/index.min.js 64.9 kB +35 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/annotations/index.min.js 2.78 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 487 B
build/block-directory/index.min.js 7.16 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 2.71 kB
build/block-editor/content.css 2.71 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/index.min.js 182 kB
build/block-editor/style-rtl.css 14.7 kB
build/block-editor/style.css 14.7 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 84 B
build/block-library/blocks/avatar/style.css 84 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 485 B
build/block-library/blocks/button/editor.css 485 B
build/block-library/blocks/button/style-rtl.css 532 B
build/block-library/blocks/button/style.css 532 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 100 B
build/block-library/blocks/categories/style.css 100 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 612 B
build/block-library/blocks/cover/editor.css 613 B
build/block-library/blocks/cover/style-rtl.css 1.57 kB
build/block-library/blocks/cover/style.css 1.56 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 253 B
build/block-library/blocks/file/style.css 254 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 984 B
build/block-library/blocks/gallery/editor.css 988 B
build/block-library/blocks/gallery/style-rtl.css 1.55 kB
build/block-library/blocks/gallery/style.css 1.55 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 829 B
build/block-library/blocks/image/editor.css 828 B
build/block-library/blocks/image/style-rtl.css 627 B
build/block-library/blocks/image/style.css 630 B
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/latest-comments/style-rtl.css 298 B
build/block-library/blocks/latest-comments/style.css 298 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 507 B
build/block-library/blocks/media-text/style.css 505 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 716 B
build/block-library/blocks/navigation-link/editor.css 715 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.15 kB
build/block-library/blocks/navigation/editor.css 2.16 kB
build/block-library/blocks/navigation/style-rtl.css 2.23 kB
build/block-library/blocks/navigation/style.css 2.21 kB
build/block-library/blocks/navigation/view-modal.min.js 2.81 kB
build/block-library/blocks/navigation/view.min.js 447 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 376 B
build/block-library/blocks/page-list/editor.css 376 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 174 B
build/block-library/blocks/paragraph/editor.css 174 B
build/block-library/blocks/paragraph/style-rtl.css 279 B
build/block-library/blocks/paragraph/style.css 281 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 501 B
build/block-library/blocks/post-comments-form/style.css 501 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 586 B
build/block-library/blocks/post-featured-image/editor.css 584 B
build/block-library/blocks/post-featured-image/style-rtl.css 318 B
build/block-library/blocks/post-featured-image/style.css 318 B
build/block-library/blocks/post-navigation-link/style-rtl.css 153 B
build/block-library/blocks/post-navigation-link/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 326 B
build/block-library/blocks/pullquote/style.css 325 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 440 B
build/block-library/blocks/query/editor.css 440 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 409 B
build/block-library/blocks/search/style.css 406 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 490 B
build/block-library/blocks/site-logo/editor.css 490 B
build/block-library/blocks/site-logo/style-rtl.css 203 B
build/block-library/blocks/site-logo/style.css 203 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.4 kB
build/block-library/blocks/social-links/style.css 1.39 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 457 B
build/block-library/blocks/table/editor.css 457 B
build/block-library/blocks/table/style-rtl.css 651 B
build/block-library/blocks/table/style.css 650 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 404 B
build/block-library/blocks/template-part/editor.css 404 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 691 B
build/block-library/blocks/video/editor.css 694 B
build/block-library/blocks/video/style-rtl.css 179 B
build/block-library/blocks/video/style.css 179 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 162 B
build/block-library/classic.css 162 B
build/block-library/common-rtl.css 1.05 kB
build/block-library/common.css 1.05 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.7 kB
build/block-library/editor.css 11.7 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 198 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 12.4 kB
build/block-library/style.css 12.4 kB
build/block-library/theme-rtl.css 698 B
build/block-library/theme.css 703 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 50.4 kB
build/components/index.min.js 204 kB
build/components/style-rtl.css 11.6 kB
build/components/style.css 11.6 kB
build/compose/index.min.js 12.3 kB
build/core-data/index.min.js 15.9 kB
build/customize-widgets/index.min.js 11.7 kB
build/customize-widgets/style-rtl.css 1.41 kB
build/customize-widgets/style.css 1.41 kB
build/data-controls/index.min.js 663 B
build/data/index.min.js 8.16 kB
build/date/index.min.js 32.1 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.71 kB
build/edit-navigation/index.min.js 16.2 kB
build/edit-navigation/style-rtl.css 4.11 kB
build/edit-navigation/style.css 4.12 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 34.7 kB
build/edit-post/style-rtl.css 7.45 kB
build/edit-post/style.css 7.44 kB
build/edit-site/style-rtl.css 9.06 kB
build/edit-site/style.css 9.06 kB
build/edit-widgets/index.min.js 16.8 kB
build/edit-widgets/style-rtl.css 4.46 kB
build/edit-widgets/style.css 4.46 kB
build/editor/index.min.js 44.1 kB
build/editor/style-rtl.css 3.69 kB
build/editor/style.css 3.68 kB
build/element/index.min.js 4.93 kB
build/escape-html/index.min.js 548 B
build/experiments/index.min.js 882 B
build/format-library/index.min.js 7.2 kB
build/format-library/style-rtl.css 598 B
build/format-library/style.css 597 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.79 kB
build/keycodes/index.min.js 1.86 kB
build/list-reusable-blocks/index.min.js 2.13 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.94 kB
build/notices/index.min.js 977 B
build/plugins/index.min.js 1.95 kB
build/preferences-persistence/index.min.js 2.23 kB
build/preferences/index.min.js 1.35 kB
build/primitives/index.min.js 960 B
build/priority-queue/index.min.js 1.59 kB
build/react-i18n/index.min.js 702 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.75 kB
build/reusable-blocks/index.min.js 2.26 kB
build/reusable-blocks/style-rtl.css 283 B
build/reusable-blocks/style.css 283 B
build/rich-text/index.min.js 10.7 kB
build/server-side-render/index.min.js 2.09 kB
build/shortcode/index.min.js 1.52 kB
build/style-engine/index.min.js 1.53 kB
build/token-list/index.min.js 650 B
build/url/index.min.js 3.7 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 1.09 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.27 kB
build/widgets/style-rtl.css 1.21 kB
build/widgets/style.css 1.21 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@dmsnell dmsnell force-pushed the fix/tag-processor-back-too-far branch 4 times, most recently from 9551114 to b11e861 Compare December 20, 2022 05:55
@dmsnell dmsnell force-pushed the fix/tag-processor-back-too-far branch from b11e861 to 6bd6a6a Compare December 20, 2022 05:56
Copy link
Contributor

@anton-vlasenko anton-vlasenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I confirm this PR passes PHPUnit tests on all Core-supported PHP versions (5.6 - 8.2). So I approve that PR.
But I'd prefer someone else to also approve this PR as I'm not very familiar with the `WP_HTML_Tag_Processor' class. This PR changes the order in which element attributes are sorted.

@ockham
Copy link
Contributor

ockham commented Dec 20, 2022

👋 Coming here from #46680, which seems to be fixed by this PR. Thank you for that! 🎉

Can we maybe add the test coverage from that PR here? I.e.

diff --git a/phpunit/html/wp-html-tag-processor-test.php b/phpunit/html/wp-html-tag-processor-test.php
index cab1496249..fbf629088c 100644
--- a/phpunit/html/wp-html-tag-processor-test.php
+++ b/phpunit/html/wp-html-tag-processor-test.php
@@ -378,12 +378,14 @@ class WP_HTML_Tag_Processor_Test extends WP_UnitTestCase {
         *
         * @covers set_attribute
         * @covers get_updated_html
+        * @covers get_attribute
         */
        public function test_set_attribute_with_a_non_existing_attribute_adds_a_new_attribute_to_the_markup() {
                $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
                $p->next_tag();
                $p->set_attribute( 'test-attribute', 'test-value' );
                $this->assertSame( '<div test-attribute="test-value" id="first"><span id="second">Text</span></div>', $p->get_updated_html() );
+               $this->assertSame( 'test-value', $p->get_attribute( 'test-attribute' ) );
        }
 
        /**

(And maybe add an assertion like that to other set_attribute() tests as well; or add a separate test case.)

@anton-vlasenko
Copy link
Contributor

anton-vlasenko commented Dec 20, 2022

👋 Coming here from #46680, which seems to be fixed by this PR. Thank you for that! 🎉

Can we maybe add the test coverage from that PR here? I.e.

I'd appreciate it if these tests could be added later.
I need to get this PR merged to unblock #46510.
Thanks.

@dmsnell dmsnell force-pushed the fix/tag-processor-back-too-far branch from 6bd6a6a to f68508d Compare December 20, 2022 19:10
…46598)

A defect introduced in #46018 led to the tag processor backing up
one index too far after flushing its queued changes on a document.

For most operations this didn't cause any harm because when immediately
moving forward after an update, the `next_tag()` returned to the same
spot: it was backing up to one position before the current tag instead
of at the start of the current tag.

Unfortunately, when the current tag was the first in the document this
would lead the processor to rewind to position `-1`, right before the
start of the document, and lead to errors with `strpos()` when it
received out-of-bounds indices.

In this fix we're correcting the adjustment for the HTML tag's `<` and
documenting the math in the file so that it's clearer why it's there
and providing guidance should another fix be necessary.

As supporting work to this patch we're making the text replacement sort
stable, inside the tag processor, for when determining the order in which
to apply text replacements. This isn't necessary for the runtime but is
a nuissance for testing because different PHP versions produce different
unstable sort orderings and this prevents that from causing the unit
tests to fail in one version but pass in another.

Props to @anton-vlasenko for finding this bug.

Enforce sort stability when flushing out text replacements
@dmsnell dmsnell force-pushed the fix/tag-processor-back-too-far branch from f68508d to 696d63f Compare December 20, 2022 19:35
@dmsnell dmsnell merged commit 696d63f into trunk Dec 20, 2022
@dmsnell dmsnell deleted the fix/tag-processor-back-too-far branch December 20, 2022 20:15
@github-actions github-actions bot added this to the Gutenberg 14.9 milestone Dec 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

One of the recent updates broke WP_HTML_Tag_Processor's PHPUnit tests
4 participants