4b0161e92e2c2c31362d28d68ed47e6780ea95b0
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Unit / ContentObject / ContentObjectRendererTest.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Tests\Unit\ContentObject;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
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.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Log\LoggerInterface;
18 use TYPO3\CMS\Core\Charset\CharsetConverter;
19 use TYPO3\CMS\Core\Core\ApplicationContext;
20 use TYPO3\CMS\Core\Log\LogManager;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
23 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
24
25 /**
26 * Testcase for TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
27 */
28 class ContentObjectRendererTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
29
30 /**
31 * @var array A backup of registered singleton instances
32 */
33 protected $singletonInstances = array();
34
35 /**
36 * @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface|\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
37 */
38 protected $subject = NULL;
39
40 /**
41 * @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
42 */
43 protected $typoScriptFrontendControllerMock = NULL;
44
45 /**
46 * @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\TypoScript\TemplateService
47 */
48 protected $templateServiceMock = NULL;
49
50 /**
51 * Default content object name -> class name map, shipped with TYPO3 CMS
52 *
53 * @var array
54 */
55 protected $contentObjectMap = array(
56 'TEXT' => \TYPO3\CMS\Frontend\ContentObject\TextContentObject::class,
57 'CASE' => \TYPO3\CMS\Frontend\ContentObject\CaseContentObject::class,
58 'COBJ_ARRAY' => \TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayContentObject::class,
59 'COA' => \TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayContentObject::class,
60 'COA_INT' => \TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayInternalContentObject::class,
61 'USER' => \TYPO3\CMS\Frontend\ContentObject\UserContentObject::class,
62 'USER_INT' => \TYPO3\CMS\Frontend\ContentObject\UserInternalContentObject::class,
63 'FILE' => \TYPO3\CMS\Frontend\ContentObject\FileContentObject::class,
64 'FILES' => \TYPO3\CMS\Frontend\ContentObject\FilesContentObject::class,
65 'IMAGE' => \TYPO3\CMS\Frontend\ContentObject\ImageContentObject::class,
66 'IMG_RESOURCE' => \TYPO3\CMS\Frontend\ContentObject\ImageResourceContentObject::class,
67 'CONTENT' => \TYPO3\CMS\Frontend\ContentObject\ContentContentObject::class,
68 'RECORDS' => \TYPO3\CMS\Frontend\ContentObject\RecordsContentObject::class,
69 'HMENU' => \TYPO3\CMS\Frontend\ContentObject\HierarchicalMenuContentObject::class,
70 'CASEFUNC' => \TYPO3\CMS\Frontend\ContentObject\CaseContentObject::class,
71 'LOAD_REGISTER' => \TYPO3\CMS\Frontend\ContentObject\LoadRegisterContentObject::class,
72 'RESTORE_REGISTER' => \TYPO3\CMS\Frontend\ContentObject\RestoreRegisterContentObject::class,
73 'TEMPLATE' => \TYPO3\CMS\Frontend\ContentObject\TemplateContentObject::class,
74 'FLUIDTEMPLATE' => \TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject::class,
75 'SVG' => \TYPO3\CMS\Frontend\ContentObject\ScalableVectorGraphicsContentObject::class,
76 'EDITPANEL' => \TYPO3\CMS\Frontend\ContentObject\EditPanelContentObject::class
77 );
78
79 /**
80 * Set up
81 */
82 protected function setUp() {
83 $this->singletonInstances = \TYPO3\CMS\Core\Utility\GeneralUtility::getSingletonInstances();
84 $this->createMockedLoggerAndLogManager();
85
86 $this->templateServiceMock = $this->getMock(\TYPO3\CMS\Core\TypoScript\TemplateService::class, array('getFileName', 'linkData'));
87 $pageRepositoryMock = $this->getMock(\TYPO3\CMS\Frontend\Page\PageRepository::class, array('getRawRecord'));
88
89 $this->typoScriptFrontendControllerMock = $this->getAccessibleMock(\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::class, array('dummy'), array(), '', FALSE);
90 $this->typoScriptFrontendControllerMock->tmpl = $this->templateServiceMock;
91 $this->typoScriptFrontendControllerMock->config = array();
92 $this->typoScriptFrontendControllerMock->page = array();
93 $this->typoScriptFrontendControllerMock->sys_page = $pageRepositoryMock;
94 $this->typoScriptFrontendControllerMock->csConvObj = new CharsetConverter();
95 $this->typoScriptFrontendControllerMock->renderCharset = 'utf-8';
96 $GLOBALS['TSFE'] = $this->typoScriptFrontendControllerMock;
97
98 $GLOBALS['TYPO3_DB'] = $this->getMock(\TYPO3\CMS\Core\Database\DatabaseConnection::class, array());
99 $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_utils'] = 'mbstring';
100
101 $this->subject = $this->getAccessibleMock(
102 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class,
103 array('getResourceFactory', 'getEnvironmentVariable'),
104 array($this->typoScriptFrontendControllerMock)
105 );
106 $this->subject->setContentObjectClassMap($this->contentObjectMap);
107 $this->subject->start(array(), 'tt_content');
108 }
109
110 protected function tearDown() {
111 GeneralUtility::resetSingletonInstances($this->singletonInstances);
112 parent::tearDown();
113 }
114
115 //////////////////////
116 // Utility functions
117 //////////////////////
118
119 /**
120 * Avoid logging to the file system (file writer is currently the only configured writer)
121 */
122 protected function createMockedLoggerAndLogManager() {
123 $logManagerMock = $this->getMock(LogManager::class);
124 $loggerMock = $this->getMock(LoggerInterface::class);
125 $logManagerMock->expects($this->any())
126 ->method('getLogger')
127 ->willReturn($loggerMock);
128 GeneralUtility::setSingletonInstance(LogManager::class, $logManagerMock);
129 }
130
131 /**
132 * Converts the subject and the expected result into the target charset.
133 *
134 * @param string $charset the target charset
135 * @param string $subject the subject, will be modified
136 * @param string $expected the expected result, will be modified
137 */
138 protected function handleCharset($charset, &$subject, &$expected) {
139 $GLOBALS['TSFE']->renderCharset = $charset;
140 $subject = $GLOBALS['TSFE']->csConvObj->conv($subject, 'iso-8859-1', $charset);
141 $expected = $GLOBALS['TSFE']->csConvObj->conv($expected, 'iso-8859-1', $charset);
142 }
143
144 /////////////////////////////////////////////
145 // Tests concerning the getImgResource hook
146 /////////////////////////////////////////////
147 /**
148 * @test
149 */
150 public function getImgResourceCallsGetImgResourcePostProcessHook() {
151 $this->templateServiceMock
152 ->expects($this->atLeastOnce())
153 ->method('getFileName')
154 ->with('typo3/clear.gif')
155 ->will($this->returnValue('typo3/clear.gif'));
156
157 $resourceFactory = $this->getMock(\TYPO3\CMS\Core\Resource\ResourceFactory::class, array(), array(), '', FALSE);
158 $this->subject->expects($this->any())->method('getResourceFactory')->will($this->returnValue($resourceFactory));
159
160 $className = $this->getUniqueId('tx_coretest');
161 $getImgResourceHookMock = $this->getMock(\TYPO3\CMS\Frontend\ContentObject\ContentObjectGetImageResourceHookInterface::class, array('getImgResourcePostProcess'), array(), $className);
162 $getImgResourceHookMock
163 ->expects($this->once())
164 ->method('getImgResourcePostProcess')
165 ->will($this->returnCallback(array($this, 'isGetImgResourceHookCalledCallback')));
166 $getImgResourceHookObjects = array($getImgResourceHookMock);
167 $this->subject->_setRef('getImgResourceHookObjects', $getImgResourceHookObjects);
168 $this->subject->getImgResource('typo3/clear.gif', array());
169 }
170
171 /**
172 * Handles the arguments that have been sent to the getImgResource hook.
173 *
174 * @return array
175 * @see getImgResourceHookGetsCalled
176 */
177 public function isGetImgResourceHookCalledCallback() {
178 list($file, $fileArray, $imageResource, $parent) = func_get_args();
179 $this->assertEquals('typo3/clear.gif', $file);
180 $this->assertEquals('typo3/clear.gif', $imageResource['origFile']);
181 $this->assertTrue(is_array($fileArray));
182 $this->assertTrue($parent instanceof \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer);
183 return $imageResource;
184 }
185
186
187 //////////////////////////////////////
188 // Tests concerning getContentObject
189 //////////////////////////////////////
190
191 public function getContentObjectValidContentObjectsDataProvider() {
192 $dataProvider = array();
193 foreach ($this->contentObjectMap as $name => $className) {
194 $dataProvider[] = array($name, $className);
195 }
196 return $dataProvider;
197 }
198
199 /**
200 * @test
201 * @dataProvider getContentObjectValidContentObjectsDataProvider
202 * @param string $name TypoScript name of content object
203 * @param string $fullClassName Expected class name
204 */
205 public function getContentObjectCallsMakeInstanceForNewContentObjectInstance($name, $fullClassName) {
206 $contentObjectInstance = $this->getMock($fullClassName, array(), array(), '', FALSE);
207 \TYPO3\CMS\Core\Utility\GeneralUtility::addInstance($fullClassName, $contentObjectInstance);
208 $this->assertSame($contentObjectInstance, $this->subject->getContentObject($name));
209 }
210
211 /////////////////////////////////////////
212 // Tests concerning getQueryArguments()
213 /////////////////////////////////////////
214 /**
215 * @test
216 */
217 public function getQueryArgumentsExcludesParameters() {
218 $this->subject->expects($this->any())->method('getEnvironmentVariable')->with($this->equalTo('QUERY_STRING'))->will(
219 $this->returnValue('key1=value1&key2=value2&key3[key31]=value31&key3[key32][key321]=value321&key3[key32][key322]=value322')
220 );
221 $getQueryArgumentsConfiguration = array();
222 $getQueryArgumentsConfiguration['exclude'] = array();
223 $getQueryArgumentsConfiguration['exclude'][] = 'key1';
224 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key31]';
225 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key32][key321]';
226 $getQueryArgumentsConfiguration['exclude'] = implode(',', $getQueryArgumentsConfiguration['exclude']);
227 $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key2=value2&key3[key32][key322]=value322');
228 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration);
229 $this->assertEquals($expectedResult, $actualResult);
230 }
231
232 /**
233 * @test
234 */
235 public function getQueryArgumentsExcludesGetParameters() {
236 $_GET = array(
237 'key1' => 'value1',
238 'key2' => 'value2',
239 'key3' => array(
240 'key31' => 'value31',
241 'key32' => array(
242 'key321' => 'value321',
243 'key322' => 'value322'
244 )
245 )
246 );
247 $getQueryArgumentsConfiguration = array();
248 $getQueryArgumentsConfiguration['method'] = 'GET';
249 $getQueryArgumentsConfiguration['exclude'] = array();
250 $getQueryArgumentsConfiguration['exclude'][] = 'key1';
251 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key31]';
252 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key32][key321]';
253 $getQueryArgumentsConfiguration['exclude'] = implode(',', $getQueryArgumentsConfiguration['exclude']);
254 $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key2=value2&key3[key32][key322]=value322');
255 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration);
256 $this->assertEquals($expectedResult, $actualResult);
257 }
258
259 /**
260 * @test
261 */
262 public function getQueryArgumentsOverrulesSingleParameter() {
263 $this->subject->expects($this->any())->method('getEnvironmentVariable')->with($this->equalTo('QUERY_STRING'))->will(
264 $this->returnValue('key1=value1')
265 );
266 $getQueryArgumentsConfiguration = array();
267 $overruleArguments = array(
268 // Should be overridden
269 'key1' => 'value1Overruled',
270 // Shouldn't be set: Parameter doesn't exist in source array and is not forced
271 'key2' => 'value2Overruled'
272 );
273 $expectedResult = '&key1=value1Overruled';
274 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration, $overruleArguments);
275 $this->assertEquals($expectedResult, $actualResult);
276 }
277
278 /**
279 * @test
280 */
281 public function getQueryArgumentsOverrulesMultiDimensionalParameters() {
282 $_POST = array(
283 'key1' => 'value1',
284 'key2' => 'value2',
285 'key3' => array(
286 'key31' => 'value31',
287 'key32' => array(
288 'key321' => 'value321',
289 'key322' => 'value322'
290 )
291 )
292 );
293 $getQueryArgumentsConfiguration = array();
294 $getQueryArgumentsConfiguration['method'] = 'POST';
295 $getQueryArgumentsConfiguration['exclude'] = array();
296 $getQueryArgumentsConfiguration['exclude'][] = 'key1';
297 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key31]';
298 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key32][key321]';
299 $getQueryArgumentsConfiguration['exclude'] = implode(',', $getQueryArgumentsConfiguration['exclude']);
300 $overruleArguments = array(
301 // Should be overriden
302 'key2' => 'value2Overruled',
303 'key3' => array(
304 'key32' => array(
305 // Shouldn't be set: Parameter is excluded and not forced
306 'key321' => 'value321Overruled',
307 // Should be overriden: Parameter is not excluded
308 'key322' => 'value322Overruled',
309 // Shouldn't be set: Parameter doesn't exist in source array and is not forced
310 'key323' => 'value323Overruled'
311 )
312 )
313 );
314 $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key2=value2Overruled&key3[key32][key322]=value322Overruled');
315 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration, $overruleArguments);
316 $this->assertEquals($expectedResult, $actualResult);
317 }
318
319 /**
320 * @test
321 */
322 public function getQueryArgumentsOverrulesMultiDimensionalForcedParameters() {
323 $this->subject->expects($this->any())->method('getEnvironmentVariable')->with($this->equalTo('QUERY_STRING'))->will(
324 $this->returnValue('key1=value1&key2=value2&key3[key31]=value31&key3[key32][key321]=value321&key3[key32][key322]=value322')
325 );
326 $_POST = array(
327 'key1' => 'value1',
328 'key2' => 'value2',
329 'key3' => array(
330 'key31' => 'value31',
331 'key32' => array(
332 'key321' => 'value321',
333 'key322' => 'value322'
334 )
335 )
336 );
337 $getQueryArgumentsConfiguration = array();
338 $getQueryArgumentsConfiguration['exclude'] = array();
339 $getQueryArgumentsConfiguration['exclude'][] = 'key1';
340 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key31]';
341 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key32][key321]';
342 $getQueryArgumentsConfiguration['exclude'][] = 'key3[key32][key322]';
343 $getQueryArgumentsConfiguration['exclude'] = implode(',', $getQueryArgumentsConfiguration['exclude']);
344 $overruleArguments = array(
345 // Should be overriden
346 'key2' => 'value2Overruled',
347 'key3' => array(
348 'key32' => array(
349 // Should be set: Parameter is excluded but forced
350 'key321' => 'value321Overruled',
351 // Should be set: Parameter doesn't exist in source array but is forced
352 'key323' => 'value323Overruled'
353 )
354 )
355 );
356 $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key2=value2Overruled&key3[key32][key321]=value321Overruled&key3[key32][key323]=value323Overruled');
357 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration, $overruleArguments, TRUE);
358 $this->assertEquals($expectedResult, $actualResult);
359 $getQueryArgumentsConfiguration['method'] = 'POST';
360 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration, $overruleArguments, TRUE);
361 $this->assertEquals($expectedResult, $actualResult);
362 }
363
364 /**
365 * @test
366 */
367 public function getQueryArgumentsWithMethodPostGetMergesParameters() {
368 $_POST = array(
369 'key1' => 'POST1',
370 'key2' => 'POST2',
371 'key3' => array(
372 'key31' => 'POST31',
373 'key32' => 'POST32',
374 'key33' => array(
375 'key331' => 'POST331',
376 'key332' => 'POST332',
377 )
378 )
379 );
380 $_GET = array(
381 'key2' => 'GET2',
382 'key3' => array(
383 'key32' => 'GET32',
384 'key33' => array(
385 'key331' => 'GET331',
386 )
387 )
388 );
389 $getQueryArgumentsConfiguration = array();
390 $getQueryArgumentsConfiguration['method'] = 'POST,GET';
391 $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key1=POST1&key2=GET2&key3[key31]=POST31&key3[key32]=GET32&key3[key33][key331]=GET331&key3[key33][key332]=POST332');
392 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration);
393 $this->assertEquals($expectedResult, $actualResult);
394 }
395
396 /**
397 * @test
398 */
399 public function getQueryArgumentsWithMethodGetPostMergesParameters() {
400 $_GET = array(
401 'key1' => 'GET1',
402 'key2' => 'GET2',
403 'key3' => array(
404 'key31' => 'GET31',
405 'key32' => 'GET32',
406 'key33' => array(
407 'key331' => 'GET331',
408 'key332' => 'GET332',
409 )
410 )
411 );
412 $_POST = array(
413 'key2' => 'POST2',
414 'key3' => array(
415 'key32' => 'POST32',
416 'key33' => array(
417 'key331' => 'POST331',
418 )
419 )
420 );
421 $getQueryArgumentsConfiguration = array();
422 $getQueryArgumentsConfiguration['method'] = 'GET,POST';
423 $expectedResult = $this->rawUrlEncodeSquareBracketsInUrl('&key1=GET1&key2=POST2&key3[key31]=GET31&key3[key32]=POST32&key3[key33][key331]=POST331&key3[key33][key332]=GET332');
424 $actualResult = $this->subject->getQueryArguments($getQueryArgumentsConfiguration);
425 $this->assertEquals($expectedResult, $actualResult);
426 }
427
428 /**
429 * Encodes square brackets in URL.
430 *
431 * @param string $string
432 * @return string
433 */
434 private function rawUrlEncodeSquareBracketsInUrl($string) {
435 return str_replace(array('[', ']'), array('%5B', '%5D'), $string);
436 }
437
438 //////////////////////////
439 // Tests concerning crop
440 //////////////////////////
441 /**
442 * @test
443 */
444 public function cropIsMultibyteSafe() {
445 $this->assertEquals('бла', $this->subject->crop('бла', '3|...'));
446 }
447
448 //////////////////////////////
449 // Tests concerning cropHTML
450 //////////////////////////////
451 /**
452 * This is the data provider for the tests of crop and cropHTML below. It provides all combinations
453 * of charset, text type, and configuration options to be tested.
454 *
455 * @return array two-dimensional array with the second level like this:
456 * @see cropHtmlWithDataProvider
457 */
458 public function cropHtmlDataProvider() {
459 $plainText = 'Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j implemented the original version of the crop function.';
460 $textWithMarkup = '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a>' . ' implemented</strong> the original version of the crop function.';
461 $textWithEntities = 'Kasper Sk&aring;rh&oslash;j implemented the; original ' . 'version of the crop function.';
462 $charsets = array('iso-8859-1', 'utf-8', 'ascii', 'big5');
463 $data = array();
464 foreach ($charsets as $charset) {
465 $data = array_merge($data, array(
466 $charset . ' plain text; 11|...' => array(
467 '11|...',
468 $plainText,
469 'Kasper Sk' . chr(229) . 'r...',
470 $charset
471 ),
472 $charset . ' plain text; -58|...' => array(
473 '-58|...',
474 $plainText,
475 '...h' . chr(248) . 'j implemented the original version of the crop function.',
476 $charset
477 ),
478 $charset . ' plain text; 4|...|1' => array(
479 '4|...|1',
480 $plainText,
481 'Kasp...',
482 $charset
483 ),
484 $charset . ' plain text; 20|...|1' => array(
485 '20|...|1',
486 $plainText,
487 'Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j...',
488 $charset
489 ),
490 $charset . ' plain text; -5|...|1' => array(
491 '-5|...|1',
492 $plainText,
493 '...tion.',
494 $charset
495 ),
496 $charset . ' plain text; -49|...|1' => array(
497 '-49|...|1',
498 $plainText,
499 '...the original version of the crop function.',
500 $charset
501 ),
502 $charset . ' text with markup; 11|...' => array(
503 '11|...',
504 $textWithMarkup,
505 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'r...</a></strong>',
506 $charset
507 ),
508 $charset . ' text with markup; 13|...' => array(
509 '13|...',
510 $textWithMarkup,
511 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . '...</a></strong>',
512 $charset
513 ),
514 $charset . ' text with markup; 14|...' => array(
515 '14|...',
516 $textWithMarkup,
517 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a>...</strong>',
518 $charset
519 ),
520 $charset . ' text with markup; 15|...' => array(
521 '15|...',
522 $textWithMarkup,
523 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a> ...</strong>',
524 $charset
525 ),
526 $charset . ' text with markup; 29|...' => array(
527 '29|...',
528 $textWithMarkup,
529 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a> implemented</strong> th...',
530 $charset
531 ),
532 $charset . ' text with markup; -58|...' => array(
533 '-58|...',
534 $textWithMarkup,
535 '<strong><a href="mailto:kasper@typo3.org">...h' . chr(248) . 'j</a> implemented</strong> the original version of the crop function.',
536 $charset
537 ),
538 $charset . ' text with markup 4|...|1' => array(
539 '4|...|1',
540 $textWithMarkup,
541 '<strong><a href="mailto:kasper@typo3.org">Kasp...</a></strong>',
542 $charset
543 ),
544 $charset . ' text with markup; 11|...|1' => array(
545 '11|...|1',
546 $textWithMarkup,
547 '<strong><a href="mailto:kasper@typo3.org">Kasper...</a></strong>',
548 $charset
549 ),
550 $charset . ' text with markup; 13|...|1' => array(
551 '13|...|1',
552 $textWithMarkup,
553 '<strong><a href="mailto:kasper@typo3.org">Kasper...</a></strong>',
554 $charset
555 ),
556 $charset . ' text with markup; 14|...|1' => array(
557 '14|...|1',
558 $textWithMarkup,
559 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a>...</strong>',
560 $charset
561 ),
562 $charset . ' text with markup; 15|...|1' => array(
563 '15|...|1',
564 $textWithMarkup,
565 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a>...</strong>',
566 $charset
567 ),
568 $charset . ' text with markup; 29|...|1' => array(
569 '29|...|1',
570 $textWithMarkup,
571 '<strong><a href="mailto:kasper@typo3.org">Kasper Sk' . chr(229) . 'rh' . chr(248) . 'j</a> implemented</strong>...',
572 $charset
573 ),
574 $charset . ' text with markup; -66|...|1' => array(
575 '-66|...|1',
576 $textWithMarkup,
577 '<strong><a href="mailto:kasper@typo3.org">...Sk' . chr(229) . 'rh' . chr(248) . 'j</a> implemented</strong> the original version of the crop function.',
578 $charset
579 ),
580 $charset . ' text with entities 9|...' => array(
581 '9|...',
582 $textWithEntities,
583 'Kasper Sk...',
584 $charset
585 ),
586 $charset . ' text with entities 10|...' => array(
587 '10|...',
588 $textWithEntities,
589 'Kasper Sk&aring;...',
590 $charset
591 ),
592 $charset . ' text with entities 11|...' => array(
593 '11|...',
594 $textWithEntities,
595 'Kasper Sk&aring;r...',
596 $charset
597 ),
598 $charset . ' text with entities 13|...' => array(
599 '13|...',
600 $textWithEntities,
601 'Kasper Sk&aring;rh&oslash;...',
602 $charset
603 ),
604 $charset . ' text with entities 14|...' => array(
605 '14|...',
606 $textWithEntities,
607 'Kasper Sk&aring;rh&oslash;j...',
608 $charset
609 ),
610 $charset . ' text with entities 15|...' => array(
611 '15|...',
612 $textWithEntities,
613 'Kasper Sk&aring;rh&oslash;j ...',
614 $charset
615 ),
616 $charset . ' text with entities 16|...' => array(
617 '16|...',
618 $textWithEntities,
619 'Kasper Sk&aring;rh&oslash;j i...',
620 $charset
621 ),
622 $charset . ' text with entities -57|...' => array(
623 '-57|...',
624 $textWithEntities,
625 '...j implemented the; original version of the crop function.',
626 $charset
627 ),
628 $charset . ' text with entities -58|...' => array(
629 '-58|...',
630 $textWithEntities,
631 '...&oslash;j implemented the; original version of the crop function.',
632 $charset
633 ),
634 $charset . ' text with entities -59|...' => array(
635 '-59|...',
636 $textWithEntities,
637 '...h&oslash;j implemented the; original version of the crop function.',
638 $charset
639 ),
640 $charset . ' text with entities 4|...|1' => array(
641 '4|...|1',
642 $textWithEntities,
643 'Kasp...',
644 $charset
645 ),
646 $charset . ' text with entities 9|...|1' => array(
647 '9|...|1',
648 $textWithEntities,
649 'Kasper...',
650 $charset
651 ),
652 $charset . ' text with entities 10|...|1' => array(
653 '10|...|1',
654 $textWithEntities,
655 'Kasper...',
656 $charset
657 ),
658 $charset . ' text with entities 11|...|1' => array(
659 '11|...|1',
660 $textWithEntities,
661 'Kasper...',
662 $charset
663 ),
664 $charset . ' text with entities 13|...|1' => array(
665 '13|...|1',
666 $textWithEntities,
667 'Kasper...',
668 $charset
669 ),
670 $charset . ' text with entities 14|...|1' => array(
671 '14|...|1',
672 $textWithEntities,
673 'Kasper Sk&aring;rh&oslash;j...',
674 $charset
675 ),
676 $charset . ' text with entities 15|...|1' => array(
677 '15|...|1',
678 $textWithEntities,
679 'Kasper Sk&aring;rh&oslash;j...',
680 $charset
681 ),
682 $charset . ' text with entities 16|...|1' => array(
683 '16|...|1',
684 $textWithEntities,
685 'Kasper Sk&aring;rh&oslash;j...',
686 $charset
687 ),
688 $charset . ' text with entities -57|...|1' => array(
689 '-57|...|1',
690 $textWithEntities,
691 '...implemented the; original version of the crop function.',
692 $charset
693 ),
694 $charset . ' text with entities -58|...|1' => array(
695 '-58|...|1',
696 $textWithEntities,
697 '...implemented the; original version of the crop function.',
698 $charset
699 ),
700 $charset . ' text with entities -59|...|1' => array(
701 '-59|...|1',
702 $textWithEntities,
703 '...implemented the; original version of the crop function.',
704 $charset
705 ),
706 $charset . ' text with dash in html-element 28|...|1' => array(
707 '28|...|1',
708 'Some text with a link to <link email.address@example.org - mail "Open email window">my email.address@example.org</link> and text after it',
709 'Some text with a link to <link email.address@example.org - mail "Open email window">my...</link>',
710 $charset
711 ),
712 $charset . ' html elements with dashes in attributes' => array(
713 '9',
714 '<em data-foo="x">foobar</em>foobaz',
715 '<em data-foo="x">foobar</em>foo',
716 $charset
717 ),
718 ));
719 }
720 return $data;
721 }
722
723 /**
724 * Checks if stdWrap.cropHTML works with plain text cropping from left
725 *
726 * @test
727 * @dataProvider cropHtmlDataProvider
728 * @param string $settings
729 * @param string $subject the string to crop
730 * @param string $expected the expected cropped result
731 * @param string $charset the charset that will be set as renderCharset
732 */
733 public function cropHtmlWithDataProvider($settings, $subject, $expected, $charset) {
734 $this->handleCharset($charset, $subject, $expected);
735 $this->assertEquals($expected, $this->subject->cropHTML($subject, $settings), 'cropHTML failed with settings: "' . $settings . '" and charset "' . $charset . '"');
736 }
737
738 /**
739 * Checks if stdWrap.cropHTML works with a complex content with many tags. Currently cropHTML
740 * counts multiple invisible characters not as one (as the browser will output the content).
741 *
742 * @test
743 */
744 public function cropHtmlWorksWithComplexContent() {
745 $GLOBALS['TSFE']->renderCharset = 'iso-8859-1';
746 $input =
747 '<h1>Blog Example</h1>' . LF .
748 '<hr>' . LF .
749 '<div class="csc-header csc-header-n1">' . LF .
750 ' <h2 class="csc-firstHeader">Welcome to Blog #1</h2>' . LF .
751 '</div>' . LF .
752 '<p class="bodytext">' . LF .
753 ' A blog about TYPO3 extension development. In order to start blogging, read the <a href="#">Help section</a>. If you have any further questions, feel free to contact the administrator John Doe (<a href="mailto:john.doe@example.com">john.doe@example.com)</a>.' . LF .
754 '</p>' . LF .
755 '<div class="tx-blogexample-list-container">' . LF .
756 ' <p class="bodytext">' . LF .
757 ' Below are the most recent posts:' . LF .
758 ' </p>' . LF .
759 ' <ul>' . LF .
760 ' <li data-element="someId">' . LF .
761 ' <h3>' . LF .
762 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[blog]=&amp;tx_blogexample_pi1[action]=show&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=003b0131ed">The Post #1</a>' . LF .
763 ' </h3>' . LF .
764 ' <p class="bodytext">' . LF .
765 ' Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut...' . LF .
766 ' </p>' . LF .
767 ' <p class="metadata">' . LF .
768 ' Published on 26.08.2009 by Jochen Rau' . LF .
769 ' </p>' . LF .
770 ' <p>' . LF .
771 ' Tags: [MVC]&nbsp;[Domain Driven Design]&nbsp;<br>' . LF .
772 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[action]=show&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=f982643bc3">read more &gt;&gt;</a><br>' . LF .
773 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[blog][uid]=70&amp;tx_blogexample_pi1[action]=edit&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=5b481bc8f0">Edit</a>&nbsp;<a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[blog][uid]=70&amp;tx_blogexample_pi1[action]=delete&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=4e52879656">Delete</a>' . LF .
774 ' </p>' . LF .
775 ' </li>' . LF .
776 ' </ul>' . LF .
777 ' <p>' . LF .
778 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[blog][uid]=70&amp;tx_blogexample_pi1[action]=new&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=2718a4b1a0">Create a new Post</a>' . LF .
779 ' </p>' . LF .
780 '</div>' . LF .
781 '<hr>' . LF .
782 '<p>' . LF .
783 ' ? TYPO3 Association' . LF .
784 '</p>';
785
786 $result = $this->subject->cropHTML($input, '300');
787
788 $expected =
789 '<h1>Blog Example</h1>' . LF .
790 '<hr>' . LF .
791 '<div class="csc-header csc-header-n1">' . LF .
792 ' <h2 class="csc-firstHeader">Welcome to Blog #1</h2>' . LF .
793 '</div>' . LF .
794 '<p class="bodytext">' . LF .
795 ' A blog about TYPO3 extension development. In order to start blogging, read the <a href="#">Help section</a>. If you have any further questions, feel free to contact the administrator John Doe (<a href="mailto:john.doe@example.com">john.doe@example.com)</a>.' . LF .
796 '</p>' . LF .
797 '<div class="tx-blogexample-list-container">' . LF .
798 ' <p class="bodytext">' . LF .
799 ' Below are the most recent posts:' . LF .
800 ' </p>' . LF .
801 ' <ul>' . LF .
802 ' <li data-element="someId">' . LF .
803 ' <h3>' . LF .
804 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[blog]=&amp;tx_blogexample_pi1[action]=show&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=003b0131ed">The Post</a></h3></li></ul></div>';
805
806 $this->assertEquals($expected, $result);
807
808 $result = $this->subject->cropHTML($input, '-100');
809
810 $expected =
811 '<div class="tx-blogexample-list-container"><ul><li data-element="someId"><p> Design]&nbsp;<br>' . LF .
812 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[action]=show&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=f982643bc3">read more &gt;&gt;</a><br>' . LF .
813 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[blog][uid]=70&amp;tx_blogexample_pi1[action]=edit&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=5b481bc8f0">Edit</a>&nbsp;<a href="index.php?id=99&amp;tx_blogexample_pi1[post][uid]=211&amp;tx_blogexample_pi1[blog][uid]=70&amp;tx_blogexample_pi1[action]=delete&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=4e52879656">Delete</a>' . LF .
814 ' </p>' . LF .
815 ' </li>' . LF .
816 ' </ul>' . LF .
817 ' <p>' . LF .
818 ' <a href="index.php?id=99&amp;tx_blogexample_pi1[blog][uid]=70&amp;tx_blogexample_pi1[action]=new&amp;tx_blogexample_pi1[controller]=Post&amp;cHash=2718a4b1a0">Create a new Post</a>' . LF .
819 ' </p>' . LF .
820 '</div>' . LF .
821 '<hr>' . LF .
822 '<p>' . LF .
823 ' ? TYPO3 Association' . LF .
824 '</p>';
825
826 $this->assertEquals($expected, $result);
827 }
828
829 /**
830 * @return array
831 */
832 public function stdWrap_roundDataProvider() {
833 return array(
834 'rounding off without any configuration' => array(
835 1.123456789,
836 array(),
837 1
838 ),
839 'rounding up without any configuration' => array(
840 1.523456789,
841 array(),
842 2
843 ),
844 'regular rounding (off) to two decimals' => array(
845 0.123456789,
846 array(
847 'decimals' => 2
848 ),
849 0.12
850 ),
851 'regular rounding (up) to two decimals' => array(
852 0.1256789,
853 array(
854 'decimals' => 2
855 ),
856 0.13
857 ),
858 'rounding up to integer with type ceil' => array(
859 0.123456789,
860 array(
861 'roundType' => 'ceil'
862 ),
863 1
864 ),
865 'rounding down to integer with type floor' => array(
866 2.3481,
867 array(
868 'roundType' => 'floor'
869 ),
870 2
871 )
872 );
873 }
874
875 /**
876 * Checks if stdWrap.cropHTML handles linebreaks correctly (by ignoring them)
877 *
878 * @test
879 */
880 public function cropHtmlWorksWithLinebreaks() {
881 $subject = "Lorem ipsum dolor sit amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam";
882 $expected = "Lorem ipsum dolor sit amet,\nconsetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt ut labore et dolore magna";
883 $result = $this->subject->cropHTML($subject, '121');
884 $this->assertEquals($expected, $result);
885 }
886
887 /**
888 * Test for the stdWrap function "round"
889 *
890 * @param float $float
891 * @param array $conf
892 * @param float $expected
893 * @return void
894 * @dataProvider stdWrap_roundDataProvider
895 * @test
896 */
897 public function stdWrap_round($float, $conf, $expected) {
898 $conf = array(
899 'round.' => $conf
900 );
901 $result = $this->subject->stdWrap_round($float, $conf);
902 $this->assertEquals($expected, $result);
903 }
904
905 /**
906 * @return array
907 */
908 public function stdWrap_strPadDataProvider() {
909 return array(
910 'pad string with default settings and length 10' => array(
911 'Alien',
912 array(
913 'length' => '10',
914 ),
915 'Alien ',
916 ),
917 'pad string with padWith -= and type left and length 10' => array(
918 'Alien',
919 array(
920 'length' => '10',
921 'padWith' => '-=',
922 'type' => 'left',
923 ),
924 '-=-=-Alien',
925 ),
926 'pad string with padWith _ and type both and length 10' => array(
927 'Alien',
928 array(
929 'length' => '10',
930 'padWith' => '_',
931 'type' => 'both',
932 ),
933 '__Alien___',
934 ),
935 'pad string with padWith 0 and type both and length 10' => array(
936 'Alien',
937 array(
938 'length' => '10',
939 'padWith' => '0',
940 'type' => 'both',
941 ),
942 '00Alien000',
943 ),
944 'pad string with padWith ___ and type both and length 6' => array(
945 'Alien',
946 array(
947 'length' => '6',
948 'padWith' => '___',
949 'type' => 'both',
950 ),
951 'Alien_',
952 ),
953 'pad string with padWith _ and type both and length 12, using stdWrap for length' => array(
954 'Alien',
955 array(
956 'length' => '1',
957 'length.' => array(
958 'wrap' => '|2',
959 ),
960 'padWith' => '_',
961 'type' => 'both',
962 ),
963 '___Alien____',
964 ),
965 'pad string with padWith _ and type both and length 12, using stdWrap for padWidth' => array(
966 'Alien',
967 array(
968 'length' => '12',
969 'padWith' => '_',
970 'padWith.' => array(
971 'wrap' => '-|=',
972 ),
973 'type' => 'both',
974 ),
975 '-_=Alien-_=-',
976 ),
977 'pad string with padWith _ and type both and length 12, using stdWrap for type' => array(
978 'Alien',
979 array(
980 'length' => '12',
981 'padWith' => '_',
982 'type' => 'both',
983 // make type become "left"
984 'type.' => array(
985 'substring' => '2,1',
986 'wrap' => 'lef|',
987 ),
988 ),
989 '_______Alien',
990 ),
991 );
992 }
993
994 /**
995 * Test for the stdWrap function "strPad"
996 *
997 * @param string $content
998 * @param array $conf
999 * @param string $expected
1000 *
1001 * @dataProvider stdWrap_strPadDataProvider
1002 * @test
1003 */
1004 public function stdWrap_strPad($content, $conf, $expected) {
1005 $conf = array(
1006 'strPad.' => $conf
1007 );
1008 $result = $this->subject->stdWrap_strPad($content, $conf);
1009 $this->assertEquals($expected, $result);
1010 }
1011
1012 /**
1013 * Data provider for the hash test
1014 *
1015 * @return array multi-dimensional array with the second level like this:
1016 * @see hash
1017 */
1018 public function hashDataProvider() {
1019 $data = array(
1020 'testing md5' => array(
1021 'joh316',
1022 array(
1023 'hash' => 'md5'
1024 ),
1025 'bacb98acf97e0b6112b1d1b650b84971'
1026 ),
1027 'testing sha1' => array(
1028 'joh316',
1029 array(
1030 'hash' => 'sha1'
1031 ),
1032 '063b3d108bed9f88fa618c6046de0dccadcf3158'
1033 ),
1034 'testing non-existing hashing algorithm' => array(
1035 'joh316',
1036 array(
1037 'hash' => 'non-existing'
1038 ),
1039 ''
1040 ),
1041 'testing stdWrap capability' => array(
1042 'joh316',
1043 array(
1044 'hash.' => array(
1045 'cObject' => 'TEXT',
1046 'cObject.' => array(
1047 'value' => 'md5'
1048 )
1049 )
1050 ),
1051 'bacb98acf97e0b6112b1d1b650b84971'
1052 )
1053 );
1054 return $data;
1055 }
1056
1057 /**
1058 * Test for the stdWrap function "hash"
1059 *
1060 * @param string $text
1061 * @param array $conf
1062 * @param string $expected
1063 * @return void
1064 * @dataProvider hashDataProvider
1065 * @test
1066 */
1067 public function stdWrap_hash($text, array $conf, $expected) {
1068 $result = $this->subject->stdWrap_hash($text, $conf);
1069 $this->assertEquals($expected, $result);
1070 }
1071
1072 /**
1073 * @test
1074 */
1075 public function recursiveStdWrapProperlyRendersBasicString() {
1076 $stdWrapConfiguration = array(
1077 'noTrimWrap' => '|| 123|',
1078 'stdWrap.' => array(
1079 'wrap' => '<b>|</b>'
1080 )
1081 );
1082 $this->assertSame(
1083 '<b>Test</b> 123',
1084 $this->subject->stdWrap('Test', $stdWrapConfiguration)
1085 );
1086 }
1087
1088 /**
1089 * @test
1090 */
1091 public function recursiveStdWrapIsOnlyCalledOnce() {
1092 $stdWrapConfiguration = array(
1093 'append' => 'TEXT',
1094 'append.' => array(
1095 'data' => 'register:Counter'
1096 ),
1097 'stdWrap.' => array(
1098 'append' => 'LOAD_REGISTER',
1099 'append.' => array(
1100 'Counter.' => array(
1101 'prioriCalc' => 'intval',
1102 'cObject' => 'TEXT',
1103 'cObject.' => array(
1104 'data' => 'register:Counter',
1105 'wrap' => '|+1',
1106 )
1107 )
1108 )
1109 )
1110 );
1111 $this->assertSame(
1112 'Counter:1',
1113 $this->subject->stdWrap('Counter:', $stdWrapConfiguration)
1114 );
1115 }
1116
1117 /**
1118 * Data provider for the numberFormat test
1119 *
1120 * @return array multi-dimensional array with the second level like this:
1121 * @see numberFormat
1122 */
1123 public function numberFormatDataProvider() {
1124 $data = array(
1125 'testing decimals' => array(
1126 0.8,
1127 array(
1128 'decimals' => 2
1129 ),
1130 '0.80'
1131 ),
1132 'testing decimals with input as string' => array(
1133 '0.8',
1134 array(
1135 'decimals' => 2
1136 ),
1137 '0.80'
1138 ),
1139 'testing dec_point' => array(
1140 0.8,
1141 array(
1142 'decimals' => 1,
1143 'dec_point' => ','
1144 ),
1145 '0,8'
1146 ),
1147 'testing thousands_sep' => array(
1148 999.99,
1149 array(
1150 'decimals' => 0,
1151 'thousands_sep.' => array(
1152 'char' => 46
1153 )
1154 ),
1155 '1.000'
1156 ),
1157 'testing mixture' => array(
1158 1281731.45,
1159 array(
1160 'decimals' => 1,
1161 'dec_point.' => array(
1162 'char' => 44
1163 ),
1164 'thousands_sep.' => array(
1165 'char' => 46
1166 )
1167 ),
1168 '1.281.731,5'
1169 )
1170 );
1171 return $data;
1172 }
1173
1174 /**
1175 * Check if stdWrap.numberFormat and all of its properties work properly
1176 *
1177 * @dataProvider numberFormatDataProvider
1178 * @test
1179 */
1180 public function numberFormat($float, $formatConf, $expected) {
1181 $result = $this->subject->numberFormat($float, $formatConf);
1182 $this->assertEquals($expected, $result);
1183 }
1184
1185 /**
1186 * Data provider for the replacement test
1187 *
1188 * @return array multi-dimensional array with the second level like this:
1189 * @see replacement
1190 */
1191 public function replacementDataProvider() {
1192 $data = array(
1193 'multiple replacements, including regex' => array(
1194 'There_is_a_cat,_a_dog_and_a_tiger_in_da_hood!_Yeah!',
1195 array(
1196 'replacement.' => array(
1197 '120.' => array(
1198 'search' => 'in da hood',
1199 'replace' => 'around the block'
1200 ),
1201 '20.' => array(
1202 'search' => '_',
1203 'replace.' => array('char' => '32')
1204 ),
1205 '130.' => array(
1206 'search' => '#a (Cat|Dog|Tiger)#i',
1207 'replace' => 'an animal',
1208 'useRegExp' => '1'
1209 )
1210 )
1211 ),
1212 'There is an animal, an animal and an animal around the block! Yeah!'
1213 ),
1214 'replacement with optionSplit, normal pattern' => array(
1215 'There_is_a_cat,_a_dog_and_a_tiger_in_da_hood!_Yeah!',
1216 array(
1217 'replacement.' => array(
1218 '10.' => array(
1219 'search' => '_',
1220 'replace' => '1 || 2 || 3',
1221 'useOptionSplitReplace' => '1'
1222 ),
1223 )
1224 ),
1225 'There1is2a3cat,3a3dog3and3a3tiger3in3da3hood!3Yeah!'
1226 ),
1227 'replacement with optionSplit, using regex' => array(
1228 'There is a cat, a dog and a tiger in da hood! Yeah!',
1229 array(
1230 'replacement.' => array(
1231 '10.' => array(
1232 'search' => '#(a) (Cat|Dog|Tiger)#i',
1233 'replace' => '${1} tiny ${2} || ${1} midsized ${2} || ${1} big ${2}',
1234 'useOptionSplitReplace' => '1',
1235 'useRegExp' => '1'
1236 )
1237 )
1238 ),
1239 'There is a tiny cat, a midsized dog and a big tiger in da hood! Yeah!'
1240 ),
1241 );
1242 return $data;
1243 }
1244
1245 /**
1246 * Check if stdWrap.replacement and all of its properties work properly
1247 *
1248 * @dataProvider replacementDataProvider
1249 * @test
1250 */
1251 public function replacement($input, $conf, $expected) {
1252 $result = $this->subject->stdWrap_replacement($input, $conf);
1253 $this->assertEquals($expected, $result);
1254 }
1255
1256 /**
1257 * Data provider for the getQuery test
1258 *
1259 * @return array multi-dimensional array with the second level like this:
1260 * @see getQuery
1261 */
1262 public function getQueryDataProvider() {
1263 $data = array(
1264 'testing empty conf' => array(
1265 'tt_content',
1266 array(),
1267 array(
1268 'SELECT' => '*'
1269 )
1270 ),
1271 'testing #17284: adding uid/pid for workspaces' => array(
1272 'tt_content',
1273 array(
1274 'selectFields' => 'header,bodytext'
1275 ),
1276 array(
1277 'SELECT' => 'header,bodytext, tt_content.uid as uid, tt_content.pid as pid, tt_content.t3ver_state as t3ver_state'
1278 )
1279 ),
1280 'testing #17284: no need to add' => array(
1281 'tt_content',
1282 array(
1283 'selectFields' => 'tt_content.*'
1284 ),
1285 array(
1286 'SELECT' => 'tt_content.*'
1287 )
1288 ),
1289 'testing #17284: no need to add #2' => array(
1290 'tt_content',
1291 array(
1292 'selectFields' => '*'
1293 ),
1294 array(
1295 'SELECT' => '*'
1296 )
1297 ),
1298 'testing #29783: joined tables, prefix tablename' => array(
1299 'tt_content',
1300 array(
1301 'selectFields' => 'tt_content.header,be_users.username',
1302 'join' => 'be_users ON tt_content.cruser_id = be_users.uid'
1303 ),
1304 array(
1305 'SELECT' => 'tt_content.header,be_users.username, tt_content.uid as uid, tt_content.pid as pid, tt_content.t3ver_state as t3ver_state'
1306 )
1307 ),
1308 'testing #34152: single count(*), add nothing' => array(
1309 'tt_content',
1310 array(
1311 'selectFields' => 'count(*)'
1312 ),
1313 array(
1314 'SELECT' => 'count(*)'
1315 )
1316 ),
1317 'testing #34152: single max(crdate), add nothing' => array(
1318 'tt_content',
1319 array(
1320 'selectFields' => 'max(crdate)'
1321 ),
1322 array(
1323 'SELECT' => 'max(crdate)'
1324 )
1325 ),
1326 'testing #34152: single min(crdate), add nothing' => array(
1327 'tt_content',
1328 array(
1329 'selectFields' => 'min(crdate)'
1330 ),
1331 array(
1332 'SELECT' => 'min(crdate)'
1333 )
1334 ),
1335 'testing #34152: single sum(is_siteroot), add nothing' => array(
1336 'tt_content',
1337 array(
1338 'selectFields' => 'sum(is_siteroot)'
1339 ),
1340 array(
1341 'SELECT' => 'sum(is_siteroot)'
1342 )
1343 ),
1344 'testing #34152: single avg(crdate), add nothing' => array(
1345 'tt_content',
1346 array(
1347 'selectFields' => 'avg(crdate)'
1348 ),
1349 array(
1350 'SELECT' => 'avg(crdate)'
1351 )
1352 )
1353 );
1354 return $data;
1355 }
1356
1357 /**
1358 * Check if sanitizeSelectPart works as expected
1359 *
1360 * @dataProvider getQueryDataProvider
1361 * @test
1362 */
1363 public function getQuery($table, $conf, $expected) {
1364 $GLOBALS['TCA'] = array(
1365 'pages' => array(
1366 'ctrl' => array(
1367 'enablecolumns' => array(
1368 'disabled' => 'hidden'
1369 )
1370 )
1371 ),
1372 'tt_content' => array(
1373 'ctrl' => array(
1374 'enablecolumns' => array(
1375 'disabled' => 'hidden'
1376 ),
1377 'versioningWS' => 2
1378 )
1379 ),
1380 );
1381 $result = $this->subject->getQuery($table, $conf, TRUE);
1382 foreach ($expected as $field => $value) {
1383 $this->assertEquals($value, $result[$field]);
1384 }
1385 }
1386
1387 /**
1388 * @test
1389 */
1390 public function getQueryCallsGetTreeListWithNegativeValuesIfRecursiveIsSet() {
1391 $GLOBALS['TCA'] = array(
1392 'pages' => array(
1393 'ctrl' => array(
1394 'enablecolumns' => array(
1395 'disabled' => 'hidden'
1396 )
1397 )
1398 ),
1399 'tt_content' => array(
1400 'ctrl' => array(
1401 'enablecolumns' => array(
1402 'disabled' => 'hidden'
1403 )
1404 )
1405 ),
1406 );
1407 $this->subject = $this->getAccessibleMock(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class, array('getTreeList'));
1408 $this->subject->start(array(), 'tt_content');
1409 $conf = array(
1410 'recursive' => '15',
1411 'pidInList' => '16, -35'
1412 );
1413 $this->subject->expects($this->at(0))
1414 ->method('getTreeList')
1415 ->with(-16, 15)
1416 ->will($this->returnValue('15,16'));
1417 $this->subject->expects($this->at(1))
1418 ->method('getTreeList')
1419 ->with(-35, 15)
1420 ->will($this->returnValue('15,35'));
1421 $this->subject->getQuery('tt_content', $conf, TRUE);
1422 }
1423
1424 /**
1425 * @test
1426 */
1427 public function getQueryCallsGetTreeListWithCurrentPageIfThisIsSet() {
1428 $GLOBALS['TCA'] = array(
1429 'pages' => array(
1430 'ctrl' => array(
1431 'enablecolumns' => array(
1432 'disabled' => 'hidden'
1433 )
1434 )
1435 ),
1436 'tt_content' => array(
1437 'ctrl' => array(
1438 'enablecolumns' => array(
1439 'disabled' => 'hidden'
1440 )
1441 )
1442 ),
1443 );
1444 $this->subject = $this->getAccessibleMock(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class, array('getTreeList'));
1445 $GLOBALS['TSFE']->id = 27;
1446 $this->subject->start(array(), 'tt_content');
1447 $conf = array(
1448 'pidInList' => 'this',
1449 'recursive' => '4'
1450 );
1451 $this->subject->expects($this->once())
1452 ->method('getTreeList')
1453 ->with(-27)
1454 ->will($this->returnValue('27'));
1455 $this->subject->getQuery('tt_content', $conf, TRUE);
1456 }
1457
1458 /**
1459 * Data provider for the stdWrap_strftime test
1460 *
1461 * @return array multi-dimensional array with the second level like this:
1462 * @see stdWrap_strftime
1463 */
1464 public function stdWrap_strftimeReturnsFormattedStringDataProvider() {
1465 $data = array(
1466 'given timestamp' => array(
1467 1346500800, // This is 2012-09-01 12:00 in UTC/GMT
1468 array(
1469 'strftime' => '%d-%m-%Y',
1470 ),
1471 ),
1472 'empty string' => array(
1473 '',
1474 array(
1475 'strftime' => '%d-%m-%Y',
1476 ),
1477 ),
1478 'testing null' => array(
1479 NULL,
1480 array(
1481 'strftime' => '%d-%m-%Y',
1482 ),
1483 ),
1484 );
1485 return $data;
1486 }
1487
1488 /**
1489 * @test
1490 * @dataProvider stdWrap_strftimeReturnsFormattedStringDataProvider
1491 */
1492 public function stdWrap_strftimeReturnsFormattedString($content, $conf) {
1493 // Set exec_time to a hard timestamp
1494 $GLOBALS['EXEC_TIME'] = 1346500800;
1495 // Save current timezone and set to UTC to make the system under test behave
1496 // the same in all server timezone settings
1497 $timezoneBackup = date_default_timezone_get();
1498 date_default_timezone_set('UTC');
1499
1500 $result = $this->subject->stdWrap_strftime($content, $conf);
1501
1502 // Reset timezone
1503 date_default_timezone_set($timezoneBackup);
1504
1505 $this->assertEquals('01-09-2012', $result);
1506 }
1507
1508 /**
1509 * Data provider for the stdWrap_strtotime test
1510 *
1511 * @return array
1512 * @see stdWrap_strtotime
1513 */
1514 public function stdWrap_strtotimeReturnsTimestampDataProvider() {
1515 return array(
1516 'date from content' => array(
1517 '2014-12-04',
1518 array(
1519 'strtotime' => '1',
1520 ),
1521 1417651200,
1522 ),
1523 'manipulation of date from content' => array(
1524 '2014-12-04',
1525 array(
1526 'strtotime' => '+ 2 weekdays',
1527 ),
1528 1417996800,
1529 ),
1530 'date from configuration' => array(
1531 '',
1532 array(
1533 'strtotime' => '2014-12-04',
1534 ),
1535 1417651200,
1536 ),
1537 'manipulation of date from configuration' => array(
1538 '',
1539 array(
1540 'strtotime' => '2014-12-04 + 2 weekdays',
1541 ),
1542 1417996800,
1543 ),
1544 'empty input' => array(
1545 '',
1546 array(
1547 'strtotime' => '1',
1548 ),
1549 FALSE,
1550 ),
1551 'date from content and configuration' => array(
1552 '2014-12-04',
1553 array(
1554 'strtotime' => '2014-12-05',
1555 ),
1556 FALSE,
1557 ),
1558 );
1559 }
1560
1561 /**
1562 * @param string|NULL $content
1563 * @param array $configuration
1564 * @param int $expected
1565 * @dataProvider stdWrap_strtotimeReturnsTimestampDataProvider
1566 * @test
1567 */
1568 public function stdWrap_strtotimeReturnsTimestamp($content, $configuration, $expected) {
1569 // Set exec_time to a hard timestamp
1570 $GLOBALS['EXEC_TIME'] = 1417392000;
1571 // Save current timezone and set to UTC to make the system under test behave
1572 // the same in all server timezone settings
1573 $timezoneBackup = date_default_timezone_get();
1574 date_default_timezone_set('UTC');
1575
1576 $result = $this->subject->stdWrap_strtotime($content, $configuration);
1577
1578 // Reset timezone
1579 date_default_timezone_set($timezoneBackup);
1580
1581 $this->assertEquals($expected, $result);
1582 }
1583
1584 /**
1585 * @param string|NULL $content
1586 * @param array $configuration
1587 * @param string $expected
1588 * @dataProvider stdWrap_ifNullDeterminesNullValuesDataProvider
1589 * @test
1590 */
1591 public function stdWrap_ifNullDeterminesNullValues($content, array $configuration, $expected) {
1592 $result = $this->subject->stdWrap_ifNull($content, $configuration);
1593 $this->assertEquals($expected, $result);
1594 }
1595
1596 /**
1597 * Data provider for stdWrap_ifNullDeterminesNullValues test
1598 *
1599 * @return array
1600 */
1601 public function stdWrap_ifNullDeterminesNullValuesDataProvider() {
1602 return array(
1603 'null value' => array(
1604 NULL,
1605 array(
1606 'ifNull' => '1',
1607 ),
1608 '1',
1609 ),
1610 'zero value' => array(
1611 '0',
1612 array(
1613 'ifNull' => '1',
1614 ),
1615 '0',
1616 ),
1617 );
1618 }
1619
1620 /**
1621 * Data provider for stdWrap_ifEmptyDeterminesEmptyValues test
1622 *
1623 * @return array
1624 */
1625 public function stdWrap_ifEmptyDeterminesEmptyValuesDataProvider() {
1626 return array(
1627 'null value' => array(
1628 NULL,
1629 array(
1630 'ifEmpty' => '1',
1631 ),
1632 '1',
1633 ),
1634 'empty value' => array(
1635 '',
1636 array(
1637 'ifEmpty' => '1',
1638 ),
1639 '1',
1640 ),
1641 'string value' => array(
1642 'string',
1643 array(
1644 'ifEmpty' => '1',
1645 ),
1646 'string',
1647 ),
1648 'empty string value' => array(
1649 ' ',
1650 array(
1651 'ifEmpty' => '1',
1652 ),
1653 '1',
1654 ),
1655 );
1656 }
1657
1658 /**
1659 * @param string|NULL $content
1660 * @param array $configuration
1661 * @param string $expected
1662 * @dataProvider stdWrap_ifEmptyDeterminesEmptyValuesDataProvider
1663 * @test
1664 */
1665 public function stdWrap_ifEmptyDeterminesEmptyValues($content, array $configuration, $expected) {
1666 $result = $this->subject->stdWrap_ifEmpty($content, $configuration);
1667 $this->assertEquals($expected, $result);
1668 }
1669
1670 /**
1671 * @param $content
1672 * @param array $configuration
1673 * @param $expected
1674 * @dataProvider stdWrap_noTrimWrapAcceptsSplitCharDataProvider
1675 * @test
1676 */
1677 public function stdWrap_noTrimWrapAcceptsSplitChar($content, array $configuration, $expected) {
1678 $result = $this->subject->stdWrap_noTrimWrap($content, $configuration);
1679 $this->assertEquals($expected, $result);
1680 }
1681
1682 /**
1683 * Data provider for stdWrap_noTrimWrapAcceptsSplitChar test
1684 *
1685 * @return array
1686 */
1687 public function stdWrap_noTrimWrapAcceptsSplitCharDataProvider() {
1688 return array(
1689 'No char given' => array(
1690 'middle',
1691 array(
1692 'noTrimWrap' => '| left | right |',
1693 ),
1694 ' left middle right '
1695 ),
1696 'Zero char given' => array(
1697 'middle',
1698 array(
1699 'noTrimWrap' => '0 left 0 right 0',
1700 'noTrimWrap.' => array('splitChar' => '0'),
1701
1702 ),
1703 ' left middle right '
1704 ),
1705 'Default char given' => array(
1706 'middle',
1707 array(
1708 'noTrimWrap' => '| left | right |',
1709 'noTrimWrap.' => array('splitChar' => '|'),
1710 ),
1711 ' left middle right '
1712 ),
1713 'Split char is a' => array(
1714 'middle',
1715 array(
1716 'noTrimWrap' => 'a left a right a',
1717 'noTrimWrap.' => array('splitChar' => 'a'),
1718 ),
1719 ' left middle right '
1720 ),
1721 'Split char is multi-char (ab)' => array(
1722 'middle',
1723 array(
1724 'noTrimWrap' => 'ab left ab right ab',
1725 'noTrimWrap.' => array('splitChar' => 'ab'),
1726 ),
1727 ' left middle right '
1728 ),
1729 'Split char accepts stdWrap' => array(
1730 'middle',
1731 array(
1732 'noTrimWrap' => 'abc left abc right abc',
1733 'noTrimWrap.' => array(
1734 'splitChar' => 'b',
1735 'splitChar.' => array('wrap' => 'a|c'),
1736 ),
1737 ),
1738 ' left middle right '
1739 ),
1740 );
1741 }
1742
1743 /**
1744 * @param array $expectedTags
1745 * @param array $configuration
1746 * @test
1747 * @dataProvider stdWrap_addPageCacheTagsAddsPageTagsDataProvider
1748 */
1749 public function stdWrap_addPageCacheTagsAddsPageTags(array $expectedTags, array $configuration) {
1750 $this->subject->stdWrap_addPageCacheTags('', $configuration);
1751 $this->assertEquals($expectedTags, $this->typoScriptFrontendControllerMock->_get('pageCacheTags'));
1752 }
1753
1754 /**
1755 * @return array
1756 */
1757 public function stdWrap_addPageCacheTagsAddsPageTagsDataProvider() {
1758 return array(
1759 'No Tag' => array(
1760 array(),
1761 array('addPageCacheTags' => ''),
1762 ),
1763 'Two expectedTags' => array(
1764 array('tag1', 'tag2'),
1765 array('addPageCacheTags' => 'tag1,tag2'),
1766 ),
1767 'Two expectedTags plus one with stdWrap' => array(
1768 array('tag1', 'tag2', 'tag3'),
1769 array(
1770 'addPageCacheTags' => 'tag1,tag2',
1771 'addPageCacheTags.' => array('wrap' => '|,tag3')
1772 ),
1773 ),
1774 );
1775 }
1776
1777 /**
1778 * Data provider for stdWrap_encodeForJavaScriptValue test
1779 *
1780 * @return array multi-dimensional array with the second level like this:
1781 * @see encodeForJavaScriptValue
1782 */
1783 public function stdWrap_encodeForJavaScriptValueDataProvider() {
1784 return array(
1785 'double quote in string' => array(
1786 'double quote"',
1787 array(),
1788 '\'double\u0020quote\u0022\''
1789 ),
1790 'backslash in string' => array(
1791 'backslash \\',
1792 array(),
1793 '\'backslash\u0020\u005C\''
1794 ),
1795 'exclamation mark' => array(
1796 'exclamation!',
1797 array(),
1798 '\'exclamation\u0021\''
1799 ),
1800 'whitespace tab, newline and carriage return' => array(
1801 "white\tspace\ns\r",
1802 array(),
1803 '\'white\u0009space\u000As\u000D\''
1804 ),
1805 'single quote in string' => array(
1806 'single quote \'',
1807 array(),
1808 '\'single\u0020quote\u0020\u0027\''
1809 ),
1810 'tag' => array(
1811 '<tag>',
1812 array(),
1813 '\'\u003Ctag\u003E\''
1814 ),
1815 'ampersand in string' => array(
1816 'amper&sand',
1817 array(),
1818 '\'amper\u0026sand\''
1819 ),
1820 );
1821 }
1822
1823 /**
1824 * Check if encodeForJavaScriptValue works properly
1825 *
1826 * @dataProvider stdWrap_encodeForJavaScriptValueDataProvider
1827 * @test
1828 */
1829 public function stdWrap_encodeForJavaScriptValue($input, $conf, $expected) {
1830 $result = $this->subject->stdWrap_encodeForJavaScriptValue($input, $conf);
1831 $this->assertEquals($expected, $result);
1832 }
1833
1834
1835 ///////////////////////////////
1836 // Tests concerning getData()
1837 ///////////////////////////////
1838
1839 /**
1840 * @return array
1841 */
1842 public function getDataWithTypeGpDataProvider() {
1843 return array(
1844 'Value in get-data' => array('onlyInGet', 'GetValue'),
1845 'Value in post-data' => array('onlyInPost', 'PostValue'),
1846 'Value in post-data overriding get-data' => array('inGetAndPost', 'ValueInPost'),
1847 );
1848 }
1849
1850 /**
1851 * Checks if getData() works with type "gp"
1852 *
1853 * @test
1854 * @dataProvider getDataWithTypeGpDataProvider
1855 */
1856 public function getDataWithTypeGp($key, $expectedValue) {
1857 $_GET = array(
1858 'onlyInGet' => 'GetValue',
1859 'inGetAndPost' => 'ValueInGet',
1860 );
1861 $_POST = array(
1862 'onlyInPost' => 'PostValue',
1863 'inGetAndPost' => 'ValueInPost',
1864 );
1865 $this->assertEquals($expectedValue, $this->subject->getData('gp:' . $key));
1866 }
1867
1868 /**
1869 * Checks if getData() works with type "tsfe"
1870 *
1871 * @test
1872 */
1873 public function getDataWithTypeTsfe() {
1874 $this->assertEquals($GLOBALS['TSFE']->renderCharset, $this->subject->getData('tsfe:renderCharset'));
1875 }
1876
1877 /**
1878 * Checks if getData() works with type "getenv"
1879 *
1880 * @test
1881 */
1882 public function getDataWithTypeGetenv() {
1883 $envName = $this->getUniqueId('frontendtest');
1884 $value = $this->getUniqueId('someValue');
1885 putenv($envName . '=' . $value);
1886 $this->assertEquals($value, $this->subject->getData('getenv:' . $envName));
1887 }
1888
1889 /**
1890 * Checks if getData() works with type "getindpenv"
1891 *
1892 * @test
1893 */
1894 public function getDataWithTypeGetindpenv() {
1895 $this->subject->expects($this->once())->method('getEnvironmentVariable')
1896 ->with($this->equalTo('SCRIPT_FILENAME'))->will($this->returnValue('dummyPath'));
1897 $this->assertEquals('dummyPath', $this->subject->getData('getindpenv:SCRIPT_FILENAME'));
1898 }
1899
1900 /**
1901 * Checks if getData() works with type "field"
1902 *
1903 * @test
1904 */
1905 public function getDataWithTypeField() {
1906 $key = 'someKey';
1907 $value = 'someValue';
1908 $field = array($key => $value);
1909
1910 $this->assertEquals($value, $this->subject->getData('field:' . $key, $field));
1911 }
1912
1913 /**
1914 * Checks if getData() works with type "field" of the field content
1915 * is multi-dimensional (e.g. an array)
1916 *
1917 * @test
1918 */
1919 public function getDataWithTypeFieldAndFieldIsMultiDimensional() {
1920 $key = 'somekey|level1|level2';
1921 $value = 'somevalue';
1922 $field = array('somekey' => array('level1' => array('level2' => 'somevalue')));
1923
1924 $this->assertEquals($value, $this->subject->getData('field:' . $key, $field));
1925 }
1926
1927 /**
1928 * Basic check if getData gets the uid of a file object
1929 *
1930 * @test
1931 */
1932 public function getDataWithTypeFileReturnsUidOfFileObject() {
1933 $uid = $this->getUniqueId();
1934 $file = $this->getMock(\TYPO3\CMS\Core\Resource\File::class, array(), array(), '', FALSE);
1935 $file->expects($this->once())->method('getUid')->will($this->returnValue($uid));
1936 $this->subject->setCurrentFile($file);
1937 $this->assertEquals($uid, $this->subject->getData('file:current:uid'));
1938 }
1939
1940 /**
1941 * Checks if getData() works with type "parameters"
1942 *
1943 * @test
1944 */
1945 public function getDataWithTypeParameters() {
1946 $key = $this->getUniqueId('someKey');
1947 $value = $this->getUniqueId('someValue');
1948 $this->subject->parameters[$key] = $value;
1949
1950 $this->assertEquals($value, $this->subject->getData('parameters:' . $key));
1951 }
1952
1953 /**
1954 * Checks if getData() works with type "register"
1955 *
1956 * @test
1957 */
1958 public function getDataWithTypeRegister() {
1959 $key = $this->getUniqueId('someKey');
1960 $value = $this->getUniqueId('someValue');
1961 $GLOBALS['TSFE']->register[$key] = $value;
1962
1963 $this->assertEquals($value, $this->subject->getData('register:' . $key));
1964 }
1965
1966 /**
1967 * Checks if getData() works with type "level"
1968 *
1969 * @test
1970 */
1971 public function getDataWithTypeLevel() {
1972 $rootline = array(
1973 0 => array('uid' => 1, 'title' => 'title1'),
1974 1 => array('uid' => 2, 'title' => 'title2'),
1975 2 => array('uid' => 3, 'title' => 'title3'),
1976 );
1977
1978 $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
1979 $this->assertEquals(2, $this->subject->getData('level'));
1980 }
1981
1982 /**
1983 * Checks if getData() works with type "global"
1984 *
1985 * @test
1986 */
1987 public function getDataWithTypeGlobal() {
1988 $this->assertEquals($GLOBALS['TSFE']->renderCharset, $this->subject->getData('global:TSFE|renderCharset'));
1989 }
1990
1991 /**
1992 * Checks if getData() works with type "leveltitle"
1993 *
1994 * @test
1995 */
1996 public function getDataWithTypeLeveltitle() {
1997 $rootline = array(
1998 0 => array('uid' => 1, 'title' => 'title1'),
1999 1 => array('uid' => 2, 'title' => 'title2'),
2000 2 => array('uid' => 3, 'title' => ''),
2001 );
2002
2003 $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
2004 $this->assertEquals('', $this->subject->getData('leveltitle:-1'));
2005 // since "title3" is not set, it will slide to "title2"
2006 $this->assertEquals('title2', $this->subject->getData('leveltitle:-1,slide'));
2007 }
2008
2009 /**
2010 * Checks if getData() works with type "levelmedia"
2011 *
2012 * @test
2013 */
2014 public function getDataWithTypeLevelmedia() {
2015 $rootline = array(
2016 0 => array('uid' => 1, 'title' => 'title1', 'media' => 'media1'),
2017 1 => array('uid' => 2, 'title' => 'title2', 'media' => 'media2'),
2018 2 => array('uid' => 3, 'title' => 'title3', 'media' => ''),
2019 );
2020
2021 $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
2022 $this->assertEquals('', $this->subject->getData('levelmedia:-1'));
2023 // since "title3" is not set, it will slide to "title2"
2024 $this->assertEquals('media2', $this->subject->getData('levelmedia:-1,slide'));
2025 }
2026
2027 /**
2028 * Checks if getData() works with type "leveluid"
2029 *
2030 * @test
2031 */
2032 public function getDataWithTypeLeveluid() {
2033 $rootline = array(
2034 0 => array('uid' => 1, 'title' => 'title1'),
2035 1 => array('uid' => 2, 'title' => 'title2'),
2036 2 => array('uid' => 3, 'title' => 'title3'),
2037 );
2038
2039 $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
2040 $this->assertEquals(3, $this->subject->getData('leveluid:-1'));
2041 // every element will have a uid - so adding slide doesn't really make sense, just for completeness
2042 $this->assertEquals(3, $this->subject->getData('leveluid:-1,slide'));
2043 }
2044
2045 /**
2046 * Checks if getData() works with type "levelfield"
2047 *
2048 * @test
2049 */
2050 public function getDataWithTypeLevelfield() {
2051 $rootline = array(
2052 0 => array('uid' => 1, 'title' => 'title1', 'testfield' => 'field1'),
2053 1 => array('uid' => 2, 'title' => 'title2', 'testfield' => 'field2'),
2054 2 => array('uid' => 3, 'title' => 'title3', 'testfield' => ''),
2055 );
2056
2057 $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
2058 $this->assertEquals('', $this->subject->getData('levelfield:-1,testfield'));
2059 $this->assertEquals('field2', $this->subject->getData('levelfield:-1,testfield,slide'));
2060 }
2061
2062 /**
2063 * Checks if getData() works with type "fullrootline"
2064 *
2065 * @test
2066 */
2067 public function getDataWithTypeFullrootline() {
2068 $rootline1 = array(
2069 0 => array('uid' => 1, 'title' => 'title1', 'testfield' => 'field1'),
2070 );
2071 $rootline2 = array(
2072 0 => array('uid' => 1, 'title' => 'title1', 'testfield' => 'field1'),
2073 1 => array('uid' => 2, 'title' => 'title2', 'testfield' => 'field2'),
2074 2 => array('uid' => 3, 'title' => 'title3', 'testfield' => 'field3'),
2075 );
2076
2077 $GLOBALS['TSFE']->tmpl->rootLine = $rootline1;
2078 $GLOBALS['TSFE']->rootLine = $rootline2;
2079 $this->assertEquals('field2', $this->subject->getData('fullrootline:-1,testfield'));
2080 }
2081
2082 /**
2083 * Checks if getData() works with type "date"
2084 *
2085 * @test
2086 */
2087 public function getDataWithTypeDate() {
2088 $format = 'Y-M-D';
2089 $defaultFormat = 'd/m Y';
2090
2091 $this->assertEquals(date($format, $GLOBALS['EXEC_TIME']), $this->subject->getData('date:' . $format));
2092 $this->assertEquals(date($defaultFormat, $GLOBALS['EXEC_TIME']), $this->subject->getData('date'));
2093 }
2094
2095 /**
2096 * Checks if getData() works with type "page"
2097 *
2098 * @test
2099 */
2100 public function getDataWithTypePage() {
2101 $uid = rand();
2102 $GLOBALS['TSFE']->page['uid'] = $uid;
2103 $this->assertEquals($uid, $this->subject->getData('page:uid'));
2104 }
2105
2106 /**
2107 * Checks if getData() works with type "current"
2108 *
2109 * @test
2110 */
2111 public function getDataWithTypeCurrent() {
2112 $key = $this->getUniqueId('someKey');
2113 $value = $this->getUniqueId('someValue');
2114 $this->subject->data[$key] = $value;
2115 $this->subject->currentValKey = $key;
2116 $this->assertEquals($value, $this->subject->getData('current'));
2117 }
2118
2119 /**
2120 * Checks if getData() works with type "db"
2121 *
2122 * @test
2123 */
2124 public function getDataWithTypeDb() {
2125 $dummyRecord = array('uid' => 5, 'title' => 'someTitle');
2126
2127 $GLOBALS['TSFE']->sys_page->expects($this->atLeastOnce())->method('getRawRecord')->with('tt_content', '106')->will($this->returnValue($dummyRecord));
2128 $this->assertEquals($dummyRecord['title'], $this->subject->getData('db:tt_content:106:title'));
2129 }
2130
2131 /**
2132 * Checks if getData() works with type "lll"
2133 *
2134 * @test
2135 */
2136 public function getDataWithTypeLll() {
2137 $key = $this->getUniqueId('someKey');
2138 $value = $this->getUniqueId('someValue');
2139 $language = $this->getUniqueId('someLanguage');
2140 $GLOBALS['TSFE']->LL_labels_cache[$language]['LLL:' . $key] = $value;
2141 $GLOBALS['TSFE']->lang = $language;
2142
2143 $this->assertEquals($value, $this->subject->getData('lll:' . $key));
2144 }
2145
2146 /**
2147 * Checks if getData() works with type "path"
2148 *
2149 * @test
2150 */
2151 public function getDataWithTypePath() {
2152 $filenameIn = $this->getUniqueId('someValue');
2153 $filenameOut = $this->getUniqueId('someValue');
2154 $this->templateServiceMock->expects($this->atLeastOnce())->method('getFileName')->with($filenameIn)->will($this->returnValue($filenameOut));
2155 $this->assertEquals($filenameOut, $this->subject->getData('path:' . $filenameIn));
2156 }
2157
2158 /**
2159 * Checks if getData() works with type "parentRecordNumber"
2160 *
2161 * @test
2162 */
2163 public function getDataWithTypeParentRecordNumber() {
2164 $recordNumber = rand();
2165 $this->subject->parentRecordNumber = $recordNumber;
2166 $this->assertEquals($recordNumber, $this->subject->getData('cobj:parentRecordNumber'));
2167 }
2168
2169 /**
2170 * Checks if getData() works with type "debug:rootLine"
2171 *
2172 * @test
2173 */
2174 public function getDataWithTypeDebugRootline() {
2175 $rootline = array(
2176 0 => array('uid' => 1, 'title' => 'title1'),
2177 1 => array('uid' => 2, 'title' => 'title2'),
2178 2 => array('uid' => 3, 'title' => ''),
2179 );
2180 $expectedResult = 'array(3items)0=>array(2items)uid=>1(integer)title=>"title1"(6chars)1=>array(2items)uid=>2(integer)title=>"title2"(6chars)2=>array(2items)uid=>3(integer)title=>""(0chars)';
2181 $GLOBALS['TSFE']->tmpl->rootLine = $rootline;
2182
2183 $result = $this->subject->getData('debug:rootLine');
2184 $cleanedResult = strip_tags($result);
2185 $cleanedResult = str_replace("\r", '', $cleanedResult);
2186 $cleanedResult = str_replace("\n", '', $cleanedResult);
2187 $cleanedResult = str_replace("\t", '', $cleanedResult);
2188 $cleanedResult = str_replace(' ', '', $cleanedResult);
2189
2190 $this->assertEquals($expectedResult, $cleanedResult);
2191 }
2192
2193 /**
2194 * Checks if getData() works with type "debug:fullRootLine"
2195 *
2196 * @test
2197 */
2198 public function getDataWithTypeDebugFullRootline() {
2199 $rootline = array(
2200 0 => array('uid' => 1, 'title' => 'title1'),
2201 1 => array('uid' => 2, 'title' => 'title2'),
2202 2 => array('uid' => 3, 'title' => ''),
2203 );
2204 $expectedResult = 'array(3items)0=>array(2items)uid=>1(integer)title=>"title1"(6chars)1=>array(2items)uid=>2(integer)title=>"title2"(6chars)2=>array(2items)uid=>3(integer)title=>""(0chars)';
2205 $GLOBALS['TSFE']->rootLine = $rootline;
2206
2207 $result = $this->subject->getData('debug:fullRootLine');
2208 $cleanedResult = strip_tags($result);
2209 $cleanedResult = str_replace("\r", '', $cleanedResult);
2210 $cleanedResult = str_replace("\n", '', $cleanedResult);
2211 $cleanedResult = str_replace("\t", '', $cleanedResult);
2212 $cleanedResult = str_replace(' ', '', $cleanedResult);
2213
2214 $this->assertEquals($expectedResult, $cleanedResult);
2215 }
2216
2217 /**
2218 * Checks if getData() works with type "debug:data"
2219 *
2220 * @test
2221 */
2222 public function getDataWithTypeDebugData() {
2223 $key = $this->getUniqueId('someKey');
2224 $value = $this->getUniqueId('someValue');
2225 $this->subject->data = array($key => $value);
2226
2227 $expectedResult = 'array(1item)' . $key . '=>"' . $value . '"(' . strlen($value) . 'chars)';
2228
2229 $result = $this->subject->getData('debug:data');
2230 $cleanedResult = strip_tags($result);
2231 $cleanedResult = str_replace("\r", '', $cleanedResult);
2232 $cleanedResult = str_replace("\n", '', $cleanedResult);
2233 $cleanedResult = str_replace("\t", '', $cleanedResult);
2234 $cleanedResult = str_replace(' ', '', $cleanedResult);
2235
2236 $this->assertEquals($expectedResult, $cleanedResult);
2237 }
2238
2239 /**
2240 * Checks if getData() works with type "debug:register"
2241 *
2242 * @test
2243 */
2244 public function getDataWithTypeDebugRegister() {
2245 $key = $this->getUniqueId('someKey');
2246 $value = $this->getUniqueId('someValue');
2247 $GLOBALS['TSFE']->register = array($key => $value);
2248
2249 $expectedResult = 'array(1item)' . $key . '=>"' . $value . '"(' . strlen($value) . 'chars)';
2250
2251 $result = $this->subject->getData('debug:register');
2252 $cleanedResult = strip_tags($result);
2253 $cleanedResult = str_replace("\r", '', $cleanedResult);
2254 $cleanedResult = str_replace("\n", '', $cleanedResult);
2255 $cleanedResult = str_replace("\t", '', $cleanedResult);
2256 $cleanedResult = str_replace(' ', '', $cleanedResult);
2257
2258 $this->assertEquals($expectedResult, $cleanedResult);
2259 }
2260
2261 /**
2262 * Checks if getData() works with type "data:page"
2263 *
2264 * @test
2265 */
2266 public function getDataWithTypeDebugPage() {
2267 $uid = rand();
2268 $GLOBALS['TSFE']->page = array('uid' => $uid);
2269
2270 $expectedResult = 'array(1item)uid=>' . $uid . '(integer)';
2271
2272 $result = $this->subject->getData('debug:page');
2273 $cleanedResult = strip_tags($result);
2274 $cleanedResult = str_replace("\r", '', $cleanedResult);
2275 $cleanedResult = str_replace("\n", '', $cleanedResult);
2276 $cleanedResult = str_replace("\t", '', $cleanedResult);
2277 $cleanedResult = str_replace(' ', '', $cleanedResult);
2278
2279 $this->assertEquals($expectedResult, $cleanedResult);
2280 }
2281
2282 /**
2283 * @test
2284 */
2285 public function getTreeListReturnsChildPageUids() {
2286 $GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTgetSingleRow')->with('treelist')->will($this->returnValue(NULL));
2287 $GLOBALS['TSFE']->sys_page
2288 ->expects($this->any())
2289 ->method('getRawRecord')
2290 ->will(
2291 $this->onConsecutiveCalls(
2292 array('uid' => 17),
2293 array('uid' => 321),
2294 array('uid' => 719),
2295 array('uid' => 42)
2296 )
2297 );
2298
2299 $GLOBALS['TSFE']->sys_page->expects($this->any())->method('getMountPointInfo')->will($this->returnValue(NULL));
2300 $GLOBALS['TYPO3_DB']
2301 ->expects($this->any())
2302 ->method('exec_SELECTgetRows')
2303 ->will(
2304 $this->onConsecutiveCalls(
2305 array(
2306 array('uid' => 321)
2307 ),
2308 array(
2309 array('uid' => 719)
2310 ),
2311 array(
2312 array('uid' => 42)
2313 )
2314 )
2315 );
2316 // 17 = pageId, 5 = recursionLevel, 0 = begin (entry to recursion, internal), TRUE = do not check enable fields
2317 // 17 is positive, we expect 17 NOT to be included in result
2318 $result = $this->subject->getTreeList(17, 5, 0, TRUE);
2319 $expectedResult = '42,719,321';
2320 $this->assertEquals($expectedResult, $result);
2321 }
2322
2323 /**
2324 * @test
2325 */
2326 public function getTreeListReturnsChildPageUidsAndOriginalPidForNegativeValue() {
2327 $GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTgetSingleRow')->with('treelist')->will($this->returnValue(NULL));
2328 $GLOBALS['TSFE']->sys_page
2329 ->expects($this->any())
2330 ->method('getRawRecord')
2331 ->will(
2332 $this->onConsecutiveCalls(
2333 array('uid' => 17),
2334 array('uid' => 321),
2335 array('uid' => 719),
2336 array('uid' => 42)
2337 )
2338 );
2339
2340 $GLOBALS['TSFE']->sys_page->expects($this->any())->method('getMountPointInfo')->will($this->returnValue(NULL));
2341 $GLOBALS['TYPO3_DB']
2342 ->expects($this->any())
2343 ->method('exec_SELECTgetRows')
2344 ->will(
2345 $this->onConsecutiveCalls(
2346 array(
2347 array('uid' => 321)
2348 ),
2349 array(
2350 array('uid' => 719)
2351 ),
2352 array(
2353 array('uid' => 42)
2354 )
2355 )
2356 );
2357 // 17 = pageId, 5 = recursionLevel, 0 = begin (entry to recursion, internal), TRUE = do not check enable fields
2358 // 17 is negative, we expect 17 to be included in result
2359 $result = $this->subject->getTreeList(-17, 5, 0, TRUE);
2360 $expectedResult = '42,719,321,17';
2361 $this->assertEquals($expectedResult, $result);
2362 }
2363
2364 /**
2365 * @test
2366 */
2367 public function aTagParamsHasLeadingSpaceIfNotEmpty() {
2368 $aTagParams = $this->subject->getATagParams(array('ATagParams' => 'data-test="testdata"'));
2369 $this->assertEquals(' data-test="testdata"', $aTagParams );
2370 }
2371
2372 /**
2373 * @test
2374 */
2375 public function aTagParamsHaveSpaceBetweenLocalAndGlobalParams() {
2376 $GLOBALS['TSFE']->ATagParams = 'data-global="dataglobal"';
2377 $aTagParams = $this->subject->getATagParams(array('ATagParams' => 'data-test="testdata"'));
2378 $this->assertEquals(' data-global="dataglobal" data-test="testdata"', $aTagParams );
2379 }
2380
2381 /**
2382 * @test
2383 */
2384 public function aTagParamsHasNoLeadingSpaceIfEmpty() {
2385 // make sure global ATagParams are empty
2386 $GLOBALS['TSFE']->ATagParams = '';
2387 $aTagParams = $this->subject->getATagParams(array('ATagParams' => ''));
2388 $this->assertEquals('', $aTagParams);
2389 }
2390
2391 /**
2392 * @return array
2393 */
2394 public function getImageTagTemplateFallsBackToDefaultTemplateIfNoTemplateIsFoundDataProvider() {
2395 return array(
2396 array(NULL, NULL),
2397 array('', NULL),
2398 array('', array()),
2399 array('fooo', array('foo' => 'bar'))
2400 );
2401 }
2402
2403 /**
2404 * Make sure that the rendering falls back to the classic <img style if nothing else is found
2405 *
2406 * @test
2407 * @dataProvider getImageTagTemplateFallsBackToDefaultTemplateIfNoTemplateIsFoundDataProvider
2408 * @param string $key
2409 * @param array $configuration
2410 */
2411 public function getImageTagTemplateFallsBackToDefaultTemplateIfNoTemplateIsFound($key, $configuration) {
2412 $defaultImgTagTemplate = '<img src="###SRC###" width="###WIDTH###" height="###HEIGHT###" ###PARAMS### ###ALTPARAMS### ###BORDER######SELFCLOSINGTAGSLASH###>';
2413 $result = $this->subject->getImageTagTemplate($key, $configuration);
2414 $this->assertEquals($result, $defaultImgTagTemplate);
2415 }
2416
2417 /**
2418 * @return array
2419 */
2420 public function getImageTagTemplateReturnTemplateElementIdentifiedByKeyDataProvider() {
2421 return array(
2422 array(
2423 'foo',
2424 array(
2425 'layout.' => array(
2426 'foo.' => array(
2427 'element' => '<img src="###SRC###" srcset="###SOURCES###" ###PARAMS### ###ALTPARAMS### ###FOOBAR######SELFCLOSINGTAGSLASH###>'
2428 )
2429 )
2430 ),
2431 '<img src="###SRC###" srcset="###SOURCES###" ###PARAMS### ###ALTPARAMS### ###FOOBAR######SELFCLOSINGTAGSLASH###>'
2432 )
2433
2434 );
2435 }
2436
2437 /**
2438 * Assure if a layoutKey and layout is given the selected layout is returned
2439 *
2440 * @test
2441 * @dataProvider getImageTagTemplateReturnTemplateElementIdentifiedByKeyDataProvider
2442 * @param string $key
2443 * @param array $configuration
2444 * @param string $expectation
2445 */
2446 public function getImageTagTemplateReturnTemplateElementIdentifiedByKey($key, $configuration, $expectation) {
2447 $result = $this->subject->getImageTagTemplate($key, $configuration);
2448 $this->assertEquals($result, $expectation);
2449 }
2450
2451 /**
2452 * @return array
2453 */
2454 public function getImageSourceCollectionReturnsEmptyStringIfNoSourcesAreDefinedDataProvider() {
2455 return array(
2456 array(NULL, NULL, NULL),
2457 array('foo', NULL, NULL),
2458 array('foo', array('sourceCollection.' => 1), 'bar')
2459 );
2460 }
2461
2462 /**
2463 * Make sure the source collection is empty if no valid configuration or source collection is defined
2464 *
2465 * @test
2466 * @dataProvider getImageSourceCollectionReturnsEmptyStringIfNoSourcesAreDefinedDataProvider
2467 * @param string $layoutKey
2468 * @param array $configuration
2469 * @param string $file
2470 */
2471 public function getImageSourceCollectionReturnsEmptyStringIfNoSourcesAreDefined($layoutKey, $configuration, $file) {
2472 $result = $this->subject->getImageSourceCollection($layoutKey, $configuration, $file);
2473 $this->assertSame($result, '');
2474 }
2475
2476 /**
2477 * Make sure the generation of subimages calls the generation of the subimages and uses the layout -> source template
2478 *
2479 * @test
2480 */
2481 public function getImageSourceCollectionRendersDefinedSources() {
2482 /** @var $cObj \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
2483 $cObj = $this->getMock(
2484 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class,
2485 array('stdWrap','getImgResource')
2486 );
2487 $cObj->start(array(), 'tt_content');
2488
2489 $layoutKey = 'test';
2490
2491 $configuration = array(
2492 'layoutKey' => 'test',
2493 'layout.' => array (
2494 'test.' => array(
2495 'element' => '<img ###SRC### ###SRCCOLLECTION### ###SELFCLOSINGTAGSLASH###>',
2496 'source' => '---###SRC###---'
2497 )
2498 ),
2499 'sourceCollection.' => array(
2500 '1.' => array(
2501 'width' => '200'
2502 )
2503 )
2504 );
2505
2506 $file = 'testImageName';
2507
2508 // Avoid calling of stdWrap
2509 $cObj
2510 ->expects($this->any())
2511 ->method('stdWrap')
2512 ->will($this->returnArgument(0));
2513
2514 // Avoid calling of imgResource
2515 $cObj
2516 ->expects($this->exactly(1))
2517 ->method('getImgResource')
2518 ->with($this->equalTo('testImageName'))
2519 ->will($this->returnValue(array(100, 100, NULL, 'bar')));
2520
2521 $result = $cObj->getImageSourceCollection($layoutKey, $configuration, $file);
2522
2523 $this->assertEquals('---bar---', $result);
2524 }
2525
2526 /**
2527 * Data provider for the getImageSourceCollectionRendersDefinedLayoutKeyDefault test
2528 *
2529 * @return array multi-dimensional array with the second level like this:
2530 * @see getImageSourceCollectionRendersDefinedLayoutKeyDefault
2531 */
2532 public function getImageSourceCollectionRendersDefinedLayoutKeyDataDefaultProvider() {
2533 /**
2534 * @see css_styled_content/static/setup.txt
2535 */
2536 $sourceCollectionArray = array(
2537 'small.' => array(
2538 'width' => '200',
2539 'srcsetCandidate' => '600w',
2540 'mediaQuery' => '(max-device-width: 600px)',
2541 'dataKey' => 'small',
2542 ),
2543 'smallRetina.' => array(
2544 'if.directReturn' => 0,
2545 'width' => '200',
2546 'pixelDensity' => '2',
2547 'srcsetCandidate' => '600w 2x',
2548 'mediaQuery' => '(max-device-width: 600px) AND (min-resolution: 192dpi)',
2549 'dataKey' => 'smallRetina',
2550 )
2551 );
2552 return array(
2553 array(
2554 'default',
2555 array(
2556 'layoutKey' => 'default',
2557 'layout.' => array (
2558 'default.' => array(
2559 'element' => '<img src="###SRC###" width="###WIDTH###" height="###HEIGHT###" ###PARAMS### ###ALTPARAMS### ###BORDER######SELFCLOSINGTAGSLASH###>',
2560 'source' => ''
2561 )
2562 ),
2563 'sourceCollection.' => $sourceCollectionArray
2564 )
2565 ),
2566 );
2567 }
2568
2569 /**
2570 * Make sure the generation of subimages renders the expected HTML Code for the sourceset
2571 *
2572 * @test
2573 * @dataProvider getImageSourceCollectionRendersDefinedLayoutKeyDataDefaultProvider
2574 * @param string $layoutKey
2575 * @param array $configuration
2576 */
2577 public function getImageSourceCollectionRendersDefinedLayoutKeyDefault($layoutKey , $configuration) {
2578 /** @var $cObj \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
2579 $cObj = $this->getMock(
2580 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class,
2581 array('stdWrap','getImgResource')
2582 );
2583 $cObj->start(array(), 'tt_content');
2584
2585 $file = 'testImageName';
2586
2587 // Avoid calling of stdWrap
2588 $cObj
2589 ->expects($this->any())
2590 ->method('stdWrap')
2591 ->will($this->returnArgument(0));
2592
2593 $result = $cObj->getImageSourceCollection($layoutKey, $configuration, $file);
2594
2595 $this->assertEmpty($result);
2596 }
2597
2598 /**
2599 * Data provider for the getImageSourceCollectionRendersDefinedLayoutKeyData test
2600 *
2601 * @return array multi-dimensional array with the second level like this:
2602 * @see getImageSourceCollectionRendersDefinedLayoutKeyData
2603 */
2604 public function getImageSourceCollectionRendersDefinedLayoutKeyDataDataProvider() {
2605 /**
2606 * @see css_styled_content/static/setup.txt
2607 */
2608 $sourceCollectionArray = array(
2609 'small.' => array(
2610 'width' => '200',
2611 'srcsetCandidate' => '600w',
2612 'mediaQuery' => '(max-device-width: 600px)',
2613 'dataKey' => 'small',
2614 ),
2615 'smallRetina.' => array(
2616 'if.directReturn' => 1,
2617 'width' => '200',
2618 'pixelDensity' => '2',
2619 'srcsetCandidate' => '600w 2x',
2620 'mediaQuery' => '(max-device-width: 600px) AND (min-resolution: 192dpi)',
2621 'dataKey' => 'smallRetina',
2622 )
2623 );
2624 return array(
2625 array(
2626 'srcset',
2627 array(
2628 'layoutKey' => 'srcset',
2629 'layout.' => array (
2630 'srcset.' => array(
2631 'element' => '<img src="###SRC###" srcset="###SOURCECOLLECTION###" ###PARAMS### ###ALTPARAMS######SELFCLOSINGTAGSLASH###>',
2632 'source' => '|*|###SRC### ###SRCSETCANDIDATE###,|*|###SRC### ###SRCSETCANDIDATE###'
2633 )
2634 ),
2635 'sourceCollection.' => $sourceCollectionArray
2636 ),
2637 'xhtml_strict',
2638 'bar-file.jpg 600w,bar-file.jpg 600w 2x',
2639 ),
2640 array(
2641 'picture',
2642 array(
2643 'layoutKey' => 'picture',
2644 'layout.' => array (
2645 'picture.' => array(
2646 'element' => '<picture>###SOURCECOLLECTION###<img src="###SRC###" ###PARAMS### ###ALTPARAMS######SELFCLOSINGTAGSLASH###></picture>',
2647 'source' => '<source src="###SRC###" media="###MEDIAQUERY###"###SELFCLOSINGTAGSLASH###>'
2648 )
2649 ),
2650 'sourceCollection.' => $sourceCollectionArray,
2651 ),
2652 'xhtml_strict',
2653 '<source src="bar-file.jpg" media="(max-device-width: 600px)" /><source src="bar-file.jpg" media="(max-device-width: 600px) AND (min-resolution: 192dpi)" />',
2654 ),
2655 array(
2656 'picture',
2657 array(
2658 'layoutKey' => 'picture',
2659 'layout.' => array (
2660 'picture.' => array(
2661 'element' => '<picture>###SOURCECOLLECTION###<img src="###SRC###" ###PARAMS### ###ALTPARAMS######SELFCLOSINGTAGSLASH###></picture>',
2662 'source' => '<source src="###SRC###" media="###MEDIAQUERY###"###SELFCLOSINGTAGSLASH###>'
2663 )
2664 ),
2665 'sourceCollection.' => $sourceCollectionArray,
2666 ),
2667 '',
2668 '<source src="bar-file.jpg" media="(max-device-width: 600px)"><source src="bar-file.jpg" media="(max-device-width: 600px) AND (min-resolution: 192dpi)">',
2669 ),
2670 array(
2671 'data',
2672 array(
2673 'layoutKey' => 'data',
2674 'layout.' => array (
2675 'data.' => array(
2676 'element' => '<img src="###SRC###" ###SOURCECOLLECTION### ###PARAMS### ###ALTPARAMS######SELFCLOSINGTAGSLASH###>',
2677 'source' => 'data-###DATAKEY###="###SRC###"'
2678 )
2679 ),
2680 'sourceCollection.' => $sourceCollectionArray
2681 ),
2682 'xhtml_strict',
2683 'data-small="bar-file.jpg"data-smallRetina="bar-file.jpg"',
2684 ),
2685 );
2686 }
2687
2688 /**
2689 * Make sure the generation of subimages renders the expected HTML Code for the sourceset
2690 *
2691 * @test
2692 * @dataProvider getImageSourceCollectionRendersDefinedLayoutKeyDataDataProvider
2693 * @param string $layoutKey
2694 * @param array $configuration
2695 * @param string $xhtmlDoctype
2696 * @param string $expectedHtml
2697 */
2698 public function getImageSourceCollectionRendersDefinedLayoutKeyData($layoutKey , $configuration, $xhtmlDoctype, $expectedHtml) {
2699 /** @var $cObj \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
2700 $cObj = $this->getMock(
2701 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class,
2702 array('stdWrap','getImgResource')
2703 );
2704 $cObj->start(array(), 'tt_content');
2705
2706 $file = 'testImageName';
2707
2708 $GLOBALS['TSFE']->xhtmlDoctype = $xhtmlDoctype;
2709
2710 // Avoid calling of stdWrap
2711 $cObj
2712 ->expects($this->any())
2713 ->method('stdWrap')
2714 ->will($this->returnArgument(0));
2715
2716 // Avoid calling of imgResource
2717 $cObj
2718 ->expects($this->exactly(2))
2719 ->method('getImgResource')
2720 ->with($this->equalTo('testImageName'))
2721 ->will($this->returnValue(array(100, 100, NULL, 'bar-file.jpg')));
2722
2723 $result = $cObj->getImageSourceCollection($layoutKey, $configuration, $file);
2724
2725 $this->assertEquals($expectedHtml, $result);
2726 }
2727
2728 /**
2729 * Make sure the hook in get sourceCollection is called
2730 *
2731 * @test
2732 */
2733 public function getImageSourceCollectionHookCalled() {
2734 $this->subject = $this->getAccessibleMock(
2735 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class,
2736 array('getResourceFactory', 'stdWrap', 'getImgResource')
2737 );
2738 $this->subject->start(array(), 'tt_content');
2739
2740 // Avoid calling stdwrap and getImgResource
2741 $this->subject->expects($this->any())
2742 ->method('stdWrap')
2743 ->will($this->returnArgument(0));
2744
2745 $this->subject->expects($this->any())
2746 ->method('getImgResource')
2747 ->will($this->returnValue(array(100, 100, NULL, 'bar-file.jpg')));
2748
2749 $resourceFactory = $this->getMock(\TYPO3\CMS\Core\Resource\ResourceFactory::class, array(), array(), '', FALSE);
2750 $this->subject->expects($this->any())->method('getResourceFactory')->will($this->returnValue($resourceFactory));
2751
2752 $className = $this->getUniqueId('tx_coretest_getImageSourceCollectionHookCalled');
2753 $getImageSourceCollectionHookMock = $this->getMock(\TYPO3\CMS\Frontend\ContentObject\ContentObjectOneSourceCollectionHookInterface::class, array('getOneSourceCollection'), array(), $className);
2754 $GLOBALS['T3_VAR']['getUserObj'][$className] = $getImageSourceCollectionHookMock;
2755 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'][] = $className;
2756
2757 $getImageSourceCollectionHookMock
2758 ->expects($this->exactly(1))
2759 ->method('getOneSourceCollection')
2760 ->will($this->returnCallback(array($this, 'isGetOneSourceCollectionCalledCallback')));
2761
2762 $configuration = array(
2763 'layoutKey' => 'data',
2764 'layout.' => array (
2765 'data.' => array(
2766 'element' => '<img src="###SRC###" ###SOURCECOLLECTION### ###PARAMS### ###ALTPARAMS######SELFCLOSINGTAGSLASH###>',
2767 'source' => 'data-###DATAKEY###="###SRC###"'
2768 )
2769 ),
2770 'sourceCollection.' => array(
2771 'small.' => array(
2772 'width' => '200',
2773 'srcsetCandidate' => '600w',
2774 'mediaQuery' => '(max-device-width: 600px)',
2775 'dataKey' => 'small',
2776 ),
2777 ),
2778 );
2779
2780 $result = $this->subject->getImageSourceCollection('data', $configuration, $this->getUniqueId('testImage-'));
2781
2782 $this->assertSame($result, 'isGetOneSourceCollectionCalledCallback');
2783 }
2784
2785 /**
2786 * Handles the arguments that have been sent to the getImgResource hook.
2787 *
2788 * @return string
2789 * @see getImageSourceCollectionHookCalled
2790 */
2791 public function isGetOneSourceCollectionCalledCallback() {
2792 list($sourceRenderConfiguration, $sourceConfiguration, $oneSourceCollection, $parent) = func_get_args();
2793 $this->assertTrue(is_array($sourceRenderConfiguration));
2794 $this->assertTrue(is_array($sourceConfiguration));
2795 return 'isGetOneSourceCollectionCalledCallback';
2796 }
2797
2798 /**
2799 * @param string $expected The expected URL
2800 * @param string $url The URL to parse and manipulate
2801 * @param array $configuration The configuration array
2802 * @test
2803 * @dataProvider forceAbsoluteUrlReturnsCorrectAbsoluteUrlDataProvider
2804 */
2805 public function forceAbsoluteUrlReturnsCorrectAbsoluteUrl($expected, $url, array $configuration) {
2806 // Force hostname
2807 $this->subject->expects($this->any())->method('getEnvironmentVariable')->will($this->returnValueMap(
2808 array(
2809 array('HTTP_HOST', 'localhost'),
2810 array('TYPO3_SITE_PATH', '/'),
2811 )
2812 ));
2813 $GLOBALS['TSFE']->absRefPrefix = '';
2814
2815 $this->assertEquals($expected, $this->subject->_call('forceAbsoluteUrl', $url