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