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