c688bb643982682df0ba2752e9bc9dc806d39eb3
[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\Tests\Unit\Utility\Fixtures\BackendUtilityFixture;
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\Authentication\BackendUserAuthentication;
26 use TYPO3\CMS\Core\Database\Connection;
27 use TYPO3\CMS\Core\Database\ConnectionPool;
28 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
29 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
30 use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
31 use TYPO3\CMS\Core\Database\RelationHandler;
32 use TYPO3\CMS\Core\Localization\LanguageService;
33 use TYPO3\CMS\Core\Utility\GeneralUtility;
34
35 /**
36 * Test case
37 */
38 class BackendUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
39 {
40 /**
41 * Subject is not notice free, disable E_NOTICES
42 */
43 protected static $suppressNotices = true;
44
45 ///////////////////////////////////////
46 // Tests concerning calcAge
47 ///////////////////////////////////////
48 /**
49 * Data provider for calcAge function
50 *
51 * @return array
52 */
53 public function calcAgeDataProvider()
54 {
55 return [
56 'Single year' => [
57 'seconds' => 60 * 60 * 24 * 365,
58 'expectedLabel' => '1 year'
59 ],
60 'Plural years' => [
61 'seconds' => 60 * 60 * 24 * 365 * 2,
62 'expectedLabel' => '2 yrs'
63 ],
64 'Single negative year' => [
65 'seconds' => 60 * 60 * 24 * 365 * -1,
66 'expectedLabel' => '-1 year'
67 ],
68 'Plural negative years' => [
69 'seconds' => 60 * 60 * 24 * 365 * 2 * -1,
70 'expectedLabel' => '-2 yrs'
71 ],
72 'Single day' => [
73 'seconds' => 60 * 60 * 24,
74 'expectedLabel' => '1 day'
75 ],
76 'Plural days' => [
77 'seconds' => 60 * 60 * 24 * 2,
78 'expectedLabel' => '2 days'
79 ],
80 'Single negative day' => [
81 'seconds' => 60 * 60 * 24 * -1,
82 'expectedLabel' => '-1 day'
83 ],
84 'Plural negative days' => [
85 'seconds' => 60 * 60 * 24 * 2 * -1,
86 'expectedLabel' => '-2 days'
87 ],
88 'Single hour' => [
89 'seconds' => 60 * 60,
90 'expectedLabel' => '1 hour'
91 ],
92 'Plural hours' => [
93 'seconds' => 60 * 60 * 2,
94 'expectedLabel' => '2 hrs'
95 ],
96 'Single negative hour' => [
97 'seconds' => 60 * 60 * -1,
98 'expectedLabel' => '-1 hour'
99 ],
100 'Plural negative hours' => [
101 'seconds' => 60 * 60 * 2 * -1,
102 'expectedLabel' => '-2 hrs'
103 ],
104 'Single minute' => [
105 'seconds' => 60,
106 'expectedLabel' => '1 min'
107 ],
108 'Plural minutes' => [
109 'seconds' => 60 * 2,
110 'expectedLabel' => '2 min'
111 ],
112 'Single negative minute' => [
113 'seconds' => 60 * -1,
114 'expectedLabel' => '-1 min'
115 ],
116 'Plural negative minutes' => [
117 'seconds' => 60 * 2 * -1,
118 'expectedLabel' => '-2 min'
119 ],
120 'Zero seconds' => [
121 'seconds' => 0,
122 'expectedLabel' => '0 min'
123 ]
124 ];
125 }
126
127 /**
128 * @test
129 * @dataProvider calcAgeDataProvider
130 *
131 * @param int $seconds
132 * @param string $expectedLabel
133 */
134 public function calcAgeReturnsExpectedValues($seconds, $expectedLabel)
135 {
136 $this->assertSame($expectedLabel, BackendUtility::calcAge($seconds));
137 }
138
139 ///////////////////////////////////////
140 // Tests concerning getProcessedValue
141 ///////////////////////////////////////
142 /**
143 * @test
144 * @see http://forge.typo3.org/issues/20994
145 */
146 public function getProcessedValueForZeroStringIsZero()
147 {
148 $GLOBALS['TCA'] = [
149 'tt_content' => [
150 'columns' => [
151 'header' => [
152 'config' => [
153 'type' => 'input',
154 ],
155 ],
156 ],
157 ],
158 ];
159 $this->assertEquals('0', BackendUtility::getProcessedValue('tt_content', 'header', '0'));
160 }
161
162 /**
163 * @test
164 */
165 public function getProcessedValueForGroup()
166 {
167 $GLOBALS['TCA'] = [
168 'tt_content' => [
169 'columns' => [
170 'multimedia' => [
171 'config' => [
172 'type' => 'group',
173 ],
174 ],
175 ],
176 ],
177 ];
178 $this->assertSame('1, 2', BackendUtility::getProcessedValue('tt_content', 'multimedia', '1,2'));
179 }
180
181 /**
182 * @test
183 */
184 public function getProcessedValueForGroupWithOneAllowedTable()
185 {
186 $GLOBALS['TCA'] = [
187 'tt_content' => [
188 'columns' => [
189 'pages' => [
190 'config' => [
191 'type' => 'group',
192 'allowed' => 'pages',
193 'internal_type' => 'db',
194 'maxitems' => 22,
195 'minitems' => 0,
196 'size' => 3,
197 ],
198 ],
199 ],
200 ],
201 ];
202
203 $this->assertSame('Page 1, Page 2', ProcessedValueForGroupWithOneAllowedTableFixture::getProcessedValue('tt_content', 'pages', '1,2'));
204 }
205
206 /**
207 * @test
208 */
209 public function getProcessedValueForGroupWithMultipleAllowedTables()
210 {
211 $GLOBALS['TCA'] = [
212 'index_config' => [
213 'columns' => [
214 'indexcfgs' => [
215 'config' => [
216 'type' => 'group',
217 'internal_type' => 'db',
218 'allowed' => 'index_config,pages',
219 'size' => 5,
220 ],
221 ],
222 ],
223 ],
224 ];
225
226 $this->assertSame('Page 1, Configuration 2', ProcessedValueForGroupWithMultipleAllowedTablesFixture::getProcessedValue('index_config', 'indexcfgs', 'pages_1,index_config_2'));
227 }
228
229 /**
230 * Prepare a mock database setup for a Doctrine connection
231 * and return an array of all prophets to set expectations upon.
232 *
233 * @param string $tableName
234 * @return array
235 */
236 protected function mockDatabaseConnection($tableName = 'sys_category')
237 {
238 $connectionProphet = $this->prophesize(Connection::class);
239 $connectionProphet->quote(Argument::cetera())->will(function ($arguments) {
240 return "'" . $arguments[0] . "'";
241 });
242 $connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
243 return '`' . $arguments[0] . '`';
244 });
245
246 $restrictionProphet = $this->prophesize(DefaultRestrictionContainer::class);
247 $restrictionProphet->removeAll()->willReturn($restrictionProphet->reveal());
248 $restrictionProphet->add(Argument::cetera())->willReturn($restrictionProphet->reveal());
249
250 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
251 $queryBuilderProphet->expr()->willReturn(
252 GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
253 );
254 $queryBuilderProphet->getRestrictions()->willReturn($restrictionProphet->reveal());
255 $queryBuilderProphet->quoteIdentifier(Argument::cetera())->will(function ($arguments) {
256 return '`' . $arguments[0] . '`';
257 });
258
259 $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
260 $connectionPoolProphet->getConnectionForTable($tableName)
261 ->willReturn($connectionProphet->reveal());
262 $connectionPoolProphet->getQueryBuilderForTable($tableName)
263 ->shouldBeCalled()
264 ->willReturn($queryBuilderProphet->reveal());
265
266 return [$queryBuilderProphet, $connectionPoolProphet, $connectionProphet, $restrictionProphet];
267 }
268
269 /**
270 * @test
271 */
272 public function getProcessedValueForSelectWithMMRelation()
273 {
274 /** @var RelationHandler|ObjectProphecy $relationHandlerProphet */
275 $relationHandlerProphet = $this->prophesize(RelationHandler::class);
276 $relationHandlerProphet->start(Argument::cetera())->shouldBeCalled();
277
278 $relationHandlerInstance = $relationHandlerProphet->reveal();
279 $relationHandlerInstance->tableArray['sys_category'] = [1, 2];
280
281 list($queryBuilderProphet, $connectionPoolProphet) = $this->mockDatabaseConnection('sys_category');
282 $statementProphet = $this->prophesize(\Doctrine\DBAL\Driver\Statement::class);
283 $statementProphet->fetch()->shouldBeCalled()->willReturn(
284 [
285 'uid' => 1,
286 'title' => 'Category 1',
287 ],
288 [
289 'uid' => 2,
290 'title' => 'Category 2',
291 ],
292 false
293 );
294
295 /** @var QueryBuilder|ObjectProphecy $queryBuilderProphet */
296 $queryBuilderProphet->select('uid', 'sys_category.title')->willReturn($queryBuilderProphet->reveal());
297 $queryBuilderProphet->from('sys_category')->willReturn($queryBuilderProphet->reveal());
298 $queryBuilderProphet->where('`uid` IN (:dcValue1)')->willReturn($queryBuilderProphet->reveal());
299 $queryBuilderProphet->createNamedParameter([1, 2], Connection::PARAM_INT_ARRAY)->willReturn(':dcValue1');
300 $queryBuilderProphet->execute()->willReturn($statementProphet->reveal());
301
302 GeneralUtility::addInstance(RelationHandler::class, $relationHandlerInstance);
303 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
304
305 $GLOBALS['TCA'] = [
306 'pages' => [
307 'columns' => [
308 'categories' => [
309 'config' => [
310 'type' => 'select',
311 'foreign_table' => 'sys_category',
312 'MM' => 'sys_category_record_mm',
313 'MM_match_fields' => [
314 'fieldname' => 'categories',
315 'tablesnames' => 'pages',
316 ],
317 'MM_opposite_field' => 'items',
318 ],
319 ],
320 ],
321 ],
322 'sys_category' => [
323 'ctrl' => ['label' => 'title'],
324 'columns' => [
325 'items' => [
326 'config' => [
327 'type' => 'group',
328 'internal_type' => 'db',
329 'allowed' => '*',
330 'MM' => 'sys_category_record_mm',
331 'MM_oppositeUsage' => [],
332 ]
333 ]
334 ],
335 ],
336 ];
337
338 $this->assertSame(
339 'Category 1; Category 2',
340 ProcessedValueForSelectWithMMRelationFixture::getProcessedValue(
341 'pages',
342 'categories',
343 '2',
344 0,
345 false,
346 false,
347 1
348 )
349 );
350 }
351
352 /**
353 * @test
354 */
355 public function getProcessedValueDisplaysAgeForDateInputFieldsIfSettingAbsent()
356 {
357 /** @var ObjectProphecy $languageServiceProphecy */
358 $languageServiceProphecy = $this->prophesize(LanguageService::class);
359 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
360 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
361
362 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 8, 30, 2015);
363
364 $GLOBALS['TCA'] = [
365 'tt_content' => [
366 'columns' => [
367 'date' => [
368 'config' => [
369 'type' => 'input',
370 'eval' => 'date',
371 ],
372 ],
373 ],
374 ],
375 ];
376 $this->assertSame('28-08-15 (-2 days)', BackendUtility::getProcessedValue('tt_content', 'date', mktime(0, 0, 0, 8, 28, 2015)));
377 }
378
379 /**
380 * @return array
381 */
382 public function inputTypeDateDisplayOptions()
383 {
384 return [
385 'typeSafe Setting' => [
386 true,
387 '28-08-15',
388 ],
389 'non typesafe setting' => [
390 1,
391 '28-08-15',
392 ],
393 'setting disabled typesafe' => [
394 false,
395 '28-08-15 (-2 days)',
396 ],
397 'setting disabled not typesafe' => [
398 0,
399 '28-08-15 (-2 days)',
400 ],
401 ];
402 }
403
404 /**
405 * @test
406 *
407 * @dataProvider inputTypeDateDisplayOptions
408 *
409 * @param string $input
410 * @param string $expected
411 */
412 public function getProcessedValueHandlesAgeDisplayCorrectly($input, $expected)
413 {
414 /** @var ObjectProphecy $languageServiceProphecy */
415 $languageServiceProphecy = $this->prophesize(LanguageService::class);
416 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
417 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
418
419 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 8, 30, 2015);
420
421 $GLOBALS['TCA'] = [
422 'tt_content' => [
423 'columns' => [
424 'date' => [
425 'config' => [
426 'type' => 'input',
427 'eval' => 'date',
428 'disableAgeDisplay' => $input,
429 ],
430 ],
431 ],
432 ],
433 ];
434 $this->assertSame($expected, BackendUtility::getProcessedValue('tt_content', 'date', mktime(0, 0, 0, 8, 28, 2015)));
435 }
436
437 /**
438 * Tests concerning getCommonSelectFields
439 */
440
441 /**
442 * Data provider for getCommonSelectFieldsReturnsCorrectFields
443 *
444 * @return array The test data with $table, $prefix, $presetFields, $tca, $expectedFields
445 */
446 public function getCommonSelectFieldsReturnsCorrectFieldsDataProvider()
447 {
448 return [
449 'only uid' => [
450 'table' => 'test_table',
451 'prefix' => '',
452 'presetFields' => [],
453 'tca' => [],
454 'expectedFields' => 'uid'
455 ],
456 'label set' => [
457 'table' => 'test_table',
458 'prefix' => '',
459 'presetFields' => [],
460 'tca' => [
461 'ctrl' => [
462 'label' => 'label'
463 ]
464 ],
465 'expectedFields' => 'uid,label'
466 ],
467 'label_alt set' => [
468 'table' => 'test_table',
469 'prefix' => '',
470 'presetFields' => [],
471 'tca' => [
472 'ctrl' => [
473 'label_alt' => 'label,label2'
474 ]
475 ],
476 'expectedFields' => 'uid,label,label2'
477 ],
478 'versioningWS set' => [
479 'table' => 'test_table',
480 'prefix' => '',
481 'presetFields' => [],
482 'tca' => [
483 'ctrl' => [
484 'versioningWS' => true
485 ]
486 ],
487 'expectedFields' => 'uid,t3ver_id,t3ver_state,t3ver_wsid,t3ver_count'
488 ],
489 'selicon_field set' => [
490 'table' => 'test_table',
491 'prefix' => '',
492 'presetFields' => [],
493 'tca' => [
494 'ctrl' => [
495 'selicon_field' => 'field'
496 ]
497 ],
498 'expectedFields' => 'uid,field'
499 ],
500 'typeicon_column set' => [
501 'table' => 'test_table',
502 'prefix' => '',
503 'presetFields' => [],
504 'tca' => [
505 'ctrl' => [
506 'typeicon_column' => 'field'
507 ]
508 ],
509 'expectedFields' => 'uid,field'
510 ],
511 'enablecolumns set' => [
512 'table' => 'test_table',
513 'prefix' => '',
514 'presetFields' => [],
515 'tca' => [
516 'ctrl' => [
517 'enablecolumns' => [
518 'disabled' => 'hidden',
519 'starttime' => 'start',
520 'endtime' => 'stop',
521 'fe_group' => 'groups'
522 ]
523 ]
524 ],
525 'expectedFields' => 'uid,hidden,start,stop,groups'
526 ],
527 'label set to uid' => [
528 'table' => 'test_table',
529 'prefix' => '',
530 'presetFields' => [],
531 'tca' => [
532 'ctrl' => [
533 'label' => 'uid'
534 ]
535 ],
536 'expectedFields' => 'uid'
537 ]
538 ];
539 }
540
541 /**
542 * @test
543 * @dataProvider getCommonSelectFieldsReturnsCorrectFieldsDataProvider
544 *
545 * @param string $table
546 * @param string $prefix
547 * @param array $presetFields
548 * @param array $tca
549 * @param string $expectedFields
550 */
551 public function getCommonSelectFieldsReturnsCorrectFields($table, $prefix = '', array $presetFields, array $tca, $expectedFields = '')
552 {
553 $GLOBALS['TCA'][$table] = $tca;
554 $selectFields = BackendUtility::getCommonSelectFields($table, $prefix, $presetFields);
555 $this->assertEquals($selectFields, $expectedFields);
556 }
557
558 /**
559 * Tests concerning getLabelFromItemlist
560 */
561
562 /**
563 * Data provider for getLabelFromItemlistReturnsCorrectFields
564 *
565 * @return array The test data with $table, $col, $key, $expectedLabel
566 */
567 public function getLabelFromItemlistReturnsCorrectFieldsDataProvider()
568 {
569 return [
570 'item set' => [
571 'table' => 'tt_content',
572 'col' => 'menu_type',
573 'key' => '1',
574 'tca' => [
575 'columns' => [
576 'menu_type' => [
577 'config' => [
578 'items' => [
579 ['Item 1', '0'],
580 ['Item 2', '1'],
581 ['Item 3', '3']
582 ]
583 ]
584 ]
585 ]
586 ],
587 'expectedLabel' => 'Item 2'
588 ],
589 'item set twice' => [
590 'table' => 'tt_content',
591 'col' => 'menu_type',
592 'key' => '1',
593 'tca' => [
594 'columns' => [
595 'menu_type' => [
596 'config' => [
597 'items' => [
598 ['Item 1', '0'],
599 ['Item 2a', '1'],
600 ['Item 2b', '1'],
601 ['Item 3', '3']
602 ]
603 ]
604 ]
605 ]
606 ],
607 'expectedLabel' => 'Item 2a'
608 ],
609 'item not found' => [
610 'table' => 'tt_content',
611 'col' => 'menu_type',
612 'key' => '5',
613 'tca' => [
614 'columns' => [
615 'menu_type' => [
616 'config' => [
617 'items' => [
618 ['Item 1', '0'],
619 ['Item 2', '1'],
620 ['Item 3', '2']
621 ]
622 ]
623 ]
624 ]
625 ],
626 'expectedLabel' => null
627 ]
628 ];
629 }
630
631 /**
632 * @test
633 * @dataProvider getLabelFromItemlistReturnsCorrectFieldsDataProvider
634 *
635 * @param string $table
636 * @param string $col
637 * @param string $key
638 * @param array $tca
639 * @param string $expectedLabel
640 */
641 public function getLabelFromItemlistReturnsCorrectFields($table, $col = '', $key = '', array $tca, $expectedLabel = '')
642 {
643 $GLOBALS['TCA'][$table] = $tca;
644 $label = BackendUtility::getLabelFromItemlist($table, $col, $key);
645 $this->assertEquals($label, $expectedLabel);
646 }
647
648 /**
649 * Tests concerning getLabelFromItemListMerged
650 */
651
652 /**
653 * Data provider for getLabelFromItemListMerged
654 *
655 * @return array The test data with $pageId, $table, $column, $key, $expectedLabel
656 */
657 public function getLabelFromItemListMergedReturnsCorrectFieldsDataProvider()
658 {
659 return [
660 'no field found' => [
661 'pageId' => '123',
662 'table' => 'tt_content',
663 'col' => 'menu_type',
664 'key' => '10',
665 'tca' => [
666 'columns' => [
667 'menu_type' => [
668 'config' => [
669 'items' => [
670 ['Item 1', '0'],
671 ['Item 2', '1'],
672 ['Item 3', '3']
673 ]
674 ]
675 ]
676 ]
677 ],
678 'expectedLabel' => ''
679 ],
680 'no tsconfig set' => [
681 'pageId' => '123',
682 'table' => 'tt_content',
683 'col' => 'menu_type',
684 'key' => '1',
685 'tca' => [
686 'columns' => [
687 'menu_type' => [
688 'config' => [
689 'items' => [
690 ['Item 1', '0'],
691 ['Item 2', '1'],
692 ['Item 3', '3']
693 ]
694 ]
695 ]
696 ]
697 ],
698 'expectedLabel' => 'Item 2'
699 ]
700 ];
701 }
702
703 /**
704 * @test
705 * @dataProvider getLabelFromItemListMergedReturnsCorrectFieldsDataProvider
706 *
707 * @param int $pageId
708 * @param string $table
709 * @param string $column
710 * @param string $key
711 * @param array $tca
712 * @param string $expectedLabel
713 */
714 public function getLabelFromItemListMergedReturnsCorrectFields($pageId, $table, $column = '', $key = '', array $tca, $expectedLabel = '')
715 {
716 $GLOBALS['TCA'][$table] = $tca;
717
718 $this->assertEquals($expectedLabel, LabelFromItemListMergedReturnsCorrectFieldsFixture::getLabelFromItemListMerged($pageId, $table, $column, $key));
719 }
720
721 /**
722 * Tests concerning getFuncCheck
723 */
724
725 /**
726 * @test
727 */
728 public function getFuncCheckReturnsInputTagWithValueAttribute()
729 {
730 $this->assertStringMatchesFormat('<input %Svalue="1"%S/>', BackendUtility::getFuncCheck('params', 'test', true));
731 }
732
733 /*
734 * Tests concerning getLabelsFromItemsList
735 */
736
737 /**
738 * @return array
739 */
740 public function getLabelsFromItemsListDataProvider()
741 {
742 return [
743 'return value if found' => [
744 'foobar', // table
745 'someColumn', // col
746 'foo, bar', // keyList
747 [ // TCA
748 'columns' => [
749 'someColumn' => [
750 'config' => [
751 'items' => [
752 '0' => ['aFooLabel', 'foo'],
753 '1' => ['aBarLabel', 'bar']
754 ]
755 ]
756 ]
757 ]
758 ],
759 [], // page TSconfig
760 'aFooLabel, aBarLabel' // expected
761 ],
762 'page TSconfig overrules TCA' => [
763 'foobar', // table
764 'someColumn', // col
765 'foo,bar, add', // keyList
766 [ // TCA
767 'columns' => [
768 'someColumn' => [
769 'config' => [
770 'items' => [
771 '0' => ['aFooLabel', 'foo'],
772 '1' => ['aBarLabel', 'bar']
773 ]
774 ]
775 ]
776 ]
777 ],
778 [ // page TSconfig
779 'addItems.' => ['add' => 'aNewLabel'],
780 'altLabels.' => ['bar' => 'aBarDiffLabel'],
781 ],
782 'aFooLabel, aBarDiffLabel, aNewLabel' // expected
783 ]
784 ];
785 }
786
787 /**
788 * @test
789 * @dataProvider getLabelsFromItemsListDataProvider
790 *
791 * @param string $table
792 * @param string $col
793 * @param string $keyList
794 * @param array $tca
795 * @param array $pageTsConfig
796 * @param string $expectedLabel
797 */
798 public function getLabelsFromItemsListReturnsCorrectValue($table, $col, $keyList, $tca, array $pageTsConfig, $expectedLabel)
799 {
800 // Stub LanguageService and let sL() return the same value that came in again
801 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
802 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
803
804 $GLOBALS['TCA'][$table] = $tca;
805 $label = BackendUtility::getLabelsFromItemsList($table, $col, $keyList, $pageTsConfig);
806 $this->assertEquals($expectedLabel, $label);
807 }
808
809 /**
810 * @test
811 */
812 public function getProcessedValueReturnsLabelsForExistingValuesSolely()
813 {
814 $table = 'foobar';
815 $col = 'someColumn';
816 $tca = [
817 'columns' => [
818 'someColumn' => [
819 'config' => [
820 'type' => 'select',
821 'items' => [
822 '0' => ['aFooLabel', 'foo'],
823 '1' => ['aBarLabel', 'bar']
824 ]
825 ]
826 ]
827 ]
828 ];
829 // Stub LanguageService and let sL() return the same value that came in again
830 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
831 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
832
833 $GLOBALS['TCA'][$table] = $tca;
834 $label = BackendUtility::getProcessedValue($table, $col, 'foo,invalidKey,bar');
835 $this->assertEquals('aFooLabel, aBarLabel', $label);
836 }
837
838 /**
839 * @test
840 */
841 public function getProcessedValueReturnsPlainValueIfItemIsNotFound()
842 {
843 $table = 'foobar';
844 $col = 'someColumn';
845 $tca = [
846 'columns' => [
847 'someColumn' => [
848 'config' => [
849 'type' => 'select',
850 'items' => [
851 '0' => ['aFooLabel', 'foo']
852 ]
853 ]
854 ]
855 ]
856 ];
857 // Stub LanguageService and let sL() return the same value that came in again
858 $GLOBALS['LANG'] = $this->createMock(LanguageService::class);
859 $GLOBALS['LANG']->expects($this->any())->method('sL')->will($this->returnArgument(0));
860
861 $GLOBALS['TCA'][$table] = $tca;
862 $label = BackendUtility::getProcessedValue($table, $col, 'invalidKey');
863 $this->assertEquals('invalidKey', $label);
864 }
865
866 /**
867 * Tests concerning viewOnClick
868 */
869
870 /**
871 * @test
872 */
873 public function viewOnClickReturnsOnClickCodeWithAlternativeUrl()
874 {
875 // Make sure the hook inside viewOnClick is not fired. This may be removed if unit tests
876 // bootstrap does not initialize TYPO3_CONF_VARS anymore.
877 unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['viewOnClickClass']);
878
879 $alternativeUrl = 'https://typo3.org/about/typo3-the-cms/the-history-of-typo3/#section';
880 $onclickCode = 'var previewWin = window.open(' . GeneralUtility::quoteJSvalue($alternativeUrl) . ',\'newTYPO3frontendWindow\');' . LF
881 . 'if (previewWin.location.href === ' . GeneralUtility::quoteJSvalue($alternativeUrl) . ') { previewWin.location.reload(); };';
882 $this->assertStringMatchesFormat(
883 $onclickCode,
884 BackendUtility::viewOnClick(null, null, null, null, $alternativeUrl, null, false)
885 );
886 }
887
888 /**
889 * @test
890 */
891 public function getModTSconfigIgnoresValuesFromUserTsConfigIfNoSet()
892 {
893 $completeConfiguration = [
894 'value' => 'bar',
895 'properties' => [
896 'permissions.' => [
897 'file.' => [
898 'default.' => ['readAction' => '1'],
899 '1.' => ['writeAction' => '1'],
900 '0.' => ['readAction' => '0'],
901 ],
902 ]
903 ]
904 ];
905
906 $GLOBALS['BE_USER'] = $this->createMock(BackendUserAuthentication::class);
907 $GLOBALS['BE_USER']->expects($this->at(0))->method('getTSConfig')->will($this->returnValue($completeConfiguration));
908 $GLOBALS['BE_USER']->expects($this->at(1))->method('getTSConfig')->will($this->returnValue(['value' => null, 'properties' => null]));
909
910 $this->assertSame($completeConfiguration, BackendUtilityFixture::getModTSconfig(42, 'notrelevant'));
911 }
912
913 /**
914 * @test
915 */
916 public function dateTimeAgeReturnsCorrectValues()
917 {
918 /** @var ObjectProphecy|LanguageService $languageServiceProphecy */
919 $languageServiceProphecy = $this->prophesize(LanguageService::class);
920 $languageServiceProphecy->sL(Argument::cetera())->willReturn(' min| hrs| days| yrs| min| hour| day| year');
921 $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
922 $GLOBALS['EXEC_TIME'] = mktime(0, 0, 0, 3, 23, 2016);
923
924 $this->assertSame('24-03-16 00:00 (-1 day)', BackendUtility::dateTimeAge($GLOBALS['EXEC_TIME'] + 86400));
925 $this->assertSame('24-03-16 (-1 day)', BackendUtility::dateTimeAge($GLOBALS['EXEC_TIME'] + 86400, 1, 'date'));
926 }
927
928 ///////////////////////////////////////
929 // Tests concerning getTCAtypes
930 ///////////////////////////////////////
931
932 /**
933 * @test
934 */
935 public function getTCAtypesReturnsCorrectValuesDataProvider()
936 {
937 return [
938 'no input' => [
939 '', // table
940 [], // rec
941 '', // useFieldNameAsKey
942 null // expected
943 ],
944 'non-existant table' => [
945 'fooBar', // table
946 [], // rec
947 '', // useFieldNameAsKey
948 null // expected
949 ],
950 'Doktype=1: one simple field' => [
951 'pages',
952 [
953 'uid' => '1',
954 'doktype' => '1'
955 ],
956 false,
957 [
958 0 => [
959 'field' => 'title',
960 'title' => null,
961 'palette' => null,
962 'spec' => [],
963 'origString' => 'title'
964 ]
965 ]
966 ],
967 'non-existant type given: Return for type 1' => [
968 'pages', // table
969 [
970 'uid' => '1',
971 'doktype' => '999'
972 ], // rec
973 '', // useFieldNameAsKey
974 [
975 0 => [
976 'field' => 'title',
977 'title' => null,
978 'palette' => null,
979 'spec' => [],
980 'origString' => 'title'
981 ]
982 ] // expected
983 ],
984 'Doktype=1: one simple field, useFieldNameAsKey=true' => [
985 'pages',
986 [
987 'uid' => '1',
988 'doktype' => '1'
989 ],
990 true,
991 [
992 'title' => [
993 'field' => 'title',
994 'title' => null,
995 'palette' => null,
996 'spec' => [],
997 'origString' => 'title'
998 ]
999 ]
1000 ],
1001 'Empty showitem Field' => [
1002 'test',
1003 [
1004 'uid' => '1',
1005 'fooBar' => '99'
1006 ],
1007 true,
1008 [
1009 '' => [
1010 'field' => '',
1011 'title' => null,
1012 'palette' => null,
1013 'spec' => [],
1014 'origString' => ''
1015 ]
1016 ]
1017 ],
1018 'RTE field within a palette' => [
1019 'pages',
1020 [
1021 'uid' => '1',
1022 'doktype' => '10',
1023 ],
1024 false,
1025 [
1026 0 => [
1027 'field' => '--div--',
1028 'title' => 'General',
1029 'palette' => null,
1030 'spec' => [],
1031 'origString' => '--div--;General'
1032 ],
1033 1 => [
1034 'field' => '--palette--',
1035 'title' => 'Palette',
1036 'palette' => '123',
1037 'spec' => [],
1038 'origString' => '--palette--;Palette;123'
1039 ],
1040 2 => [
1041 'field' => 'title',
1042 'title' => null,
1043 'palette' => null,
1044 'spec' => [],
1045 'origString' => 'title'
1046 ],
1047 3 => [
1048 'field' => 'text',
1049 'title' => null,
1050 'palette' => null,
1051 'spec' => [],
1052 'origString' => 'text'
1053 ],
1054 4 => [
1055 'field' => 'select',
1056 'title' => 'Select field',
1057 'palette' => null,
1058 'spec' => [],
1059 'origString' => 'select;Select field'
1060 ]
1061 ]
1062 ],
1063 'RTE field with more settings within a palette' => [
1064 'pages',
1065 [
1066 'uid' => 1,
1067 'doktype' => 2
1068 ],
1069 false,
1070 [
1071 0 => [
1072 'field' => '--div--',
1073 'title' => 'General',
1074 'palette' => null,
1075 'spec' => [],
1076 'origString' => '--div--;General'
1077 ],
1078 1 => [
1079 'field' => '--palette--',
1080 'title' => 'RTE palette',
1081 'palette' => '456',
1082 'spec' => [],
1083 'origString' => '--palette--;RTE palette;456'
1084 ],
1085 2 => [
1086 'field' => 'text2',
1087 'title' => null,
1088 'palette' => null,
1089 'spec' => [],
1090 'origString' => 'text2'
1091 ]
1092 ]
1093 ]
1094 ];
1095 }
1096
1097 /**
1098 * @test
1099 * @dataProvider getTCAtypesReturnsCorrectValuesDataProvider
1100 *
1101 * @param string $table
1102 * @param array $rec
1103 * @param bool $useFieldNameAsKey
1104 * @param array $expected
1105 */
1106 public function getTCAtypesReturnsCorrectValues($table, $rec, $useFieldNameAsKey, $expected)
1107 {
1108 $GLOBALS['TCA'] = [
1109 'pages' => [
1110 'ctrl' => [
1111 'type' => 'doktype'
1112 ],
1113 'columns' => [
1114 'title' => [
1115 'label' => 'Title test',
1116 'config' => [
1117 'type' => 'input'
1118 ]
1119 ],
1120 'text' => [
1121 'label' => 'RTE Text',
1122 'config' => [
1123 'type' => 'text',
1124 'cols' => 40,
1125 'rows' => 5
1126 ],
1127 ],
1128 'text2' => [
1129 'label' => 'RTE Text 2',
1130 'config' => [
1131 'type' => 'text',
1132 'cols' => 40,
1133 'rows' => 5
1134 ],
1135 ],
1136 'select' => [
1137 'label' => 'Select test',
1138 'config' => [
1139 'items' => [
1140 ['Please select', 0],
1141 ['Option 1', 1],
1142 ['Option 2', 2]
1143 ]
1144 ],
1145 'maxitems' => 1,
1146 'renderType' => 'selectSingle'
1147 ]
1148 ],
1149 'types' => [
1150 '1' => [
1151 'showitem' => 'title'
1152 ],
1153 '2' => [
1154 'showitem' => '--div--;General,--palette--;RTE palette;456'
1155 ],
1156 '10' => [
1157 'showitem' => '--div--;General,--palette--;Palette;123,title'
1158 ],
1159 '14' => [
1160 'showitem' => '--div--;General,title'
1161 ]
1162 ],
1163 'palettes' => [
1164 '123' => [
1165 'showitem' => 'text,select;Select field'
1166 ],
1167 '456' => [
1168 'showitem' => 'text2'
1169 ]
1170 ]
1171 ],
1172 'test' => [
1173 'ctrl' => [
1174 'type' => 'fooBar'
1175 ],
1176 'types' => [
1177 '99' => [ 'showitem' => '']
1178 ]
1179 ]
1180 ];
1181
1182 $return = BackendUtility::getTCAtypes($table, $rec, $useFieldNameAsKey);
1183 $this->assertSame($expected, $return);
1184 }
1185
1186 /**
1187 * @test
1188 */
1189 public function purgeComputedPropertyNamesRemovesPropertiesStartingWithUnderscore()
1190 {
1191 $propertyNames = [
1192 'uid',
1193 'pid',
1194 '_ORIG_PID'
1195 ];
1196 $computedPropertyNames = BackendUtility::purgeComputedPropertyNames($propertyNames);
1197 self::assertSame(['uid', 'pid'], $computedPropertyNames);
1198 }
1199
1200 /**
1201 * @test
1202 */
1203 public function purgeComputedPropertiesFromRecordRemovesPropertiesStartingWithUnderscore()
1204 {
1205 $record = [
1206 'uid' => 1,
1207 'pid' => 2,
1208 '_ORIG_PID' => 1
1209 ];
1210 $expected = [
1211 'uid' => 1,
1212 'pid' => 2
1213 ];
1214 $computedProperties = BackendUtility::purgeComputedPropertiesFromRecord($record);
1215 self::assertSame($expected, $computedProperties);
1216 }
1217 }