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