d4c7413ca74b53b9def44209361b39cd6832cfc4
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / DataHandling / DataHandlerTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\DataHandler;
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 TYPO3\Components\TestingFramework\Core\AccessibleObjectInterface;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Cache\CacheManager;
21 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
22 use TYPO3\CMS\Core\DataHandling\DataHandler;
23 use TYPO3\CMS\Core\Tests\Unit\DataHandling\Fixtures\AllowAccessHookFixture;
24 use TYPO3\CMS\Core\Tests\Unit\DataHandling\Fixtures\InvalidHookFixture;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27 /**
28 * Test case
29 */
30 class DataHandlerTest extends \TYPO3\Components\TestingFramework\Core\UnitTestCase
31 {
32 /**
33 * @var array A backup of registered singleton instances
34 */
35 protected $singletonInstances = [];
36
37 /**
38 * @var DataHandler|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface
39 */
40 protected $subject;
41
42 /**
43 * @var BackendUserAuthentication a mock logged-in back-end user
44 */
45 protected $backEndUser;
46
47 /**
48 * Set up the tests
49 */
50 protected function setUp()
51 {
52 $GLOBALS['TCA'] = [];
53 $this->singletonInstances = GeneralUtility::getSingletonInstances();
54 $this->backEndUser = $this->createMock(BackendUserAuthentication::class);
55 $this->subject = $this->getAccessibleMock(DataHandler::class, ['dummy']);
56 $this->subject->start([], '', $this->backEndUser);
57 }
58
59 /**
60 * Tear down the tests
61 */
62 protected function tearDown()
63 {
64 GeneralUtility::resetSingletonInstances($this->singletonInstances);
65 parent::tearDown();
66 }
67
68 //////////////////////////////////////
69 // Tests for the basic functionality
70 //////////////////////////////////////
71 /**
72 * @test
73 */
74 public function fixtureCanBeCreated()
75 {
76 $this->assertTrue($this->subject instanceof DataHandler);
77 }
78
79 //////////////////////////////////////////
80 // Test concerning checkModifyAccessList
81 //////////////////////////////////////////
82 /**
83 * @test
84 */
85 public function adminIsAllowedToModifyNonAdminTable()
86 {
87 $this->subject->admin = true;
88 $this->assertTrue($this->subject->checkModifyAccessList('tt_content'));
89 }
90
91 /**
92 * @test
93 */
94 public function nonAdminIsNorAllowedToModifyNonAdminTable()
95 {
96 $this->subject->admin = false;
97 $this->assertFalse($this->subject->checkModifyAccessList('tt_content'));
98 }
99
100 /**
101 * @test
102 */
103 public function nonAdminWithTableModifyAccessIsAllowedToModifyNonAdminTable()
104 {
105 $this->subject->admin = false;
106 $this->backEndUser->groupData['tables_modify'] = 'tt_content';
107 $this->assertTrue($this->subject->checkModifyAccessList('tt_content'));
108 }
109
110 /**
111 * @test
112 */
113 public function adminIsAllowedToModifyAdminTable()
114 {
115 $this->subject->admin = true;
116 $this->assertTrue($this->subject->checkModifyAccessList('be_users'));
117 }
118
119 /**
120 * @test
121 */
122 public function nonAdminIsNotAllowedToModifyAdminTable()
123 {
124 $this->subject->admin = false;
125 $this->assertFalse($this->subject->checkModifyAccessList('be_users'));
126 }
127
128 /**
129 * @test
130 */
131 public function nonAdminWithTableModifyAccessIsNotAllowedToModifyAdminTable()
132 {
133 $tableName = $this->getUniqueId('aTable');
134 $GLOBALS['TCA'] = [
135 $tableName => [
136 'ctrl' => [
137 'adminOnly' => true,
138 ],
139 ],
140 ];
141 $this->subject->admin = false;
142 $this->backEndUser->groupData['tables_modify'] = $tableName;
143 $this->assertFalse($this->subject->checkModifyAccessList($tableName));
144 }
145
146 /**
147 * @test
148 */
149 public function evalCheckValueDouble2()
150 {
151 $testData = [
152 '-0,5' => '-0.50',
153 '1000' => '1000.00',
154 '1000,10' => '1000.10',
155 '1000,0' => '1000.00',
156 '600.000.000,00' => '600000000.00',
157 '60aaa00' => '6000.00'
158 ];
159 foreach ($testData as $value => $expectedReturnValue) {
160 $returnValue = $this->subject->checkValue_input_Eval($value, ['double2'], '');
161 $this->assertSame($returnValue['value'], $expectedReturnValue);
162 }
163 }
164
165 public function dataProviderDatetime()
166 {
167 // Three elements: input, timezone of input, expected output (UTC)
168 return [
169 // German standard time (without DST) is one hour ahead of UTC
170 'date in 2016 in German timezone' => [
171 1457103519, 'Europe/Berlin', 1457103519 - 3600
172 ],
173 'date in 1969 in German timezone' => [
174 -7200, 'Europe/Berlin', -10800
175 ],
176 // Los Angeles is 8 hours behind UTC
177 'date in 2016 in Los Angeles timezone' => [
178 1457103519, 'America/Los_Angeles', 1457103519 + 28800
179 ],
180 'date in UTC' => [
181 1457103519, 'UTC', 1457103519
182 ]
183 ];
184 }
185
186 /**
187 * @test
188 * @dataProvider dataProviderDatetime
189 */
190 public function evalCheckValueDatetime($input, $serverTimezone, $expectedOutput)
191 {
192 $oldTimezone = date_default_timezone_get();
193 date_default_timezone_set($serverTimezone);
194
195 $output = $this->subject->checkValue_input_Eval($input, ['datetime'], '');
196
197 // set before the assertion is performed, so it is restored even for failing tests
198 date_default_timezone_set($oldTimezone);
199
200 $this->assertEquals($expectedOutput, $output['value']);
201 }
202
203 /**
204 * Data provider for inputValueCheckRecognizesStringValuesAsIntegerValuesCorrectly
205 *
206 * @return array
207 */
208 public function inputValuesStringsDataProvider()
209 {
210 return [
211 '"0" returns zero as integer' => [
212 '0',
213 0
214 ],
215 '"-1999999" is interpreted correctly as -1999999 and is lot lower than -200000' => [
216 '-1999999',
217 -1999999
218 ],
219 '"3000000" is interpreted correctly as 3000000 but is higher then 200000 and set to 200000' => [
220 '3000000',
221 2000000
222 ],
223 ];
224 }
225
226 /**
227 * @test
228 * @dataProvider inputValuesStringsDataProvider
229 * @param string $value
230 * @param int $expectedReturnValue
231 */
232 public function inputValueCheckRecognizesStringValuesAsIntegerValuesCorrectly($value, $expectedReturnValue)
233 {
234 $tcaFieldConf = [
235 'input' => [],
236 'eval' => 'int',
237 'range' => [
238 'lower' => '-2000000',
239 'upper' => '2000000'
240 ]
241 ];
242 $returnValue = $this->subject->_call('checkValueForInput', $value, $tcaFieldConf, '', 0, 0, '');
243 $this->assertSame($returnValue['value'], $expectedReturnValue);
244 }
245
246 /**
247 * @return array
248 */
249 public function inputValueCheckDoesNotCallGetDateTimeFormatsForNonDatetimeFieldsDataProvider()
250 {
251 return [
252 'tca without dbType' => [
253 [
254 'input' => []
255 ]
256 ],
257 'tca with dbType != date/datetime' => [
258 [
259 'input' => [],
260 'dbType' => 'foo'
261 ]
262 ]
263 ];
264 }
265
266 /**
267 * @test
268 * @param array $tcaFieldConf
269 * @dataProvider inputValueCheckDoesNotCallGetDateTimeFormatsForNonDatetimeFieldsDataProvider
270 */
271 public function inputValueCheckDoesNotCallGetDateTimeFormatsForNonDatetimeFields($tcaFieldConf)
272 {
273 $this->subject->_call('checkValueForInput', '', $tcaFieldConf, '', 0, 0, '');
274 }
275
276 ///////////////////////////////////////////
277 // Tests concerning checkModifyAccessList
278 ///////////////////////////////////////////
279 //
280 /**
281 * Tests whether a wrong interface on the 'checkModifyAccessList' hook throws an exception.
282 * @test
283 */
284 public function doesCheckModifyAccessListThrowExceptionOnWrongHookInterface()
285 {
286 $this->expectException(\UnexpectedValueException::class);
287 $this->expectExceptionCode(1251892472);
288
289 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'][] = InvalidHookFixture::class;
290 $this->subject->checkModifyAccessList('tt_content');
291 }
292
293 /**
294 * Tests whether the 'checkModifyAccessList' hook is called correctly.
295 *
296 * @test
297 */
298 public function doesCheckModifyAccessListHookGetsCalled()
299 {
300 $hookClass = $this->getUniqueId('tx_coretest');
301 $hookMock = $this->getMockBuilder(\TYPO3\CMS\Core\DataHandling\DataHandlerCheckModifyAccessListHookInterface::class)
302 ->setMethods(['checkModifyAccessList'])
303 ->setMockClassName($hookClass)
304 ->getMock();
305 $hookMock->expects($this->once())->method('checkModifyAccessList');
306 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'][] = $hookClass;
307 GeneralUtility::addInstance($hookClass, $hookMock);
308 $this->subject->checkModifyAccessList('tt_content');
309 }
310
311 /**
312 * Tests whether the 'checkModifyAccessList' hook modifies the $accessAllowed variable.
313 *
314 * @test
315 */
316 public function doesCheckModifyAccessListHookModifyAccessAllowed()
317 {
318 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'][] = AllowAccessHookFixture::class;
319 $this->assertTrue($this->subject->checkModifyAccessList('tt_content'));
320 }
321
322 /////////////////////////////////////
323 // Tests concerning process_datamap
324 /////////////////////////////////////
325 /**
326 * @test
327 */
328 public function processDatamapForFrozenNonZeroWorkspaceReturnsFalse()
329 {
330 /** @var DataHandler $subject */
331 $subject = $this->getMockBuilder(DataHandler::class)
332 ->setMethods(['newlog'])
333 ->getMock();
334 $this->backEndUser->workspace = 1;
335 $this->backEndUser->workspaceRec = ['freeze' => true];
336 $subject->BE_USER = $this->backEndUser;
337 $this->assertFalse($subject->process_datamap());
338 }
339
340 /**
341 * @test
342 */
343 public function processDatamapWhenEditingRecordInWorkspaceCreatesNewRecordInWorkspace()
344 {
345 $GLOBALS['TCA'] = [
346 'pages' => [
347 'columns' => [],
348 ],
349 ];
350
351 /** @var $subject DataHandler|\PHPUnit_Framework_MockObject_MockObject */
352 $subject = $this->getMockBuilder(DataHandler::class)
353 ->setMethods([
354 'newlog',
355 'checkModifyAccessList',
356 'tableReadOnly',
357 'checkRecordUpdateAccess',
358 'recordInfo',
359 'getCacheManager',
360 'registerElementsToBeDeleted',
361 'unsetElementsToBeDeleted',
362 'resetElementsToBeDeleted'
363 ])
364 ->disableOriginalConstructor()
365 ->getMock();
366
367 $subject->bypassWorkspaceRestrictions = false;
368 $subject->datamap = [
369 'pages' => [
370 '1' => [
371 'header' => 'demo'
372 ]
373 ]
374 ];
375
376 $cacheManagerMock = $this->getMockBuilder(CacheManager::class)
377 ->setMethods(['flushCachesInGroupByTags'])
378 ->getMock();
379 $cacheManagerMock->expects($this->once())->method('flushCachesInGroupByTags')->with('pages', []);
380
381 $subject->expects($this->once())->method('getCacheManager')->willReturn($cacheManagerMock);
382 $subject->expects($this->once())->method('recordInfo')->will($this->returnValue(null));
383 $subject->expects($this->once())->method('checkModifyAccessList')->with('pages')->will($this->returnValue(true));
384 $subject->expects($this->once())->method('tableReadOnly')->with('pages')->will($this->returnValue(false));
385 $subject->expects($this->once())->method('checkRecordUpdateAccess')->will($this->returnValue(true));
386 $subject->expects($this->once())->method('unsetElementsToBeDeleted')->willReturnArgument(0);
387
388 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $backEndUser */
389 $backEndUser = $this->createMock(BackendUserAuthentication::class);
390 $backEndUser->workspace = 1;
391 $backEndUser->workspaceRec = ['freeze' => false];
392 $backEndUser->expects($this->once())->method('workspaceAllowAutoCreation')->will($this->returnValue(true));
393 $backEndUser->expects($this->once())->method('workspaceCannotEditRecord')->will($this->returnValue(true));
394 $backEndUser->expects($this->once())->method('recordEditAccessInternals')->with('pages', 1)->will($this->returnValue(true));
395 $subject->BE_USER = $backEndUser;
396 $createdDataHandler = $this->createMock(DataHandler::class);
397 $createdDataHandler->expects($this->once())->method('start')->with([], [
398 'pages' => [
399 1 => [
400 'version' => [
401 'action' => 'new',
402 'label' => 'Auto-created for WS #1'
403 ]
404 ]
405 ]
406 ]);
407 $createdDataHandler->expects($this->never())->method('process_datamap');
408 $createdDataHandler->expects($this->once())->method('process_cmdmap');
409 GeneralUtility::addInstance(DataHandler::class, $createdDataHandler);
410 $subject->process_datamap();
411 }
412
413 /**
414 * @test
415 */
416 public function doesCheckFlexFormValueHookGetsCalled()
417 {
418 $hookClass = $this->getUniqueId('tx_coretest');
419 $hookMock = $this->getMockBuilder($hookClass)
420 ->setMethods(['checkFlexFormValue_beforeMerge'])
421 ->getMock();
422 $hookMock->expects($this->once())->method('checkFlexFormValue_beforeMerge');
423 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkFlexFormValue'][] = $hookClass;
424 GeneralUtility::addInstance($hookClass, $hookMock);
425 $flexFormToolsProphecy = $this->prophesize(FlexFormTools::class);
426 $flexFormToolsProphecy->getDataStructureIdentifier(Argument::cetera())->willReturn('anIdentifier');
427 $flexFormToolsProphecy->parseDataStructureByIdentifier('anIdentifier')->willReturn([]);
428 GeneralUtility::addInstance(FlexFormTools::class, $flexFormToolsProphecy->reveal());
429 $this->subject->_call('checkValueForFlex', [], [], [], '', 0, '', '', 0, 0, 0, [], '');
430 }
431
432 /////////////////////////////////////
433 // Tests concerning log
434 /////////////////////////////////////
435 /**
436 * @test
437 */
438 public function logCallsWriteLogOfBackendUserIfLoggingIsEnabled()
439 {
440 $backendUser = $this->createMock(BackendUserAuthentication::class);
441 $backendUser->expects($this->once())->method('writelog');
442 $this->subject->enableLogging = true;
443 $this->subject->BE_USER = $backendUser;
444 $this->subject->log('', 23, 0, 42, 0, 'details');
445 }
446
447 /**
448 * @test
449 */
450 public function logDoesNotCallWriteLogOfBackendUserIfLoggingIsDisabled()
451 {
452 $backendUser = $this->createMock(BackendUserAuthentication::class);
453 $backendUser->expects($this->never())->method('writelog');
454 $this->subject->enableLogging = false;
455 $this->subject->BE_USER = $backendUser;
456 $this->subject->log('', 23, 0, 42, 0, 'details');
457 }
458
459 /**
460 * @test
461 */
462 public function logAddsEntryToLocalErrorLogArray()
463 {
464 $backendUser = $this->createMock(BackendUserAuthentication::class);
465 $this->subject->BE_USER = $backendUser;
466 $this->subject->enableLogging = true;
467 $this->subject->errorLog = [];
468 $logDetailsUnique = $this->getUniqueId('details');
469 $this->subject->log('', 23, 0, 42, 1, $logDetailsUnique);
470 $this->assertStringEndsWith($logDetailsUnique, $this->subject->errorLog[0]);
471 }
472
473 /**
474 * @test
475 */
476 public function logFormatsDetailMessageWithAdditionalDataInLocalErrorArray()
477 {
478 $backendUser = $this->createMock(BackendUserAuthentication::class);
479 $this->subject->BE_USER = $backendUser;
480 $this->subject->enableLogging = true;
481 $this->subject->errorLog = [];
482 $logDetails = $this->getUniqueId('details');
483 $this->subject->log('', 23, 0, 42, 1, '%1$s' . $logDetails . '%2$s', -1, ['foo', 'bar']);
484 $expected = 'foo' . $logDetails . 'bar';
485 $this->assertStringEndsWith($expected, $this->subject->errorLog[0]);
486 }
487
488 /**
489 * @param bool $expected
490 * @param string $submittedValue
491 * @param string $storedValue
492 * @param string $storedType
493 * @param bool $allowNull
494 *
495 * @dataProvider equalSubmittedAndStoredValuesAreDeterminedDataProvider
496 * @test
497 */
498 public function equalSubmittedAndStoredValuesAreDetermined($expected, $submittedValue, $storedValue, $storedType, $allowNull)
499 {
500 $result = $this->callInaccessibleMethod(
501 $this->subject,
502 'isSubmittedValueEqualToStoredValue',
503 $submittedValue, $storedValue, $storedType, $allowNull
504 );
505 $this->assertEquals($expected, $result);
506 }
507
508 /**
509 * @return array
510 */
511 public function equalSubmittedAndStoredValuesAreDeterminedDataProvider()
512 {
513 return [
514 // String
515 'string value "" vs. ""' => [
516 true,
517 '', '', 'string', false
518 ],
519 'string value 0 vs. "0"' => [
520 true,
521 0, '0', 'string', false
522 ],
523 'string value 1 vs. "1"' => [
524 true,
525 1, '1', 'string', false
526 ],
527 'string value "0" vs. ""' => [
528 false,
529 '0', '', 'string', false
530 ],
531 'string value 0 vs. ""' => [
532 false,
533 0, '', 'string', false
534 ],
535 'string value null vs. ""' => [
536 true,
537 null, '', 'string', false
538 ],
539 // Integer
540 'integer value 0 vs. 0' => [
541 true,
542 0, 0, 'int', false
543 ],
544 'integer value "0" vs. "0"' => [
545 true,
546 '0', '0', 'int', false
547 ],
548 'integer value 0 vs. "0"' => [
549 true,
550 0, '0', 'int', false
551 ],
552 'integer value "" vs. "0"' => [
553 true,
554 '', '0', 'int', false
555 ],
556 'integer value "" vs. 0' => [
557 true,
558 '', 0, 'int', false
559 ],
560 'integer value "0" vs. 0' => [
561 true,
562 '0', 0, 'int', false
563 ],
564 'integer value 1 vs. 1' => [
565 true,
566 1, 1, 'int', false
567 ],
568 'integer value 1 vs. "1"' => [
569 true,
570 1, '1', 'int', false
571 ],
572 'integer value "1" vs. "1"' => [
573 true,
574 '1', '1', 'int', false
575 ],
576 'integer value "1" vs. 1' => [
577 true,
578 '1', 1, 'int', false
579 ],
580 'integer value "0" vs. "1"' => [
581 false,
582 '0', '1', 'int', false
583 ],
584 // String with allowed NULL values
585 'string with allowed null value "" vs. ""' => [
586 true,
587 '', '', 'string', true
588 ],
589 'string with allowed null value 0 vs. "0"' => [
590 true,
591 0, '0', 'string', true
592 ],
593 'string with allowed null value 1 vs. "1"' => [
594 true,
595 1, '1', 'string', true
596 ],
597 'string with allowed null value "0" vs. ""' => [
598 false,
599 '0', '', 'string', true
600 ],
601 'string with allowed null value 0 vs. ""' => [
602 false,
603 0, '', 'string', true
604 ],
605 'string with allowed null value null vs. ""' => [
606 false,
607 null, '', 'string', true
608 ],
609 'string with allowed null value "" vs. null' => [
610 false,
611 '', null, 'string', true
612 ],
613 'string with allowed null value null vs. null' => [
614 true,
615 null, null, 'string', true
616 ],
617 // Integer with allowed NULL values
618 'integer with allowed null value 0 vs. 0' => [
619 true,
620 0, 0, 'int', true
621 ],
622 'integer with allowed null value "0" vs. "0"' => [
623 true,
624 '0', '0', 'int', true
625 ],
626 'integer with allowed null value 0 vs. "0"' => [
627 true,
628 0, '0', 'int', true
629 ],
630 'integer with allowed null value "" vs. "0"' => [
631 true,
632 '', '0', 'int', true
633 ],
634 'integer with allowed null value "" vs. 0' => [
635 true,
636 '', 0, 'int', true
637 ],
638 'integer with allowed null value "0" vs. 0' => [
639 true,
640 '0', 0, 'int', true
641 ],
642 'integer with allowed null value 1 vs. 1' => [
643 true,
644 1, 1, 'int', true
645 ],
646 'integer with allowed null value "1" vs. "1"' => [
647 true,
648 '1', '1', 'int', true
649 ],
650 'integer with allowed null value "1" vs. 1' => [
651 true,
652 '1', 1, 'int', true
653 ],
654 'integer with allowed null value 1 vs. "1"' => [
655 true,
656 1, '1', 'int', true
657 ],
658 'integer with allowed null value "0" vs. "1"' => [
659 false,
660 '0', '1', 'int', true
661 ],
662 'integer with allowed null value null vs. ""' => [
663 false,
664 null, '', 'int', true
665 ],
666 'integer with allowed null value "" vs. null' => [
667 false,
668 '', null, 'int', true
669 ],
670 'integer with allowed null value null vs. null' => [
671 true,
672 null, null, 'int', true
673 ],
674 'integer with allowed null value null vs. "0"' => [
675 false,
676 null, '0', 'int', true
677 ],
678 'integer with allowed null value null vs. 0' => [
679 false,
680 null, 0, 'int', true
681 ],
682 'integer with allowed null value "0" vs. null' => [
683 false,
684 '0', null, 'int', true
685 ],
686 ];
687 }
688
689 /**
690 * @param bool $expected
691 * @param array $eval
692 * @dataProvider getPlaceholderTitleForTableLabelReturnsLabelThatsMatchesLabelFieldConditionsDataProvider
693 * @test
694 */
695 public function getPlaceholderTitleForTableLabelReturnsLabelThatsMatchesLabelFieldConditions($expected, $eval)
696 {
697 $table = 'phpunit_dummy';
698
699 /** @var DataHandler|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface $subject */
700 $subject = $this->getAccessibleMock(
701 DataHandler::class,
702 ['dummy']
703 );
704
705 $backendUser = $this->createMock(BackendUserAuthentication::class);
706 $subject->BE_USER = $backendUser;
707 $subject->BE_USER->workspace = 1;
708
709 $GLOBALS['TCA'][$table] = [];
710 $GLOBALS['TCA'][$table]['ctrl'] = ['label' => 'dummy'];
711 $GLOBALS['TCA'][$table]['columns'] = [
712 'dummy' => [
713 'config' => [
714 'eval' => $eval
715 ]
716 ]
717 ];
718
719 $this->assertEquals($expected, $subject->_call('getPlaceholderTitleForTableLabel', $table));
720 }
721
722 /**
723 * @return array
724 */
725 public function getPlaceholderTitleForTableLabelReturnsLabelThatsMatchesLabelFieldConditionsDataProvider()
726 {
727 return [
728 [
729 0.10,
730 'double2'
731 ],
732 [
733 0,
734 'int'
735 ],
736 [
737 '0',
738 'datetime'
739 ],
740 [
741 '[PLACEHOLDER, WS#1]',
742 ''
743 ]
744 ];
745 }
746
747 /**
748 * @test
749 */
750 public function deletePagesOnRootLevelIsDenied()
751 {
752 /** @var DataHandler|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface $dataHandlerMock */
753 $dataHandlerMock = $this->getMockBuilder(DataHandler::class)
754 ->setMethods(['canDeletePage', 'newlog2'])
755 ->getMock();
756 $dataHandlerMock
757 ->expects($this->never())
758 ->method('canDeletePage');
759 $dataHandlerMock
760 ->expects($this->once())
761 ->method('newlog2')
762 ->with('Deleting all pages starting from the root-page is disabled.', 'pages', 0, 0, 2);
763
764 $dataHandlerMock->deletePages(0);
765 }
766
767 /**
768 * @test
769 */
770 public function deleteRecord_procBasedOnFieldTypeRespectsEnableCascadingDelete()
771 {
772 $table = $this->getUniqueId('foo_');
773 $conf = [
774 'type' => 'inline',
775 'foreign_table' => $this->getUniqueId('foreign_foo_'),
776 'behaviour' => [
777 'enableCascadingDelete' => 0,
778 ]
779 ];
780
781 /** @var \TYPO3\CMS\Core\Database\RelationHandler $mockRelationHandler */
782 $mockRelationHandler = $this->createMock(\TYPO3\CMS\Core\Database\RelationHandler::class);
783 $mockRelationHandler->itemArray = [
784 '1' => ['table' => $this->getUniqueId('bar_'), 'id' => 67]
785 ];
786
787 /** @var DataHandler|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface $mockDataHandler */
788 $mockDataHandler = $this->getAccessibleMock(DataHandler::class, ['getInlineFieldType', 'deleteAction', 'createRelationHandlerInstance'], [], '', false);
789 $mockDataHandler->expects($this->once())->method('getInlineFieldType')->will($this->returnValue('field'));
790 $mockDataHandler->expects($this->once())->method('createRelationHandlerInstance')->will($this->returnValue($mockRelationHandler));
791 $mockDataHandler->expects($this->never())->method('deleteAction');
792 $mockDataHandler->deleteRecord_procBasedOnFieldType($table, 42, 'foo', 'bar', $conf);
793 }
794
795 /**
796 * @return array
797 */
798 public function checkValue_checkReturnsExpectedValuesDataProvider()
799 {
800 return [
801 'None item selected' => [
802 0,
803 0
804 ],
805 'All items selected' => [
806 7,
807 7
808 ],
809 'Item 1 and 2 are selected' => [
810 3,
811 3
812 ],
813 'Value is higher than allowed (all checkboxes checked)' => [
814 15,
815 7
816 ],
817 'Value is higher than allowed (some checkboxes checked)' => [
818 11,
819 3
820 ],
821 'Negative value' => [
822 -5,
823 0
824 ]
825 ];
826 }
827
828 /**
829 * @param string $value
830 * @param string $expectedValue
831 *
832 * @dataProvider checkValue_checkReturnsExpectedValuesDataProvider
833 * @test
834 */
835 public function checkValue_checkReturnsExpectedValues($value, $expectedValue)
836 {
837 $expectedResult = [
838 'value' => $expectedValue
839 ];
840 $result = [];
841 $tcaFieldConfiguration = [
842 'items' => [
843 ['Item 1', 0],
844 ['Item 2', 0],
845 ['Item 3', 0]
846 ]
847 ];
848 $this->assertSame($expectedResult, $this->subject->_call('checkValueForCheck', $result, $value, $tcaFieldConfiguration, '', 0, 0, ''));
849 }
850
851 /**
852 * @test
853 */
854 public function checkValueForInputConvertsNullToEmptyString()
855 {
856 $previousLanguageService = $GLOBALS['LANG'];
857 $GLOBALS['LANG'] = GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
858 $GLOBALS['LANG']->init('default');
859 $expectedResult = ['value' => ''];
860 $this->assertSame($expectedResult, $this->subject->_call('checkValueForInput', null, ['type' => 'string', 'max' => 40], 'tt_content', 'NEW55c0e67f8f4d32.04974534', 89, 'table_caption'));
861 $GLOBALS['LANG'] = $previousLanguageService;
862 }
863
864 /**
865 * @param mixed $value
866 * @param array $configuration
867 * @param int|string $expected
868 * @test
869 * @dataProvider referenceValuesAreCastedDataProvider
870 */
871 public function referenceValuesAreCasted($value, array $configuration, $expected)
872 {
873 $this->assertEquals(
874 $expected,
875 $this->subject->_call('castReferenceValue', $value, $configuration)
876 );
877 }
878
879 /**
880 * @return array
881 */
882 public function referenceValuesAreCastedDataProvider()
883 {
884 return [
885 'all empty' => [
886 '', [], ''
887 ],
888 'cast zero with MM table' => [
889 '', ['MM' => 'table'], 0
890 ],
891 'cast zero with MM table with default value' => [
892 '', ['MM' => 'table', 'default' => 13], 0
893 ],
894 'cast zero with foreign field' => [
895 '', ['foreign_field' => 'table', 'default' => 13], 0
896 ],
897 'cast zero with foreign field with default value' => [
898 '', ['foreign_field' => 'table'], 0
899 ],
900 'pass zero' => [
901 '0', [], '0'
902 ],
903 'pass value' => [
904 '1', ['default' => 13], '1'
905 ],
906 'use default value' => [
907 '', ['default' => 13], 13
908 ],
909 ];
910 }
911 }