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