[BUGFIX] Allow getPagesTSconfig to be called without BE_USER
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Utility / BackendUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Backend\Tests\Unit\Utility;
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 Prophecy\Argument;
18 use Prophecy\Prophecy\ObjectProphecy;
19 use TYPO3\CMS\Backend\Configuration\TsConfigParser;
20 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\LabelFromItemListMergedReturnsCorrectFieldsFixture;
21 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithMultipleAllowedTablesFixture;
22 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForGroupWithOneAllowedTableFixture;
23 use TYPO3\CMS\Backend\Tests\Unit\Utility\Fixtures\ProcessedValueForSelectWithMMRelationFixture;
24 use TYPO3\CMS\Backend\Utility\BackendUtility;
25 use TYPO3\CMS\Core\Cache\CacheManager;
26 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
27 use TYPO3\CMS\Core\Database\Connection;
28 use TYPO3\CMS\Core\Database\ConnectionPool;
29 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
30 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
31 use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
32 use TYPO3\CMS\Core\Database\RelationHandler;
33 use TYPO3\CMS\Core\Localization\LanguageService;
34 use TYPO3\CMS\Core\Utility\GeneralUtility;
35
36 /**
37 * Test case
38 */
39 class BackendUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
40 {
41 /**
42 * @var bool
43 */
44 protected $resetSingletonInstances = true;
45
46 ///////////////////////////////////////
47 // Tests concerning calcAge
48 ///////////////////////////////////////
49 /**
50 * Data provider for calcAge function
51 *
52 * @return array
53 */
54 public function calcAgeDataProvider()
55 {
56 return [
57 'Single year' => [
58 'seconds' => 60 * 60 * 24 * 365,
59 'expectedLabel' => '1 year'
60 ],
61 'Plural years' => [
62 'seconds' => 60 * 60 * 24 * 365 * 2,
63 'expectedLabel' => '2 yrs'
64 ],
65 'Single negative year' => [
66 'seconds' => 60 * 60 * 24 * 365 * -1,
67 'expectedLabel' => '-1 year'
68 ],
69 'Plural negative years' => [
70 'seconds' => 60 * 60 * 24 * 365 * 2 * -1,
71 'expectedLabel' => '-2 yrs'
72 ],
73 'Single day' => [
74 'seconds' => 60 * 60 * 24,
75 'expectedLabel' => '1 day'
76 ],
77 'Plural days' => [
78 'seconds' => 60 * 60 * 24 * 2,
79 'expectedLabel' => '2 days'
80 ],
81 'Single negative day' => [
82 'seconds' => 60 * 60 * 24 * -1,
83 'expectedLabel' => '-1 day'
84 ],
85 'Plural negative days' => [
86 'seconds' => 60 * 60 * 24 * 2 * -1,
87 'expectedLabel' => '-2 days'
88 ],
89 'Single hour' => [
90 'seconds' => 60 * 60,
91 'expectedLabel' => '1 hour'
92 ],
93 'Plural hours' => [
94 'seconds' => 60 * 60 * 2,
95 'expectedLabel' => '2 hrs'
96 ],
97 'Single negative hour' => [
98 'seconds' => 60 * 60 * -1,
99 'expectedLabel' => '-1 hour'
100 ],
101 'Plural negative hours' => [
102 'seconds' => 60 * 60 * 2 * -1,
103 'expectedLabel' => '-2 hrs'
104 ],
105 'Single minute' => [
106 'seconds' => 60,
107 'expectedLabel' => '1 min'
108 ],
109 'Plural minutes' => [
110 'seconds' => 60 * 2,
111 'expectedLabel' => '2 min'
112 ],
113 'Single negative minute' => [
114 'seconds' => 60 * -1,
115 'expectedLabel' => '-1 min'
116 ],
117 'Plural negative minutes' => [
118 'seconds' => 60 * 2 * -1,
119 'expectedLabel' => '-2 min'
120 ],
121 'Zero seconds' => [
122 'seconds' => 0,
123 'expectedLabel' => '0 min'
124 ]
125 ];
126 }
127
128 /**
129 * @test
130 * @dataProvider calcAgeDataProvider
131 *
132 * @param int $seconds
133 * @param string $expectedLabel
134 */
135 public function calcAgeReturnsExpectedValues($seconds, $expectedLabel)
136 {
137 $this->assertSame($expectedLabel, BackendUtility::calcAge($seconds));
138 }
139
140 ///////////////////////////////////////
141 // Tests concerning getProcessedValue
142 ///////////////////////////////////////
143 /**
144 * @test
145 * @see http://forge.typo3.org/issues/20994
146 */
147 public function getProcessedValueForZeroStringIsZero()
148 {
149 $GLOBALS['TCA'] = [
150 'tt_content' => [
151 'columns' => [
152 'header' => [
153 'config' => [
154 'type' => 'input',
155 ],
156 ],
157 ],
158 ],
159 ];
160 $GLOBALS['LANG'] = [];
161 $this->assertEquals('0', BackendUtility::getProcessedValue('tt_content', 'header', '0'));
162 }
163
164 /**
165 * @test
166 */
167 public function getProcessedValueForGroup()
168 {
169 $GLOBALS['TCA'] = [
170 'tt_content' => [
171 'columns' => [
172 'multimedia' => [
173 'config' => [
174 'type' => 'group',
175 ],
176 ],
177 ],
178 ],
179 ];
180 $GLOBALS['LANG'] = [];
181 $this->assertSame('1, 2', BackendUtility::getProcessedValue('tt_content', 'multimedia', '1,2'));
182 }
183
184 /**
185 * @test
186 */
187 public function getProcessedValueForGroupWithOneAllowedTable()
188 {
189 $GLOBALS['TCA'] = [
190 'tt_content' => [
191 'columns' => [
192 'pages' => [
193 'config' => [
194 'type' => 'group',
195 'allowed' => 'pages',
196 'internal_type' => 'db',
197 'maxitems' => 22,
198 'minitems' => 0,
199 'size' => 3,
200 ],
201 ],
202 ],
203 ],
204 ];
205 $GLOBALS['LANG'] = [];
206 $this->assertSame('Page 1, Page 2', ProcessedValueForGroupWithOneAllowedTableFixture::getProcessedValue('tt_content', 'pages', '1,2'));
207 }
208
209 /**
210 * @test
211 */
212 public function getProcessedValueForGroupWithMultipleAllowedTables()
213 {
214 $GLOBALS['TCA'] = [
215 'index_config' => [
216 'columns' => [
217 'indexcfgs' => [
218 'config' => [
219 'type' => 'group',
220 'internal_type' => 'db',
221 'allowed' => 'index_config,pages',
222 'size' => 5,
223 ],
224 ],
225 ],
226 ],
227 ];
228 $GLOBALS['LANG'] = [];
229 $this->assertSame('Page 1, Configuration 2', ProcessedValueForGroupWithMultipleAllowedTablesFixture::getProcessedValue('index_config', 'indexcfgs', 'pages_1,index_config_2'));
230 }
231
232 /**
233 * Prepare a mock database setup for a Doctrine connection
234 * and return an array of all prophets to set expectations upon.
235 *
236 * @param string $tableName
237 * @return array
238 */
239 protected function mockDatabaseConnection($tableName = 'sys_category')
240 {
241 $connectionProphet = $this->prophesize(Connection::class);
242 $connectionProphet->quote(Argument::cetera())->will(function ($arguments) {
243 return "'" . $arguments[0] . "'";
244 });
245 $connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
246 return '`' . $arguments[0] . '`';
247 });
248
249 $restrictionProphet = $this->prophesize(DefaultRestrictionContainer::class);
250 $restrictionProphet->removeAll()->willReturn($restrictionProphet->reveal());
251 $restrictionProphet->add(Argument::cetera())->willReturn($restrictionProphet->reveal());
252
253 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
254 $queryBuilderProphet->expr()->willReturn(
255 GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
256 );
257 $queryBuilderProphet->getRestrictions()->willReturn($restrictionProphet->reveal());
258 $queryBuilderProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
259 return '`' . $arguments[0] . '`';
260 });
261
262 $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
263 $connectionPoolProphet->getConnectionForTable($tableName)
264 ->willReturn($connectionProphet->reveal());
265 $connectionPoolProphet->getQueryBuilderForTable($tableName)
266 ->shouldBeCalled()
267 ->willReturn($queryBuilderProphet->reveal());
268
269 return [$queryBuilderProphet, $connectionPoolProphet, $connectionProphet, $restrictionProphet];
270 }
271
272 /**
273 * @test
274 */
275 public function getProcessedValueForSelectWithMMRelation()
276 {
277 /** @var RelationHandler|ObjectProphecy $relationHandlerProphet */
278 $relationHandlerProphet = $this->prophesize(RelationHandler::class);
279 $relationHandlerProphet->start(Argument::cetera())->shouldBeCalled();
280
281 $relationHandlerInstance = $relationHandlerProphet->reveal();
282 $relationHandlerInstance->tableArray['sys_category'] = [1, 2];
283
284 list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection('sys_category');
285 $statementProphet = $this->prophesize(\Doctrine\DBAL\Driver\Statement::class);
286 $statementProphet->fetch()->shouldBeCalled()->willReturn(
287 [
288 'uid' => 1,
289 'title' => 'Category 1',
290 ],
291 [
292 'uid' => 2,
293 'title' => 'Category 2',
294 ],
295 false
296 );
297
298 /** @var QueryBuilder|ObjectProphecy $queryBuilderProphet */
299 $queryBuilderProphet->select('uid', 'sys_category.title')->willReturn($queryBuilderProphet->reveal());
300 $queryBuilderProphet->from('sys_category')->willReturn($queryBuilderProphet->reveal());
301 $queryBuilderProphet->where('`uid` IN (:dcValue1)')->willReturn($queryBuilderProphet->reveal());
302 $queryBuilderProphet->createNamedParameter([1, 2], Connection::PARAM_INT_ARRAY)->willReturn(':dcValue1');
303 $queryBuilderProphet->execute()->willReturn($statementProphet->reveal());
304
305 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerInstance);
306 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
307
308 $GLOBALS['TCA'] = [
309 'pages' => [
310 'columns' => [
311 'categories' => [
312 'config' => [
313 'type' => 'select',
314 'foreign_table' => 'sys_category',
315 'MM' => 'sys_category_record_mm',
316 'MM_match_fields' => [
317 'fieldname' => 'categories',
318 'tablesnames' => 'pages',
319 ],
320 'MM_opposite_field' => 'items',
321 ],
322 ],
323 ],
324 ],
325 'sys_category' => [
326 'ctrl' => ['label' => 'title'],
327 'columns' => [
328 'items' => [
329 'config' => [
330 'type' => 'group',
331 'internal_type' => 'db',
332 'allowed' => '*',
333 'MM' => 'sys_category_record_mm',
334 'MM_oppositeUsage' => [],
335 ]
336 ]
337 ],
338 ],
339 ];
340 $GLOBALS['LANG'] = [];
341
342 $this->assertSame(
343 'Category 1; Category 2',
344 ProcessedValueForSelectWithMMRelationFixture::getProcessedValue(
345 'pages',
346 'categories',
347 '2',
348 0,
349 false,
350 false,
351 1
352 )
353 );
354 }
355
356 /**
357 * @test
358 */
359 public function getProcessedValueDisplaysAgeForDateInputFieldsIfSettingAbsent()
360 {
361 /** @var ObjectProphecy $languageServiceProphecy */
362 $languageServiceProphecy = $this->prophesize(LanguageService::class);
363 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
364 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
365
366 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 8, 30, 2015);
367
368 $GLOBALS['TCA'] = [
369 'tt_content' => [
370 'columns' => [
371 'date' => [
372 'config' => [
373 'type' => 'input',
374 'eval' => 'date',
375 ],
376 ],
377 ],
378 ],
379 ];
380 $this->assertSame('28-08-15 (-2 days)', BackendUtility::getProcessedValue('tt_content', 'date', mktime(0, 0, 0, 8, 28, 2015)));
381 }
382
383 /**
384 * @return array
385 */
386 public function inputTypeDateDisplayOptions()
387 {
388 return [
389 'typeSafe Setting' => [
390 true,
391 '28-08-15',
392 ],
393 'non typesafe setting' => [
394 1,
395 '28-08-15',
396 ],
397 'setting disabled typesafe' => [
398 false,
399 '28-08-15 (-2 days)',
400 ],
401 'setting disabled not typesafe' => [
402 0,
403 '28-08-15 (-2 days)',
404 ],
405 ];
406 }
407
408 /**
409 * @test
410 *
411 * @dataProvider inputTypeDateDisplayOptions
412 *
413 * @param string $input
414 * @param string $expected
415 */
416 public function getProcessedValueHandlesAgeDisplayCorrectly($input, $expected)
417 {
418 /** @var ObjectProphecy $languageServiceProphecy */
419 $languageServiceProphecy = $this->prophesize(LanguageService::class);
420 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
421 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
422
423 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 8, 30, 2015);
424
425 $GLOBALS['TCA'] = [
426 'tt_content' => [
427 'columns' => [
428 'date' => [
429 'config' => [
430 'type' => 'input',
431 'eval' => 'date',
432 'disableAgeDisplay' => $input,
433 ],
434 ],
435 ],
436 ],
437 ];
438 $this->assertSame($expected, BackendUtility::getProcessedValue('tt_content', 'date', mktime(0, 0, 0, 8, 28, 2015)));
439 }
440
441 /**
442 * Tests concerning getCommonSelectFields
443 */
444
445 /**
446 * Data provider for getCommonSelectFieldsReturnsCorrectFields
447 *
448 * @return array The test data with $table, $prefix, $presetFields, $tca, $expectedFields
449 */
450 public function getCommonSelectFieldsReturnsCorrectFieldsDataProvider()
451 {
452 return [
453 'only uid' => [
454 'table' => 'test_table',
455 'prefix' => '',
456 'presetFields' => [],
457 'tca' => [],
458 'expectedFields' => 'uid'
459 ],
460 'label set' => [
461 'table' => 'test_table',
462 'prefix' => '',
463 'presetFields' => [],
464 'tca' => [
465 'ctrl' => [
466 'label' => 'label'
467 ]
468 ],
469 'expectedFields' => 'uid,label'
470 ],
471 'label_alt set' => [
472 'table' => 'test_table',
473 'prefix' => '',
474 'presetFields' => [],
475 'tca' => [
476 'ctrl' => [
477 'label_alt' => 'label,label2'
478 ]
479 ],
480 'expectedFields' => 'uid,label,label2'
481 ],
482 'versioningWS set' => [
483 'table' => 'test_table',
484 'prefix' => '',
485 'presetFields' => [],
486 'tca' => [
487 'ctrl' => [
488 'versioningWS' => true
489 ]
490 ],
491 'expectedFields' => 'uid,t3ver_id,t3ver_state,t3ver_wsid,t3ver_count'
492 ],
493 'selicon_field set' => [
494 'table' => 'test_table',
495 'prefix' => '',
496 'presetFields' => [],
497 'tca' => [
498 'ctrl' => [
499 'selicon_field' => 'field'
500 ]
501 ],
502 'expectedFields' => 'uid,field'
503 ],
504 'typeicon_column set' => [
505 'table' => 'test_table',
506 'prefix' => '',
507 'presetFields' => [],
508 'tca' => [
509 'ctrl' => [
510 'typeicon_column' => 'field'
511 ]
512 ],
513 'expectedFields' => 'uid,field'
514 ],
515 'enablecolumns set' => [
516 'table' => 'test_table',
517 'prefix' => '',
518 'presetFields' => [],
519 'tca' => [
520 'ctrl' => [
521 'enablecolumns' => [
522 'disabled' => 'hidden',
523 'starttime' => 'start',
524 'endtime' => 'stop',
525 'fe_group' => 'groups'
526 ]
527 ]
528 ],
529 'expectedFields' => 'uid,hidden,start,stop,groups'
530 ],
531 'label set to uid' => [
532 'table' => 'test_table',
533 'prefix' => '',
534 'presetFields' => [],
535 'tca' => [
536 'ctrl' => [
537 'label' => 'uid'
538 ]
539 ],
540 'expectedFields' => 'uid'
541 ]
542 ];
543 }
544
545 /**
546 * @test
547 * @dataProvider getCommonSelectFieldsReturnsCorrectFieldsDataProvider
548 *
549 * @param string $table
550 * @param string $prefix
551 * @param array $presetFields
552 * @param array $tca
553 * @param string $expectedFields
554 */
555 public function getCommonSelectFieldsReturnsCorrectFields($table, $prefix = '', array $presetFields, array $tca, $expectedFields = '')
556 {
557 $GLOBALS['TCA'][$table] = $tca;
558 $selectFields = BackendUtility::getCommonSelectFields($table, $prefix, $presetFields);
559 $this->assertEquals($selectFields, $expectedFields);
560 }
561
562 /**
563 * Tests concerning getLabelFromItemlist
564 */
565
566 /**
567 * Data provider for getLabelFromItemlistReturnsCorrectFields
568 *
569 * @return array The test data with $table, $col, $key, $expectedLabel
570 */
571 public function getLabelFromItemlistReturnsCorrectFieldsDataProvider()
572 {
573 return [
574 'item set' => [
575 'table' => 'tt_content',
576 'col' => 'menu_type',
577 'key' => '1',
578 'tca' => [
579 'columns' => [
580 'menu_type' => [
581 'config' => [
582 'items' => [
583 ['Item 1', '0'],
584 ['Item 2', '1'],
585 ['Item 3', '3']
586 ]
587 ]
588 ]
589 ]
590 ],
591 'expectedLabel' => 'Item 2'
592 ],
593 'item set twice' => [
594 'table' => 'tt_content',
595 'col' => 'menu_type',
596 'key' => '1',
597 'tca' => [
598 'columns' => [
599 'menu_type' => [
600 'config' => [
601 'items' => [
602 ['Item 1', '0'],
603 ['Item 2a', '1'],
604 ['Item 2b', '1'],
605 ['Item 3', '3']
606 ]
607 ]
608 ]
609 ]
610 ],
611 'expectedLabel' => 'Item 2a'
612 ],
613 'item not found' => [
614 'table' => 'tt_content',
615 'col' => 'menu_type',
616 'key' => '5',
617 'tca' => [
618 'columns' => [
619 'menu_type' => [
620 'config' => [
621 'items' => [
622 ['Item 1', '0'],
623 ['Item 2', '1'],
624 ['Item 3', '2']
625 ]
626 ]
627 ]
628 ]
629 ],
630 'expectedLabel' => null
631 ]
632 ];
633 }
634
635 /**
636 * @test
637 * @dataProvider getLabelFromItemlistReturnsCorrectFieldsDataProvider
638 *
639 * @param string $table
640 * @param string $col
641 * @param string $key
642 * @param array $tca
643 * @param string $expectedLabel
644 */
645 public function getLabelFromItemlistReturnsCorrectFields($table, $col = '', $key = '', array $tca, $expectedLabel = '')
646 {
647 $GLOBALS['TCA'][$table] = $tca;
648 $label = BackendUtility::getLabelFromItemlist($table, $col, $key);
649 $this->assertEquals($label, $expectedLabel);
650 }
651
652 /**
653 * Tests concerning getLabelFromItemListMerged
654 */
655
656 /**
657 * Data provider for getLabelFromItemListMerged
658 *
659 * @return array The test data with $pageId, $table, $column, $key, $expectedLabel
660 */
661 public function getLabelFromItemListMergedReturnsCorrectFieldsDataProvider()
662 {
663 return [
664 'no field found' => [
665 'pageId' => '123',
666 'table' => 'tt_content',
667 'col' => 'menu_type',
668 'key' => '10',
669 'tca' => [
670 'columns' => [
671 'menu_type' => [
672 'config' => [
673 'items' => [
674 ['Item 1', '0'],
675 ['Item 2', '1'],
676 ['Item 3', '3']
677 ]
678 ]
679 ]
680 ]
681 ],
682 'expectedLabel' => ''
683 ],
684 'no tsconfig set' => [
685 'pageId' => '123',
686 'table' => 'tt_content',
687 'col' => 'menu_type',
688 'key' => '1',
689 'tca' => [
690 'columns' => [
691 'menu_type' => [
692 'config' => [
693 'items' => [
694 ['Item 1', '0'],
695 ['Item 2', '1'],
696 ['Item 3', '3']
697 ]
698 ]
699 ]
700 ]
701 ],
702 'expectedLabel' => 'Item 2'
703 ]
704 ];
705 }
706
707 /**
708 * @test
709 * @dataProvider getLabelFromItemListMergedReturnsCorrectFieldsDataProvider
710 *
711 * @param int $pageId
712 * @param string $table
713 * @param string $column
714 * @param string $key
715 * @param array $tca
716 * @param string $expectedLabel
717 */
718 public function getLabelFromItemListMergedReturnsCorrectFields($pageId, $table, $column = '', $key = '', array $tca, $expectedLabel = '')
719 {
720 $GLOBALS['TCA'][$table] = $tca;
721
722 $this->assertEquals($expectedLabel, LabelFromItemListMergedReturnsCorrectFieldsFixture::getLabelFromItemListMerged($pageId, $table, $column, $key));
723 }
724
725 /**
726 * Tests concerning getFuncCheck
727 */
728
729 /**
730 * @test
731 */
732 public function getFuncCheckReturnsInputTagWithValueAttribute()
733 {
734 $this->assertStringMatchesFormat('<input %Svalue="1"%S/>', BackendUtility::getFuncCheck('params', 'test', true));
735 }
736
737 /*
738 * Tests concerning getLabelsFromItemsList
739 */
740
741 /**
742 * @return array
743 */
744 public function getLabelsFromItemsListDataProvider()
745 {
746 return [
747 'return value if found' => [
748 'foobar', // table
749 'someColumn', // col
750 'foo, bar', // keyList
751 [ // TCA
752 'columns' => [
753 'someColumn' => [
754 'config' => [
755 'items' => [
756 '0' => ['aFooLabel', 'foo'],
757 '1' => ['aBarLabel', 'bar']
758 ]
759 ]
760 ]
761 ]
762 ],
763 [], // page TSconfig
764 'aFooLabel, aBarLabel' // expected
765 ],
766 'page TSconfig overrules TCA' => [
767 'foobar', // table
768 'someColumn', // col
769 'foo,bar, add', // keyList
770 [ // TCA
771 'columns' => [
772 'someColumn' => [
773 'config' => [
774 'items' => [
775 '0' => ['aFooLabel', 'foo'],
776 '1' => ['aBarLabel', 'bar']
777 ]
778 ]
779 ]
780 ]
781 ],
782 [ // page TSconfig
783 'addItems.' => ['add' => 'aNewLabel'],
784 'altLabels.' => ['bar' => 'aBarDiffLabel'],
785 ],
786 'aFooLabel, aBarDiffLabel, aNewLabel' // expected
787 ]
788 ];
789 }
790
791 /**
792 * @test
793 * @dataProvider getLabelsFromItemsListDataProvider
794 *
795 * @param string $table
796 * @param string $col
797 * @param string $keyList
798 * @param array $tca
799 * @param array $pageTsConfig
800 * @param string $expectedLabel
801 */
802 public function getLabelsFromItemsListReturnsCorrectValue($table, $col, $keyList, $tca, array $pageTsConfig, $expectedLabel)
803 {
804 // Stub LanguageService and let sL() return the same value that came in again
805 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
806 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
807
808 $GLOBALS['TCA'][$table] = $tca;
809 $label = BackendUtility::getLabelsFromItemsList($table, $col, $keyList, $pageTsConfig);
810 $this->assertEquals($expectedLabel, $label);
811 }
812
813 /**
814 * @test
815 */
816 public function getProcessedValueReturnsLabelsForExistingValuesSolely()
817 {
818 $table = 'foobar';
819 $col = 'someColumn';
820 $tca = [
821 'columns' => [
822 'someColumn' => [
823 'config' => [
824 'type' => 'select',
825 'items' => [
826 '0' => ['aFooLabel', 'foo'],
827 '1' => ['aBarLabel', 'bar']
828 ]
829 ]
830 ]
831 ]
832 ];
833 // Stub LanguageService and let sL() return the same value that came in again
834 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
835 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
836
837 $GLOBALS['TCA'][$table] = $tca;
838 $label = BackendUtility::getProcessedValue($table, $col, 'foo,invalidKey,bar');
839 $this->assertEquals('aFooLabel, aBarLabel', $label);
840 }
841
842 /**
843 * @test
844 */
845 public function getProcessedValueReturnsPlainValueIfItemIsNotFound()
846 {
847 $table = 'foobar';
848 $col = 'someColumn';
849 $tca = [
850 'columns' => [
851 'someColumn' => [
852 'config' => [
853 'type' => 'select',
854 'items' => [
855 '0' => ['aFooLabel', 'foo']
856 ]
857 ]
858 ]
859 ]
860 ];
861 // Stub LanguageService and let sL() return the same value that came in again
862 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
863 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
864
865 $GLOBALS['TCA'][$table] = $tca;
866 $label = BackendUtility::getProcessedValue($table, $col, 'invalidKey');
867 $this->assertEquals('invalidKey', $label);
868 }
869
870 /**
871 * Tests concerning viewOnClick
872 */
873
874 /**
875 * @test
876 */
877 public function viewOnClickReturnsOnClickCodeWithAlternativeUrl()
878 {
879 // Make sure the hook inside viewOnClick is not fired. This may be removed if unit tests
880 // bootstrap does not initialize TYPO3_CONF_VARS anymore.
881 unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass']);
882
883 $alternativeUrl = 'https://typo3.org/about/typo3-the-cms/the-history-of-typo3/#section';
884 $onclickCode = 'var previewWin = window.open(' . GeneralUtility::quoteJSvalue($alternativeUrl) . ',\'newTYPO3frontendWindow\');' . LF
885 . 'if (previewWin.location.href === ' . GeneralUtility::quoteJSvalue($alternativeUrl) . ') { previewWin.location.reload(); };';
886 $this->assertStringMatchesFormat(
887 $onclickCode,
888 BackendUtility::viewOnClick(null, null, null, null, $alternativeUrl, null, false)
889 );
890 }
891
892 /**
893 * @test
894 */
895 public function dateTimeAgeReturnsCorrectValues()
896 {
897 /** @var ObjectProphecy|LanguageService $languageServiceProphecy */
898 $languageServiceProphecy = $this->prophesize(LanguageService::class);
899 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
900 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
901 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 3, 23, 2016);
902
903 $this->assertSame('24-03-16 00:00 (-1 day)', BackendUtility::dateTimeAge($GLOBALS['EXEC_TIME'] + 86400));
904 $this->assertSame('24-03-16 (-1 day)', BackendUtility::dateTimeAge($GLOBALS['EXEC_TIME'] + 86400, 1, 'date'));
905 }
906
907 /**
908 * @test
909 */
910 public function purgeComputedPropertyNamesRemovesPropertiesStartingWithUnderscore()
911 {
912 $propertyNames = [
913 'uid',
914 'pid',
915 '_ORIG_PID'
916 ];
917 $computedPropertyNames = BackendUtility::purgeComputedPropertyNames($propertyNames);
918 self::assertSame(['uid', 'pid'], $computedPropertyNames);
919 }
920
921 /**
922 * @test
923 */
924 public function purgeComputedPropertiesFromRecordRemovesPropertiesStartingWithUnderscore()
925 {
926 $record = [
927 'uid' => 1,
928 'pid' => 2,
929 '_ORIG_PID' => 1
930 ];
931 $expected = [
932 'uid' => 1,
933 'pid' => 2
934 ];
935 $computedProperties = BackendUtility::purgeComputedPropertiesFromRecord($record);
936 self::assertSame($expected, $computedProperties);
937 }
938
939 public function splitTableUidDataProvider()
940 {
941 return [
942 'simple' => [
943 'pages_23',
944 ['pages', '23']
945 ],
946 'complex' => [
947 'tt_content_13',
948 ['tt_content', '13']
949 ],
950 'multiple underscores' => [
951 'tx_runaway_domain_model_crime_scene_1234',
952 ['tx_runaway_domain_model_crime_scene', '1234']
953 ]
954 ];
955 }
956
957 /**
958 * @test
959 * @dataProvider splitTableUidDataProvider
960 */
961 public function splitTableUid($input, $expected)
962 {
963 $result = BackendUtility::splitTable_Uid($input);
964 self::assertSame($expected, $result);
965 }
966
967 /**
968 * Tests if the method getPagesTSconfig can be called without having a GLOBAL['BE_USER'] object.
969 * However, this test also shows all the various other dependencies this method has.
970 *
971 * @test
972 */
973 public function getPagesTSconfigWorksWithoutInitializedBackendUser()
974 {
975 $expected = ['called.' => ['config']];
976 $pageId = 13;
977 $parserProphecy = $this->prophesize(TsConfigParser::class);
978 $parserProphecy->parseTSconfig(Argument::cetera())->willReturn(['hash' => $pageId, 'TSconfig' => $expected]);
979 GeneralUtility::addInstance(TsConfigParser::class, $parserProphecy->reveal());
980
981 $cacheManagerProphecy = $this->prophesize(CacheManager::class);
982 $cacheProphecy = $this->prophesize(FrontendInterface::class);
983 $cacheManagerProphecy->getCache('cache_runtime')->willReturn($cacheProphecy->reveal());
984 $cacheHashProphecy = $this->prophesize(FrontendInterface::class);
985 $cacheManagerProphecy->hasCache('extbase_reflection')->willReturn(false);
986 $cacheManagerProphecy->getCache('cache_hash')->willReturn($cacheHashProphecy->reveal());
987 $cacheProphecy->has(Argument::cetera())->willReturn(false);
988 $cacheProphecy->get(Argument::cetera())->willReturn(false);
989 $cacheProphecy->set(Argument::cetera())->willReturn(false);
990 $cacheProphecy->get('backendUtilityBeGetRootLine')->willReturn(['13--1' => []]);
991 GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
992 $result = BackendUtility::getPagesTSconfig($pageId);
993 $this->assertEquals($expected, $result);
994 }
995 }