[!!!][TASK] Driver API has too many crosscutting concerns
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Resource / Driver / LocalDriverTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Resource\Driver;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2011-2013 Andreas Wolf <andreas.wolf@ikt-werk.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Core\Utility\GeneralUtility;
31 use \org\bovigo\vfs\vfsStream;
32 use \org\bovigo\vfs\vfsStreamWrapper;
33
34 /**
35 * Testcase for the local storage driver class of the TYPO3 VFS
36 *
37 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
38 */
39 class LocalDriverTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
40
41 /**
42 * @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver
43 */
44 protected $localDriver = NULL;
45
46 /**
47 * @var array A backup of registered singleton instances
48 */
49 protected $singletonInstances = array();
50
51 /**
52 * @var array
53 */
54 static private $testDirs = array();
55
56
57 static public function tearDownAfterClass() {
58 foreach (self::$testDirs as $dir) {
59 chmod($dir, 0777);
60 \TYPO3\CMS\Core\Utility\GeneralUtility::rmdir($dir, TRUE);
61 }
62 }
63
64 /**
65 * Creates a "real" directory for doing tests. This is neccessary because some file system properties (e.g. permissions)
66 * cannot be reflected by vfsStream, and some methods (like touch()) don't work there either.
67 *
68 * Created directories are automatically destroyed by the tearDownAfterClass() method.
69 *
70 * @return string
71 */
72 protected function createRealTestdir() {
73 $basedir = PATH_site . 'typo3temp/' . uniqid('fal-test-');
74 mkdir($basedir);
75 self::$testDirs[] = $basedir;
76 return $basedir;
77 }
78
79 /**
80 * Create a "real" directory together with a driverFixture configured
81 * for this directory.
82 *
83 * @return array With path to base directory and driver fixture
84 */
85 protected function prepareRealTestEnvironment() {
86 $basedir = $this->createRealTestdir();
87 $fixture = $this->createDriverFixture(array(
88 'basePath' => $basedir
89 ));
90 return array($basedir, $fixture);
91 }
92
93 /**
94 * Creates a driver fixture object, optionally using a given mount object.
95 *
96 * IMPORTANT: Call this only after setting up the virtual file system (with the addTo* methods)!
97 *
98 * @param array $driverConfiguration
99 * @param array $mockedDriverMethods
100 * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver
101 */
102 protected function createDriverFixture($driverConfiguration = array(), $mockedDriverMethods = array()) {
103 // it's important to do that here, so vfsContents could have been set before
104 if (!isset($driverConfiguration['basePath'])) {
105 $this->initializeVfs();
106 $driverConfiguration['basePath'] = $this->getMountRootUrl();
107 }
108 /** @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver $driver */
109 $mockedDriverMethods[] = 'isPathValid';
110 $driver = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', $mockedDriverMethods, array($driverConfiguration));
111 $driver->expects($this->any())
112 ->method('isPathValid')
113 ->will(
114 $this->returnValue(TRUE)
115 );
116
117 $driver->setStorageUid(5);
118 $driver->processConfiguration();
119 $driver->initialize();
120 return $driver;
121 }
122
123 /**
124 * @test
125 */
126 public function getDefaultFolderReturnsFolderForUserUploadPath() {
127 $fixture = $this->createDriverFixture();
128 $folderIdentifier = $fixture->getDefaultFolder();
129 $this->assertEquals('/user_upload/', $folderIdentifier);
130 }
131
132 /**
133 * @test
134 */
135 public function defaultLevelFolderFolderIsCreatedIfItDoesntExist() {
136 $fixture = $this->createDriverFixture();
137 $this->assertFileExists($this->getUrlInMount($fixture->getDefaultFolder()));
138 }
139
140 /**
141 * @test
142 */
143 public function getFolderInFolderReturnsCorrectFolderObject() {
144 $this->addToMount(array(
145 'someDir' => array(
146 'someSubdir' => array()
147 )
148 ));
149 $fixture = $this->createDriverFixture();
150 $folder = $fixture->getFolderInFolder('someSubdir', '/someDir/');
151 $this->assertEquals('/someDir/someSubdir/', $folder);
152 }
153
154 /**
155 * @test
156 */
157 public function createFolderCreatesFolderOnDisk() {
158 $this->addToMount(array('some' => array('folder' => array())));
159 $fixture = $this->createDriverFixture();
160 $fixture->createFolder('path', '/some/folder/');
161 $this->assertFileExists($this->getUrlInMount('/some/folder/'));
162 $this->assertFileExists($this->getUrlInMount('/some/folder/path'));
163 }
164
165 /**
166 * @test
167 */
168 public function createFolderReturnsFolderObject() {
169 $this->addToMount(array('some' => array('folder' => array())));
170 $fixture = $this->createDriverFixture();
171 $createdFolder = $fixture->createFolder('path', '/some/folder/');
172 $this->assertEquals('/some/folder/path/', $createdFolder);
173 }
174
175 public static function createFolderSanitizesFolderNameBeforeCreationDataProvider() {
176 return array(
177 'folder name with NULL character' => array(
178 'some' . chr(0) . 'Folder',
179 'some_Folder'
180 ),
181 'folder name with directory part' => array(
182 '../someFolder',
183 '.._someFolder'
184 )
185 );
186 }
187
188 /**
189 * @test
190 * @dataProvider createFolderSanitizesFolderNameBeforeCreationDataProvider
191 */
192 public function createFolderSanitizesFolderNameBeforeCreation($newFolderName, $expectedFolderName) {
193 $this->addToMount(array('some' => array('folder' => array())));
194 $fixture = $this->createDriverFixture();
195 $fixture->createFolder($newFolderName, '/some/folder/');
196 $this->assertFileExists($this->getUrlInMount('/some/folder/' . $expectedFolderName));
197 }
198
199 /**
200 * @test
201 */
202 public function basePathIsNormalizedWithTrailingSlash() {
203 $fixture = $this->createDriverFixture();
204 $this->assertEquals('/', substr($fixture->_call('getAbsoluteBasePath'), -1));
205 }
206
207 /**
208 * @test
209 */
210 public function noSecondSlashIsAddedIfBasePathAlreadyHasTrailingSlash() {
211 $fixture = $this->createDriverFixture();
212 $this->assertNotEquals('/', substr($fixture->_call('getAbsoluteBasePath'), -2, 1));
213 }
214
215 /**
216 * @test
217 */
218 public function getAbsolutePathReturnsCorrectPath() {
219 $this->addToMount(array(
220 'someFolder' => array(
221 'file1.ext' => 'asdfg'
222 )
223 ));
224 $fixture = $this->createDriverFixture();
225 $path = $fixture->_call('getAbsolutePath', '/someFolder/file1.ext');
226 $this->assertTrue(file_exists($path));
227 $this->assertEquals($this->getUrlInMount('/someFolder/file1.ext'), $path);
228 }
229
230 /**
231 * @test
232 */
233 public function addFileMovesFileToCorrectLocation() {
234 $this->addToMount(array('targetFolder' => array()));
235 $this->addToVfs(array(
236 'sourceFolder' => array(
237 'file' => 'asdf'
238 )
239 ));
240 $fixture = $this->createDriverFixture(
241 array(),
242 array('getMimeTypeOfFile')
243 );
244 $this->assertTrue(file_exists($this->getUrl('sourceFolder/file')));
245 $fixture->addFile($this->getUrl('sourceFolder/file'), '/targetFolder/', 'file');
246 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/file')));
247 }
248
249 /**
250 * @test
251 */
252 public function addFileUsesFilenameIfGiven() {
253 $this->addToMount(array('targetFolder' => array()));
254 $this->addToVfs(array(
255 'sourceFolder' => array(
256 'file' => 'asdf'
257 )
258 ));
259 $fixture = $this->createDriverFixture(
260 array(),
261 array('getMimeTypeOfFile')
262 );
263 $this->assertTrue(file_exists($this->getUrl('sourceFolder/file')));
264 $fixture->addFile($this->getUrl('sourceFolder/file'), '/targetFolder/', 'targetFile');
265 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/targetFile')));
266 }
267
268 /**
269 * @test
270 */
271 public function addFileFailsIfFileIsInDriverStorage() {
272 $this->setExpectedException('InvalidArgumentException', '', 1314778269);
273 $this->addToMount(array(
274 'targetFolder' => array(
275 'file' => 'asdf'
276 )
277 ));
278 $fixture = $this->createDriverFixture();
279 $fixture->addFile($this->getUrlInMount('/targetFolder/file'), '/targetFolder/', 'file');
280 }
281
282 /**
283 * @test
284 */
285 public function addFileReturnsFileIdentifier() {
286 $this->addToMount(array('targetFolder' => array()));
287 $this->addToVfs(array(
288 'sourceFolder' => array(
289 'file' => 'asdf'
290 )
291 ));
292 $fixture = $this->createDriverFixture(
293 array(),
294 array('getMimeTypeOfFile')
295 );
296 $this->assertTrue(file_exists($this->getUrl('sourceFolder/file')));
297 $fileIdentifier = $fixture->addFile($this->getUrl('sourceFolder/file'), '/targetFolder/', 'file');
298 $this->assertEquals('file', basename($fileIdentifier));
299 $this->assertEquals('/targetFolder/file', $fileIdentifier);
300 }
301
302 /**
303 * @test
304 */
305 public function existenceChecksWorkForFilesAndFolders() {
306 $this->addToMount(array(
307 'file' => 'asdf',
308 'folder' => array()
309 ));
310 $fixture = $this->createDriverFixture();
311 // Using slashes at the beginning of paths because they will be stored in the DB this way.
312 $this->assertTrue($fixture->fileExists('/file'));
313 $this->assertTrue($fixture->folderExists('/folder/'));
314 $this->assertFalse($fixture->fileExists('/nonexistingFile'));
315 $this->assertFalse($fixture->folderExists('/nonexistingFolder/'));
316 }
317
318 /**
319 * @test
320 */
321 public function existenceChecksInFolderWorkForFilesAndFolders() {
322 $this->addToMount(array(
323 'subfolder' => array(
324 'file' => 'asdf',
325 'folder' => array()
326 )
327 ));
328 $fixture = $this->createDriverFixture();
329 $this->assertTrue($fixture->fileExistsInFolder('file', '/subfolder/'));
330 $this->assertTrue($fixture->folderExistsInFolder('folder', '/subfolder/'));
331 $this->assertFalse($fixture->fileExistsInFolder('nonexistingFile', '/subfolder/'));
332 $this->assertFalse($fixture->folderExistsInFolder('nonexistingFolder', '/subfolder/'));
333 }
334
335 /**
336 * @test
337 */
338 public function getPublicUrlReturnsCorrectUriForConfiguredBaseUri() {
339 $baseUri = 'http://example.org/foobar/' . uniqid();
340 $this->addToMount(array(
341 'file.ext' => 'asdf',
342 'subfolder' => array(
343 'file2.ext' => 'asdf'
344 )
345 ));
346 $fixture = $this->createDriverFixture(array(
347 'baseUri' => $baseUri
348 ));
349 $this->assertEquals($baseUri . '/file.ext', $fixture->getPublicUrl('/file.ext'));
350 $this->assertEquals($baseUri . '/subfolder/file2.ext', $fixture->getPublicUrl('/subfolder/file2.ext'));
351 }
352
353 /**
354 * @test
355 */
356 public function fileContentsCanBeWrittenAndRead() {
357 $fileContents = 'asdf';
358 $this->addToMount(array(
359 'file.ext' => $fileContents
360 ));
361 $fixture = $this->createDriverFixture();
362 $this->assertEquals($fileContents, $fixture->getFileContents('/file.ext'), 'File contents could not be read');
363 $newFileContents = 'asdfgh';
364 $fixture->setFileContents('/file.ext', $newFileContents);
365 $this->assertEquals($newFileContents, $fixture->getFileContents('/file.ext'), 'New file contents could not be read.');
366 }
367
368 /**
369 * @test
370 */
371 public function setFileContentsReturnsNumberOfBytesWrittenToFile() {
372 $fileContents = 'asdf';
373 $this->addToMount(array(
374 'file.ext' => $fileContents
375 ));
376 $fixture = $this->createDriverFixture();
377 $newFileContents = 'asdfgh';
378 $bytesWritten = $fixture->setFileContents('/file.ext', $newFileContents);
379 $this->assertEquals(strlen($newFileContents), $bytesWritten);
380 }
381
382 /**
383 * @test
384 */
385 public function newFilesCanBeCreated() {
386 $fixture = $this->createDriverFixture();
387 $fixture->createFile('testfile.txt', '/');
388 $this->assertTrue($fixture->fileExists('/testfile.txt'));
389 }
390
391 /**
392 * @test
393 *
394 */
395 public function createdFilesAreEmpty() {
396 $fixture = $this->createDriverFixture();
397 $fixture->createFile('testfile.txt', '/');
398 $this->assertTrue($fixture->fileExists('/testfile.txt'));
399 $fileData = $fixture->getFileContents('/testfile.txt');
400 $this->assertEquals(0, strlen($fileData));
401 }
402
403 /**
404 * @test
405 */
406 public function createFileFixesPermissionsOnCreatedFile() {
407 if (TYPO3_OS == 'WIN') {
408 $this->markTestSkipped('createdFilesHaveCorrectRights() tests not available on Windows');
409 }
410
411 // No one will use this as his default file create mask so we hopefully don't get any false positives
412 $testpattern = '0646';
413 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = $testpattern;
414
415 $this->addToMount(
416 array(
417 'someDir' => array()
418 )
419 );
420 /** @var $fixture \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
421 list($basedir, $fixture) = $this->prepareRealTestEnvironment();
422 mkdir($basedir . '/someDir');
423 $fixture->createFile('testfile.txt', '/someDir');
424 $this->assertEquals($testpattern, decoct(fileperms($basedir . '/someDir/testfile.txt') & 0777));
425 }
426
427 /**********************************
428 * File and directory listing
429 **********************************/
430 /**
431 * @test
432 */
433 public function getFileReturnsCorrectIdentifier() {
434 $this->addToMount(array(
435 'someDir' => array(
436 'someFile' => 'asdfg'
437 ),
438 'someFileAtRootLevel' => 'foobar'
439 ));
440 $fixture = $this->createDriverFixture(
441 array(),
442 array('getMimeTypeOfFile')
443 );
444 $subdirFileInfo = $fixture->getFileInfoByIdentifier('/someDir/someFile');
445 $this->assertEquals('/someDir/someFile', $subdirFileInfo['identifier']);
446 $rootFileInfo = $fixture->getFileInfoByIdentifier('/someFileAtRootLevel');
447 $this->assertEquals('/someFileAtRootLevel', $rootFileInfo['identifier']);
448 }
449
450 /**
451 * @test
452 */
453 public function getFileThrowsExceptionIfFileDoesNotExist() {
454 $this->setExpectedException('InvalidArgumentException', '', 1314516809);
455 $fixture = $this->createDriverFixture();
456 $fixture->getFileInfoByIdentifier('/some/file/at/a/random/path');
457 }
458
459 /**
460 * @test
461 */
462 public function getFilesInFolderReturnsEmptyArrayForEmptyDirectory() {
463 $fixture = $this->createDriverFixture();
464 $fileList = $fixture->getFilesInFolder('/');
465 $this->assertEmpty($fileList);
466 }
467
468 /**
469 * @test
470 */
471 public function getFileListReturnsAllFilesInDirectory() {
472 $dirStructure = array(
473 'aDir' => array(),
474 'file1' => 'asdfg',
475 'file2' => 'fdsa'
476 );
477 $this->addToMount($dirStructure);
478 $fixture = $this->createDriverFixture(
479 array(),
480 // Mocked because finfo() can not deal with vfs streams and throws warnings
481 array('getMimeTypeOfFile')
482 );
483 $fileList = $fixture->getFilesInFolder('/');
484 $this->assertEquals(array('/file1', '/file2'), array_keys($fileList));
485 }
486
487 /**
488 * @test
489 */
490 public function getFileListReturnsAllFilesInSubdirectoryIfRecursiveParameterIsSet() {
491 $dirStructure = array(
492 'aDir' => array(
493 'file3' => 'asdfgh',
494 'subdir' => array(
495 'file4' => 'asklfjklasjkl'
496 )
497 ),
498 'file1' => 'asdfg',
499 'file2' => 'fdsa'
500 );
501 $this->addToMount($dirStructure);
502 $fixture = $this->createDriverFixture(
503 array(),
504 // Mocked because finfo() can not deal with vfs streams and throws warnings
505 array('getMimeTypeOfFile')
506 );
507 $fileList = $fixture->getFilesInFolder('/', 0, 0, TRUE);
508 $this->assertEquals(array('/aDir/subdir/file4', '/aDir/file3', '/file1', '/file2'), array_keys($fileList));
509 }
510
511 /**
512 * @test
513 */
514 public function getFileListFailsIfDirectoryDoesNotExist() {
515 $this->setExpectedException('InvalidArgumentException', '', 1314349666);
516 $this->addToMount(array('somefile' => ''));
517 $fixture = $this->createDriverFixture();
518 $fixture->getFilesInFolder('somedir/');
519 }
520
521 /**
522 * @test
523 */
524 public function getFileInFolderCallsConfiguredCallbackFunctionWithGivenItemName() {
525 $dirStructure = array(
526 'file2' => 'fdsa'
527 );
528 // register static callback to self
529 $callback = array(
530 array(
531 get_class($this),
532 'callbackStaticTestFunction'
533 )
534 );
535 $this->addToMount($dirStructure);
536 $fixture = $this->createDriverFixture();
537 // the callback function will throw an exception used to check if it was called with correct $itemName
538 $this->setExpectedException('InvalidArgumentException', '$itemName', 1336159604);
539 $fixture->getFilesInFolder('/', 0, 0, FALSE, $callback);
540 }
541
542 /**
543 * Static callback function used to test if the filter callbacks work
544 * As it is static we are using an exception to test if it is really called and works
545 *
546 * @static
547 * @throws \InvalidArgumentException
548 * @see getFileListCallsConfiguredCallbackFunction
549 */
550 static public function callbackStaticTestFunction() {
551 list($itemName) = func_get_args();
552 if ($itemName === 'file2') {
553 throw new \InvalidArgumentException('$itemName', 1336159604);
554 }
555 }
556
557 /**
558 * @test
559 */
560 public function getFileListFiltersItemsWithGivenFilterMethods() {
561 $dirStructure = array(
562 'fileA' => 'asdfg',
563 'fileB' => 'fdsa'
564 );
565 $this->addToMount($dirStructure);
566 $fixture = $this->createDriverFixture(
567 array(),
568 // Mocked because finfo() can not deal with vfs streams and throws warnings
569 array('getMimeTypeOfFile')
570 );
571 $filterCallbacks = array(
572 array(
573 'TYPO3\CMS\Core\Tests\Unit\Resource\Driver\Fixtures\LocalDriverFilenameFilter',
574 'filterFilename',
575 ),
576 );
577 $fileList = $fixture->getFilesInFolder('/', 0, 0, FALSE, $filterCallbacks);
578 $this->assertNotContains('/fileA', array_keys($fileList));
579 }
580
581 /**
582 * @test
583 */
584 public function getFolderListReturnsAllDirectoriesInDirectory() {
585 $dirStructure = array(
586 'dir1' => array(),
587 'dir2' => array(),
588 'file' => 'asdfg'
589 );
590 $this->addToMount($dirStructure);
591 $fixture = $this->createDriverFixture();
592 $fileList = $fixture->getFoldersInFolder('/');
593 $this->assertEquals(array('/dir1/', '/dir2/'), array_keys($fileList));
594 }
595
596 /**
597 * @test
598 */
599 public function getFolderListReturnsHiddenFoldersByDefault() {
600 $dirStructure = array(
601 '.someHiddenDir' => array(),
602 'aDir' => array(),
603 'file1' => ''
604 );
605 $this->addToMount($dirStructure);
606 $fixture = $this->createDriverFixture();
607
608 $fileList = $fixture->getFoldersInFolder('/');
609
610 $this->assertEquals(array('/.someHiddenDir/', '/aDir/'), array_keys($fileList));
611 }
612
613 /**
614 * Checks if the folder names . and .. are ignored when listing subdirectories
615 *
616 * @test
617 */
618 public function getFolderListLeavesOutNavigationalEntries() {
619 // we have to add .. and . manually, as these are not included in vfsStream directory listings (as opposed
620 // to normal file listings)
621 $this->addToMount(array(
622 '..' => array(),
623 '.' => array()
624 ));
625 $fixture = $this->createDriverFixture();
626 $fileList = $fixture->getFoldersInFolder('/');
627 $this->assertEmpty($fileList);
628 }
629
630 /**
631 * @test
632 */
633 public function getFolderListFiltersItemsWithGivenFilterMethods() {
634 $dirStructure = array(
635 'folderA' => array(),
636 'folderB' => array()
637 );
638 $this->addToMount($dirStructure);
639 $fixture = $this->createDriverFixture();
640 $filterCallbacks = array(
641 array(
642 'TYPO3\CMS\Core\Tests\Unit\Resource\Driver\Fixtures\LocalDriverFilenameFilter',
643 'filterFilename',
644 ),
645 );
646 $folderList = $fixture->getFoldersInFolder('/', 0, 0, $filterCallbacks);
647 $this->assertNotContains('folderA', array_keys($folderList));
648 }
649
650 /**
651 * @test
652 */
653 public function getFolderListFailsIfDirectoryDoesNotExist() {
654 $this->setExpectedException('InvalidArgumentException', '', 1314349666);
655 $fixture = $this->createDriverFixture();
656 vfsStream::create(array($this->basedir => array('somefile' => '')));
657 $fixture->getFoldersInFolder('somedir/');
658 }
659
660 /**
661 * @test
662 */
663 public function hashReturnsCorrectHashes() {
664 $contents = '68b329da9893e34099c7d8ad5cb9c940';
665 $expectedMd5Hash = '8c67dbaf0ba22f2e7fbc26413b86051b';
666 $expectedSha1Hash = 'a60cd808ba7a0bcfa37fa7f3fb5998e1b8dbcd9d';
667 $this->addToMount(array('hashFile' => $contents));
668 $fixture = $this->createDriverFixture();
669 $this->assertEquals($expectedSha1Hash, $fixture->hash('/hashFile', 'sha1'));
670 $this->assertEquals($expectedMd5Hash, $fixture->hash('/hashFile', 'md5'));
671 }
672
673 /**
674 * @test
675 */
676 public function hashingWithUnsupportedAlgorithmFails() {
677 $this->setExpectedException('InvalidArgumentException', '', 1304964032);
678 $fixture = $this->createDriverFixture();
679 $fixture->hash('/hashFile', uniqid());
680 }
681
682 /**
683 * @test
684 * @covers TYPO3\CMS\Core\Resource\Driver\LocalDriver::getFileForLocalProcessing
685 */
686 public function getFileForLocalProcessingCreatesCopyOfFileByDefault() {
687 $fileContents = 'asdfgh';
688 $this->addToMount(array(
689 'someDir' => array(
690 'someFile' => $fileContents
691 )
692 ));
693 $fixture = $this->createDriverFixture(array(), array('copyFileToTemporaryPath'));
694 $fixture->expects($this->once())->method('copyFileToTemporaryPath');
695 $fixture->getFileForLocalProcessing('/someDir/someFile');
696 }
697
698 /**
699 * @test
700 */
701 public function getFileForLocalProcessingReturnsOriginalFilepathForReadonlyAccess() {
702 $fileContents = 'asdfgh';
703 $this->addToMount(array(
704 'someDir' => array(
705 'someFile' => $fileContents
706 )
707 ));
708 $fixture = $this->createDriverFixture();
709 $filePath = $fixture->getFileForLocalProcessing('/someDir/someFile', FALSE);
710 $this->assertEquals($filePath, $this->getUrlInMount('someDir/someFile'));
711 }
712
713 /**
714 * @test
715 */
716 public function filesCanBeCopiedToATemporaryPath() {
717 $fileContents = 'asdfgh';
718 $this->addToMount(array(
719 'someDir' => array(
720 'someFile' => $fileContents
721 )
722 ));
723 $fixture = $this->createDriverFixture();
724 $filePath = GeneralUtility::fixWindowsFilePath($fixture->_call('copyFileToTemporaryPath', '/someDir/someFile'));
725 $this->assertContains('/typo3temp/', $filePath);
726 $this->assertEquals($fileContents, file_get_contents($filePath));
727 }
728
729 /**
730 * @test
731 */
732 public function permissionsAreCorrectlyRetrievedForAllowedFile() {
733 /** @var $fixture \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
734 list($basedir, $fixture) = $this->prepareRealTestEnvironment();
735 touch($basedir . '/someFile');
736 chmod($basedir . '/someFile', 448);
737 clearstatcache();
738 $this->assertEquals(array('r' => TRUE, 'w' => TRUE), $fixture->getPermissions('/someFile'));
739 }
740
741 /**
742 * @test
743 */
744 public function permissionsAreCorrectlyRetrievedForForbiddenFile() {
745 if (function_exists('posix_getegid') && posix_getegid() === 0) {
746 $this->markTestSkipped('Test skipped if run on linux as root');
747 } elseif (TYPO3_OS === 'WIN') {
748 $this->markTestSkipped('Test skipped if run on Windows system');
749 }
750 /** @var $fixture \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
751 list($basedir, $fixture) = $this->prepareRealTestEnvironment();
752 touch($basedir . '/someForbiddenFile');
753 chmod($basedir . '/someForbiddenFile', 0);
754 clearstatcache();
755 $this->assertEquals(array('r' => FALSE, 'w' => FALSE), $fixture->getPermissions('/someForbiddenFile'));
756 }
757
758 /**
759 * @test
760 */
761 public function permissionsAreCorrectlyRetrievedForAllowedFolder() {
762 /** @var $fixture \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
763 list($basedir, $fixture) = $this->prepareRealTestEnvironment();
764 mkdir($basedir . '/someFolder');
765 chmod($basedir . '/someFolder', 448);
766 clearstatcache();
767 $this->assertEquals(array('r' => TRUE, 'w' => TRUE), $fixture->getPermissions('/someFolder'));
768 }
769
770 /**
771 * @test
772 */
773 public function permissionsAreCorrectlyRetrievedForForbiddenFolder() {
774 if (function_exists('posix_getegid') && posix_getegid() === 0) {
775 $this->markTestSkipped('Test skipped if run on linux as root');
776 } elseif (TYPO3_OS === 'WIN') {
777 $this->markTestSkipped('Test skipped if run on Windows system');
778 }
779 /** @var $fixture \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
780 list($basedir, $fixture) = $this->prepareRealTestEnvironment();
781 mkdir($basedir . '/someForbiddenFolder');
782 chmod($basedir . '/someForbiddenFolder', 0);
783 clearstatcache();
784 $result = $fixture->getPermissions('/someForbiddenFolder');
785 // Change permissions back to writable, so the sub-folder can be removed in tearDown
786 chmod($basedir . '/someForbiddenFolder', 0777);
787 $this->assertEquals(array('r' => FALSE, 'w' => FALSE), $result);
788 }
789
790 /**
791 * Dataprovider for getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser test
792 *
793 * @return array group, filemode and expected result
794 */
795 public function getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser_dataProvider() {
796 $data = array();
797 // On some OS, the posix_* functions do not exits
798 if (function_exists('posix_getgid')) {
799 $data = array(
800 'current group, readable/writable' => array(
801 posix_getgid(),
802 48,
803 array('r' => TRUE, 'w' => TRUE)
804 ),
805 'current group, readable/not writable' => array(
806 posix_getgid(),
807 32,
808 array('r' => TRUE, 'w' => FALSE)
809 ),
810 'current group, not readable/not writable' => array(
811 posix_getgid(),
812 0,
813 array('r' => FALSE, 'w' => FALSE)
814 )
815 );
816 }
817 $data = array_merge_recursive($data, array(
818 'arbitrary group, readable/writable' => array(
819 vfsStream::GROUP_USER_1,
820 6,
821 array('r' => TRUE, 'w' => TRUE)
822 ),
823 'arbitrary group, readable/not writable' => array(
824 vfsStream::GROUP_USER_1,
825 436,
826 array('r' => TRUE, 'w' => FALSE)
827 ),
828 'arbitrary group, not readable/not writable' => array(
829 vfsStream::GROUP_USER_1,
830 432,
831 array('r' => FALSE, 'w' => FALSE)
832 )
833 ));
834 return $data;
835 }
836
837 /**
838 * @test
839 * @dataProvider getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser_dataProvider
840 */
841 public function getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser($group, $permissions, $expectedResult) {
842 if (TYPO3_OS === 'WIN') {
843 $this->markTestSkipped('Test skipped if run on Windows system');
844 }
845 $this->addToMount(array(
846 'testfile' => 'asdfg'
847 ));
848 $fixture = $this->createDriverFixture();
849 /** @var $fileObject vfsStreamContent */
850 $fileObject = vfsStreamWrapper::getRoot()->getChild($this->mountDir)->getChild('testfile');
851 // just use an "arbitrary" user here - it is only important that
852 $fileObject->chown(vfsStream::OWNER_USER_1);
853 $fileObject->chgrp($group);
854 $fileObject->chmod($permissions);
855 $this->assertEquals($expectedResult, $fixture->getPermissions('/testfile'));
856 }
857
858 /**
859 * @test
860 */
861 public function isWithinRecognizesFilesWithinFolderAndInOtherFolders() {
862 $fixture = $this->createDriverFixture();
863 $this->assertTrue($fixture->isWithin('/someFolder/', '/someFolder/test.jpg'));
864 $this->assertTrue($fixture->isWithin('/someFolder/', '/someFolder/subFolder/test.jpg'));
865 $this->assertFalse($fixture->isWithin('/someFolder/', '/someFolderWithALongName/test.jpg'));
866 }
867
868 /**
869 * @test
870 */
871 public function isWithinAcceptsFileAndFolderObjectsAsContent() {
872 $fixture = $this->createDriverFixture();
873 $this->assertTrue($fixture->isWithin('/someFolder/', '/someFolder/test.jpg'));
874 $this->assertTrue($fixture->isWithin('/someFolder/', '/someFolder/subfolder/'));
875 }
876
877 /**********************************
878 * Copy/move file
879 **********************************/
880
881 /**
882 * @test
883 */
884 public function filesCanBeCopiedWithinStorage() {
885 $fileContents = uniqid();
886 $this->addToMount(array(
887 'someFile' => $fileContents,
888 'targetFolder' => array()
889 ));
890 $fixture = $this->createDriverFixture(
891 array(),
892 array('getMimeTypeOfFile')
893 );
894 $fixture->copyFileWithinStorage('/someFile', '/targetFolder/', 'someFile');
895 $this->assertFileEquals($this->getUrlInMount('/someFile'), $this->getUrlInMount('/targetFolder/someFile'));
896 }
897
898 /**
899 * @test
900 */
901 public function filesCanBeMovedWithinStorage() {
902 $fileContents = uniqid();
903 $this->addToMount(array(
904 'targetFolder' => array(),
905 'someFile' => $fileContents
906 ));
907 $fixture = $this->createDriverFixture();
908 $newIdentifier = $fixture->moveFileWithinStorage('/someFile', '/targetFolder/', 'file');
909 $this->assertEquals($fileContents, file_get_contents($this->getUrlInMount('/targetFolder/file')));
910 $this->assertFileNotExists($this->getUrlInMount('/someFile'));
911 $this->assertEquals('/targetFolder/file', $newIdentifier);
912 }
913
914 /**
915 * @test
916 */
917 public function fileMetadataIsChangedAfterMovingFile() {
918 $fileContents = uniqid();
919 $this->addToMount(array(
920 'targetFolder' => array(),
921 'someFile' => $fileContents
922 ));
923 $fixture = $this->createDriverFixture(
924 array(),
925 // Mocked because finfo() can not deal with vfs streams and throws warnings
926 array('getMimeTypeOfFile')
927 );
928 $newIdentifier = $fixture->moveFileWithinStorage('/someFile', '/targetFolder/', 'file');
929 $fileMetadata = $fixture->getFileInfoByIdentifier($newIdentifier);
930 $this->assertEquals($newIdentifier, $fileMetadata['identifier']);
931 }
932
933 public function renamingFiles_dataProvider() {
934 return array(
935 'file in subfolder' => array(
936 array(
937 'targetFolder' => array('file' => '')
938 ),
939 '/targetFolder/file',
940 'newFile',
941 '/targetFolder/newFile'
942 ),
943 'file in rootfolder' => array(
944 array(
945 'fileInRoot' => ''
946 ),
947 '/fileInRoot',
948 'newFile',
949 '/newFile'
950 )
951 );
952 }
953
954 /**
955 * @test
956 * @dataProvider renamingFiles_dataProvider
957 */
958 public function renamingFilesChangesFilenameOnDisk(array $filesystemStructure, $oldFileIdentifier, $newFileName, $expectedNewIdentifier) {
959 $this->addToMount($filesystemStructure);
960 $fixture = $this->createDriverFixture();
961 $newIdentifier = $fixture->renameFile($oldFileIdentifier, $newFileName);
962 $this->assertFalse($fixture->fileExists($oldFileIdentifier));
963 $this->assertTrue($fixture->fileExists($newIdentifier));
964 $this->assertEquals($expectedNewIdentifier, $newIdentifier);
965 }
966
967 /**
968 * @test
969 */
970 public function renamingFilesFailsIfTargetFileExists() {
971 $this->setExpectedException('TYPO3\\CMS\\Core\\Resource\\Exception\\ExistingTargetFileNameException', '', 1320291063);
972 $this->addToMount(array(
973 'targetFolder' => array('file' => '', 'newFile' => '')
974 ));
975 $fixture = $this->createDriverFixture();
976 $fixture->renameFile('/targetFolder/file', 'newFile');
977 }
978
979 /**
980 * We use this data provider for testing move methods because there are some issues with the
981 *
982 * @return array
983 */
984 public function renamingFolders_dataProvider() {
985 return array(
986 'folder in root folder' => array(
987 array(
988 'someFolder' => array()
989 ),
990 '/someFolder/',
991 'newFolder',
992 '/newFolder/'
993 ),
994 'file in subfolder' => array(
995 array(
996 'subfolder' => array(
997 'someFolder' => array()
998 )
999 ),
1000 '/subfolder/someFolder/',
1001 'newFolder',
1002 '/subfolder/newFolder/'
1003 )
1004 );
1005 }
1006
1007 /**
1008 * @test
1009 * @dataProvider renamingFolders_dataProvider
1010 */
1011 public function renamingFoldersChangesFolderNameOnDisk(array $filesystemStructure, $oldFolderIdentifier, $newFolderName, $expectedNewIdentifier) {
1012 $this->addToMount($filesystemStructure);
1013 $fixture = $this->createDriverFixture();
1014 $mapping = $fixture->renameFolder($oldFolderIdentifier, $newFolderName);
1015 $this->assertFalse($fixture->folderExists($oldFolderIdentifier));
1016 $this->assertTrue($fixture->folderExists($expectedNewIdentifier));
1017 $this->assertEquals($expectedNewIdentifier, $mapping[$oldFolderIdentifier]);
1018 }
1019
1020 /**
1021 * @test
1022 */
1023 public function renameFolderReturnsCorrectMappingInformationForAllFiles() {
1024 $fileContents = 'asdfg';
1025 $this->addToMount(array(
1026 'sourceFolder' => array(
1027 'subFolder' => array('file' => $fileContents),
1028 'file2' => 'asdfg'
1029 )
1030 ));
1031 $fixture = $this->createDriverFixture();
1032 $mappingInformation = $fixture->renameFolder('/sourceFolder/', 'newFolder');
1033 $this->isTrue(is_array($mappingInformation));
1034 $this->assertEquals('/newFolder/', $mappingInformation['/sourceFolder/']);
1035 $this->assertEquals('/newFolder/file2', $mappingInformation['/sourceFolder/file2']);
1036 $this->assertEquals('/newFolder/subFolder/file', $mappingInformation['/sourceFolder/subFolder/file']);
1037 $this->assertEquals('/newFolder/subFolder/', $mappingInformation['/sourceFolder/subFolder/']);
1038 }
1039
1040 /**
1041 * @test
1042 */
1043 public function renameFolderRevertsRenamingIfFilenameMapCannotBeCreated() {
1044 $this->setExpectedException('\\RuntimeException', '', 1334160746);
1045 $this->addToMount(array(
1046 'sourceFolder' => array(
1047 'file' => 'asdfg'
1048 )
1049 ));
1050 $fixture = $this->createDriverFixture(array(), array('createIdentifierMap'));
1051 $fixture->expects($this->atLeastOnce())->method('createIdentifierMap')->will($this->throwException(new \TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException()));
1052 $fixture->renameFolder('/sourceFolder/', 'newFolder');
1053 $this->assertFileExists($this->getUrlInMount('/sourceFolder/file'));
1054 }
1055
1056 /**
1057 * @test
1058 */
1059 public function isFolderEmptyReturnsTrueForEmptyFolder() {
1060 // This also prepares the next few tests, so add more info than required for this test
1061 $this->addToMount(array(
1062 'emptyFolder' => array()
1063 ));
1064 $fixture = $this->createDriverFixture();
1065 $this->assertTrue($fixture->isFolderEmpty('/emptyFolder/'));
1066 return $fixture;
1067 }
1068
1069 /**
1070 * @test
1071 */
1072 public function isFolderEmptyReturnsFalseIfFolderHasFile() {
1073 $this->addToMount(array(
1074 'folderWithFile' => array(
1075 'someFile' => ''
1076 )
1077 ));
1078 $fixture = $this->createDriverFixture();
1079 $this->assertFalse($fixture->isFolderEmpty('/folderWithFile/'));
1080 }
1081
1082 /**
1083 * @test
1084 */
1085 public function isFolderEmptyReturnsFalseIfFolderHasSubfolder() {
1086 $this->addToMount(array(
1087 'folderWithSubfolder' => array(
1088 'someFolder' => array()
1089 )
1090 ));
1091 $fixture = $this->createDriverFixture();
1092 $this->assertFalse($fixture->isFolderEmpty('/folderWithSubfolder/'));
1093 }
1094
1095 /**********************************
1096 * Copy/move folder
1097 **********************************/
1098 /**
1099 * @test
1100 */
1101 public function foldersCanBeMovedWithinStorage() {
1102 $fileContents = uniqid();
1103 $this->addToMount(array(
1104 'sourceFolder' => array(
1105 'file' => $fileContents,
1106 ),
1107 'targetFolder' => array(),
1108 ));
1109 $fixture = $this->createDriverFixture();
1110 /** @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver $fixture */
1111 $fixture->moveFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'someFolder');
1112 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/someFolder/')));
1113 $this->assertEquals($fileContents, file_get_contents($this->getUrlInMount('/targetFolder/someFolder/file')));
1114 $this->assertFileNotExists($this->getUrlInMount('/sourceFolder'));
1115 }
1116
1117 /**
1118 * @test
1119 */
1120 public function moveFolderWithinStorageReturnsCorrectMappingInformationForAllFiles() {
1121 $fileContents = 'asdfg';
1122 $this->addToMount(array(
1123 'targetFolder' => array(),
1124 'sourceFolder' => array(
1125 'subFolder' => array('file' => $fileContents),
1126 'file' => 'asdfg'
1127 )
1128 ));
1129 $fixture = $this->createDriverFixture();
1130 $mappingInformation = $fixture->moveFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'sourceFolder');
1131 $this->assertEquals('/targetFolder/sourceFolder/file', $mappingInformation['/sourceFolder/file']);
1132 $this->assertEquals('/targetFolder/sourceFolder/subFolder/file', $mappingInformation['/sourceFolder/subFolder/file']);
1133 $this->assertEquals('/targetFolder/sourceFolder/subFolder/', $mappingInformation['/sourceFolder/subFolder/']);
1134 }
1135
1136 /**
1137 * @test
1138 */
1139 public function folderCanBeRenamedWhenMoving() {
1140 $this->addToMount(array(
1141 'sourceFolder' => array(
1142 'file' => uniqid(),
1143 ),
1144 'targetFolder' => array(),
1145 ));
1146 $fixture = $this->createDriverFixture();
1147 $fixture->moveFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolder');
1148 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/newFolder/')));
1149 }
1150
1151 /**
1152 * @test
1153 */
1154 public function copyFolderWithinStorageCopiesSingleFileToNewFolderName() {
1155 $this->addToMount(array(
1156 'sourceFolder' => array(
1157 'file' => uniqid(),
1158 ),
1159 'targetFolder' => array(),
1160 ));
1161 $fixture = $this->createDriverFixture();
1162 $fixture->copyFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolderName');
1163 $this->assertTrue(is_file($this->getUrlInMount('/targetFolder/newFolderName/file')));
1164 }
1165
1166 /**
1167 * @test
1168 */
1169 public function copyFolderWithinStorageCopiesSingleSubFolderToNewFolderName() {
1170 list($basePath, $fixture) = $this->prepareRealTestEnvironment();
1171 GeneralUtility::mkdir_deep($basePath, '/sourceFolder/subFolder');
1172 GeneralUtility::mkdir_deep($basePath, '/targetFolder');
1173
1174 $fixture->copyFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolderName');
1175 $this->isTrue(is_dir($basePath . '/targetFolder/newFolderName/subFolder'));
1176 }
1177
1178 /**
1179 * @test
1180 */
1181 public function copyFolderWithinStorageCopiesFileInSingleSubFolderToNewFolderName() {
1182 list($basePath, $fixture) = $this->prepareRealTestEnvironment();
1183 GeneralUtility::mkdir_deep($basePath, '/sourceFolder/subFolder');
1184 GeneralUtility::mkdir_deep($basePath, '/targetFolder');
1185 file_put_contents($basePath . '/sourceFolder/subFolder/file', uniqid());
1186 GeneralUtility::fixPermissions($basePath . '/sourceFolder/subFolder/file');
1187
1188 $fixture->copyFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolderName');
1189 $this->assertTrue(is_file($basePath . '/targetFolder/newFolderName/subFolder/file'));
1190 }
1191
1192 }