Make WordPress Core


Ignore:
Timestamp:
09/02/2019 10:24:18 AM (6 years ago)
Author:
flixos90
Message:

Formatting: Improve accuracy of force_balance_tags() and add support for custom element tags.

This changeset includes a major iteration on the regular expression used to balance tags, with comprehensive test coverage to ensure that all scenarios are supported or unsupported as expected.

Props dmsnell, westonruter, birgire.
Fixes #47014.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/formatting/balanceTags.php

    r42343 r45929  
    3838    }
    3939
     40    function supported_traditional_tag_names() {
     41        return array(
     42            array( 'a' ),
     43            array( 'div' ),
     44            array( 'blockquote' ),
     45            // HTML tag names can be CAPITALIZED and are case-insensitive.
     46            array( 'A' ),
     47            array( 'dIv' ),
     48            array( 'BLOCKQUOTE' ),
     49        );
     50    }
     51
     52    function supported_custom_element_tag_names() {
     53        return array(
     54            array( 'custom-element' ),
     55            array( 'my-custom-element' ),
     56            array( 'weekday-5-item' ),
     57            array( 'a-big-old-tag-name' ),
     58            array( 'with_underscores-and_the_dash' ),
     59            array( 'a-.' ),
     60            array( 'a._-.-_' ),
     61        );
     62    }
     63
     64    function invalid_tag_names() {
     65        return array(
     66            array( '<0-day>inside', '&lt;0-day>inside' ), // Can't start with a number - handled by the "<3" fix.
     67            array( '<UPPERCASE-TAG>inside', '<UPPERCASE-TAG>inside' ), // Custom elements cannot be uppercase.
     68        );
     69    }
     70
     71    /**
     72     * These are valid custom elements but we don't support them yet.
     73     *
     74     * @see https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
     75     */
     76    function unsupported_valid_tag_names() {
     77        return array(
     78            // We don't allow ending in a dash.
     79            array( '<what->inside' ),
     80            // Examples from the spec working document.
     81            array( 'math-α' ),
     82            array( 'emotion-😍' ),
     83            // UNICODE ranges
     84            // 0x00b7
     85            array( 'b-·' ),
     86            // Latin characters with accents/modifiers.
     87            // 0x00c0-0x00d6
     88            // 0x00d8-0x00f6
     89            array( 'a-À-Ó-Ý' ),
     90            // 0x00f8-0x037d
     91            array( 'a-ͳ' ),
     92            // No 0x037e, which is a Greek semicolon.
     93            // 0x037f-0x1fff
     94            array( 'a-Ფ' ),
     95            // Zero-width characters, probably never supported.
     96            // 0x200c-0x200d
     97            array( 'a-‌to-my-left-is-a-zero-width-non-joiner-do-not-delete-it' ),
     98            array( 'a-‍to-my-left-is-a-zero-width-joiner-do-not-delete-it' ),
     99            // Ties.
     100            // 0x203f-0x2040
     101            array( 'under-‿-tie' ),
     102            array( 'over-⁀-tie' ),
     103            // 0x2170-0x218f
     104            array( 'a-⁰' ),
     105            array( 'a-⅀' ),
     106            array( 'tag-ↀ-it' ),
     107            // 0x2c00-0x2fef
     108            array( 'a-Ⰰ' ),
     109            array( 'b-ⴓ-c' ),
     110            array( 'd-⽗' ),
     111            // 0x3001-0xd7ff
     112            array( 'a-、' ),
     113            array( 'z-态' ),
     114            array( 'a-送-䠺-ퟱ-퟿' ),
     115            // 0xf900-0xfdcf
     116            array( 'a-豈' ),
     117            array( 'my-切' ),
     118            array( 'aﴀ-tag' ),
     119            array( 'my-﷌' ),
     120            // 0xfdf0-0xfffd
     121            array( 'a-ﷰ' ),
     122            array( 'a-￰-￸-�' ), // Warning; blank characters are in there.
     123            // Extended ranges.
     124            // 0x10000-0xeffff
     125            array( 'a-𐀀' ),
     126            array( 'my-𝀀' ),
     127            array( 'a𞀀-𜿐' ),
     128        );
     129    }
     130
     131    /**
     132     * These are invalid custom elements but we support them right now in order to keep the parser simpler.
     133     *
     134     * @see https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
     135     */
     136    function supported_invalid_tag_names() {
     137        return array(
     138            // Reserved names for custom elements.
     139            array( 'annotation-xml' ),
     140            array( 'color-profile' ),
     141            array( 'font-face' ),
     142            array( 'font-face-src' ),
     143            array( 'font-face-uri' ),
     144            array( 'font-face-format' ),
     145            array( 'font-face-name' ),
     146            array( 'missing-glyph' ),
     147        );
     148    }
     149
     150    /**
     151     * @ticket 47014
     152     * @dataProvider supported_traditional_tag_names
     153     */
     154    function test_detects_traditional_tag_names( $tag ) {
     155        $normalized = strtolower( $tag );
     156
     157        $this->assertEquals( "<$normalized>inside</$normalized>", balanceTags( "<$tag>inside", true ) );
     158    }
     159
     160    /**
     161     * @ticket 47014
     162     * @dataProvider supported_custom_element_tag_names
     163     */
     164    function test_detects_supported_custom_element_tag_names( $tag ) {
     165        $this->assertEquals( "<$tag>inside</$tag>", balanceTags( "<$tag>inside", true ) );
     166    }
     167
     168    /**
     169     * @ticket 47014
     170     * @dataProvider invalid_tag_names
     171     */
     172    function test_ignores_invalid_tag_names( $input, $output ) {
     173        $this->assertEquals( $output, balanceTags( $input, true ) );
     174    }
     175
     176    /**
     177     * @ticket 47014
     178     * @dataProvider unsupported_valid_tag_names
     179     */
     180    function test_ignores_unsupported_custom_tag_names( $tag ) {
     181        $this->assertEquals( "<$tag>inside", balanceTags( "<$tag>inside", true ) );
     182    }
     183
     184    /**
     185     * @ticket 47014
     186     * @dataProvider supported_invalid_tag_names
     187     */
     188    function test_detects_supported_invalid_tag_names( $tag ) {
     189        $this->assertEquals( "<$tag>inside</$tag>", balanceTags( "<$tag>inside", true ) );
     190    }
     191
    40192    /**
    41193     * If a recognized valid single tag appears unclosed, it should get self-closed
     
    69221            '<p class="main1"/>',
    70222            '<p class="main2" />',
     223            '<STRONG/>',
    71224        );
    72225        $expected = array(
     
    75228            '<p class="main1"></p>',
    76229            '<p class="main2"></p>',
     230            // Valid tags are transformed to lowercase.
     231            '<strong></strong>',
    77232        );
    78233
     
    222377    }
    223378
     379    /**
     380     * Get custom element data.
     381     *
     382     * @return array Data.
     383     */
     384    public function data_custom_elements() {
     385        return array(
     386            // Valid custom element tags.
     387            array(
     388                '<my-custom-element data-attribute="value"/>',
     389                '<my-custom-element data-attribute="value"></my-custom-element>',
     390            ),
     391            array(
     392                '<my-custom-element>Test</my-custom-element>',
     393                '<my-custom-element>Test</my-custom-element>',
     394            ),
     395            array(
     396                '<my-custom-element>Test',
     397                '<my-custom-element>Test</my-custom-element>',
     398            ),
     399            array(
     400                'Test</my-custom-element>',
     401                'Test',
     402            ),
     403            array(
     404                '</my-custom-element>Test',
     405                'Test',
     406            ),
     407            array(
     408                '<my-custom-element/>',
     409                '<my-custom-element></my-custom-element>',
     410            ),
     411            array(
     412                '<my-custom-element />',
     413                '<my-custom-element></my-custom-element>',
     414            ),
     415            // Invalid (or at least temporarily unsupported) custom element tags.
     416            array(
     417                '<MY-CUSTOM-ELEMENT>Test',
     418                '<MY-CUSTOM-ELEMENT>Test',
     419            ),
     420            array(
     421                '<my->Test',
     422                '<my->Test',
     423            ),
     424            array(
     425                '<--->Test',
     426                '<--->Test',
     427            ),
     428        );
     429    }
     430
     431    /**
     432     * Test custom elements.
     433     *
     434     * @ticket 47014
     435     * @dataProvider data_custom_elements
     436     *
     437     * @param string $source   Source.
     438     * @param string $expected Expected.
     439     */
     440    public function test_custom_elements( $source, $expected ) {
     441        $this->assertEquals( $expected, balanceTags( $source, true ) );
     442    }
    224443}
Note: See TracChangeset for help on using the changeset viewer.