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