2 declare(strict_types = 1);
18 use Prophecy\Argument;
27 use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
28 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
59 protected function setUp()
62 $cacheManagerProphecy = $this->prophesize(CacheManager::class);
63 GeneralUtility::setSingletonInstance(CacheManager::class, $cacheManagerProphecy->reveal());
64 $cacheFrontendProphecy = $this->prophesize(FrontendInterface::class);
65 $cacheManagerProphecy->getCache(
'cache_runtime')->willReturn($cacheFrontendProphecy->reveal());
66 $this->backEndUser = $this->createMock(BackendUserAuthentication::class);
67 $this->subject = $this->getAccessibleMock(DataHandler::class, [
'dummy']);
68 $this->subject->start([],
'', $this->backEndUser);
76 $this->assertTrue($this->subject instanceof
DataHandler);
87 $this->subject->admin =
true;
88 $this->assertTrue($this->subject->checkModifyAccessList(
'tt_content'));
96 $this->subject->admin =
false;
97 $this->assertFalse($this->subject->checkModifyAccessList(
'tt_content'));
105 $this->subject->admin =
false;
106 $this->backEndUser->groupData[
'tables_modify'] =
'tt_content';
107 $this->assertTrue($this->subject->checkModifyAccessList(
'tt_content'));
115 $this->subject->admin =
true;
116 $this->assertTrue($this->subject->checkModifyAccessList(
'be_users'));
124 $this->subject->admin =
false;
125 $this->assertFalse($this->subject->checkModifyAccessList(
'be_users'));
133 $tableName = $this->getUniqueId(
'aTable');
141 $this->subject->admin =
false;
142 $this->backEndUser->groupData[
'tables_modify'] = $tableName;
143 $this->assertFalse($this->subject->checkModifyAccessList($tableName));
154 '1000,10' =>
'1000.10',
155 '1000,0' =>
'1000.00',
156 '600.000.000,00' =>
'600000000.00',
157 '60aaa00' =>
'6000.00'
159 foreach ($testData as $value => $expectedReturnValue) {
160 $returnValue = $this->subject->checkValue_input_Eval($value, [
'double2'],
'');
161 $this->assertSame($returnValue[
'value'], $expectedReturnValue);
172 'timestamp is passed through, as it is UTC' => [
173 1457103519,
'Europe/Berlin', 1457103519
175 'ISO date is interpreted as local date and is output as correct timestamp' => [
176 '2017-06-07T00:10:00Z',
'Europe/Berlin', 1496787000
187 $oldTimezone = date_default_timezone_get();
188 date_default_timezone_set($serverTimezone);
190 $output = $this->subject->checkValue_input_Eval($input, [
'datetime'],
'');
193 date_default_timezone_set($oldTimezone);
195 $this->assertEquals($expectedOutput,
$output[
'value']);
205 $inputValue =
'$1$GNu9HdMt$RwkPb28pce4nXZfnplVZY/';
207 $this->assertSame($inputValue, $result[
'value']);
217 $inputValue =
'M$1$GNu9HdMt$RwkPb28pce4nXZfnplVZY/';
219 $this->assertSame($inputValue, $result[
'value']);
228 $inputValue =
'myPassword';
231 $this->assertNotSame($inputValue, $result[
'value']);
242 '"0" returns zero as integer' => [
246 '"-2000001" is interpreted correctly as -2000001 but is lower than -2000000 and set to -2000000' => [
250 '"-2000000" is interpreted correctly as -2000000 and is equal to -2000000' => [
254 '"2000000" is interpreted correctly as 2000000 and is equal to 2000000' => [
258 '"2000001" is interpreted correctly as 2000001 but is greater then 2000000 and set to 2000000' => [
277 'lower' =>
'-2000000',
281 $returnValue = $this->subject->_call(
'checkValueForInput', $value, $tcaFieldConf,
'', 0, 0,
'');
282 $this->assertSame($returnValue[
'value'], $expectedReturnValue);
291 'undershot date adjusted' => [
292 '2018-02-28T00:00:00Z',
295 'exact lower date accepted' => [
296 '2018-03-01T00:00:00Z',
299 'exact upper date accepted' => [
300 '2018-03-31T23:59:59Z',
303 'exceeded date adjusted' => [
304 '2018-04-01T00:00:00Z',
321 'eval' =>
'datetime',
324 'lower' => gmmktime(0, 0, 0, 3, 1, 2018),
326 'upper' => gmmktime(23, 59, 59, 3, 31, 2018),
331 $previousTimezone = date_default_timezone_get();
332 date_default_timezone_set(
'UTC');
334 $returnValue = $this->subject->_call(
'checkValueForInput', $value, $tcaFieldConf,
'', 0, 0,
'');
336 date_default_timezone_set($previousTimezone);
338 $this->assertSame($returnValue[
'value'], $expected);
347 'tca without dbType' => [
352 'tca with dbType != date/datetime/time' => [
368 $this->subject->_call(
'checkValueForInput',
'', $tcaFieldConf,
'', 0, 0,
'');
378 'time from inputDateTime' => [
379 '1970-01-01T18:54:00Z',
383 'date from inputDateTime' => [
384 '2020-11-25T00:00:00Z',
388 'datetime from inputDateTime' => [
389 '2020-11-25T18:54:00Z',
391 '2020-11-25 18:54:00',
394 'time from copying a record' => [
399 'date from copying a record' => [
404 'datetime from copying a record' => [
405 '2020-11-25 18:54:00',
407 '2020-11-25 18:54:00',
428 $oldTimezone = date_default_timezone_get();
429 date_default_timezone_set(
'Europe/Berlin');
431 $returnValue = $this->subject->_call(
'checkValueForInput', $value, $tcaFieldConf,
'', 0, 0,
'');
434 date_default_timezone_set($oldTimezone);
436 self::assertEquals($expectedOutput, $returnValue[
'value']);
449 $this->expectException(\UnexpectedValueException::class);
450 $this->expectExceptionCode(1251892472);
452 $GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'checkModifyAccessList'][] = InvalidHookFixture::class;
453 $this->subject->checkModifyAccessList(
'tt_content');
463 $hookClass = $this->getUniqueId(
'tx_coretest');
464 $hookMock = $this->getMockBuilder(\
TYPO3\CMS\Core\DataHandling\DataHandlerCheckModifyAccessListHookInterface::class)
465 ->setMethods([
'checkModifyAccessList'])
466 ->setMockClassName($hookClass)
468 $hookMock->expects($this->once())->method(
'checkModifyAccessList');
469 $GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'checkModifyAccessList'][] = $hookClass;
470 GeneralUtility::addInstance($hookClass, $hookMock);
471 $this->subject->checkModifyAccessList(
'tt_content');
481 $GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'checkModifyAccessList'][] = AllowAccessHookFixture::class;
482 $this->assertTrue($this->subject->checkModifyAccessList(
'tt_content'));
494 $subject = $this->getMockBuilder(DataHandler::class)
495 ->setMethods([
'newlog'])
497 $this->backEndUser->workspace = 1;
498 $this->backEndUser->workspaceRec = [
'freeze' =>
true];
515 $subject = $this->getMockBuilder(DataHandler::class)
518 'checkModifyAccessList',
520 'checkRecordUpdateAccess',
523 'registerElementsToBeDeleted',
524 'unsetElementsToBeDeleted',
525 'resetElementsToBeDeleted'
527 ->disableOriginalConstructor()
530 $subject->bypassWorkspaceRestrictions =
false;
539 $cacheManagerMock = $this->getMockBuilder(CacheManager::class)
540 ->setMethods([
'flushCachesInGroupByTags'])
542 $cacheManagerMock->expects($this->once())->method(
'flushCachesInGroupByTags')->with(
'pages', []);
544 $subject->expects($this->once())->method(
'getCacheManager')->willReturn($cacheManagerMock);
545 $subject->expects($this->once())->method(
'recordInfo')->will($this->returnValue(
null));
546 $subject->expects($this->once())->method(
'checkModifyAccessList')->with(
'pages')->will($this->returnValue(
true));
547 $subject->expects($this->once())->method(
'tableReadOnly')->with(
'pages')->will($this->returnValue(
false));
548 $subject->expects($this->once())->method(
'checkRecordUpdateAccess')->will($this->returnValue(
true));
549 $subject->expects($this->once())->method(
'unsetElementsToBeDeleted')->willReturnArgument(0);
552 $backEndUser = $this->createMock(BackendUserAuthentication::class);
555 $backEndUser->expects($this->once())->method(
'workspaceAllowAutoCreation')->will($this->returnValue(
true));
556 $backEndUser->expects($this->once())->method(
'workspaceCannotEditRecord')->will($this->returnValue(
true));
557 $backEndUser->expects($this->once())->method(
'recordEditAccessInternals')->with(
'pages', 1)->will($this->returnValue(
true));
559 $createdDataHandler = $this->createMock(DataHandler::class);
560 $createdDataHandler->expects($this->once())->method(
'start')->with([], [
565 'label' =>
'Auto-created for WS #1'
570 $createdDataHandler->expects($this->never())->method(
'process_datamap');
571 $createdDataHandler->expects($this->once())->method(
'process_cmdmap');
572 GeneralUtility::addInstance(DataHandler::class, $createdDataHandler);
581 $hookClass = $this->getUniqueId(
'tx_coretest');
582 $hookMock = $this->getMockBuilder($hookClass)
583 ->setMethods([
'checkFlexFormValue_beforeMerge'])
585 $hookMock->expects($this->once())->method(
'checkFlexFormValue_beforeMerge');
586 $GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
't3lib/class.t3lib_tcemain.php'][
'checkFlexFormValue'][] = $hookClass;
587 GeneralUtility::addInstance($hookClass, $hookMock);
588 $flexFormToolsProphecy = $this->prophesize(FlexFormTools::class);
589 $flexFormToolsProphecy->getDataStructureIdentifier(Argument::cetera())->willReturn(
'anIdentifier');
590 $flexFormToolsProphecy->parseDataStructureByIdentifier(
'anIdentifier')->willReturn([]);
591 GeneralUtility::addInstance(FlexFormTools::class, $flexFormToolsProphecy->reveal());
592 $this->subject->_call(
'checkValueForFlex', [], [], [],
'', 0,
'',
'', 0, 0, 0, [],
'');
603 $backendUser = $this->createMock(BackendUserAuthentication::class);
604 $backendUser->expects($this->once())->method(
'writelog');
605 $this->subject->enableLogging =
true;
606 $this->subject->BE_USER = $backendUser;
607 $this->subject->log(
'', 23, 0, 42, 0,
'details');
615 $backendUser = $this->createMock(BackendUserAuthentication::class);
616 $backendUser->expects($this->never())->method(
'writelog');
617 $this->subject->enableLogging =
false;
618 $this->subject->BE_USER = $backendUser;
619 $this->subject->log(
'', 23, 0, 42, 0,
'details');
627 $backendUser = $this->createMock(BackendUserAuthentication::class);
628 $this->subject->BE_USER = $backendUser;
629 $this->subject->enableLogging =
true;
630 $this->subject->errorLog = [];
631 $logDetailsUnique = $this->getUniqueId(
'details');
632 $this->subject->log(
'', 23, 0, 42, 1, $logDetailsUnique);
633 $this->assertStringEndsWith($logDetailsUnique, $this->subject->errorLog[0]);
641 $backendUser = $this->createMock(BackendUserAuthentication::class);
642 $this->subject->BE_USER = $backendUser;
643 $this->subject->enableLogging =
true;
644 $this->subject->errorLog = [];
645 $logDetails = $this->getUniqueId(
'details');
646 $this->subject->log(
'', 23, 0, 42, 1,
'%1$s' . $logDetails .
'%2$s', -1, [
'foo',
'bar']);
647 $expected =
'foo' . $logDetails .
'bar';
648 $this->assertStringEndsWith($expected, $this->subject->errorLog[0]);
663 $result = $this->callInaccessibleMethod(
665 'isSubmittedValueEqualToStoredValue',
671 $this->assertEquals($expected, $result);
681 'string value "" vs. ""' => [
683 '',
'',
'string', false
685 'string value 0 vs. "0"' => [
687 0,
'0',
'string', false
689 'string value 1 vs. "1"' => [
691 1,
'1',
'string', false
693 'string value "0" vs. ""' => [
695 '0',
'',
'string', false
697 'string value 0 vs. ""' => [
699 0,
'',
'string', false
701 'string value null vs. ""' => [
703 null,
'',
'string', false
706 'integer value 0 vs. 0' => [
710 'integer value "0" vs. "0"' => [
712 '0',
'0',
'int', false
714 'integer value 0 vs. "0"' => [
718 'integer value "" vs. "0"' => [
720 '',
'0',
'int', false
722 'integer value "" vs. 0' => [
726 'integer value "0" vs. 0' => [
730 'integer value 1 vs. 1' => [
734 'integer value 1 vs. "1"' => [
738 'integer value "1" vs. "1"' => [
740 '1',
'1',
'int', false
742 'integer value "1" vs. 1' => [
746 'integer value "0" vs. "1"' => [
748 '0',
'1',
'int', false
751 'string with allowed null value "" vs. ""' => [
753 '',
'',
'string', true
755 'string with allowed null value 0 vs. "0"' => [
757 0,
'0',
'string', true
759 'string with allowed null value 1 vs. "1"' => [
761 1,
'1',
'string', true
763 'string with allowed null value "0" vs. ""' => [
765 '0',
'',
'string', true
767 'string with allowed null value 0 vs. ""' => [
769 0,
'',
'string', true
771 'string with allowed null value null vs. ""' => [
773 null,
'',
'string', true
775 'string with allowed null value "" vs. null' => [
777 '',
null,
'string', true
779 'string with allowed null value null vs. null' => [
781 null,
null,
'string', true
784 'integer with allowed null value 0 vs. 0' => [
788 'integer with allowed null value "0" vs. "0"' => [
790 '0',
'0',
'int', true
792 'integer with allowed null value 0 vs. "0"' => [
796 'integer with allowed null value "" vs. "0"' => [
800 'integer with allowed null value "" vs. 0' => [
804 'integer with allowed null value "0" vs. 0' => [
808 'integer with allowed null value 1 vs. 1' => [
812 'integer with allowed null value "1" vs. "1"' => [
814 '1',
'1',
'int', true
816 'integer with allowed null value "1" vs. 1' => [
820 'integer with allowed null value 1 vs. "1"' => [
824 'integer with allowed null value "0" vs. "1"' => [
826 '0',
'1',
'int', true
828 'integer with allowed null value null vs. ""' => [
830 null,
'',
'int', true
832 'integer with allowed null value "" vs. null' => [
834 '',
null,
'int', true
836 'integer with allowed null value null vs. null' => [
838 null,
null,
'int', true
840 'integer with allowed null value null vs. "0"' => [
842 null,
'0',
'int', true
844 'integer with allowed null value null vs. 0' => [
848 'integer with allowed null value "0" vs. null' => [
850 '0',
null,
'int', true
863 $table =
'phpunit_dummy';
871 $backendUser = $this->createMock(BackendUserAuthentication::class);
876 $GLOBALS[
'TCA'][$table][
'ctrl'] = [
'label' =>
'dummy'];
885 $this->assertEquals($expected,
$subject->_call(
'getPlaceholderTitleForTableLabel', $table));
907 '[PLACEHOLDER, WS#1]',
919 $dataHandlerMock = $this->getMockBuilder(DataHandler::class)
920 ->setMethods([
'canDeletePage',
'log'])
923 ->expects($this->never())
924 ->method(
'canDeletePage');
926 ->expects($this->once())
928 ->with(
'pages', 0, 0, 0, 2,
'Deleting all pages starting from the root-page is disabled.', -1, [], 0);
930 $dataHandlerMock->deletePages(0);
938 $table = $this->getUniqueId(
'foo_');
941 'foreign_table' => $this->getUniqueId(
'foreign_foo_'),
943 'enableCascadingDelete' => 0,
948 $mockRelationHandler = $this->createMock(\
TYPO3\CMS\Core\Database\RelationHandler::class);
949 $mockRelationHandler->itemArray = [
950 '1' => [
'table' => $this->getUniqueId(
'bar_'),
'id' => 67]
954 $mockDataHandler = $this->getAccessibleMock(DataHandler::class, [
'getInlineFieldType',
'deleteAction',
'createRelationHandlerInstance'], [],
'',
false);
955 $mockDataHandler->expects($this->once())->method(
'getInlineFieldType')->will($this->returnValue(
'field'));
956 $mockDataHandler->expects($this->once())->method(
'createRelationHandlerInstance')->will($this->returnValue($mockRelationHandler));
957 $mockDataHandler->expects($this->never())->method(
'deleteAction');
958 $mockDataHandler->deleteRecord_procBasedOnFieldType($table, 42,
'foo',
'bar', $conf);
967 'None item selected' => [
971 'All items selected' => [
975 'Item 1 and 2 are selected' => [
979 'Value is higher than allowed (all checkboxes checked)' => [
983 'Value is higher than allowed (some checkboxes checked)' => [
987 'Negative value' => [
1004 'value' => $expectedValue
1007 $tcaFieldConfiguration = [
1014 $this->assertSame($expectedResult, $this->subject->_call(
'checkValueForCheck', $result, $value, $tcaFieldConfiguration,
'', 0, 0,
''));
1022 $GLOBALS[
'LANG'] = GeneralUtility::makeInstance(\
TYPO3\CMS\Core\Localization\LanguageService::class);
1024 $expectedResult = [
'value' =>
''];
1025 $this->assertSame($expectedResult, $this->subject->_call(
'checkValueForInput',
null, [
'type' =>
'string',
'max' => 40],
'tt_content',
'NEW55c0e67f8f4d32.04974534', 89,
'table_caption'));
1037 $this->assertEquals(
1039 $this->subject->_call(
'castReferenceValue', $value, $configuration)
1052 'cast zero with MM table' => [
1053 '', [
'MM' =>
'table'], 0
1055 'cast zero with MM table with default value' => [
1056 '', [
'MM' =>
'table',
'default' => 13], 0
1058 'cast zero with foreign field' => [
1059 '', [
'foreign_field' =>
'table',
'default' => 13], 0
1061 'cast zero with foreign field with default value' => [
1062 '', [
'foreign_field' =>
'table'], 0
1068 '1', [
'default' => 13],
'1'
1070 'use default value' => [
1071 '', [
'default' => 13], 13
1082 'normal case' => [
'Test (copy 42)',
'Test'],
1084 'with double spaces before' => [
'Test (copy 42)',
'Test '],
1085 'with three spaces before' => [
'Test (copy 42)',
'Test '],
1086 'with space after' => [
'Test (copy 42) ',
'Test (copy 42) '],
1087 'with double spaces after' => [
'Test (copy 42) ',
'Test (copy 42) '],
1088 'with three spaces after' => [
'Test (copy 42) ',
'Test (copy 42) '],
1089 'with double tab before' => [
'Test' .
"\t" .
'(copy 42)',
'Test'],
1090 'with double tab after' => [
'Test (copy 42)' .
"\t",
'Test (copy 42)' .
"\t"],
1102 $languageServiceProphecy = $this->prophesize(\
TYPO3\CMS\Core\Localization\LanguageService::class);
1103 $languageServiceProphecy->sL(
'testLabel')->willReturn(
'(copy %s)');
1104 $GLOBALS[
'LANG'] = $languageServiceProphecy->reveal();
1105 $GLOBALS[
'TCA'][
'testTable'][
'ctrl'][
'prependAtCopy'] =
'testLabel';
1106 $this->assertEquals($expected, (
new DataHandler())->clearPrefixFromValue(
'testTable', $input));