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