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