Tests_Kses::data_slash_zero_removal()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 41
Code Lines 29

Duplication

Lines 40
Ratio 97.56 %

Importance

Changes 0
Metric Value
cc 1
eloc 29
nc 1
nop 0
dl 40
loc 41
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Some simple test cases for KSES post content filtering
4
 *
5
 * @group formatting
6
 * @group kses
7
 */
8
class Tests_Kses extends WP_UnitTestCase
9
{
10
11
    /**
12
     * @ticket 20210
13
     */
14
    function test_wp_filter_post_kses_address() 
15
    {
16
        global $allowedposttags;
17
18
        $attributes = array(
19
         'class' => 'classname',
20
         'id' => 'id',
21
         'style' => 'color: red;',
22
         'style' => 'color: red',
23
         'style' => 'color: red; text-align:center',
24
         'style' => 'color: red; text-align:center;',
25
         'title' => 'title',
26
        );
27
28 View Code Duplication
        foreach ( $attributes as $name => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
29
               $string = "<address $name='$value'>1 WordPress Avenue, The Internet.</address>";
30
               $expect_string = "<address $name='" . str_replace('; ', ';', trim($value, ';')) . "'>1 WordPress Avenue, The Internet.</address>";
31
               $this->assertEquals($expect_string, wp_kses($string, $allowedposttags));
32
        }
33
    }
34
35
    /**
36
     * @ticket 20210
37
     */
38
    function test_wp_filter_post_kses_a() 
39
    {
40
        global $allowedposttags;
41
42
        $attributes = array(
43
         'class' => 'classname',
44
         'id' => 'id',
45
         'style' => 'color: red;',
46
         'title' => 'title',
47
         'href' => 'http://example.com',
48
         'rel' => 'related',
49
         'rev' => 'revision',
50
         'name' => 'name',
51
         'target' => '_blank',
52
        );
53
54 View Code Duplication
        foreach ( $attributes as $name => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
55
               $string = "<a $name='$value'>I link this</a>";
56
               $expect_string = "<a $name='" . trim($value, ';') . "'>I link this</a>";
57
               $this->assertEquals($expect_string, wp_kses($string, $allowedposttags));
58
        }
59
    }
60
61
    /**
62
     * @ticket 20210
63
     */
64
    function test_wp_filter_post_kses_abbr() 
65
    {
66
        global $allowedposttags;
67
68
        $attributes = array(
69
         'class' => 'classname',
70
         'id' => 'id',
71
         'style' => 'color: red;',
72
         'title' => 'title',
73
        );
74
75 View Code Duplication
        foreach ( $attributes as $name => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
76
               $string = "<abbr $name='$value'>WP</abbr>";
77
               $expect_string = "<abbr $name='" . trim($value, ';') . "'>WP</abbr>";
78
               $this->assertEquals($expect_string, wp_kses($string, $allowedposttags));
79
        }
80
    }
81
82
    function test_feed_links() 
83
    {
84
        global $allowedposttags;
85
86
        $content = <<<EOF
87
<a href="feed:javascript:alert(1)">CLICK ME</a>
88
<a href="feed:javascript:feed:alert(1)">CLICK ME</a>
89
<a href="feed:feed:javascript:alert(1)">CLICK ME</a>
90
<a href="javascript:feed:alert(1)">CLICK ME</a>
91
<a href="javascript:feed:javascript:alert(1)">CLICK ME</a>
92
<a href="feed:feed:feed:javascript:alert(1)">CLICK ME</a>
93
<a href="feed:feed:feed:feed:javascript:alert(1)">CLICK ME</a>
94
<a href="feed:feed:feed:feed:feed:javascript:alert(1)">CLICK ME</a>
95
<a href="feed:javascript:feed:javascript:feed:javascript:alert(1)">CLICK ME</a>
96
<a href="feed:javascript:feed:javascript:feed:javascript:feed:javascript:feed:javascript:alert(1)">CLICK ME</a>
97
<a href="feed:feed:feed:http:alert(1)">CLICK ME</a>
98
EOF;
99
100
        $expected = <<<EOF
101
<a href="feed:alert(1)">CLICK ME</a>
102
<a href="feed:feed:alert(1)">CLICK ME</a>
103
<a href="feed:feed:alert(1)">CLICK ME</a>
104
<a href="feed:alert(1)">CLICK ME</a>
105
<a href="feed:alert(1)">CLICK ME</a>
106
<a href="">CLICK ME</a>
107
<a href="">CLICK ME</a>
108
<a href="">CLICK ME</a>
109
<a href="">CLICK ME</a>
110
<a href="">CLICK ME</a>
111
<a href="">CLICK ME</a>
112
EOF;
113
114
        $this->assertEquals($expected, wp_kses($content, $allowedposttags));
115
    }
116
117
    function test_wp_kses_bad_protocol() 
118
    {
119
        $bad = array(
120
         'dummy:alert(1)',
121
         'javascript:alert(1)',
122
         'JaVaScRiPt:alert(1)',
123
         'javascript:alert(1);',
124
         'javascript&#58;alert(1);',
125
         'javascript&#0058;alert(1);',
126
         'javascript&#0000058alert(1);',
127
         'javascript&#x3A;alert(1);',
128
         'javascript&#X3A;alert(1);',
129
         'javascript&#X3a;alert(1);',
130
         'javascript&#x3a;alert(1);',
131
         'javascript&#x003a;alert(1);',
132
         '&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29',
133
         'jav	ascript:alert(1);',
134
         'jav&#x09;ascript:alert(1);',
135
         'jav&#x0A;ascript:alert(1);',
136
         'jav&#x0D;ascript:alert(1);',
137
         ' &#14;  javascript:alert(1);',
138
         'javascript:javascript:alert(1);',
139
         'javascript&#58;javascript:alert(1);',
140
         'javascript&#0000058javascript:alert(1);',
141
         'javascript:javascript&#58;alert(1);',
142
         'javascript:javascript&#0000058alert(1);',
143
         'javascript&#0000058alert(1)//?:',
144
         'feed:javascript:alert(1)',
145
         'feed:javascript:feed:javascript:feed:javascript:alert(1)',
146
        );
147
        foreach ( $bad as $k => $x ) {
148
               $result = wp_kses_bad_protocol(wp_kses_normalize_entities($x), wp_allowed_protocols());
149
            if (! empty($result) && $result != 'alert(1);' && $result != 'alert(1)' ) {
0 ignored issues
show
introduced by
Found "!= '". Use Yoda Condition checks, you must
Loading history...
introduced by
Expected 1 space before "!"; 0 found
Loading history...
150
                switch ( $k ) {
151
                case 6: $this->assertEquals('javascript&amp;#0000058alert(1);', $result); 
152
                    break;
153
                case 12:
154
                    $this->assertEquals(str_replace('&', '&amp;', $x), $result);
155
                    break;
156
                case 22: $this->assertEquals('javascript&amp;#0000058alert(1);', $result); 
157
                    break;
158
                case 23: $this->assertEquals('javascript&amp;#0000058alert(1)//?:', $result); 
159
                    break;
160
                case 24: $this->assertEquals('feed:alert(1)', $result); 
161
                    break;
162
                default: $this->fail("wp_kses_bad_protocol failed on $x. Result: $result");
163
                }
164
            }
165
        }
166
167
        $safe = array(
168
         'dummy:alert(1)',
169
         'HTTP://example.org/',
170
         'http://example.org/',
171
         'http&#58;//example.org/',
172
         'http&#x3A;//example.org/',
173
         'https://example.org',
174
         'http://example.org/wp-admin/post.php?post=2&amp;action=edit',
175
         'http://example.org/index.php?test=&#039;blah&#039;',
176
        );
177
        foreach ( $safe as $x ) {
178
               $result = wp_kses_bad_protocol(wp_kses_normalize_entities($x), array( 'http', 'https', 'dummy' ));
179
            if ($result != $x && $result != 'http://example.org/' ) {
0 ignored issues
show
introduced by
Found "!= '". Use Yoda Condition checks, you must
Loading history...
180
                $this->fail("wp_kses_bad_protocol incorrectly blocked $x");
181
            }
182
        }
183
    }
184
185
    public function test_hackers_attacks() 
186
    {
187
        $xss = simplexml_load_file(DIR_TESTDATA . '/formatting/xssAttacks.xml');
188
        foreach ( $xss->attack as $attack ) {
189
            if (in_array($attack->name, array( 'IMG Embedded commands 2', 'US-ASCII encoding', 'OBJECT w/Flash 2', 'Character Encoding Example' )) ) {
190
                continue;
191
            }
192
193
            $code = (string) $attack->code;
194
195
            if ($code == 'See Below' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
196
                continue;
197
            }
198
199
            if (substr($code, 0, 4) == 'perl' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
200
                $pos = strpos($code, '"') + 1;
201
                $code = substr($code, $pos, strrpos($code, '"') - $pos);
202
                $code = str_replace('\0', "\0", $code);
203
            }
204
205
            $result = trim(wp_kses_data($code));
206
207
            if ($result == '' || $result == 'XSS' || $result == 'alert("XSS");' || $result == "alert('XSS');" ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
introduced by
Found "== "". Use Yoda Condition checks, you must
Loading history...
208
                continue;
209
            }
210
211
            switch ( $attack->name ) {
212
            case 'XSS Locator':
213
                $this->assertEquals('\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//--&gt;"&gt;\'&gt;alert(String.fromCharCode(88,83,83))=&amp;{}', $result);
214
                break;
215
            case 'XSS Quick Test':
216
                $this->assertEquals('\'\';!--"=&amp;{()}', $result);
217
                break;
218
            case 'SCRIPT w/Alert()':
219
                $this->assertEquals("alert('XSS')", $result);
220
                break;
221
            case 'SCRIPT w/Char Code':
222
                $this->assertEquals('alert(String.fromCharCode(88,83,83))', $result);
223
                break;
224
            case 'IMG STYLE w/expression':
225
                $this->assertEquals('exp/*', $result);
226
                break;
227
            case 'List-style-image':
228
                $this->assertEquals('li {list-style-image: url("javascript:alert(\'XSS\')");}XSS', $result);
229
                break;
230
            case 'STYLE':
231
                $this->assertEquals("alert('XSS');", $result);
232
                break;
233
            case 'STYLE w/background-image':
234
                $this->assertEquals('.XSS{background-image:url("javascript:alert(\'XSS\')");}<A></A>', $result);
235
                break;
236
            case 'STYLE w/background':
237
                $this->assertEquals('BODY{background:url("javascript:alert(\'XSS\')")}', $result);
238
                break;
239
            case 'Remote Stylesheet 2':
240
                $this->assertEquals("@import'http://ha.ckers.org/xss.css';", $result);
241
                break;
242
            case 'Remote Stylesheet 3':
243
                $this->assertEquals('&lt;META HTTP-EQUIV=&quot;Link&quot; Content=&quot;; REL=stylesheet"&gt;', $result);
244
                break;
245
            case 'Remote Stylesheet 4':
246
                $this->assertEquals('BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}', $result);
247
                break;
248
            case 'XML data island w/CDATA':
249
                $this->assertEquals("&lt;![CDATA[]]&gt;", $result);
250
                break;
251
            case 'XML data island w/comment':
252
                $this->assertEquals("<I><B>&lt;IMG SRC=&quot;javas<!-- -->cript:alert('XSS')\"&gt;</B></I>", $result);
253
                break;
254
            case 'XML HTML+TIME':
255
                $this->assertEquals('&lt;t:set attributeName=&quot;innerHTML&quot; to=&quot;XSSalert(\'XSS\')"&gt;', $result);
256
                break;
257
            case 'Commented-out Block':
258
                $this->assertEquals("<!--[if gte IE 4]&gt;-->\nalert('XSS');", $result);
259
                break;
260
            case 'Cookie Manipulation':
261
                $this->assertEquals('&lt;META HTTP-EQUIV=&quot;Set-Cookie&quot; Content=&quot;USERID=alert(\'XSS\')"&gt;', $result);
262
                break;
263
            case 'SSI':
264
                $this->assertEquals('&lt;!--#exec cmd=&quot;/bin/echo &#039;<!--#exec cmd="/bin/echo \'=http://ha.ckers.org/xss.js&gt;\'"-->', $result);
265
                break;
266
            case 'PHP':
267
                $this->assertEquals('&lt;? echo(&#039;alert("XSS")\'); ?&gt;', $result);
268
                break;
269
            case 'UTF-7 Encoding':
270
                $this->assertEquals('+ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-', $result);
271
                break;
272
            case 'Escaping JavaScript escapes':
273
                $this->assertEquals('\";alert(\'XSS\');//', $result);
274
                break;
275
            case 'STYLE w/broken up JavaScript':
276
                $this->assertEquals('@im\port\'\ja\vasc\ript:alert("XSS")\';', $result);
277
                break;
278
            case 'Null Chars 2':
279
                $this->assertEquals('&amp;alert("XSS")', $result);
280
                break;
281
            case 'No Closing Script Tag':
282
                $this->assertEquals('&lt;SCRIPT SRC=http://ha.ckers.org/xss.js', $result);
283
                break;
284
            case 'Half-Open HTML/JavaScript':
285
                $this->assertEquals('&lt;IMG SRC=&quot;javascript:alert(&#039;XSS&#039;)&quot;', $result);
286
                break;
287
            case 'Double open angle brackets':
288
                $this->assertEquals('&lt;IFRAME SRC=http://ha.ckers.org/scriptlet.html &lt;', $result);
289
                break;
290
            case 'Extraneous Open Brackets':
291
                $this->assertEquals('&lt;alert("XSS");//&lt;', $result);
292
                break;
293
            case 'Malformed IMG Tags':
294
                $this->assertEquals('alert("XSS")"&gt;', $result);
295
                break;
296
            case 'No Quotes/Semicolons':
297
                $this->assertEquals("a=/XSS/\nalert(a.source)", $result);
298
                break;
299
            case 'Evade Regex Filter 1':
300
                $this->assertEquals('" SRC="http://ha.ckers.org/xss.js"&gt;', $result);
301
                break;
302
            case 'Evade Regex Filter 4':
303
                $this->assertEquals('\'" SRC="http://ha.ckers.org/xss.js"&gt;', $result);
304
                break;
305
            case 'Evade Regex Filter 5':
306
                $this->assertEquals('` SRC="http://ha.ckers.org/xss.js"&gt;', $result);
307
                break;
308
            case 'Filter Evasion 1':
309
                $this->assertEquals('document.write("&lt;SCRI&quot;);PT SRC="http://ha.ckers.org/xss.js"&gt;', $result);
310
                break;
311
            case 'Filter Evasion 2':
312
                $this->assertEquals('\'&gt;" SRC="http://ha.ckers.org/xss.js"&gt;', $result);
313
                break;
314
            default:
315
                $this->fail('KSES failed on ' . $attack->name . ': ' . $result);
316
            }
317
        }
318
    }
319
320
    function _wp_kses_allowed_html_filter( $html, $context ) 
321
    {
322
        if ('post' == $context ) {
323
              return array( 'a' => array( 'href' => true ) );
324
        } else {
325
              return array( 'a' => array( 'href' => false ) );
326
        }
327
    }
328
329
    /**
330
     * @ticket 20210
331
     */
332
    public function test_wp_kses_allowed_html() 
333
    {
334
        global $allowedposttags, $allowedtags, $allowedentitynames;
335
336
        $this->assertEquals($allowedposttags, wp_kses_allowed_html('post'));
337
338
        $tags = wp_kses_allowed_html('post');
339
340
        foreach ( $tags as $tag ) {
341
            $this->assertTrue($tag['class']);
342
            $this->assertTrue($tag['id']);
343
            $this->assertTrue($tag['style']);
344
            $this->assertTrue($tag['title']);
345
        }
346
347
        $this->assertEquals($allowedtags, wp_kses_allowed_html('data'));
348
        $this->assertEquals($allowedtags, wp_kses_allowed_html(''));
349
        $this->assertEquals($allowedtags, wp_kses_allowed_html());
350
351
        $tags = wp_kses_allowed_html('user_description');
352
        $this->assertTrue($tags['a']['rel']);
353
354
        $tags = wp_kses_allowed_html();
355
        $this->assertFalse(isset($tags['a']['rel']));
356
357
        $this->assertEquals(array(), wp_kses_allowed_html('strip'));
358
359
        $custom_tags = array(
360
         'a' => array(
361
          'href' => true,
362
          'rel' => true,
363
          'rev' => true,
364
          'name' => true,
365
          'target' => true,
366
         ),
367
        );
368
369
        $this->assertEquals($custom_tags, wp_kses_allowed_html($custom_tags));
370
371
        add_filter('wp_kses_allowed_html', array( $this, '_wp_kses_allowed_html_filter' ), 10, 2);
372
373
        $this->assertEquals(array( 'a' => array( 'href' => true ) ), wp_kses_allowed_html('post'));
374
        $this->assertEquals(array( 'a' => array( 'href' => false ) ), wp_kses_allowed_html('data'));
375
376
        remove_filter('wp_kses_allowed_html', array( $this, '_wp_kses_allowed_html_filter' ));
377
        $this->assertEquals($allowedposttags, wp_kses_allowed_html('post'));
378
        $this->assertEquals($allowedtags, wp_kses_allowed_html('data'));
379
    }
380
381
    function test_hyphenated_tag() 
382
    {
383
        $string = "<hyphenated-tag attribute=\"value\" otherattribute=\"value2\">Alot of hyphens.</hyphenated-tag>";
384
        $custom_tags = array(
385
         'hyphenated-tag' => array(
386
          'attribute' => true,
387
         ),
388
        );
389
        $expect_stripped_string = 'Alot of hyphens.';
390
391
        $expect_valid_string = "<hyphenated-tag attribute=\"value\">Alot of hyphens.</hyphenated-tag>";
392
        $this->assertEquals($expect_stripped_string, wp_kses_post($string));
393
        $this->assertEquals($expect_valid_string, wp_kses($string, $custom_tags));
394
    }
395
396
    /**
397
     * @ticket 26290
398
     */
399 View Code Duplication
    public function test_wp_kses_normalize_entities() 
400
    {
401
        $this->assertEquals('&spades;', wp_kses_normalize_entities('&spades;'));
402
403
        $this->assertEquals('&sup1;', wp_kses_normalize_entities('&sup1;'));
404
        $this->assertEquals('&sup2;', wp_kses_normalize_entities('&sup2;'));
405
        $this->assertEquals('&sup3;', wp_kses_normalize_entities('&sup3;'));
406
        $this->assertEquals('&frac14;', wp_kses_normalize_entities('&frac14;'));
407
        $this->assertEquals('&frac12;', wp_kses_normalize_entities('&frac12;'));
408
        $this->assertEquals('&frac34;', wp_kses_normalize_entities('&frac34;'));
409
        $this->assertEquals('&there4;', wp_kses_normalize_entities('&there4;'));
410
    }
411
412
    /**
413
     * Test removal of invalid binary data for HTML.
414
     *
415
     * @ticket       28506
416
     * @dataProvider data_ctrl_removal
417
     */
418
    function test_ctrl_removal( $input, $output ) 
419
    {
420
        global $allowedposttags;
421
422
        return $this->assertEquals($output, wp_kses($input, $allowedposttags));
423
    }
424
425 View Code Duplication
    function data_ctrl_removal() 
426
    {
427
        return array(
428
         array(
429
          "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\X1C\x1D\x1E\x1F",
430
          '',
431
         ),
432
         array(
433
          "\x00h\x01e\x02l\x03l\x04o\x05 \x06w\x07o\x08r\x0Bl\x0Cd\x0E.\x0F \x10W\x11O\x12R\x13D\x14P\x15R\x16E\x17S\x18S\x19 \x1AK\x1BS\X1CE\x1DS\x1E.\x1F/",
434
          'hello world. WORDPRESS KSES./',
435
         ),
436
         array(
437
          "\x1F\x1E\x1D\x1C\x1B\x1A\x19\x18\x17\x16\x15\x14\x13\x12\x11\x10\x0F\x0E\x0C\x0B\x08\x07\x06\x05\x04\X03\x02\x01\x00",
438
          '',
439
         ),
440
         array(
441
          "\x1Fh\x1Ee\x1Dl\x1Cl\x1Bo\x1A \x19w\x18o\x17r\x16l\x15d\x14.\x13 \x12W\x11O\x10R\x0FD\x0EP\x0CR\x0BE\x08S\x07S\x06 \x05K\x04S\X03E\x02S\x01.\x00/",
442
          'hello world. WORDPRESS KSES./',
443
         ),
444
         array(
445
          "\t\r\n word \n\r\t",
446
          "\t\r\n word \n\r\t",
447
         ),
448
        );
449
    }
450
451
    /**
452
     * Test removal of '\0' strings.
453
     *
454
     * @ticket       28699
455
     * @dataProvider data_slash_zero_removal
456
     */
457
    function test_slash_zero_removal( $input, $output ) 
458
    {
459
        global $allowedposttags;
460
461
        return $this->assertEquals($output, wp_kses($input, $allowedposttags));
462
    }
463
464 View Code Duplication
    function data_slash_zero_removal() 
465
    {
466
        return array(
467
         array(
468
          'This \\0 should be no big deal.',
469
          'This \\0 should be no big deal.',
470
         ),
471
         array(
472
          '<div>This \\0 should be no big deal.</div>',
473
          '<div>This \\0 should be no big deal.</div>',
474
         ),
475
         array(
476
          '<div align="\\0left">This should be no big deal.</div>',
477
          '<div align="\\0left">This should be no big deal.</div>',
478
         ),
479
         array(
480
          'This <div style="float:\\0left"> is more of a concern.',
481
          'This <div style="float:left"> is more of a concern.',
482
         ),
483
         array(
484
          'This <div style="float:\\0\\0left"> is more of a concern.',
485
          'This <div style="float:left"> is more of a concern.',
486
         ),
487
         array(
488
          'This <div style="float:\\\\00left"> is more of a concern.',
489
          'This <div style="float:left"> is more of a concern.',
490
         ),
491
         array(
492
          'This <div style="float:\\\\\\\\0000left"> is more of a concern.',
493
          'This <div style="float:left"> is more of a concern.',
494
         ),
495
         array(
496
          'This <div style="float:\\0000left"> is more of a concern.',
497
          'This <div style="float:left"> is more of a concern.',
498
         ),
499
         array(
500
          '<style type="text/css">div {background-image:\\0}</style>',
501
          'div {background-image:\\0}',
502
         ),
503
        );
504
    }
505
506
    /**
507
     * Test new function wp_kses_hair_parse().
508
     *
509
     * @dataProvider data_hair_parse
510
     */
511
    function test_hair_parse( $input, $output ) 
512
    {
513
        return $this->assertEquals($output, wp_kses_hair_parse($input));
514
    }
515
516
    function data_hair_parse() 
517
    {
518
        return array(
519
         array(
520
          'title="hello" href="#" id="my_id" ',
521
          array( 'title="hello" ', 'href="#" ', 'id="my_id" ' ),
522
         ),
523
         array(
524
          '[shortcode attr="value"] href="http://www.google.com/"title="moo"disabled',
525
          array( '[shortcode attr="value"] ', 'href="http://www.google.com/"', 'title="moo"', 'disabled' ),
526
         ),
527
         array(
528
          '',
529
          array(),
530
         ),
531
         array(
532
          'a',
533
          array( 'a' ),
534
         ),
535
         array(
536
          'title="hello"disabled href=# id=\'my_id\'',
537
          array( 'title="hello"', 'disabled ', 'href=# ', "id='my_id'" ),
538
         ),
539
         array(
540
          '     ', // Calling function is expected to strip leading whitespace.
541
          false,
542
         ),
543
         array(
544
          'abcd=abcd"abcd"',
545
          false,
546
         ),
547
         array(
548
          "array[1]='z'z'z'z",
549
          false,
550
         ),
551
        );
552
    }
553
554
    /**
555
     * Test new function wp_kses_attr_parse().
556
     *
557
     * @dataProvider data_attr_parse
558
     */
559
    function test_attr_parse( $input, $output ) 
560
    {
561
        return $this->assertEquals($output, wp_kses_attr_parse($input));
562
    }
563
564
    function data_attr_parse() 
565
    {
566
        return array(
567
         array(
568
          '<a title="hello" href="#" id="my_id" >',
569
          array( '<a ', 'title="hello" ', 'href="#" ', 'id="my_id" ', '>' ),
570
         ),
571
         array(
572
          '<a [shortcode attr="value"] href="http://www.google.com/"title="moo"disabled>',
573
          array( '<a ', '[shortcode attr="value"] ', 'href="http://www.google.com/"', 'title="moo"', 'disabled', '>' ),
574
         ),
575
         array(
576
          '',
577
          false,
578
         ),
579
         array(
580
          'a',
581
          false,
582
         ),
583
         array(
584
          '<a>',
585
          array( '<a', '>' ),
586
         ),
587
         array(
588
          '<a%%&&**>',
589
          false,
590
         ),
591
         array(
592
          '<a title="hello"disabled href=# id=\'my_id\'>',
593
          array( '<a ', 'title="hello"', 'disabled ', 'href=# ', "id='my_id'", ">" ),
594
         ),
595
         array(
596
          '<a     >',
597
          array( '<a     ', '>' ),
598
         ),
599
         array(
600
          '<a abcd=abcd"abcd">',
601
          false,
602
         ),
603
         array(
604
          "<a array[1]='z'z'z'z>",
605
          false,
606
         ),
607
         array(
608
          '<img title="hello" src="#" id="my_id" />',
609
          array( '<img ', 'title="hello" ', 'src="#" ', 'id="my_id"', ' />' ),
610
         ),
611
        );
612
    }
613
614
    /**
615
     * Test new function wp_kses_one_attr().
616
     *
617
     * @dataProvider data_one_attr
618
     */
619
    function test_one_attr( $element, $input, $output ) 
620
    {
621
        return $this->assertEquals($output, wp_kses_one_attr($input, $element));
622
    }
623
624
    function data_one_attr() 
625
    {
626
        return array(
627
         array(
628
          'a',
629
          ' title="hello" ',
630
          ' title="hello" ',
631
         ),
632
         array(
633
          'a',
634
          'title  =  "hello"',
635
          'title="hello"',
636
         ),
637
         array(
638
          'a',
639
          "title='hello'",
640
          "title='hello'",
641
         ),
642
         array(
643
          'a',
644
          'title=hello',
645
          'title="hello"',
646
         ),
647
         array(
648
          'a',
649
          'href="javascript:alert(1)"',
650
          'href="alert(1)"',
651
         ),
652
         array(
653
          'a',
654
          'style ="style "',
655
          'style="style"',
656
         ),
657
         array(
658
          'a',
659
          'style="style "',
660
          'style="style"',
661
         ),
662
         array(
663
          'a',
664
          'style ="style ="',
665
          '',
666
         ),
667
         array(
668
          'img',
669
          'src="mypic.jpg"',
670
          'src="mypic.jpg"',
671
         ),
672
         array(
673
          'img',
674
          'onerror=alert(1)',
675
          '',
676
         ),
677
         array(
678
          'img',
679
          'title=>',
680
          'title="&gt;"',
681
         ),
682
         array(
683
          'img',
684
          'title="&garbage";"',
685
          'title="&amp;garbage&quot;;"',
686
         ),
687
        );
688
    }
689
690
    /**
691
     * @ticket 34063
692
     */
693
    function test_bdo() 
694
    {
695
        global $allowedposttags;
696
697
        $input = '<p>This is <bdo dir="rtl">a BDO tag</bdo>. Weird, <bdo dir="ltr">right?</bdo></p>';
698
699
        $this->assertEquals($input, wp_kses($input, $allowedposttags));
700
    }
701
702
    /**
703
     * @ticket 35079
704
     */
705
    function test_ol_reversed() 
706
    {
707
        global $allowedposttags;
708
709
        $input = '<ol reversed="reversed"><li>Item 1</li><li>Item 2</li><li>Item 3</li></ol>';
710
711
        $this->assertEquals($input, wp_kses($input, $allowedposttags));
712
    }
713
}
714