2 namespace TYPO3\CMS\Core\Tests\Unit\Html
;
5 * This file is part of the TYPO3 CMS project.
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Core\Html\HtmlParser
;
20 * Testcase for \TYPO3\CMS\Core\Html\HtmlParser
22 class HtmlParserTest
extends \TYPO3\CMS\Core\Tests\UnitTestCase
{
25 * @var \TYPO3\CMS\Core\Html\HtmlParser
27 protected $subject = NULL;
29 protected function setUp() {
30 $this->subject
= new HtmlParser();
36 public function cDataWillRemainUnmodifiedDataProvider() {
38 'single-line CDATA' => array(
39 '/*<![CDATA[*/ <hello world> /*]]>*/',
40 '/*<![CDATA[*/ <hello world> /*]]>*/',
42 'multi-line CDATA #1' => array(
43 '/*<![CDATA[*/' . LF
. '<hello world> /*]]>*/',
44 '/*<![CDATA[*/' . LF
. '<hello world> /*]]>*/',
46 'multi-line CDATA #2' => array(
47 '/*<![CDATA[*/ <hello world>' . LF
. '/*]]>*/',
48 '/*<![CDATA[*/ <hello world>' . LF
. '/*]]>*/',
50 'multi-line CDATA #3' => array(
51 '/*<![CDATA[*/' . LF
. '<hello world>' . LF
. '/*]]>*/',
52 '/*<![CDATA[*/' . LF
. '<hello world>' . LF
. '/*]]>*/',
58 * Data provider for splitIntoBlock
62 public function splitIntoBlockDataProvider() {
64 'splitBlock' => array(
66 '<body><h1>Title</h1><span>Note</span></body>',
74 'splitBlock br' => array(
76 '<body><h1>Title</h1><br /><span>Note</span><br /></body>',
84 'splitBlock with attribute' => array(
86 '<body><h1 class="title">Title</h1><span>Note</span></body>',
89 '<h1 class="title">Title</h1>',
94 'splitBlock span with attribute' => array(
96 '<body><h1>Title</h1><span class="title">Note</span></body>',
98 array('<body><h1>Title</h1>',
99 '<span class="title">Note</span>',
102 'splitBlock without extra end tags' => array(
104 '<body><h1>Title</h1><span>Note</span></body></div>',
117 * @param string $tag List of tags, comma separated.
118 * @param string $content HTML-content
119 * @param bool $eliminateExtraEndTags If set, excessive end tags are ignored - you should probably set this in most cases.
120 * @param array $expected The expected result
121 * @dataProvider splitIntoBlockDataProvider
123 public function splitIntoBlock($tag, $content, $eliminateExtraEndTags, $expected) {
124 $this->assertSame($expected, $this->subject
->splitIntoBlock($tag, $content, $eliminateExtraEndTags));
129 * @param string $source
130 * @param string $expected
131 * @dataProvider cDataWillRemainUnmodifiedDataProvider
133 public function xHtmlCleaningDoesNotModifyCDATA($source, $expected) {
134 $result = $this->subject
->XHTML_clean($source);
135 $this->assertSame($expected, $result);
139 * Data provider for spanTagCorrectlyRemovedWhenRmTagIfNoAttribIsConfigured
141 public static function spanTagCorrectlyRemovedWhenRmTagIfNoAttribIsConfiguredDataProvider() {
143 'Span tag with no attrib' => array(
147 'Span tag with allowed id attrib' => array(
148 '<span id="id">text</span>',
149 '<span id="id">text</span>'
151 'Span tag with disallowed style attrib' => array(
152 '<span style="line-height: 12px;">text</span>',
160 * @param string $content
161 * @param string $expectedResult
162 * @dataProvider spanTagCorrectlyRemovedWhenRmTagIfNoAttribIsConfiguredDataProvider
164 public function tagCorrectlyRemovedWhenRmTagIfNoAttribIsConfigured($content, $expectedResult) {
166 'allowTags' => 'span',
169 'allowedAttribs' => 'id',
170 'rmTagIfNoAttrib' => 1
174 $this->assertEquals($expectedResult, $this->parseConfigAndCleanHtml($tsConfig, $content));
180 public function rmTagIfNoAttribIsConfiguredDoesNotChangeNestingType() {
182 'allowTags' => 'div,span',
183 'rmTagIfNoAttrib' => 'span',
184 'globalNesting' => 'div,span'
186 $content = '<span></span><span id="test"><div></span></div>';
187 $expectedResult = '<span id="test"></span>';
188 $this->assertEquals($expectedResult, $this->parseConfigAndCleanHtml($tsConfig, $content));
192 * Data provider for localNestingCorrectlyRemovesInvalidTags
196 public static function localNestingCorrectlyRemovesInvalidTagsDataProvider() {
198 'Valid nesting is untouched' => array(
202 'Valid nesting with content is untouched' => array(
203 'testa<B>test1<I>test2</B>test3</I>testb',
204 'testa<B>test1<I>test2</B>test3</I>testb'
206 'Superflous tags are removed' => array(
207 '</B><B><I></B></I></B>',
210 'Superflous tags with content are removed' => array(
211 'test1</B>test2<B>test3<I>test4</B>test5</I>test6</B>test7',
212 'test1test2<B>test3<I>test4</B>test5</I>test6test7'
214 'Another valid nesting test' => array(
215 '<span><div></span></div>',
216 '<span><div></span></div>',
223 * @dataProvider localNestingCorrectlyRemovesInvalidTagsDataProvider
224 * @param string $content
225 * @param string $expectedResult
227 public function localNestingCorrectlyRemovesInvalidTags($content, $expectedResult) {
229 'allowTags' => 'div,span,b,i',
230 'localNesting' => 'div,span,b,i',
232 $this->assertEquals($expectedResult, $this->parseConfigAndCleanHtml($tsConfig, $content));
236 * Data provider for globalNestingCorrectlyRemovesInvalidTags
240 public static function globalNestingCorrectlyRemovesInvalidTagsDataProvider() {
242 'Valid nesting is untouched' => array(
246 'Valid nesting with content is untouched' => array(
247 'testa<B>test1<I>test2</I>test3</B>testb',
248 'testa<B>test1<I>test2</I>test3</B>testb'
250 'Invalid nesting is cleaned' => array(
251 '</B><B><I></B></I></B>',
254 'Invalid nesting with content is cleaned' => array(
255 'test1</B>test2<B>test3<I>test4</B>test5</I>test6</B>test7',
256 'test1test2<B>test3test4</B>test5test6test7'
258 'Another invalid nesting test' => array(
259 '<span><div></span></div>',
267 * @dataProvider globalNestingCorrectlyRemovesInvalidTagsDataProvider
268 * @param string $content
269 * @param string $expectedResult
271 public function globalNestingCorrectlyRemovesInvalidTags($content, $expectedResult) {
273 'allowTags' => 'span,div,b,i',
274 'globalNesting' => 'span,div,b,i',
276 $this->assertEquals($expectedResult, $this->parseConfigAndCleanHtml($tsConfig, $content));
282 public function emptyTagsDataProvider() {
284 array(0 , NULL, FALSE, '<h1></h1>', '<h1></h1>'),
285 array(1 , NULL, FALSE, '<h1></h1>', ''),
286 array(1 , NULL, FALSE, '<h1>hallo</h1>', '<h1>hallo</h1>'),
287 array(1 , NULL, FALSE, '<h1 class="something"></h1>', ''),
288 array(1 , NULL, FALSE, '<h1 class="something"></h1><h2></h2>', ''),
289 array(1 , 'h2', FALSE, '<h1 class="something"></h1><h2></h2>', '<h1 class="something"></h1>'),
290 array(1 , 'h2, h1', FALSE, '<h1 class="something"></h1><h2></h2>', ''),
291 array(1 , NULL, FALSE, '<div><p></p></div>', ''),
292 array(1 , NULL, FALSE, '<div><p> </p></div>', '<div><p> </p></div>'),
293 array(1 , NULL, TRUE, '<div><p> </p></div>', ''),
294 array(1 , NULL, TRUE, '<div> <p></p></div>', ''),
295 array(1 , NULL, FALSE, '<div>Some content<p></p></div>', '<div>Some content</div>'),
296 array(1 , NULL, TRUE, '<div>Some content<p></p></div>', '<div>Some content</div>'),
297 array(1 , NULL, FALSE, '<div>Some content</div>', '<div>Some content</div>'),
298 array(1 , NULL, TRUE, '<div>Some content</div>', '<div>Some content</div>'),
299 array(1 , NULL, FALSE, '<a href="#skiplinks">Skiplinks </a><b></b>', '<a href="#skiplinks">Skiplinks </a>'),
300 array(1 , NULL, TRUE, '<a href="#skiplinks">Skiplinks </a><b></b>', '<a href="#skiplinks">Skiplinks </a>'),
306 * @dataProvider emptyTagsDataProvider
307 * @param bool $stripOn TRUE if stripping should be activated.
308 * @param string $tagList Comma seperated list of tags that should be stripped.
309 * @param bool $treatNonBreakingSpaceAsEmpty If TRUE will be considered empty.
310 * @param string $content The HTML code that should be modified.
311 * @param string $expectedResult The expected HTML code result.
313 public function stripEmptyTags($stripOn, $tagList, $treatNonBreakingSpaceAsEmpty, $content, $expectedResult) {
315 'keepNonMatchedTags' => 1,
316 'stripEmptyTags' => $stripOn,
317 'stripEmptyTags.' => array(
319 'treatNonBreakingSpaceAsEmpty' => $treatNonBreakingSpaceAsEmpty
323 $result = $this->parseConfigAndCleanHtml($tsConfig, $content);
324 $this->assertEquals($expectedResult, $result);
328 * Calls HTMLparserConfig() and passes the generated config to the HTMLcleaner() method on the current subject.
330 * @param array $tsConfig The TypoScript that should be used to generate the HTML parser config.
331 * @param string $content The content that should be parsed by the HTMLcleaner.
332 * @return string The parsed content.
334 protected function parseConfigAndCleanHtml(array $tsConfig, $content) {
335 $config = $this->subject
->HTMLparserConfig($tsConfig);
336 return $this->subject
->HTMLcleaner($content, $config[0], $config[1], $config[2], $config[3]);
342 public function removeFirstAndLastTagDataProvider() {
344 array('<span>Wrapper<div>Some content</div></span>', 'Wrapper<div>Some content</div>'),
345 array('<td><tr>Some content</tr></td>', '<tr>Some content</tr>'),
346 array('Something before<span>Wrapper<div>Some content</div></span>Something after', 'Wrapper<div>Some content</div>'),
347 array('<span class="hidden">Wrapper<div>Some content</div></span>', 'Wrapper<div>Some content</div>'),
348 array('<span>Wrapper<div class="hidden">Some content</div></span>', 'Wrapper<div class="hidden">Some content</div>'),
353 * Removes the first and last tag in the string
354 * Anything before the first and after the last tags respectively is also removed
357 * @dataProvider removeFirstAndLastTagDataProvider
358 * @param string $str String to process
359 * @param string $expectedResult
361 public function removeFirstAndLastTag($str, $expectedResult) {
362 $this->assertEquals($expectedResult, $this->subject
->removeFirstAndLastTag($str));