WordPress.org

Make WordPress Core

Ticket #22692: miqro-22692.8.patch

File miqro-22692.8.patch, 53.8 KB (added by miqrogroove, 7 years ago)

Merge src and tests.

  • src/wp-includes/formatting.php

     
    7373                $static_characters = array_merge( array( '---', ' -- ', '--', ' - ', 'xn–', '...', '``', '\'\'', ' (tm)' ), $cockney );
    7474                $static_replacements = array_merge( array( $em_dash, ' ' . $em_dash . ' ', $en_dash, ' ' . $en_dash . ' ', 'xn--', '…', $opening_quote, $closing_quote, ' ™' ), $cockneyreplace );
    7575
     76                // Pattern-based replacements of characters.
    7677                $dynamic = array();
    77                 if ( "'" != $apos ) {
    78                         $dynamic[ '/\'(\d\d(?:’|\')?s)/' ] = $apos . '$1'; // '99's
    79                         $dynamic[ '/\'(\d)/'                   ] = $apos . '$1'; // '99
    80                 }
     78                $spaces = wp_spaces_regexp();
     79
     80                // '99s (apostrophe)
     81                if ( "'" != $apos )
     82                        $dynamic[ '/\'(?=\d)/' ] = $apos;
     83
     84                // Single quote at start, or preceded by (, {, <, [, ", or spaces.
    8185                if ( "'" != $opening_single_quote )
    82                         $dynamic[ '/(\s|\A|[([{<]|")\'/'       ] = '$1' . $opening_single_quote; // opening single quote, even after (, {, <, [
     86                        $dynamic[ '/(?<=\A|[([{<"]|' . $spaces . ')\'/' ] = $opening_single_quote;
     87
     88                // 9" (double prime)
    8389                if ( '"' != $double_prime )
    84                         $dynamic[ '/(\d)"/'                    ] = '$1' . $double_prime; // 9" (double prime)
     90                        $dynamic[ '/(?<=\d)"/' ] = $double_prime;
     91
     92                // 9' (prime)
    8593                if ( "'" != $prime )
    86                         $dynamic[ '/(\d)\'/'                   ] = '$1' . $prime; // 9' (prime)
     94                        $dynamic[ '/(?<=\d)\'/' ] = $prime;
     95
     96                // Apostrophe in a word.  No spaces or double primes.
    8797                if ( "'" != $apos )
    88                         $dynamic[ '/(\S)\'([^\'\s])/'          ] = '$1' . $apos . '$2'; // apostrophe in a word
     98                        $dynamic[ '/(?<!' . $spaces . ')\'(?!\'|' . $spaces . ')/' ] = $apos;
     99
     100                // Double quote at start, or preceded by (, {, <, [, or spaces, and not followed by spaces.
    89101                if ( '"' != $opening_quote )
    90                         $dynamic[ '/(\s|\A|[([{<])"(?!\s)/'    ] = '$1' . $opening_quote . '$2'; // opening double quote, even after (, {, <, [
     102                        $dynamic[ '/(?<=\A|[([{<]|' . $spaces . ')"(?!' . $spaces . ')/' ] = $opening_quote;
     103
     104                // Any remaining double quotes.
    91105                if ( '"' != $closing_quote )
    92                         $dynamic[ '/"(\s|\S|\Z)/'              ] = $closing_quote . '$1'; // closing double quote
     106                        $dynamic[ '/"/' ] = $closing_quote;
     107
     108                // Single quotes followed by spaces or a period.
    93109                if ( "'" != $closing_single_quote )
    94                         $dynamic[ '/\'([\s.]|\Z)/'             ] = $closing_single_quote . '$1'; // closing single quote
     110                        $dynamic[ '/\'(?=\Z|\.|' . $spaces . ')/' ] = $closing_single_quote;
    95111
    96                 $dynamic[ '/\b(\d+)x(\d+)\b/'              ] = '$1&#215;$2'; // 9x9 (times)
     112                // 9x9 (times)
     113                $dynamic[ '/\b(\d+)x(\d+)\b/' ] = '$1&#215;$2';
    97114
    98115                $dynamic_characters = array_keys( $dynamic );
    99116                $dynamic_replacements = array_values( $dynamic );
     
    318335        }
    319336
    320337        $tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
     338        $spaces = wp_spaces_regexp();
    321339
    322340        $pattern =
    323341                  '/'
    324342                . '<p>'                              // Opening paragraph
    325                 . '\\s*+'                            // Optional leading whitespace
     343                . '(?:' . $spaces . ')*+'            // Optional leading whitespace
    326344                . '('                                // 1: The shortcode
    327345                .     '\\['                          // Opening bracket
    328346                .     "($tagregexp)"                 // 2: Shortcode name
     
    347365                .         ')?'
    348366                .     ')'
    349367                . ')'
    350                 . '\\s*+'                            // optional trailing whitespace
     368                . '(?:' . $spaces . ')*+'            // optional trailing whitespace
    351369                . '<\\/p>'                           // closing paragraph
    352370                . '/s';
    353371
     
    18651883         */
    18661884        $src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
    18671885
    1868         return sprintf( ' <img src="%s" alt="%s" class="wp-smiley" /> ', esc_url( $src_url ), esc_attr( $smiley ) );
     1886        return sprintf( '<img src="%s" alt="%s" class="wp-smiley" />', esc_url( $src_url ), esc_attr( $smiley ) );
    18691887}
    18701888
    18711889/**
     
    37813799
    37823800        return false;
    37833801}
     3802
     3803/**
     3804 * Returns the regexp for common whitespace characters.
     3805 *
     3806 * By default, spaces include new lines, tabs, nbsp entities, and the UTF-8 nbsp.
     3807 * This is designed to replace the PCRE \s sequence.  In ticket #22692, that
     3808 * sequence was found to be unreliable due to random inclusion of the A0 byte.
     3809 *
     3810 * @since 3.9.0
     3811 *
     3812 * @return string The spaces regexp.
     3813 */
     3814function wp_spaces_regexp() {
     3815        static $spaces;
     3816
     3817        if (empty($spaces)) {
     3818                $spaces = apply_filters( 'wp_spaces_regexp', '[\r\n\t ]|\xC2\xA0|&nbsp;' );
     3819        }
     3820
     3821        return $spaces;
     3822}
  • src/wp-includes/functions.php

     
    25602560         */
    25612561        krsort($wpsmiliestrans);
    25622562
    2563         $wp_smiliessearch = '/((?:\s|^)';
     2563        $spaces = wp_spaces_regexp();
    25642564
     2565        // Begin first "subpattern"
     2566        $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
     2567
    25652568        $subchar = '';
    25662569        foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
    25672570                $firstchar = substr($smiley, 0, 1);
     
    25702573                // new subpattern?
    25712574                if ($firstchar != $subchar) {
    25722575                        if ($subchar != '') {
    2573                                 $wp_smiliessearch .= ')(?=\s|$))|((?:\s|^)'; ;
     2576                                $wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
     2577                                $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
    25742578                        }
    25752579                        $subchar = $firstchar;
    25762580                        $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
     
    25802584                $wp_smiliessearch .= preg_quote($rest, '/');
    25812585        }
    25822586
    2583         $wp_smiliessearch .= ')(?=\s|$))/m';
     2587        $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
    25842588
    25852589}
    25862590
  • tests/phpunit/tests/formatting/Smilies.php

     
    275275
    276276                $wpsmiliestrans = $orig_trans; // reset original translations array
    277277        }
    278 }
    279  No newline at end of file
     278
     279        /**
     280         * Check that $wp_smiliessearch pattern will match smilies
     281         * between spaces, but never capture those spaces.
     282         *
     283         * Further check that spaces aren't randomly deleted
     284         * or added when replacing the text with an image.
     285         *
     286         * @ticket 22692
     287         */
     288        function test_spaces_around_smilies() {
     289                $nbsp = "\xC2\xA0";
     290
     291                $input  = array();
     292                $output = array();
     293
     294                $input[]  = 'My test :) smile';
     295                $output[] = array('test <img ', 'alt=":)"', ' /> smile');
     296
     297                $input[]  = 'My test ;) smile';
     298                $output[] = array('test <img ', 'alt=";)"', ' /> smile');
     299
     300                $input[]  = 'My test &nbsp;:)&nbsp;smile';
     301                $output[] = array('test &nbsp;<img ', 'alt=":)"', ' />&nbsp;smile');
     302
     303                $input[]  = 'My test &nbsp;;)&nbsp;smile';
     304                $output[] = array('test &nbsp;<img ', 'alt=";)"', ' />&nbsp;smile');
     305
     306                $input[]  = "My test {$nbsp}:){$nbsp}smile";
     307                $output[] = array("test {$nbsp}<img ", 'alt=":)"', " />{$nbsp}smile");
     308
     309                $input[]  = "My test {$nbsp};){$nbsp}smile";
     310                $output[] = array("test {$nbsp}<img ", 'alt=";)"', " />{$nbsp}smile");
     311
     312                foreach($input as $key => $in) {
     313                        $result = convert_smilies( $in );
     314                        foreach($output[$key] as $k => $out) {
     315
     316                                // Each output element must appear in the results.
     317                                $this->assertContains( $out[$k], $result );
     318
     319                        }
     320                }
     321        }
     322}
  • tests/phpunit/tests/formatting/WPTexturize.php

     
    1 <?php
    2 
    3 /**
    4  * @group formatting
    5  */
    6 class Tests_Formatting_WPTexturize extends WP_UnitTestCase {
    7         function test_dashes() {
    8                 $this->assertEquals('Hey &#8212; boo?', wptexturize('Hey -- boo?'));
    9                 $this->assertEquals('<a href="http://xx--xx">Hey &#8212; boo?</a>', wptexturize('<a href="http://xx--xx">Hey -- boo?</a>'));
    10         }
    11 
    12         function test_disable() {
    13                 $this->assertEquals('<pre>---</pre>', wptexturize('<pre>---</pre>'));
    14                 $this->assertEquals('[a]a&#8211;b[code]---[/code]a&#8211;b[/a]', wptexturize('[a]a--b[code]---[/code]a--b[/a]'));
    15                 $this->assertEquals('<pre><code></code>--</pre>', wptexturize('<pre><code></code>--</pre>'));
    16 
    17                 $this->assertEquals('<code>---</code>', wptexturize('<code>---</code>'));
    18 
    19                 $this->assertEquals('<code>href="baba"</code> &#8220;baba&#8221;', wptexturize('<code>href="baba"</code> "baba"'));
    20 
    21                 $enabled_tags_inside_code = '<code>curl -s <a href="http://x/">baba</a> | grep sfive | cut -d "\"" -f 10 &gt; topmp3.txt</code>';
    22                 $this->assertEquals($enabled_tags_inside_code, wptexturize($enabled_tags_inside_code));
    23 
    24                 $double_nest = '<pre>"baba"<code>"baba"<pre></pre></code>"baba"</pre>';
    25                 $this->assertEquals($double_nest, wptexturize($double_nest));
    26 
    27                 $invalid_nest = '<pre></code>"baba"</pre>';
    28                 $this->assertEquals($invalid_nest, wptexturize($invalid_nest));
    29 
    30         }
    31 
    32         //WP Ticket #1418
    33         function test_bracketed_quotes_1418() {
    34                 $this->assertEquals('(&#8220;test&#8221;)', wptexturize('("test")'));
    35                 $this->assertEquals('(&#8216;test&#8217;)', wptexturize("('test')"));
    36                 $this->assertEquals('(&#8217;twas)', wptexturize("('twas)"));
    37         }
    38 
    39         //WP Ticket #3810
    40         function test_bracketed_quotes_3810() {
    41                 $this->assertEquals('A dog (&#8220;Hubertus&#8221;) was sent out.', wptexturize('A dog ("Hubertus") was sent out.'));
    42         }
    43 
    44         //WP Ticket #4539
    45         function test_basic_quotes() {
    46                 $this->assertEquals('test&#8217;s', wptexturize('test\'s'));
    47                 $this->assertEquals('test&#8217;s', wptexturize('test\'s'));
    48 
    49                 $this->assertEquals('&#8216;quoted&#8217;', wptexturize('\'quoted\''));
    50                 $this->assertEquals('&#8220;quoted&#8221;', wptexturize('"quoted"'));
    51 
    52                 $this->assertEquals('space before &#8216;quoted&#8217; space after', wptexturize('space before \'quoted\' space after'));
    53                 $this->assertEquals('space before &#8220;quoted&#8221; space after', wptexturize('space before "quoted" space after'));
    54 
    55                 $this->assertEquals('(&#8216;quoted&#8217;)', wptexturize('(\'quoted\')'));
    56                 $this->assertEquals('{&#8220;quoted&#8221;}', wptexturize('{"quoted"}'));
    57 
    58                 $this->assertEquals('&#8216;qu(ot)ed&#8217;', wptexturize('\'qu(ot)ed\''));
    59                 $this->assertEquals('&#8220;qu{ot}ed&#8221;', wptexturize('"qu{ot}ed"'));
    60 
    61                 $this->assertEquals(' &#8216;test&#8217;s quoted&#8217; ', wptexturize(' \'test\'s quoted\' '));
    62                 $this->assertEquals(' &#8220;test&#8217;s quoted&#8221; ', wptexturize(' "test\'s quoted" '));
    63         }
    64 
    65         /**
    66          * @ticket 4539
    67          * @ticket 15241
    68          */
    69         function test_full_sentences_with_unmatched_single_quotes() {
    70                 $this->assertEquals(
    71                         'That means every moment you&#8217;re working on something without it being in the public it&#8217;s actually dying.',
    72                         wptexturize("That means every moment you're working on something without it being in the public it's actually dying.")
    73                 );
    74         }
    75 
    76         /**
    77          * @ticket 4539
    78          */
    79         function test_quotes() {
    80                 $this->assertEquals('&#8220;Quoted String&#8221;', wptexturize('"Quoted String"'));
    81                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"'));
    82                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link and a period</a>&#8221;.', wptexturize('Here is "<a href="http://example.com">a test with a link and a period</a>".'));
    83                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221; and a space.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>" and a space.'));
    84                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a> and some text quoted&#8221;', wptexturize('Here is "<a href="http://example.com">a test with a link</a> and some text quoted"'));
    85                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;, and a comma.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>", and a comma.'));
    86                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;; and a semi-colon.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"; and a semi-colon.'));
    87                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;- and a dash.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"- and a dash.'));
    88                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;&#8230; and ellipses.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"... and ellipses.'));
    89                 $this->assertEquals('Here is &#8220;a test <a href="http://example.com">with a link</a>&#8221;.', wptexturize('Here is "a test <a href="http://example.com">with a link</a>".'));
    90                 $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;and a work stuck to the end.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"and a work stuck to the end.'));
    91                 $this->assertEquals('A test with a finishing number, &#8220;like 23&#8221;.', wptexturize('A test with a finishing number, "like 23".'));
    92                 $this->assertEquals('A test with a number, &#8220;like 62&#8221;, is nice to have.', wptexturize('A test with a number, "like 62", is nice to have.'));
    93         }
    94 
    95         /**
    96          * @ticket 4539
    97          */
    98         function test_quotes_before_s() {
    99                 $this->assertEquals('test&#8217;s', wptexturize("test's"));
    100                 $this->assertEquals('&#8216;test&#8217;s', wptexturize("'test's"));
    101                 $this->assertEquals('&#8216;test&#8217;s&#8217;', wptexturize("'test's'"));
    102                 $this->assertEquals('&#8216;string&#8217;', wptexturize("'string'"));
    103                 $this->assertEquals('&#8216;string&#8217;s&#8217;', wptexturize("'string's'"));
    104         }
    105 
    106         /**
    107          * @ticket 4539
    108          */
    109         function test_quotes_before_numbers() {
    110                 $this->assertEquals('Class of &#8217;99', wptexturize("Class of '99"));
    111                 $this->assertEquals('Class of &#8217;99&#8217;s', wptexturize("Class of '99's"));
    112                 $this->assertEquals('&#8216;Class of &#8217;99&#8217;', wptexturize("'Class of '99'"));
    113                 $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99's'"));
    114                 $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99&#8217;s'"));
    115                 $this->assertEquals('&#8220;Class of 99&#8221;', wptexturize("\"Class of 99\""));
    116                 $this->assertEquals('&#8220;Class of &#8217;99&#8221;', wptexturize("\"Class of '99\""));
    117         }
    118 
    119         function test_quotes_after_numbers() {
    120                 $this->assertEquals('Class of &#8217;99', wptexturize("Class of '99"));
    121         }
    122 
    123         /**
    124          * @ticket 4539
    125          * @ticket 15241
    126          */
    127         function test_other_html() {
    128                 $this->assertEquals('&#8216;<strong>', wptexturize("'<strong>"));
    129                 $this->assertEquals('&#8216;<strong>Quoted Text</strong>&#8217;,', wptexturize("'<strong>Quoted Text</strong>',"));
    130                 $this->assertEquals('&#8220;<strong>Quoted Text</strong>&#8221;,', wptexturize('"<strong>Quoted Text</strong>",'));
    131         }
    132 
    133         function test_x() {
    134                 $this->assertEquals('14&#215;24', wptexturize("14x24"));
    135         }
    136 
    137         function test_minutes_seconds() {
    138                 $this->assertEquals('9&#8242;', wptexturize('9\''));
    139                 $this->assertEquals('9&#8243;', wptexturize("9\""));
    140 
    141                 $this->assertEquals('a 9&#8242; b', wptexturize('a 9\' b'));
    142                 $this->assertEquals('a 9&#8243; b', wptexturize("a 9\" b"));
    143 
    144                 $this->assertEquals('&#8220;a 9&#8242; b&#8221;', wptexturize('"a 9\' b"'));
    145                 $this->assertEquals('&#8216;a 9&#8243; b&#8217;', wptexturize("'a 9\" b'"));
    146         }
    147 
    148         /**
    149          * @ticket 8775
    150          */
    151         function test_wptexturize_quotes_around_numbers() {
    152                 $this->assertEquals('&#8220;12345&#8221;', wptexturize('"12345"'));
    153                 $this->assertEquals('&#8216;12345&#8217;', wptexturize('\'12345\''));
    154                 $this->assertEquals('&#8220;a 9&#8242; plus a &#8216;9&#8217;, maybe a 9&#8242; &#8216;9&#8217; &#8221;', wptexturize('"a 9\' plus a \'9\', maybe a 9\' \'9\' "'));
    155                 $this->assertEquals('<p>&#8216;99<br />&#8216;123&#8217;<br />&#8217;tis<br />&#8216;s&#8217;</p>', wptexturize('<p>\'99<br />\'123\'<br />\'tis<br />\'s\'</p>'));
    156         }
    157 
    158         /**
    159          * @ticket 8912
    160          */
    161         function test_wptexturize_html_comments() {
    162                 $this->assertEquals('<!--[if !IE]>--><!--<![endif]-->', wptexturize('<!--[if !IE]>--><!--<![endif]-->'));
    163                 $this->assertEquals('<!--[if !IE]>"a 9\' plus a \'9\', maybe a 9\' \'9\' "<![endif]-->', wptexturize('<!--[if !IE]>"a 9\' plus a \'9\', maybe a 9\' \'9\' "<![endif]-->'));
    164                 $this->assertEquals('<ul><li>Hello.</li><!--<li>Goodbye.</li>--></ul>', wptexturize('<ul><li>Hello.</li><!--<li>Goodbye.</li>--></ul>'));
    165         }
    166 
    167         /**
    168          * @ticket 4539
    169          * @ticket 15241
    170          */
    171         function test_entity_quote_cuddling() {
    172                 $this->assertEquals('&nbsp;&#8220;Testing&#8221;', wptexturize('&nbsp;"Testing"'));
    173                 $this->assertEquals('&#38;&#8220;Testing&#8221;', wptexturize('&#38;"Testing"'));
    174         }
    175 
    176         /**
    177          * @ticket 22823
    178          */
    179         function test_apostrophes_before_primes() {
    180                 $this->assertEquals( 'WordPress 3.5&#8217;s release date', wptexturize( "WordPress 3.5's release date" ) );
    181         }
    182 
    183         /**
    184          * @ticket 23185
    185          */
    186         function test_spaces_around_hyphens() {
    187                 $this->assertEquals( ' &#8211; ', wptexturize( ' - ' ) );
    188                 $this->assertEquals( '&nbsp;&#8211;&nbsp;', wptexturize( '&nbsp;-&nbsp;' ) );
    189                 $this->assertEquals( ' &#8211;&nbsp;', wptexturize( ' -&nbsp;' ) );
    190                 $this->assertEquals( '&nbsp;&#8211; ', wptexturize( '&nbsp;- ') );
    191 
    192                 $this->assertEquals( ' &#8212; ', wptexturize( ' -- ' ) );
    193                 $this->assertEquals( '&nbsp;&#8212;&nbsp;', wptexturize( '&nbsp;--&nbsp;' ) );
    194                 $this->assertEquals( ' &#8212;&nbsp;', wptexturize( ' --&nbsp;' ) );
    195                 $this->assertEquals( '&nbsp;&#8212; ', wptexturize( '&nbsp;-- ') );
    196         }
    197 }
     1<?php
     2
     3/**
     4 * @group formatting
     5 */
     6class Tests_Formatting_WPTexturize extends WP_UnitTestCase {
     7        function test_dashes() {
     8                $this->assertEquals('Hey &#8212; boo?', wptexturize('Hey -- boo?'));
     9                $this->assertEquals('<a href="http://xx--xx">Hey &#8212; boo?</a>', wptexturize('<a href="http://xx--xx">Hey -- boo?</a>'));
     10        }
     11
     12        function test_disable() {
     13                $this->assertEquals('<pre>---</pre>', wptexturize('<pre>---</pre>'));
     14                $this->assertEquals('[a]a&#8211;b[code]---[/code]a&#8211;b[/a]', wptexturize('[a]a--b[code]---[/code]a--b[/a]'));
     15                $this->assertEquals('<pre><code></code>--</pre>', wptexturize('<pre><code></code>--</pre>'));
     16
     17                $this->assertEquals('<code>---</code>', wptexturize('<code>---</code>'));
     18
     19                $this->assertEquals('<code>href="baba"</code> &#8220;baba&#8221;', wptexturize('<code>href="baba"</code> "baba"'));
     20
     21                $enabled_tags_inside_code = '<code>curl -s <a href="http://x/">baba</a> | grep sfive | cut -d "\"" -f 10 &gt; topmp3.txt</code>';
     22                $this->assertEquals($enabled_tags_inside_code, wptexturize($enabled_tags_inside_code));
     23
     24                $double_nest = '<pre>"baba"<code>"baba"<pre></pre></code>"baba"</pre>';
     25                $this->assertEquals($double_nest, wptexturize($double_nest));
     26
     27                $invalid_nest = '<pre></code>"baba"</pre>';
     28                $this->assertEquals($invalid_nest, wptexturize($invalid_nest));
     29
     30        }
     31
     32        //WP Ticket #1418
     33        function test_bracketed_quotes_1418() {
     34                $this->assertEquals('(&#8220;test&#8221;)', wptexturize('("test")'));
     35                $this->assertEquals('(&#8216;test&#8217;)', wptexturize("('test')"));
     36                $this->assertEquals('(&#8217;twas)', wptexturize("('twas)"));
     37        }
     38
     39        //WP Ticket #3810
     40        function test_bracketed_quotes_3810() {
     41                $this->assertEquals('A dog (&#8220;Hubertus&#8221;) was sent out.', wptexturize('A dog ("Hubertus") was sent out.'));
     42        }
     43
     44        //WP Ticket #4539
     45        function test_basic_quotes() {
     46                $this->assertEquals('test&#8217;s', wptexturize('test\'s'));
     47                $this->assertEquals('test&#8217;s', wptexturize('test\'s'));
     48
     49                $this->assertEquals('&#8216;quoted&#8217;', wptexturize('\'quoted\''));
     50                $this->assertEquals('&#8220;quoted&#8221;', wptexturize('"quoted"'));
     51
     52                $this->assertEquals('space before &#8216;quoted&#8217; space after', wptexturize('space before \'quoted\' space after'));
     53                $this->assertEquals('space before &#8220;quoted&#8221; space after', wptexturize('space before "quoted" space after'));
     54
     55                $this->assertEquals('(&#8216;quoted&#8217;)', wptexturize('(\'quoted\')'));
     56                $this->assertEquals('{&#8220;quoted&#8221;}', wptexturize('{"quoted"}'));
     57
     58                $this->assertEquals('&#8216;qu(ot)ed&#8217;', wptexturize('\'qu(ot)ed\''));
     59                $this->assertEquals('&#8220;qu{ot}ed&#8221;', wptexturize('"qu{ot}ed"'));
     60
     61                $this->assertEquals(' &#8216;test&#8217;s quoted&#8217; ', wptexturize(' \'test\'s quoted\' '));
     62                $this->assertEquals(' &#8220;test&#8217;s quoted&#8221; ', wptexturize(' "test\'s quoted" '));
     63        }
     64
     65        /**
     66         * @ticket 4539
     67         * @ticket 15241
     68         */
     69        function test_full_sentences_with_unmatched_single_quotes() {
     70                $this->assertEquals(
     71                        'That means every moment you&#8217;re working on something without it being in the public it&#8217;s actually dying.',
     72                        wptexturize("That means every moment you're working on something without it being in the public it's actually dying.")
     73                );
     74        }
     75
     76        /**
     77         * @ticket 4539
     78         */
     79        function test_quotes() {
     80                $this->assertEquals('&#8220;Quoted String&#8221;', wptexturize('"Quoted String"'));
     81                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"'));
     82                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link and a period</a>&#8221;.', wptexturize('Here is "<a href="http://example.com">a test with a link and a period</a>".'));
     83                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221; and a space.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>" and a space.'));
     84                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a> and some text quoted&#8221;', wptexturize('Here is "<a href="http://example.com">a test with a link</a> and some text quoted"'));
     85                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;, and a comma.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>", and a comma.'));
     86                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;; and a semi-colon.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"; and a semi-colon.'));
     87                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;- and a dash.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"- and a dash.'));
     88                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;&#8230; and ellipses.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"... and ellipses.'));
     89                $this->assertEquals('Here is &#8220;a test <a href="http://example.com">with a link</a>&#8221;.', wptexturize('Here is "a test <a href="http://example.com">with a link</a>".'));
     90                $this->assertEquals('Here is &#8220;<a href="http://example.com">a test with a link</a>&#8221;and a work stuck to the end.', wptexturize('Here is "<a href="http://example.com">a test with a link</a>"and a work stuck to the end.'));
     91                $this->assertEquals('A test with a finishing number, &#8220;like 23&#8221;.', wptexturize('A test with a finishing number, "like 23".'));
     92                $this->assertEquals('A test with a number, &#8220;like 62&#8221;, is nice to have.', wptexturize('A test with a number, "like 62", is nice to have.'));
     93        }
     94
     95        /**
     96         * @ticket 4539
     97         */
     98        function test_quotes_before_s() {
     99                $this->assertEquals('test&#8217;s', wptexturize("test's"));
     100                $this->assertEquals('&#8216;test&#8217;s', wptexturize("'test's"));
     101                $this->assertEquals('&#8216;test&#8217;s&#8217;', wptexturize("'test's'"));
     102                $this->assertEquals('&#8216;string&#8217;', wptexturize("'string'"));
     103                $this->assertEquals('&#8216;string&#8217;s&#8217;', wptexturize("'string's'"));
     104        }
     105
     106        /**
     107         * @ticket 4539
     108         */
     109        function test_quotes_before_numbers() {
     110                $this->assertEquals('Class of &#8217;99', wptexturize("Class of '99"));
     111                $this->assertEquals('Class of &#8217;99&#8217;s', wptexturize("Class of '99's"));
     112                $this->assertEquals('&#8216;Class of &#8217;99&#8217;', wptexturize("'Class of '99'"));
     113                $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99's'"));
     114                $this->assertEquals('&#8216;Class of &#8217;99&#8217;s&#8217;', wptexturize("'Class of '99&#8217;s'"));
     115                $this->assertEquals('&#8220;Class of 99&#8221;', wptexturize("\"Class of 99\""));
     116                $this->assertEquals('&#8220;Class of &#8217;99&#8221;', wptexturize("\"Class of '99\""));
     117        }
     118
     119        function test_quotes_after_numbers() {
     120                $this->assertEquals('Class of &#8217;99', wptexturize("Class of '99"));
     121        }
     122
     123        /**
     124         * @ticket 4539
     125         * @ticket 15241
     126         */
     127        function test_other_html() {
     128                $this->assertEquals('&#8216;<strong>', wptexturize("'<strong>"));
     129                $this->assertEquals('&#8216;<strong>Quoted Text</strong>&#8217;,', wptexturize("'<strong>Quoted Text</strong>',"));
     130                $this->assertEquals('&#8220;<strong>Quoted Text</strong>&#8221;,', wptexturize('"<strong>Quoted Text</strong>",'));
     131        }
     132
     133        function test_x() {
     134                $this->assertEquals('14&#215;24', wptexturize("14x24"));
     135        }
     136
     137        function test_minutes_seconds() {
     138                $this->assertEquals('9&#8242;', wptexturize('9\''));
     139                $this->assertEquals('9&#8243;', wptexturize("9\""));
     140
     141                $this->assertEquals('a 9&#8242; b', wptexturize('a 9\' b'));
     142                $this->assertEquals('a 9&#8243; b', wptexturize("a 9\" b"));
     143
     144                $this->assertEquals('&#8220;a 9&#8242; b&#8221;', wptexturize('"a 9\' b"'));
     145                $this->assertEquals('&#8216;a 9&#8243; b&#8217;', wptexturize("'a 9\" b'"));
     146        }
     147
     148        /**
     149         * @ticket 8775
     150         */
     151        function test_wptexturize_quotes_around_numbers() {
     152                $this->assertEquals('&#8220;12345&#8221;', wptexturize('"12345"'));
     153                $this->assertEquals('&#8216;12345&#8217;', wptexturize('\'12345\''));
     154                $this->assertEquals('&#8220;a 9&#8242; plus a &#8216;9&#8217;, maybe a 9&#8242; &#8216;9&#8217; &#8221;', wptexturize('"a 9\' plus a \'9\', maybe a 9\' \'9\' "'));
     155                $this->assertEquals('<p>&#8216;99<br />&#8216;123&#8217;<br />&#8217;tis<br />&#8216;s&#8217;</p>', wptexturize('<p>\'99<br />\'123\'<br />\'tis<br />\'s\'</p>'));
     156        }
     157
     158        /**
     159         * @ticket 8912
     160         */
     161        function test_wptexturize_html_comments() {
     162                $this->assertEquals('<!--[if !IE]>--><!--<![endif]-->', wptexturize('<!--[if !IE]>--><!--<![endif]-->'));
     163                $this->assertEquals('<!--[if !IE]>"a 9\' plus a \'9\', maybe a 9\' \'9\' "<![endif]-->', wptexturize('<!--[if !IE]>"a 9\' plus a \'9\', maybe a 9\' \'9\' "<![endif]-->'));
     164                $this->assertEquals('<ul><li>Hello.</li><!--<li>Goodbye.</li>--></ul>', wptexturize('<ul><li>Hello.</li><!--<li>Goodbye.</li>--></ul>'));
     165        }
     166
     167        /**
     168         * @ticket 4539
     169         * @ticket 15241
     170         */
     171        function test_entity_quote_cuddling() {
     172                $this->assertEquals('&nbsp;&#8220;Testing&#8221;', wptexturize('&nbsp;"Testing"'));
     173                $this->assertEquals('&#38;&#8220;Testing&#8221;', wptexturize('&#38;"Testing"'));
     174        }
     175
     176        /**
     177         * @ticket 22823
     178         */
     179        function test_apostrophes_before_primes() {
     180                $this->assertEquals( 'WordPress 3.5&#8217;s release date', wptexturize( "WordPress 3.5's release date" ) );
     181        }
     182
     183        /**
     184         * @ticket 23185
     185         */
     186        function test_spaces_around_hyphens() {
     187                $this->assertEquals( ' &#8211; ', wptexturize( ' - ' ) );
     188                $this->assertEquals( '&nbsp;&#8211;&nbsp;', wptexturize( '&nbsp;-&nbsp;' ) );
     189                $this->assertEquals( ' &#8211;&nbsp;', wptexturize( ' -&nbsp;' ) );
     190                $this->assertEquals( '&nbsp;&#8211; ', wptexturize( '&nbsp;- ') );
     191
     192                $this->assertEquals( ' &#8212; ', wptexturize( ' -- ' ) );
     193                $this->assertEquals( '&nbsp;&#8212;&nbsp;', wptexturize( '&nbsp;--&nbsp;' ) );
     194                $this->assertEquals( ' &#8212;&nbsp;', wptexturize( ' --&nbsp;' ) );
     195                $this->assertEquals( '&nbsp;&#8212; ', wptexturize( '&nbsp;-- ') );
     196        }
     197
     198        /**
     199         * @ticket 22692
     200         */
     201        function test_spaces_around_quotes() {
     202                $nbsp = "\xC2\xA0";
     203                $pi   = "\xCE\xA0";
     204
     205                // This should never happen, even if the desired output changes some day.
     206
     207                $problem_input  = "$nbsp\"A";
     208                $problem_output = "$nbsp&#8221;A";
     209
     210                $this->assertNotEquals( $problem_output, wptexturize( $problem_input ) );
     211
     212                // These are desirable outputs for the current design.
     213
     214                $input  = array();
     215                $output = array();
     216
     217                $input[]  = "stop. $nbsp\"A quote after 2 spaces.\"";
     218                $output[] = "stop. $nbsp&#8220;A quote after 2 spaces.&#8221;";
     219
     220                $input[]  = "stop.$nbsp$nbsp\"A quote after 2 spaces.\"";
     221                $output[] = "stop.$nbsp$nbsp&#8220;A quote after 2 spaces.&#8221;";
     222
     223                $input[]  = "stop. $nbsp'A quote after 2 spaces.'";
     224                $output[] = "stop. $nbsp&#8216;A quote after 2 spaces.&#8217;";
     225
     226                $input[]  = "stop.$nbsp$nbsp'A quote after 2 spaces.'";
     227                $output[] = "stop.$nbsp$nbsp&#8216;A quote after 2 spaces.&#8217;";
     228
     229                $input[]  = "stop. &nbsp;\"A quote after 2 spaces.\"";
     230                $output[] = "stop. &nbsp;&#8220;A quote after 2 spaces.&#8221;";
     231
     232                $input[]  = "stop.&nbsp;&nbsp;\"A quote after 2 spaces.\"";
     233                $output[] = "stop.&nbsp;&nbsp;&#8220;A quote after 2 spaces.&#8221;";
     234
     235                $input[]  = "stop. &nbsp;'A quote after 2 spaces.'";
     236                $output[] = "stop. &nbsp;&#8216;A quote after 2 spaces.&#8217;";
     237
     238                $input[]  = "stop.&nbsp;&nbsp;'A quote after 2 spaces.'";
     239                $output[] = "stop.&nbsp;&nbsp;&#8216;A quote after 2 spaces.&#8217;";
     240
     241                $input[]  = "Contraction: $pi's";
     242                $output[] = "Contraction: $pi&#8217;s";
     243
     244                foreach($input as $key => $in) {
     245                        $this->assertEquals( $output[$key], wptexturize( $in ) );
     246                }
     247        }
     248}
  • tests/phpunit/tests/shortcode.php

     
    1 <?php
    2 /**
    3  * @group shortcode
    4  */
    5 class Tests_Shortcode extends WP_UnitTestCase {
    6 
    7         protected $shortcodes = array( 'test-shortcode-tag', 'footag', 'bartag', 'baztag', 'dumptag', 'hyphen', 'hyphen-foo', 'hyphen-foo-bar' );
    8 
    9         function setUp() {
    10                 parent::setUp();
    11 
    12                 foreach ( $this->shortcodes as $shortcode )
    13                         add_shortcode( $shortcode, array( $this, '_shortcode_' . str_replace( '-', '_', $shortcode ) ) );
    14 
    15                 $this->atts = null;
    16                 $this->content = null;
    17                 $this->tagname = null;
    18 
    19         }
    20 
    21         function tearDown() {
    22                 global $shortcode_tags;
    23                 parent::tearDown();
    24                 foreach ( $this->shortcodes as $shortcode )
    25                         unset( $shortcode_tags[ $shortcode ] );
    26         }
    27 
    28         function _shortcode_test_shortcode_tag( $atts, $content = null, $tagname = null ) {
    29                 $this->atts = $atts;
    30                 $this->content = $content;
    31                 $this->tagname = $tagname;
    32                 $this->filter_atts_out = null;
    33                 $this->filter_atts_pairs = null;
    34                 $this->filter_atts_atts = null;
    35         }
    36 
    37         // [footag foo="bar"]
    38         function _shortcode_footag( $atts ) {
    39                 return @"foo = {$atts['foo']}";
    40         }
    41 
    42         // [bartag foo="bar"]
    43         function _shortcode_bartag( $atts ) {
    44                 extract(shortcode_atts(array(
    45                         'foo' => 'no foo',
    46                         'baz' => 'default baz',
    47                 ), $atts, 'bartag'));
    48 
    49                 return "foo = {$foo}";
    50         }
    51 
    52         // [baztag]content[/baztag]
    53         function _shortcode_baztag( $atts, $content = '' ) {
    54                 return 'content = '.do_shortcode($content);
    55         }
    56 
    57         function _shortcode_dumptag( $atts ) {
    58                 $out = '';
    59                 foreach ($atts as $k=>$v)
    60                         $out .= "$k = $v\n";
    61                 return $out;
    62         }
    63 
    64         function _shortcode_hyphen() {
    65                 return __FUNCTION__;
    66         }
    67 
    68         function _shortcode_hyphen_foo() {
    69                 return __FUNCTION__;
    70         }
    71 
    72         function _shortcode_hyphen_foo_bar() {
    73                 return __FUNCTION__;
    74         }
    75 
    76         function test_noatts() {
    77                 do_shortcode('[test-shortcode-tag /]');
    78                 $this->assertEquals( '', $this->atts );
    79                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    80         }
    81 
    82         function test_one_att() {
    83                 do_shortcode('[test-shortcode-tag foo="asdf" /]');
    84                 $this->assertEquals( array('foo' => 'asdf'), $this->atts );
    85                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    86         }
    87 
    88         function test_not_a_tag() {
    89                 $out = do_shortcode('[not-a-shortcode-tag]');
    90                 $this->assertEquals( '[not-a-shortcode-tag]', $out );
    91         }
    92 
    93         /**
    94          * @ticket 17657
    95          */
    96         function test_tag_hyphen_not_tag() {
    97                 $out = do_shortcode( '[dumptag-notreal]' );
    98                 $this->assertEquals( '[dumptag-notreal]', $out );
    99         }
    100 
    101         function test_tag_underscore_not_tag() {
    102                 $out = do_shortcode( '[dumptag_notreal]' );
    103                 $this->assertEquals( '[dumptag_notreal]', $out );
    104         }
    105 
    106         function test_tag_not_tag() {
    107                 $out = do_shortcode( '[dumptagnotreal]' );
    108                 $this->assertEquals( '[dumptagnotreal]', $out );
    109         }
    110 
    111         /**
    112          * @ticket 17657
    113          */
    114         function test_tag_hyphen() {
    115                 $this->assertEquals( '_shortcode_hyphen', do_shortcode( '[hyphen]' ) );
    116                 $this->assertEquals( '_shortcode_hyphen_foo', do_shortcode( '[hyphen-foo]' ) );
    117                 $this->assertEquals( '_shortcode_hyphen_foo_bar', do_shortcode( '[hyphen-foo-bar]' ) );
    118                 $this->assertEquals( '[hyphen-baz]', do_shortcode( '[hyphen-baz]' ) );
    119                 $this->assertEquals( '[hyphen-foo-bar-baz]', do_shortcode( '[hyphen-foo-bar-baz]' ) );
    120         }
    121 
    122         function test_two_atts() {
    123                 do_shortcode('[test-shortcode-tag foo="asdf" bar="bing" /]');
    124                 $this->assertEquals( array('foo' => 'asdf', 'bar' => 'bing'), $this->atts );
    125                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    126         }
    127 
    128         function test_noatts_enclosing() {
    129                 do_shortcode('[test-shortcode-tag]content[/test-shortcode-tag]');
    130                 $this->assertEquals( '', $this->atts );
    131                 $this->assertEquals( 'content', $this->content );
    132                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    133         }
    134 
    135         function test_one_att_enclosing() {
    136                 do_shortcode('[test-shortcode-tag foo="bar"]content[/test-shortcode-tag]');
    137                 $this->assertEquals( array('foo' => 'bar'), $this->atts );
    138                 $this->assertEquals( 'content', $this->content );
    139                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    140         }
    141 
    142         function test_two_atts_enclosing() {
    143                 do_shortcode('[test-shortcode-tag foo="bar" baz="bing"]content[/test-shortcode-tag]');
    144                 $this->assertEquals( array('foo' => 'bar', 'baz' => 'bing'), $this->atts );
    145                 $this->assertEquals( 'content', $this->content );
    146                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    147         }
    148 
    149         function test_unclosed() {
    150                 $out = do_shortcode('[test-shortcode-tag]');
    151                 $this->assertEquals( '', $out );
    152                 $this->assertEquals( '', $this->atts );
    153                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    154         }
    155 
    156         function test_positional_atts_num() {
    157                 $out = do_shortcode('[test-shortcode-tag 123]');
    158                 $this->assertEquals( '', $out );
    159                 $this->assertEquals( array(0=>'123'), $this->atts );
    160                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    161         }
    162 
    163         function test_positional_atts_url() {
    164                 $out = do_shortcode('[test-shortcode-tag http://www.youtube.com/watch?v=eBGIQ7ZuuiU]');
    165                 $this->assertEquals( '', $out );
    166                 $this->assertEquals( array(0=>'http://www.youtube.com/watch?v=eBGIQ7ZuuiU'), $this->atts );
    167                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    168         }
    169 
    170         function test_positional_atts_quotes() {
    171                 $out = do_shortcode('[test-shortcode-tag "something in quotes" "something else"]');
    172                 $this->assertEquals( '', $out );
    173                 $this->assertEquals( array(0=>'something in quotes', 1=>'something else'), $this->atts );
    174                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    175         }
    176 
    177         function test_positional_atts_mixed() {
    178                 $out = do_shortcode('[test-shortcode-tag 123 http://wordpress.com/ 0 "foo" bar]');
    179                 $this->assertEquals( '', $out );
    180                 $this->assertEquals( array(0=>'123', 1=>'http://wordpress.com/', 2=>'0', 3=>'foo', 4=>'bar'), $this->atts );
    181                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    182         }
    183 
    184         function test_positional_and_named_atts() {
    185                 $out = do_shortcode('[test-shortcode-tag 123 url=http://wordpress.com/ foo bar="baz"]');
    186                 $this->assertEquals( '', $out );
    187                 $this->assertEquals( array(0=>'123', 'url' => 'http://wordpress.com/', 1=>'foo', 'bar' => 'baz'), $this->atts );
    188                 $this->assertEquals( 'test-shortcode-tag', $this->tagname );
    189         }
    190 
    191         function test_footag_default() {
    192                 $out = do_shortcode('[footag]');
    193                 $this->assertEquals('foo = ', $out);
    194         }
    195 
    196         function test_footag_val() {
    197                 $val = rand_str();
    198                 $out = do_shortcode('[footag foo="'.$val.'"]');
    199                 $this->assertEquals('foo = '.$val, $out);
    200         }
    201 
    202         function test_nested_tags() {
    203                 $out = do_shortcode('[baztag][dumptag abc="foo" def=123 http://wordpress.com/][/baztag]');
    204                 $expected = "content = abc = foo\ndef = 123\n0 = http://wordpress.com\n";
    205                 $this->assertEquals($expected, $out);
    206         }
    207 
    208         /**
    209          * @ticket 6518
    210          */
    211         function test_tag_escaped() {
    212                 $out = do_shortcode('[[footag]] [[bartag foo="bar"]]');
    213                 $this->assertEquals('[footag] [bartag foo="bar"]', $out);
    214 
    215                 $out = do_shortcode('[[footag /]] [[bartag foo="bar" /]]');
    216                 $this->assertEquals('[footag /] [bartag foo="bar" /]', $out);
    217 
    218                 $out = do_shortcode('[[baztag foo="bar"]the content[/baztag]]');
    219                 $this->assertEquals('[baztag foo="bar"]the content[/baztag]', $out);
    220 
    221                 // double escaped
    222                 $out = do_shortcode('[[[footag]]] [[[bartag foo="bar"]]]');
    223                 $this->assertEquals('[[footag]] [[bartag foo="bar"]]', $out);
    224         }
    225 
    226         function test_tag_not_escaped() {
    227                 // these have square brackets on either end but aren't actually escaped
    228                 $out = do_shortcode('[[footag] [bartag foo="bar"]]');
    229                 $this->assertEquals('[foo =  foo = bar]', $out);
    230 
    231                 $out = do_shortcode('[[footag /] [bartag foo="bar" /]]');
    232                 $this->assertEquals('[foo =  foo = bar]', $out);
    233 
    234                 $out = do_shortcode('[[baztag foo="bar"]the content[/baztag]');
    235                 $this->assertEquals('[content = the content', $out);
    236 
    237                 $out = do_shortcode('[[not-a-tag]]');
    238                 $this->assertEquals('[[not-a-tag]]', $out);
    239 
    240                 $out = do_shortcode('[[[footag] [bartag foo="bar"]]]');
    241                 $this->assertEquals('[[foo =  foo = bar]]', $out);
    242         }
    243 
    244         function test_mixed_tags() {
    245                 $in = <<<EOF
    246 So this is a post with [footag foo="some stuff"] and a bunch of tags.
    247 
    248 [bartag]
    249 
    250 [baztag]
    251 Here's some content
    252 on more than one line
    253 [/baztag]
    254 
    255 [bartag foo=1] [baztag] [footag foo="2"] [baztag]
    256 
    257 [baztag]
    258 more content
    259 [/baztag]
    260 
    261 EOF;
    262                 $expected = <<<EOF
    263 So this is a post with foo = some stuff and a bunch of tags.
    264 
    265 foo = no foo
    266 
    267 content =
    268 Here's some content
    269 on more than one line
    270 
    271 
    272 foo = 1 content =  foo = 2 content =
    273 content =
    274 more content
    275 
    276 EOF;
    277                 $out = do_shortcode($in);
    278                 $this->assertEquals(strip_ws($expected), strip_ws($out));
    279         }
    280 
    281         /**
    282          * @ticket 6562
    283          */
    284         function test_utf8_whitespace_1() {
    285                 // NO-BREAK SPACE: U+00A0
    286                 do_shortcode("[test-shortcode-tag foo=\"bar\" \xC2\xA0baz=\"123\"]");
    287                 $this->assertEquals( array('foo' => 'bar', 'baz' => '123'), $this->atts );
    288                 $this->assertEquals( '', $this->content );
    289         }
    290 
    291         /**
    292          * @ticket 6562
    293          */
    294         function test_utf8_whitespace_2() {
    295                 // ZERO WIDTH SPACE: U+200B
    296                 do_shortcode("[test-shortcode-tag foo=\"bar\" \xE2\x80\x8Babc=\"def\"]");
    297                 $this->assertEquals( array('foo' => 'bar', 'abc' => 'def'), $this->atts );
    298                 $this->assertEquals( '', $this->content );
    299         }
    300 
    301         /**
    302          * @ticket 14050
    303          */
    304         function test_shortcode_unautop() {
    305                 // a blank line is added at the end, so test with it already there
    306                 $test_string = "[footag]\n";
    307                 $this->assertEquals( $test_string, shortcode_unautop( wpautop( $test_string ) ) );
    308         }
    309 
    310         /**
    311          * @ticket 14050
    312          */
    313         function test_multiple_shortcode_unautop() {
    314                 // a blank line is added at the end, so test with it already there
    315                 $test_string = "[footag]\n[footag]\n";
    316                 $actual = shortcode_unautop( wpautop( $test_string ) );
    317                 $this->assertEquals( $test_string, $actual );
    318         }
    319 
    320         /**
    321          * @ticket 10326
    322          */
    323         function test_strip_shortcodes() {
    324                 $this->assertEquals('before', strip_shortcodes('before[gallery]'));
    325                 $this->assertEquals('after', strip_shortcodes('[gallery]after'));
    326                 $this->assertEquals('beforeafter', strip_shortcodes('before[gallery]after'));
    327         }
    328 
    329 
    330         // Store passed in shortcode_atts_{$shortcode} args
    331         function _filter_atts( $out, $pairs, $atts ) {
    332                 $this->filter_atts_out = $out;
    333                 $this->filter_atts_pairs = $pairs;
    334                 $this->filter_atts_atts = $atts;
    335                 return $out;
    336         }
    337 
    338         // Filter shortcode atts in various ways
    339         function _filter_atts2( $out, $pairs, $atts ) {
    340                 // If foo attribute equals "foo1", change it to be default value
    341                 if ( isset( $out['foo'] ) && 'foo1' == $out['foo'] )
    342                         $out['foo'] = $pairs['foo'];
    343 
    344                 // If baz attribute is set, remove it
    345                 if ( isset( $out['baz'] ) )
    346                         unset( $out['baz'] );
    347 
    348                 $this->filter_atts_out = $out;
    349                 return $out;
    350         }
    351 
    352         function test_shortcode_atts_filter_passes_original_arguments() {
    353                 add_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts' ), 10, 3 );
    354 
    355                 do_shortcode('[bartag foo="foo1" /]');
    356                 $this->assertEquals( array( 'foo' => 'foo1', 'baz' => 'default baz' ), $this->filter_atts_out );
    357                 $this->assertEquals( array( 'foo' => 'no foo', 'baz' => 'default baz' ), $this->filter_atts_pairs );
    358                 $this->assertEquals( array( 'foo' => 'foo1' ), $this->filter_atts_atts );
    359 
    360                 remove_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts' ), 10, 3 );
    361         }
    362 
    363         function test_shortcode_atts_filtering() {
    364                 add_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts2' ), 10, 3 );
    365 
    366                 $out = do_shortcode('[bartag foo="foo1" baz="baz1" /]');
    367                 $this->assertEquals( array( 'foo' => 'no foo' ), $this->filter_atts_out );
    368                 $this->assertEquals( 'foo = no foo', $out );
    369 
    370                 $out = do_shortcode('[bartag foo="foo2" /]');
    371                 $this->assertEquals( 'foo = foo2', $out );
    372 
    373                 remove_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts2' ), 10, 3 );
    374         }
    375 
    376 }
     1<?php
     2/**
     3 * @group shortcode
     4 */
     5class Tests_Shortcode extends WP_UnitTestCase {
     6
     7        protected $shortcodes = array( 'test-shortcode-tag', 'footag', 'bartag', 'baztag', 'dumptag', 'hyphen', 'hyphen-foo', 'hyphen-foo-bar' );
     8
     9        function setUp() {
     10                parent::setUp();
     11
     12                foreach ( $this->shortcodes as $shortcode )
     13                        add_shortcode( $shortcode, array( $this, '_shortcode_' . str_replace( '-', '_', $shortcode ) ) );
     14
     15                $this->atts = null;
     16                $this->content = null;
     17                $this->tagname = null;
     18
     19        }
     20
     21        function tearDown() {
     22                global $shortcode_tags;
     23                parent::tearDown();
     24                foreach ( $this->shortcodes as $shortcode )
     25                        unset( $shortcode_tags[ $shortcode ] );
     26        }
     27
     28        function _shortcode_test_shortcode_tag( $atts, $content = null, $tagname = null ) {
     29                $this->atts = $atts;
     30                $this->content = $content;
     31                $this->tagname = $tagname;
     32                $this->filter_atts_out = null;
     33                $this->filter_atts_pairs = null;
     34                $this->filter_atts_atts = null;
     35        }
     36
     37        // [footag foo="bar"]
     38        function _shortcode_footag( $atts ) {
     39                return @"foo = {$atts['foo']}";
     40        }
     41
     42        // [bartag foo="bar"]
     43        function _shortcode_bartag( $atts ) {
     44                extract(shortcode_atts(array(
     45                        'foo' => 'no foo',
     46                        'baz' => 'default baz',
     47                ), $atts, 'bartag'));
     48
     49                return "foo = {$foo}";
     50        }
     51
     52        // [baztag]content[/baztag]
     53        function _shortcode_baztag( $atts, $content = '' ) {
     54                return 'content = '.do_shortcode($content);
     55        }
     56
     57        function _shortcode_dumptag( $atts ) {
     58                $out = '';
     59                foreach ($atts as $k=>$v)
     60                        $out .= "$k = $v\n";
     61                return $out;
     62        }
     63
     64        function _shortcode_hyphen() {
     65                return __FUNCTION__;
     66        }
     67
     68        function _shortcode_hyphen_foo() {
     69                return __FUNCTION__;
     70        }
     71
     72        function _shortcode_hyphen_foo_bar() {
     73                return __FUNCTION__;
     74        }
     75
     76        function test_noatts() {
     77                do_shortcode('[test-shortcode-tag /]');
     78                $this->assertEquals( '', $this->atts );
     79                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     80        }
     81
     82        function test_one_att() {
     83                do_shortcode('[test-shortcode-tag foo="asdf" /]');
     84                $this->assertEquals( array('foo' => 'asdf'), $this->atts );
     85                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     86        }
     87
     88        function test_not_a_tag() {
     89                $out = do_shortcode('[not-a-shortcode-tag]');
     90                $this->assertEquals( '[not-a-shortcode-tag]', $out );
     91        }
     92
     93        /**
     94         * @ticket 17657
     95         */
     96        function test_tag_hyphen_not_tag() {
     97                $out = do_shortcode( '[dumptag-notreal]' );
     98                $this->assertEquals( '[dumptag-notreal]', $out );
     99        }
     100
     101        function test_tag_underscore_not_tag() {
     102                $out = do_shortcode( '[dumptag_notreal]' );
     103                $this->assertEquals( '[dumptag_notreal]', $out );
     104        }
     105
     106        function test_tag_not_tag() {
     107                $out = do_shortcode( '[dumptagnotreal]' );
     108                $this->assertEquals( '[dumptagnotreal]', $out );
     109        }
     110
     111        /**
     112         * @ticket 17657
     113         */
     114        function test_tag_hyphen() {
     115                $this->assertEquals( '_shortcode_hyphen', do_shortcode( '[hyphen]' ) );
     116                $this->assertEquals( '_shortcode_hyphen_foo', do_shortcode( '[hyphen-foo]' ) );
     117                $this->assertEquals( '_shortcode_hyphen_foo_bar', do_shortcode( '[hyphen-foo-bar]' ) );
     118                $this->assertEquals( '[hyphen-baz]', do_shortcode( '[hyphen-baz]' ) );
     119                $this->assertEquals( '[hyphen-foo-bar-baz]', do_shortcode( '[hyphen-foo-bar-baz]' ) );
     120        }
     121
     122        function test_two_atts() {
     123                do_shortcode('[test-shortcode-tag foo="asdf" bar="bing" /]');
     124                $this->assertEquals( array('foo' => 'asdf', 'bar' => 'bing'), $this->atts );
     125                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     126        }
     127
     128        function test_noatts_enclosing() {
     129                do_shortcode('[test-shortcode-tag]content[/test-shortcode-tag]');
     130                $this->assertEquals( '', $this->atts );
     131                $this->assertEquals( 'content', $this->content );
     132                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     133        }
     134
     135        function test_one_att_enclosing() {
     136                do_shortcode('[test-shortcode-tag foo="bar"]content[/test-shortcode-tag]');
     137                $this->assertEquals( array('foo' => 'bar'), $this->atts );
     138                $this->assertEquals( 'content', $this->content );
     139                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     140        }
     141
     142        function test_two_atts_enclosing() {
     143                do_shortcode('[test-shortcode-tag foo="bar" baz="bing"]content[/test-shortcode-tag]');
     144                $this->assertEquals( array('foo' => 'bar', 'baz' => 'bing'), $this->atts );
     145                $this->assertEquals( 'content', $this->content );
     146                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     147        }
     148
     149        function test_unclosed() {
     150                $out = do_shortcode('[test-shortcode-tag]');
     151                $this->assertEquals( '', $out );
     152                $this->assertEquals( '', $this->atts );
     153                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     154        }
     155
     156        function test_positional_atts_num() {
     157                $out = do_shortcode('[test-shortcode-tag 123]');
     158                $this->assertEquals( '', $out );
     159                $this->assertEquals( array(0=>'123'), $this->atts );
     160                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     161        }
     162
     163        function test_positional_atts_url() {
     164                $out = do_shortcode('[test-shortcode-tag http://www.youtube.com/watch?v=eBGIQ7ZuuiU]');
     165                $this->assertEquals( '', $out );
     166                $this->assertEquals( array(0=>'http://www.youtube.com/watch?v=eBGIQ7ZuuiU'), $this->atts );
     167                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     168        }
     169
     170        function test_positional_atts_quotes() {
     171                $out = do_shortcode('[test-shortcode-tag "something in quotes" "something else"]');
     172                $this->assertEquals( '', $out );
     173                $this->assertEquals( array(0=>'something in quotes', 1=>'something else'), $this->atts );
     174                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     175        }
     176
     177        function test_positional_atts_mixed() {
     178                $out = do_shortcode('[test-shortcode-tag 123 http://wordpress.com/ 0 "foo" bar]');
     179                $this->assertEquals( '', $out );
     180                $this->assertEquals( array(0=>'123', 1=>'http://wordpress.com/', 2=>'0', 3=>'foo', 4=>'bar'), $this->atts );
     181                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     182        }
     183
     184        function test_positional_and_named_atts() {
     185                $out = do_shortcode('[test-shortcode-tag 123 url=http://wordpress.com/ foo bar="baz"]');
     186                $this->assertEquals( '', $out );
     187                $this->assertEquals( array(0=>'123', 'url' => 'http://wordpress.com/', 1=>'foo', 'bar' => 'baz'), $this->atts );
     188                $this->assertEquals( 'test-shortcode-tag', $this->tagname );
     189        }
     190
     191        function test_footag_default() {
     192                $out = do_shortcode('[footag]');
     193                $this->assertEquals('foo = ', $out);
     194        }
     195
     196        function test_footag_val() {
     197                $val = rand_str();
     198                $out = do_shortcode('[footag foo="'.$val.'"]');
     199                $this->assertEquals('foo = '.$val, $out);
     200        }
     201
     202        function test_nested_tags() {
     203                $out = do_shortcode('[baztag][dumptag abc="foo" def=123 http://wordpress.com/][/baztag]');
     204                $expected = "content = abc = foo\ndef = 123\n0 = http://wordpress.com\n";
     205                $this->assertEquals($expected, $out);
     206        }
     207
     208        /**
     209         * @ticket 6518
     210         */
     211        function test_tag_escaped() {
     212                $out = do_shortcode('[[footag]] [[bartag foo="bar"]]');
     213                $this->assertEquals('[footag] [bartag foo="bar"]', $out);
     214
     215                $out = do_shortcode('[[footag /]] [[bartag foo="bar" /]]');
     216                $this->assertEquals('[footag /] [bartag foo="bar" /]', $out);
     217
     218                $out = do_shortcode('[[baztag foo="bar"]the content[/baztag]]');
     219                $this->assertEquals('[baztag foo="bar"]the content[/baztag]', $out);
     220
     221                // double escaped
     222                $out = do_shortcode('[[[footag]]] [[[bartag foo="bar"]]]');
     223                $this->assertEquals('[[footag]] [[bartag foo="bar"]]', $out);
     224        }
     225
     226        function test_tag_not_escaped() {
     227                // these have square brackets on either end but aren't actually escaped
     228                $out = do_shortcode('[[footag] [bartag foo="bar"]]');
     229                $this->assertEquals('[foo =  foo = bar]', $out);
     230
     231                $out = do_shortcode('[[footag /] [bartag foo="bar" /]]');
     232                $this->assertEquals('[foo =  foo = bar]', $out);
     233
     234                $out = do_shortcode('[[baztag foo="bar"]the content[/baztag]');
     235                $this->assertEquals('[content = the content', $out);
     236
     237                $out = do_shortcode('[[not-a-tag]]');
     238                $this->assertEquals('[[not-a-tag]]', $out);
     239
     240                $out = do_shortcode('[[[footag] [bartag foo="bar"]]]');
     241                $this->assertEquals('[[foo =  foo = bar]]', $out);
     242        }
     243
     244        function test_mixed_tags() {
     245                $in = <<<EOF
     246So this is a post with [footag foo="some stuff"] and a bunch of tags.
     247
     248[bartag]
     249
     250[baztag]
     251Here's some content
     252on more than one line
     253[/baztag]
     254
     255[bartag foo=1] [baztag] [footag foo="2"] [baztag]
     256
     257[baztag]
     258more content
     259[/baztag]
     260
     261EOF;
     262                $expected = <<<EOF
     263So this is a post with foo = some stuff and a bunch of tags.
     264
     265foo = no foo
     266
     267content =
     268Here's some content
     269on more than one line
     270
     271
     272foo = 1 content =  foo = 2 content =
     273content =
     274more content
     275
     276EOF;
     277                $out = do_shortcode($in);
     278                $this->assertEquals(strip_ws($expected), strip_ws($out));
     279        }
     280
     281        /**
     282         * @ticket 6562
     283         */
     284        function test_utf8_whitespace_1() {
     285                // NO-BREAK SPACE: U+00A0
     286                do_shortcode("[test-shortcode-tag foo=\"bar\" \xC2\xA0baz=\"123\"]");
     287                $this->assertEquals( array('foo' => 'bar', 'baz' => '123'), $this->atts );
     288                $this->assertEquals( '', $this->content );
     289        }
     290
     291        /**
     292         * @ticket 6562
     293         */
     294        function test_utf8_whitespace_2() {
     295                // ZERO WIDTH SPACE: U+200B
     296                do_shortcode("[test-shortcode-tag foo=\"bar\" \xE2\x80\x8Babc=\"def\"]");
     297                $this->assertEquals( array('foo' => 'bar', 'abc' => 'def'), $this->atts );
     298                $this->assertEquals( '', $this->content );
     299        }
     300
     301        /**
     302         * @ticket 14050
     303         */
     304        function test_shortcode_unautop() {
     305                // a blank line is added at the end, so test with it already there
     306                $test_string = "[footag]\n";
     307                $this->assertEquals( $test_string, shortcode_unautop( wpautop( $test_string ) ) );
     308        }
     309
     310        /**
     311         * @ticket 14050
     312         */
     313        function test_multiple_shortcode_unautop() {
     314                // a blank line is added at the end, so test with it already there
     315                $test_string = "[footag]\n[footag]\n";
     316                $actual = shortcode_unautop( wpautop( $test_string ) );
     317                $this->assertEquals( $test_string, $actual );
     318        }
     319
     320        /**
     321         * @ticket 10326
     322         */
     323        function test_strip_shortcodes() {
     324                $this->assertEquals('before', strip_shortcodes('before[gallery]'));
     325                $this->assertEquals('after', strip_shortcodes('[gallery]after'));
     326                $this->assertEquals('beforeafter', strip_shortcodes('before[gallery]after'));
     327        }
     328
     329
     330        // Store passed in shortcode_atts_{$shortcode} args
     331        function _filter_atts( $out, $pairs, $atts ) {
     332                $this->filter_atts_out = $out;
     333                $this->filter_atts_pairs = $pairs;
     334                $this->filter_atts_atts = $atts;
     335                return $out;
     336        }
     337
     338        // Filter shortcode atts in various ways
     339        function _filter_atts2( $out, $pairs, $atts ) {
     340                // If foo attribute equals "foo1", change it to be default value
     341                if ( isset( $out['foo'] ) && 'foo1' == $out['foo'] )
     342                        $out['foo'] = $pairs['foo'];
     343
     344                // If baz attribute is set, remove it
     345                if ( isset( $out['baz'] ) )
     346                        unset( $out['baz'] );
     347
     348                $this->filter_atts_out = $out;
     349                return $out;
     350        }
     351
     352        function test_shortcode_atts_filter_passes_original_arguments() {
     353                add_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts' ), 10, 3 );
     354
     355                do_shortcode('[bartag foo="foo1" /]');
     356                $this->assertEquals( array( 'foo' => 'foo1', 'baz' => 'default baz' ), $this->filter_atts_out );
     357                $this->assertEquals( array( 'foo' => 'no foo', 'baz' => 'default baz' ), $this->filter_atts_pairs );
     358                $this->assertEquals( array( 'foo' => 'foo1' ), $this->filter_atts_atts );
     359
     360                remove_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts' ), 10, 3 );
     361        }
     362
     363        function test_shortcode_atts_filtering() {
     364                add_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts2' ), 10, 3 );
     365
     366                $out = do_shortcode('[bartag foo="foo1" baz="baz1" /]');
     367                $this->assertEquals( array( 'foo' => 'no foo' ), $this->filter_atts_out );
     368                $this->assertEquals( 'foo = no foo', $out );
     369
     370                $out = do_shortcode('[bartag foo="foo2" /]');
     371                $this->assertEquals( 'foo = foo2', $out );
     372
     373                remove_filter( 'shortcode_atts_bartag', array( $this, '_filter_atts2' ), 10, 3 );
     374        }
     375
     376        /**
     377         * Check that shortcode_unautop() will always recognize spaces around shortcodes.
     378         *
     379         * @ticket 22692
     380         */
     381        function test_spaces_around_shortcodes() {
     382                $nbsp = "\xC2\xA0";
     383
     384                $input  = array();
     385
     386                $input[] = "<p>[gallery ids=\"37,15,11\"]</p>";
     387                $input[] = "<p> [gallery ids=\"37,15,11\"] </p>";
     388                $input[] = "<p> $nbsp[gallery ids=\"37,15,11\"] $nbsp</p>";
     389                $input[] = "<p> &nbsp;[gallery ids=\"37,15,11\"] &nbsp;</p>";
     390
     391                $output = "[gallery ids=\"37,15,11\"]";
     392
     393                foreach($input as $in) {
     394                        $this->assertEquals( $output, shortcode_unautop( $in ) );
     395                }
     396        }
     397}