|
6 | 6 | * @subpackage HTML-API |
7 | 7 | */ |
8 | 8 |
|
| 9 | +if ( ! class_exists( 'WP_UnitTestCase' ) ) { |
| 10 | + class WP_UnitTestCase extends PHPUnit\Framework\TestCase {} |
| 11 | + |
| 12 | + require_once '/Users/dmsnell/code/WordPress-develop/src/wp-includes/html-api/class-wp-html-attribute-token.php'; |
| 13 | + require_once '/Users/dmsnell/code/WordPress-develop/src/wp-includes/html-api/class-wp-html-span.php'; |
| 14 | +// require_once '/Users/dmsnell/code/WordPress-develop/src/wp-includes/html-api/class-wp-html-spec.php'; |
| 15 | + require_once '/Users/dmsnell/code/WordPress-develop/src/wp-includes/html-api/class-wp-html-text-replacement.php'; |
| 16 | + require_once '/Users/dmsnell/code/WordPress-develop/src/wp-includes/html-api/class-wp-html-tag-processor.php'; |
| 17 | +// require_once '/Users/dmsnell/code/WordPress-develop/src/wp-includes/html-api/class-wp-html-processor.php'; |
| 18 | + |
| 19 | + function esc_attr( $s ) { return str_replace( [ '<', '>', '"' ], [ '<', '>', '"' ], $s ); } |
| 20 | +} |
| 21 | + |
9 | 22 | /** |
10 | 23 | * @group html-api |
11 | 24 | * |
@@ -1714,6 +1727,47 @@ public function data_next_tag_ignores_script_tag_contents() { |
1714 | 1727 | ); |
1715 | 1728 | } |
1716 | 1729 |
|
| 1730 | + /** |
| 1731 | + * Invalid tag names are comments on tag closers. |
| 1732 | + * |
| 1733 | + * See https://html.spec.whatwg.org/#parse-error-invalid-first-character-of-tag-name |
| 1734 | + * |
| 1735 | + * @ticket 58007 |
| 1736 | + * |
| 1737 | + * @dataProvider data_next_tag_ignores_invalid_first_character_of_tag_name_comments |
| 1738 | + * |
| 1739 | + * @param string $html_with_markers HTML containing an invalid tag closer whose element before and |
| 1740 | + * element after contain the "start" and "end" CSS classes. |
| 1741 | + */ |
| 1742 | + public function test_next_tag_ignores_invalid_first_character_of_tag_name_comments( $html_with_markers ) { |
| 1743 | + $p = new WP_HTML_Tag_Processor( $html_with_markers ); |
| 1744 | + $p->next_tag( array( 'class_name' => 'start' ) ); |
| 1745 | + $p->next_tag(); |
| 1746 | + |
| 1747 | + $this->assertSame( 'end', $p->get_attribute( 'class' ) ); |
| 1748 | + } |
| 1749 | + |
| 1750 | + /** |
| 1751 | + * Data provider. |
| 1752 | + * |
| 1753 | + * @return array[] |
| 1754 | + */ |
| 1755 | + public function data_next_tag_ignores_invalid_first_character_of_tag_name_comments() { |
| 1756 | + return array( |
| 1757 | + 'Invalid tag openers as normal text' => array( |
| 1758 | + '<ul><li><div class=start>I <3 when outflow > inflow</div><img class=end></li></ul>', |
| 1759 | + ), |
| 1760 | + |
| 1761 | + 'Invalid tag closers as comments' => array( |
| 1762 | + '<ul><li><div class=start>I </3 when <img> outflow <br class=end> inflow</div></li></ul>', |
| 1763 | + ), |
| 1764 | + |
| 1765 | + 'Unexpected question mark instead of tag name' => array( |
| 1766 | + '<div class=start><?xml-stylesheet type="text/css" href="style.css"?><hr class=end>', |
| 1767 | + ), |
| 1768 | + ); |
| 1769 | + } |
| 1770 | + |
1717 | 1771 | /** |
1718 | 1772 | * @ticket 56299 |
1719 | 1773 | * |
@@ -1766,6 +1820,96 @@ public function data_next_tag_ignores_contents_of_rcdata_tag() { |
1766 | 1820 | ); |
1767 | 1821 | } |
1768 | 1822 |
|
| 1823 | + /** |
| 1824 | + * Ensures that the invalid comment closing syntax "--!>" properly closes a comment. |
| 1825 | + * |
| 1826 | + * @ticket 58007 |
| 1827 | + * @covers WP_HTML_Tag_Processor::next_tag |
| 1828 | + * |
| 1829 | + */ |
| 1830 | + public function test_allows_incorrectly_closed_comments() { |
| 1831 | + $p = new WP_HTML_Tag_Processor( '<img id=before><!-- <img id=inside> --!><img id=after>--><img id=final>' ); |
| 1832 | + |
| 1833 | + $p->next_tag(); |
| 1834 | + $this->assertSame( 'before', $p->get_attribute( 'id' ), 'Did not find starting tag.' ); |
| 1835 | + |
| 1836 | + $p->next_tag(); |
| 1837 | + $this->assertSame( 'after', $p->get_attribute( 'id' ), 'Did not properly close improperly-closed comment.' ); |
| 1838 | + |
| 1839 | + $p->next_tag(); |
| 1840 | + $this->assertSame( 'final', $p->get_attribute( 'id' ), 'Did not skip over unopened comment-closer.' ); |
| 1841 | + } |
| 1842 | + |
| 1843 | + /** |
| 1844 | + * Ensures that unclosed and invalid comments don't trigger warnings or errors. |
| 1845 | + * |
| 1846 | + * @ticket 58007 |
| 1847 | + * |
| 1848 | + * @covers WP_HTML_Tag_Processor::next_tag |
| 1849 | + * @dataProvider data_html_with_unclosed_comments |
| 1850 | + * |
| 1851 | + * @param string $html_ending_before_comment_close HTML with opened comments that aren't closed |
| 1852 | + */ |
| 1853 | + public function test_documents_may_end_with_unclosed_comment( $html_ending_before_comment_close ) { |
| 1854 | + $p = new WP_HTML_Tag_Processor( $html_ending_before_comment_close ); |
| 1855 | + |
| 1856 | + $this->assertFalse( $p->next_tag() ); |
| 1857 | + } |
| 1858 | + |
| 1859 | + /** |
| 1860 | + * Data provider. |
| 1861 | + * |
| 1862 | + * @return array[] |
| 1863 | + */ |
| 1864 | + public function data_html_with_unclosed_comments() { |
| 1865 | + return array( |
| 1866 | + 'Shortest open valid comment' => array( '<!--' ), |
| 1867 | + 'Basic truncated comment' => array( '<!-- this ends --' ), |
| 1868 | + 'Comment with closer look-alike' => array( '<!-- this ends --x' ), |
| 1869 | + 'Comment with closer look-alike 2' => array( '<!-- this ends --!x' ), |
| 1870 | + 'Invalid tag-closer comment' => array( '</(when will this madness end?)' ), |
| 1871 | + 'Invalid tag-closer comment 2' => array( '</(when will this madness end?)--' ) |
| 1872 | + ); |
| 1873 | + } |
| 1874 | + |
| 1875 | + /** |
| 1876 | + * Ensures that abruptly-closed empty comments are properly closed. |
| 1877 | + * |
| 1878 | + * @ticket 58007 |
| 1879 | + * |
| 1880 | + * @covers WP_HTML_Tag_Processor::next_tag |
| 1881 | + * @dataProvider data_abruptly_closed_empty_comments |
| 1882 | + * |
| 1883 | + * @param string $html_with_after_marker HTML to test with "id=after" on element immediately following an abruptly closed comment. |
| 1884 | + */ |
| 1885 | + public function test_closes_abrupt_closing_of_empty_comment( $html_with_after_marker ) { |
| 1886 | + $p = new WP_HTML_Tag_Processor( $html_with_after_marker ); |
| 1887 | + $p->next_tag(); |
| 1888 | + $p->next_tag(); |
| 1889 | + |
| 1890 | + $this->assertSame( 'after', $p->get_attribute( 'id' ), 'Did not find tag after closing abruptly-closed comment' ); |
| 1891 | + } |
| 1892 | + |
| 1893 | + /** |
| 1894 | + * Data provider. |
| 1895 | + * |
| 1896 | + * @return array[] |
| 1897 | + */ |
| 1898 | + public function data_abruptly_closed_empty_comments() { |
| 1899 | + return array( |
| 1900 | + 'Empty comment with two dashes only' => array( '<hr><!--><hr id=after>' ), |
| 1901 | + 'Empty comment with two dashes only, improperly closed' => array( '<hr><!--!><hr id=inside>--><hr id=after>' ), |
| 1902 | + 'Comment with two dashes only, improperly closed twice' => array( '<hr><!--!><hr id=inside>--!><hr id=after>' ), |
| 1903 | + 'Empty comment with three dashes' => array( '<hr><!---><hr id=after>' ), |
| 1904 | + 'Empty comment with three dashes, improperly closed' => array( '<hr><!---!><hr id=inside>--><hr id=after>' ), |
| 1905 | + 'Comment with three dashes, improperly closed twice' => array( '<hr><!---!><hr id=inside>--!><hr id=after>' ), |
| 1906 | + 'Empty comment with four dashes' => array( '<hr><!----><hr id=after>' ), |
| 1907 | + 'Empty comment with four dashes, improperly closed' => array( '<hr><!----!><hr id=after>--><hr id=final>' ), |
| 1908 | + 'Comment with four dashes, improperly closed twice' => array( '<hr><!----!><hr id=after>--!><hr id=final>' ), |
| 1909 | + 'Comment with almost-closer inside' => array( '<hr><!-- ---!><hr id=after>--!><hr id=final>' ), |
| 1910 | + ); |
| 1911 | + } |
| 1912 | + |
1769 | 1913 | /** |
1770 | 1914 | * @ticket 56299 |
1771 | 1915 | * |
|
0 commit comments