[TASK] migrate ext:backend/Utility to doctrine
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Resource / ResourceStorageTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Resource;
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 Prophecy\Argument;
18 use TYPO3\CMS\Core\Database\Connection;
19 use TYPO3\CMS\Core\Database\ConnectionPool;
20 use TYPO3\CMS\Core\Database\DatabaseConnection;
21 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
22 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
23 use TYPO3\CMS\Core\Resource\Driver\AbstractDriver;
24 use TYPO3\CMS\Core\Resource\Driver\LocalDriver;
25 use TYPO3\CMS\Core\Resource\File;
26 use TYPO3\CMS\Core\Resource\FileRepository;
27 use TYPO3\CMS\Core\Resource\Folder;
28 use TYPO3\CMS\Core\Resource\FolderInterface;
29 use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
30 use TYPO3\CMS\Core\Resource\ResourceStorage;
31 use TYPO3\CMS\Core\Resource\ResourceStorageInterface;
32 use TYPO3\CMS\Core\Utility\ArrayUtility;
33 use TYPO3\CMS\Core\Utility\GeneralUtility;
34
35 /**
36 * Test case for ResourceStorage class
37 */
38 class ResourceStorageTest extends BaseTestCase
39 {
40 /**
41 * @var array A backup of registered singleton instances
42 */
43 protected $singletonInstances = array();
44
45 /**
46 * @var ResourceStorage|\PHPUnit_Framework_MockObject_MockObject
47 */
48 protected $subject;
49
50 protected function setUp()
51 {
52 parent::setUp();
53 $this->singletonInstances = GeneralUtility::getSingletonInstances();
54 /** @var FileRepository|\PHPUnit_Framework_MockObject_MockObject $fileRepositoryMock */
55 $fileRepositoryMock = $this->createMock(FileRepository::class);
56 GeneralUtility::setSingletonInstance(
57 FileRepository::class,
58 $fileRepositoryMock
59 );
60 $databaseMock = $this->createMock(DatabaseConnection::class);
61 $databaseMock->expects($this->any())->method('exec_SELECTgetRows')->with('*', 'sys_file_storage', '1=1', '', 'name', '', 'uid')->willReturn(array());
62 $GLOBALS['TYPO3_DB'] = $databaseMock;
63 }
64
65 protected function tearDown()
66 {
67 GeneralUtility::resetSingletonInstances($this->singletonInstances);
68 parent::tearDown();
69 }
70
71 /**
72 * Prepare ResourceStorage
73 *
74 * @param array $configuration
75 * @param bool $mockPermissionChecks
76 * @param AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverObject
77 * @param array $storageRecord
78 */
79 protected function prepareSubject(array $configuration, $mockPermissionChecks = false, AbstractDriver $driverObject = null, array $storageRecord = array())
80 {
81 $permissionMethods = array('assureFileAddPermissions', 'checkFolderActionPermission', 'checkFileActionPermission', 'checkUserActionPermission', 'checkFileExtensionPermission', 'isWithinFileMountBoundaries');
82 $mockedMethods = array();
83 $configuration = $this->convertConfigurationArrayToFlexformXml($configuration);
84 $overruleArray = array('configuration' => $configuration);
85 ArrayUtility::mergeRecursiveWithOverrule($storageRecord, $overruleArray);
86 if ($driverObject == null) {
87 $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, array(), '', false);
88 }
89 if ($mockPermissionChecks) {
90 $mockedMethods = $permissionMethods;
91 }
92 $mockedMethods[] = 'getIndexer';
93
94 $this->subject = $this->getMockBuilder(ResourceStorage::class)
95 ->setMethods($mockedMethods)
96 ->setConstructorArgs(array($driverObject, $storageRecord))
97 ->getMock();
98 $this->subject->expects($this->any())->method('getIndexer')->will($this->returnValue($this->createMock(\TYPO3\CMS\Core\Resource\Index\Indexer::class)));
99 if ($mockPermissionChecks) {
100 foreach ($permissionMethods as $method) {
101 $this->subject->expects($this->any())->method($method)->will($this->returnValue(true));
102 }
103 }
104 }
105
106 /**
107 * Converts a simple configuration array into a FlexForm data structure serialized as XML
108 *
109 * @param array $configuration
110 * @return string
111 * @see GeneralUtility::array2xml()
112 */
113 protected function convertConfigurationArrayToFlexformXml(array $configuration)
114 {
115 $flexFormArray = array('data' => array('sDEF' => array('lDEF' => array())));
116 foreach ($configuration as $key => $value) {
117 $flexFormArray['data']['sDEF']['lDEF'][$key] = array('vDEF' => $value);
118 }
119 $configuration = GeneralUtility::array2xml($flexFormArray);
120 return $configuration;
121 }
122
123 /**
124 * Creates a driver fixture object, optionally using a given mount object.
125 *
126 * IMPORTANT: Call this only after setting up the virtual file system (with the addTo* methods)!
127 *
128 * @param $driverConfiguration
129 * @param ResourceStorage $storageObject
130 * @param array $mockedDriverMethods
131 * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject
132 */
133 protected function createDriverMock($driverConfiguration, ResourceStorage $storageObject = null, $mockedDriverMethods = array())
134 {
135 $this->initializeVfs();
136
137 if (!isset($driverConfiguration['basePath'])) {
138 $driverConfiguration['basePath'] = $this->getMountRootUrl();
139 }
140
141 if ($mockedDriverMethods === null) {
142 $driver = new LocalDriver($driverConfiguration);
143 } else {
144 // We are using the LocalDriver here because PHPUnit can't mock concrete methods in abstract classes, so
145 // when using the AbstractDriver we would be in trouble when wanting to mock away some concrete method
146 $driver = $this->getMockBuilder(LocalDriver::class)
147 ->setMethods($mockedDriverMethods)
148 ->setConstructorArgs(array($driverConfiguration))
149 ->getMock();
150 }
151 if ($storageObject !== null) {
152 $storageObject->setDriver($driver);
153 }
154 $driver->setStorageUid(6);
155 $driver->processConfiguration();
156 $driver->initialize();
157 return $driver;
158 }
159
160 /**
161 * @return array
162 */
163 public function fileExtensionPermissionDataProvider()
164 {
165 return array(
166 'Permissions evaluated, extension not in allowed list' => array(
167 'fileName' => 'foo.txt',
168 'configuration' => array('allow' => 'jpg'),
169 'evaluatePermissions' => true,
170 'isAllowed' => true,
171 ),
172 'Permissions evaluated, extension in deny list' => array(
173 'fileName' => 'foo.txt',
174 'configuration' => array('deny' => 'txt'),
175 'evaluatePermissions' => true,
176 'isAllowed' => false,
177 ),
178 'Permissions not evaluated, extension is php' => array(
179 'fileName' => 'foo.php',
180 'configuration' => array(),
181 'evaluatePermissions' => false,
182 'isAllowed' => false,
183 ),
184 'Permissions evaluated, extension is php' => array(
185 'fileName' => 'foo.php',
186 // It is not possible to allow php file extension through configuration
187 'configuration' => array('allow' => 'php'),
188 'evaluatePermissions' => true,
189 'isAllowed' => false,
190 ),
191 );
192 }
193
194 /**
195 * @param string $fileName
196 * @param array $configuration
197 * @param bool $evaluatePermissions
198 * @param bool $isAllowed
199 * @test
200 * @dataProvider fileExtensionPermissionDataProvider
201 */
202 public function fileExtensionPermissionIsWorkingCorrectly($fileName, array $configuration, $evaluatePermissions, $isAllowed)
203 {
204 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']['webspace'] = $configuration;
205 $driverMock = $this->getMockForAbstractClass(AbstractDriver::class, array(), '', false);
206 $subject = $this->getAccessibleMock(ResourceStorage::class, array('dummy'), array($driverMock, array()));
207 $subject->_set('evaluatePermissions', $evaluatePermissions);
208 $this->assertSame($isAllowed, $subject->_call('checkFileExtensionPermission', $fileName));
209 }
210
211 /**
212 * @return array
213 */
214 public function isWithinFileMountBoundariesDataProvider()
215 {
216 return array(
217 'Access to file in ro file mount denied for write request' => array(
218 '$fileIdentifier' => '/fooBaz/bar.txt',
219 '$fileMountFolderIdentifier' => '/fooBaz/',
220 '$isFileMountReadOnly' => true,
221 '$checkWriteAccess' => true,
222 '$expectedResult' => false,
223 ),
224 'Access to file in ro file mount allowed for read request' => array(
225 '$fileIdentifier' => '/fooBaz/bar.txt',
226 '$fileMountFolderIdentifier' => '/fooBaz/',
227 '$isFileMountReadOnly' => true,
228 '$checkWriteAccess' => false,
229 '$expectedResult' => true,
230 ),
231 'Access to file in rw file mount allowed for write request' => array(
232 '$fileIdentifier' => '/fooBaz/bar.txt',
233 '$fileMountFolderIdentifier' => '/fooBaz/',
234 '$isFileMountReadOnly' => false,
235 '$checkWriteAccess' => true,
236 '$expectedResult' => true,
237 ),
238 'Access to file in rw file mount allowed for read request' => array(
239 '$fileIdentifier' => '/fooBaz/bar.txt',
240 '$fileMountFolderIdentifier' => '/fooBaz/',
241 '$isFileMountReadOnly' => false,
242 '$checkWriteAccess' => false,
243 '$expectedResult' => true,
244 ),
245 'Access to file not in file mount denied for write request' => array(
246 '$fileIdentifier' => '/fooBaz/bar.txt',
247 '$fileMountFolderIdentifier' => '/barBaz/',
248 '$isFileMountReadOnly' => false,
249 '$checkWriteAccess' => true,
250 '$expectedResult' => false,
251 ),
252 'Access to file not in file mount denied for read request' => array(
253 '$fileIdentifier' => '/fooBaz/bar.txt',
254 '$fileMountFolderIdentifier' => '/barBaz/',
255 '$isFileMountReadOnly' => false,
256 '$checkWriteAccess' => false,
257 '$expectedResult' => false,
258 ),
259 );
260 }
261
262 /**
263 * @param string $fileIdentifier
264 * @param string $fileMountFolderIdentifier
265 * @param bool $isFileMountReadOnly
266 * @param bool $checkWriteAccess
267 * @param bool $expectedResult
268 * @throws \TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException
269 * @test
270 * @dataProvider isWithinFileMountBoundariesDataProvider
271 */
272 public function isWithinFileMountBoundariesRespectsReadOnlyFileMounts($fileIdentifier, $fileMountFolderIdentifier, $isFileMountReadOnly, $checkWriteAccess, $expectedResult)
273 {
274 $connectionProphet = $this->prophesize(Connection::class);
275 $connectionProphet->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
276
277 $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
278 $queryBuilderProphet->expr()->willReturn(
279 GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
280 );
281
282 $connectionPoolProphet = $this->prophesize(ConnectionPool::class);
283 $connectionPoolProphet->getQueryBuilderForTable(Argument::cetera())->willReturn($queryBuilderProphet->reveal());
284 GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphet->reveal());
285
286 /** @var AbstractDriver|\PHPUnit_Framework_MockObject_MockObject $driverMock */
287 $driverMock = $this->getMockForAbstractClass(AbstractDriver::class, array(), '', false);
288 $driverMock->expects($this->any())
289 ->method('getFolderInfoByIdentifier')
290 ->willReturnCallback(function ($identifier) use ($isFileMountReadOnly) {
291 return array(
292 'identifier' => $identifier,
293 'name' => trim($identifier, '/'),
294 );
295 });
296 $driverMock->expects($this->any())
297 ->method('isWithin')
298 ->willReturnCallback(function ($folderIdentifier, $fileIdentifier) {
299 if ($fileIdentifier === ResourceStorageInterface::DEFAULT_ProcessingFolder . '/') {
300 return false;
301 } else {
302 return strpos($fileIdentifier, $folderIdentifier) === 0;
303 }
304 });
305 $this->prepareSubject(array(), false, $driverMock);
306 $fileMock = $this->getSimpleFileMock($fileIdentifier);
307 $this->subject->setEvaluatePermissions(true);
308 $this->subject->addFileMount('/' . $this->getUniqueId('random') . '/', array('read_only' => false));
309 $this->subject->addFileMount($fileMountFolderIdentifier, array('read_only' => $isFileMountReadOnly));
310 $this->subject->addFileMount('/' . $this->getUniqueId('random') . '/', array('read_only' => false));
311 $this->assertSame($expectedResult, $this->subject->isWithinFileMountBoundaries($fileMock, $checkWriteAccess));
312 }
313
314 /**
315 * @return array
316 */
317 public function capabilitiesDataProvider()
318 {
319 return array(
320 'only public' => array(
321 array(
322 'public' => true,
323 'writable' => false,
324 'browsable' => false
325 )
326 ),
327 'only writable' => array(
328 array(
329 'public' => false,
330 'writable' => true,
331 'browsable' => false
332 )
333 ),
334 'only browsable' => array(
335 array(
336 'public' => false,
337 'writable' => false,
338 'browsable' => true
339 )
340 ),
341 'all capabilities' => array(
342 array(
343 'public' => true,
344 'writable' => true,
345 'browsable' => true
346 )
347 ),
348 'none' => array(
349 array(
350 'public' => false,
351 'writable' => false,
352 'browsable' => false
353 )
354 )
355 );
356 }
357
358 /**
359 * @test
360 * @dataProvider capabilitiesDataProvider
361 * @TODO: Rewrite or move to functional suite
362 */
363 public function capabilitiesOfStorageObjectAreCorrectlySet(array $capabilities)
364 {
365 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
366 $storageRecord = array(
367 'is_public' => $capabilities['public'],
368 'is_writable' => $capabilities['writable'],
369 'is_browsable' => $capabilities['browsable'],
370 'is_online' => true
371 );
372 $mockedDriver = $this->createDriverMock(
373 array(
374 'pathType' => 'relative',
375 'basePath' => 'fileadmin/',
376 ),
377 $this->subject,
378 null
379 );
380 $this->prepareSubject(array(), false, $mockedDriver, $storageRecord);
381 $this->assertEquals($capabilities['public'], $this->subject->isPublic(), 'Capability "public" is not correctly set.');
382 $this->assertEquals($capabilities['writable'], $this->subject->isWritable(), 'Capability "writable" is not correctly set.');
383 $this->assertEquals($capabilities['browsable'], $this->subject->isBrowsable(), 'Capability "browsable" is not correctly set.');
384 }
385
386 /**
387 * @test
388 * @TODO: Rewrite or move to functional suite
389 */
390 public function fileAndFolderListFiltersAreInitializedWithDefaultFilters()
391 {
392 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
393 $this->prepareSubject(array());
394 $this->assertEquals($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['defaultFilterCallbacks'], $this->subject->getFileAndFolderNameFilters());
395 }
396
397 /**
398 * @test
399 */
400 public function addFileFailsIfFileDoesNotExist()
401 {
402 /** @var Folder|\PHPUnit_Framework_MockObject_MockObject $mockedFolder */
403 $mockedFolder = $this->createMock(Folder::class);
404 $this->expectException(\InvalidArgumentException::class);
405 $this->expectExceptionCode(1319552745);
406 $this->prepareSubject(array());
407 $this->subject->addFile('/some/random/file', $mockedFolder);
408 }
409
410 /**
411 * @test
412 */
413 public function getPublicUrlReturnsNullIfStorageIsNotOnline()
414 {
415 /** @var $driver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
416 $driver = $this->getMockBuilder(LocalDriver::class)
417 ->setConstructorArgs(array(array('basePath' => $this->getMountRootUrl())))
418 ->getMock();
419 /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
420 $subject = $this->getMockBuilder(ResourceStorage::class)
421 ->setMethods(array('isOnline'))
422 ->setConstructorArgs(array($driver, array('configuration' => array())))
423 ->getMock();
424 $subject->expects($this->once())->method('isOnline')->will($this->returnValue(false));
425
426 $sourceFileIdentifier = '/sourceFile.ext';
427 $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
428 $result = $subject->getPublicUrl($sourceFile);
429 $this->assertSame($result, null);
430 }
431
432 /**
433 * Data provider for checkFolderPermissionsRespectsFilesystemPermissions
434 *
435 * @return array
436 */
437 public function checkFolderPermissionsFilesystemPermissionsDataProvider()
438 {
439 return array(
440 'read action on readable/writable folder' => array(
441 'read',
442 array('r' => true, 'w' => true),
443 true
444 ),
445 'read action on unreadable folder' => array(
446 'read',
447 array('r' => false, 'w' => true),
448 false
449 ),
450 'write action on read-only folder' => array(
451 'write',
452 array('r' => true, 'w' => false),
453 false
454 )
455 );
456 }
457
458 /**
459 * @test
460 * @dataProvider checkFolderPermissionsFilesystemPermissionsDataProvider
461 * @param string $action 'read' or 'write'
462 * @param array $permissionsFromDriver The permissions as returned from the driver
463 * @param bool $expectedResult
464 */
465 public function checkFolderPermissionsRespectsFilesystemPermissions($action, $permissionsFromDriver, $expectedResult)
466 {
467 /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
468 $mockedDriver = $this->createMock(LocalDriver::class);
469 $mockedDriver->expects($this->any())->method('getPermissions')->will($this->returnValue($permissionsFromDriver));
470 /** @var $mockedFolder Folder|\PHPUnit_Framework_MockObject_MockObject */
471 $mockedFolder = $this->createMock(Folder::class);
472 // Let all other checks pass
473 /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject */
474 $subject = $this->getMockBuilder(ResourceStorage::class)
475 ->setMethods(array('isWritable', 'isBrowsable', 'checkUserActionPermission'))
476 ->setConstructorArgs(array($mockedDriver, array()))
477 ->getMock();
478 $subject->expects($this->any())->method('isWritable')->will($this->returnValue(true));
479 $subject->expects($this->any())->method('isBrowsable')->will($this->returnValue(true));
480 $subject->expects($this->any())->method('checkUserActionPermission')->will($this->returnValue(true));
481 $subject->setDriver($mockedDriver);
482
483 $this->assertSame($expectedResult, $subject->checkFolderActionPermission($action, $mockedFolder));
484 }
485
486 /**
487 * @test
488 */
489 public function checkUserActionPermissionsAlwaysReturnsTrueIfNoUserPermissionsAreSet()
490 {
491 $this->prepareSubject(array());
492 $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
493 }
494
495 /**
496 * @test
497 */
498 public function checkUserActionPermissionReturnsFalseIfPermissionIsSetToZero()
499 {
500 $this->prepareSubject(array());
501 $this->subject->setUserPermissions(array('readFolder' => true, 'writeFile' => true));
502 $this->assertTrue($this->subject->checkUserActionPermission('read', 'folder'));
503 }
504
505 public function checkUserActionPermission_arbitraryPermissionDataProvider()
506 {
507 return array(
508 'all lower cased' => array(
509 array('readFolder' => true),
510 'read',
511 'folder'
512 ),
513 'all upper case' => array(
514 array('readFolder' => true),
515 'READ',
516 'FOLDER'
517 ),
518 'mixed case' => array(
519 array('readFolder' => true),
520 'ReaD',
521 'FoLdEr'
522 )
523 );
524 }
525
526 /**
527 * @param array $permissions
528 * @param string $action
529 * @param string $type
530 * @test
531 * @dataProvider checkUserActionPermission_arbitraryPermissionDataProvider
532 */
533 public function checkUserActionPermissionAcceptsArbitrarilyCasedArguments(array $permissions, $action, $type)
534 {
535 $this->prepareSubject(array());
536 $this->subject->setUserPermissions($permissions);
537 $this->assertTrue($this->subject->checkUserActionPermission($action, $type));
538 }
539
540 /**
541 * @test
542 */
543 public function userActionIsDisallowedIfPermissionIsSetToFalse()
544 {
545 $this->prepareSubject(array());
546 $this->subject->setEvaluatePermissions(true);
547 $this->subject->setUserPermissions(array('readFolder' => false));
548 $this->assertFalse($this->subject->checkUserActionPermission('read', 'folder'));
549 }
550
551 /**
552 * @test
553 */
554 public function userActionIsDisallowedIfPermissionIsNotSet()
555 {
556 $this->prepareSubject(array());
557 $this->subject->setEvaluatePermissions(true);
558 $this->subject->setUserPermissions(array('readFolder' => true));
559 $this->assertFalse($this->subject->checkUserActionPermission('write', 'folder'));
560 }
561
562 /**
563 * @test
564 */
565 public function getEvaluatePermissionsWhenSetFalse()
566 {
567 $this->prepareSubject(array());
568 $this->subject->setEvaluatePermissions(false);
569 $this->assertFalse($this->subject->getEvaluatePermissions());
570 }
571
572 /**
573 * @test
574 */
575 public function getEvaluatePermissionsWhenSetTrue()
576 {
577 $this->prepareSubject(array());
578 $this->subject->setEvaluatePermissions(true);
579 $this->assertTrue($this->subject->getEvaluatePermissions());
580 }
581
582 /**
583 * @test
584 * @group integration
585 * @TODO: Rewrite or move to functional suite
586 */
587 public function setFileContentsUpdatesObjectProperties()
588 {
589 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
590 $this->initializeVfs();
591 $driverObject = $this->getMockForAbstractClass(AbstractDriver::class, array(), '', false);
592 $this->subject = $this->getMockBuilder(ResourceStorage::class)
593 ->setMethods(array('getFileIndexRepository', 'checkFileActionPermission'))
594 ->setConstructorArgs(array($driverObject, array()))
595 ->getMock();
596 $this->subject->expects($this->any())->method('checkFileActionPermission')->will($this->returnValue(true));
597 $fileInfo = array(
598 'storage' => 'A',
599 'identifier' => 'B',
600 'mtime' => 'C',
601 'ctime' => 'D',
602 'mimetype' => 'E',
603 'size' => 'F',
604 'name' => 'G',
605 );
606 $newProperties = array(
607 'storage' => $fileInfo['storage'],
608 'identifier' => $fileInfo['identifier'],
609 'tstamp' => $fileInfo['mtime'],
610 'crdate' => $fileInfo['ctime'],
611 'mime_type' => $fileInfo['mimetype'],
612 'size' => $fileInfo['size'],
613 'name' => $fileInfo['name']
614 );
615 $hash = 'asdfg';
616 /** @var $mockedDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
617 $mockedDriver = $this->getMockBuilder(LocalDriver::class)
618 ->setConstructorArgs(array(array('basePath' => $this->getMountRootUrl())))
619 ->getMock();
620 $mockedDriver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfo));
621 $mockedDriver->expects($this->once())->method('hash')->will($this->returnValue($hash));
622 $this->subject->setDriver($mockedDriver);
623 $indexFileRepositoryMock = $this->createMock(FileIndexRepository::class);
624 $this->subject->expects($this->any())->method('getFileIndexRepository')->will($this->returnValue($indexFileRepositoryMock));
625 /** @var $mockedFile File|\PHPUnit_Framework_MockObject_MockObject */
626 $mockedFile = $this->createMock(File::class);
627 $mockedFile->expects($this->any())->method('getIdentifier')->will($this->returnValue($fileInfo['identifier']));
628 // called by indexer because the properties are updated
629 $this->subject->expects($this->any())->method('getFileInfoByIdentifier')->will($this->returnValue($newProperties));
630 $mockedFile->expects($this->any())->method('getStorage')->will($this->returnValue($this->subject));
631 $mockedFile->expects($this->any())->method('getProperties')->will($this->returnValue(array_keys($fileInfo)));
632 $mockedFile->expects($this->any())->method('getUpdatedProperties')->will($this->returnValue(array_keys($newProperties)));
633 // do not update directly; that's up to the indexer
634 $indexFileRepositoryMock->expects($this->never())->method('update');
635 $this->subject->setFileContents($mockedFile, $this->getUniqueId());
636 }
637
638 /**
639 * @test
640 * @group integration
641 * @TODO: Rewrite or move to functional suite
642 */
643 public function moveFileCallsDriversMethodsWithCorrectArguments()
644 {
645 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
646 $localFilePath = '/path/to/localFile';
647 $sourceFileIdentifier = '/sourceFile.ext';
648 $fileInfoDummy = array(
649 'storage' => 'A',
650 'identifier' => 'B',
651 'mtime' => 'C',
652 'ctime' => 'D',
653 'mimetype' => 'E',
654 'size' => 'F',
655 'name' => 'G',
656 );
657 $this->addToMount(array(
658 'targetFolder' => array()
659 ));
660 $this->initializeVfs();
661 $targetFolder = $this->getSimpleFolderMock('/targetFolder/');
662 /** @var $sourceDriver LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
663 $sourceDriver = $this->createMock(LocalDriver::class);
664 $sourceDriver->expects($this->once())->method('deleteFile')->with($this->equalTo($sourceFileIdentifier));
665 $configuration = $this->convertConfigurationArrayToFlexformXml(array());
666 $sourceStorage = new ResourceStorage($sourceDriver, array('configuration' => $configuration));
667 $sourceFile = $this->getSimpleFileMock($sourceFileIdentifier);
668 $sourceFile->expects($this->once())->method('getForLocalProcessing')->will($this->returnValue($localFilePath));
669 $sourceFile->expects($this->any())->method('getStorage')->will($this->returnValue($sourceStorage));
670 $sourceFile->expects($this->once())->method('getUpdatedProperties')->will($this->returnValue(array_keys($fileInfoDummy)));
671 $sourceFile->expects($this->once())->method('getProperties')->will($this->returnValue($fileInfoDummy));
672 /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject */
673 $mockedDriver = $this->getMockBuilder(LocalDriver::class)
674 ->setConstructorArgs(array(array('basePath' => $this->getMountRootUrl())))
675 ->getMock();
676 $mockedDriver->expects($this->once())->method('getFileInfoByIdentifier')->will($this->returnValue($fileInfoDummy));
677 $mockedDriver->expects($this->once())->method('addFile')->with($localFilePath, '/targetFolder/', $this->equalTo('file.ext'))->will($this->returnValue('/targetFolder/file.ext'));
678 /** @var $subject ResourceStorage */
679 $subject = $this->getMockBuilder(ResourceStorage::class)
680 ->setMethods(array('assureFileMovePermissions'))
681 ->setConstructorArgs(array($mockedDriver, array('configuration' => $configuration)))
682 ->getMock();
683 $subject->moveFile($sourceFile, $targetFolder, 'file.ext');
684 }
685
686 /**
687 * @test
688 * @group integration
689 * @TODO: Rewrite or move to functional suite
690 */
691 public function storageUsesInjectedFilemountsToCheckForMountBoundaries()
692 {
693 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
694 $mockedFile = $this->getSimpleFileMock('/mountFolder/file');
695 $this->addToMount(array(
696 'mountFolder' => array(
697 'file' => 'asdfg'
698 )
699 ));
700 $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
701 $this->initializeVfs();
702 $this->prepareSubject(array(), null, $mockedDriver);
703 $this->subject->addFileMount('/mountFolder');
704 $this->assertEquals(1, count($this->subject->getFileMounts()));
705 $this->subject->isWithinFileMountBoundaries($mockedFile);
706 }
707
708 /**
709 * @test
710 * @TODO: Rewrite or move to functional suite
711 */
712 public function createFolderChecksIfParentFolderExistsBeforeCreatingFolder()
713 {
714 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
715 $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
716 $mockedDriver = $this->createDriverMock(array());
717 $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(true));
718 $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'))->will($this->returnValue($mockedParentFolder));
719 $this->prepareSubject(array(), true);
720 $this->subject->setDriver($mockedDriver);
721 $this->subject->createFolder('newFolder', $mockedParentFolder);
722 }
723
724 /**
725 * @test
726 */
727 public function deleteFolderThrowsExceptionIfFolderIsNotEmptyAndRecursiveDeleteIsDisabled()
728 {
729 $this->expectException(\RuntimeException::class);
730 $this->expectExceptionCode(1325952534);
731
732 /** @var \TYPO3\CMS\Core\Resource\Folder|\PHPUnit_Framework_MockObject_MockObject $folderMock */
733 $folderMock = $this->createMock(Folder::class);
734 /** @var $mockedDriver \TYPO3\CMS\Core\Resource\Driver\AbstractDriver|\PHPUnit_Framework_MockObject_MockObject */
735 $mockedDriver = $this->getMockForAbstractClass(AbstractDriver::class);
736 $mockedDriver->expects($this->once())->method('isFolderEmpty')->will($this->returnValue(false));
737 /** @var $subject ResourceStorage|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface */
738 $subject = $this->getAccessibleMock(ResourceStorage::class, array('checkFolderActionPermission'), array(), '', false);
739 $subject->expects($this->any())->method('checkFolderActionPermission')->will($this->returnValue(true));
740 $subject->_set('driver', $mockedDriver);
741 $subject->deleteFolder($folderMock, false);
742 }
743
744 /**
745 * @test
746 * @TODO: Rewrite or move to functional suite
747 */
748 public function createFolderCallsDriverForFolderCreation()
749 {
750 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
751 $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
752 $this->prepareSubject(array(), true);
753 $mockedDriver = $this->createDriverMock(array(), $this->subject);
754 $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('newFolder'), $this->equalTo('/someFolder/'))->will($this->returnValue(true));
755 $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(true));
756 $this->subject->createFolder('newFolder', $mockedParentFolder);
757 }
758
759 /**
760 * @test
761 * @TODO: Rewrite or move to functional suite
762 */
763 public function createFolderCanRecursivelyCreateFolders()
764 {
765 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
766 $this->addToMount(array('someFolder' => array()));
767 $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
768 $this->prepareSubject(array(), true, $mockedDriver);
769 $parentFolder = $this->subject->getFolder('/someFolder/');
770 $newFolder = $this->subject->createFolder('subFolder/secondSubfolder', $parentFolder);
771 $this->assertEquals('secondSubfolder', $newFolder->getName());
772 $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/'));
773 $this->assertFileExists($this->getUrlInMount('/someFolder/subFolder/secondSubfolder/'));
774 }
775
776 /**
777 * @test
778 * @TODO: Rewrite or move to functional suite
779 */
780 public function createFolderUsesRootFolderAsParentFolderIfNotGiven()
781 {
782 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
783 $this->prepareSubject(array(), true);
784 $mockedDriver = $this->createDriverMock(array(), $this->subject);
785 $mockedDriver->expects($this->once())->method('getRootLevelFolder')->with()->will($this->returnValue('/'));
786 $mockedDriver->expects($this->once())->method('createFolder')->with($this->equalTo('someFolder'));
787 $this->subject->createFolder('someFolder');
788 }
789
790 /**
791 * @test
792 * @TODO: Rewrite or move to functional suite
793 */
794 public function createFolderCreatesNestedStructureEvenIfPartsAlreadyExist()
795 {
796 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
797 $this->addToMount(array(
798 'existingFolder' => array()
799 ));
800 $this->initializeVfs();
801 $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
802 $this->prepareSubject(array(), true, $mockedDriver);
803 $rootFolder = $this->subject->getFolder('/');
804 $newFolder = $this->subject->createFolder('existingFolder/someFolder', $rootFolder);
805 $this->assertEquals('someFolder', $newFolder->getName());
806 $this->assertFileExists($this->getUrlInMount('existingFolder/someFolder'));
807 }
808
809 /**
810 * @test
811 */
812 public function createFolderThrowsExceptionIfParentFolderDoesNotExist()
813 {
814 $this->expectException(\InvalidArgumentException::class);
815 $this->expectExceptionCode(1325689164);
816 $mockedParentFolder = $this->getSimpleFolderMock('/someFolder/');
817 $this->prepareSubject(array(), true);
818 $mockedDriver = $this->createDriverMock(array(), $this->subject);
819 $mockedDriver->expects($this->once())->method('folderExists')->with($this->equalTo('/someFolder/'))->will($this->returnValue(false));
820 $this->subject->createFolder('newFolder', $mockedParentFolder);
821 }
822
823 /**
824 * @test
825 */
826 public function replaceFileFailsIfLocalFileDoesNotExist()
827 {
828 $this->expectException(\InvalidArgumentException::class);
829 $this->expectExceptionCode(1325842622);
830 $this->prepareSubject(array(), true);
831 $mockedFile = $this->getSimpleFileMock('/someFile');
832 $this->subject->replaceFile($mockedFile, PATH_site . $this->getUniqueId());
833 }
834
835 /**
836 * @test
837 * @TODO: Rewrite or move to functional suite
838 */
839 public function getRoleReturnsDefaultForRegularFolders()
840 {
841 $this->markTestSkipped('This test does way to much and is mocked incomplete. Skipped for now.');
842 $folderIdentifier = $this->getUniqueId();
843 $this->addToMount(array(
844 $folderIdentifier => array()
845 ));
846 $this->prepareSubject(array());
847
848 $role = $this->subject->getRole($this->getSimpleFolderMock('/' . $folderIdentifier . '/'));
849
850 $this->assertSame(FolderInterface::ROLE_DEFAULT, $role);
851 }
852
853 /**
854 * @test
855 */
856 public function getProcessingRootFolderTest()
857 {
858 $this->prepareSubject(array());
859 $processingFolder = $this->subject->getProcessingFolder();
860
861 $this->assertInstanceOf(Folder::class, $processingFolder);
862 }
863
864 /**
865 * @test
866 */
867 public function getNestedProcessingFolderTest()
868 {
869 $mockedDriver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), null, null);
870 $this->prepareSubject(array(), true, $mockedDriver);
871 $mockedFile = $this->getSimpleFileMock('/someFile');
872
873 $rootProcessingFolder = $this->subject->getProcessingFolder();
874 $processingFolder = $this->subject->getProcessingFolder($mockedFile);
875
876 $this->assertInstanceOf(Folder::class, $processingFolder);
877 $this->assertNotEquals($rootProcessingFolder, $processingFolder);
878
879 for ($i = ResourceStorage::PROCESSING_FOLDER_LEVELS; $i>0; $i--) {
880 $processingFolder = $processingFolder->getParentFolder();
881 }
882 $this->assertEquals($rootProcessingFolder, $processingFolder);
883 }
884 }