[TASK] Move access right parameters from BE to SYS configuration
[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 * 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\Tests\FileStreamWrapper;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use org\bovigo\vfs\vfsStream;
20 use org\bovigo\vfs\vfsStreamWrapper;
21
22 /**
23 * Testcase for the local storage driver class of the TYPO3 VFS
24 */
25 class LocalDriverTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase
26 {
27 /**
28 * @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver
29 */
30 protected $localDriver = null;
31
32 /**
33 * @var array A backup of registered singleton instances
34 */
35 protected $singletonInstances = array();
36
37 /**
38 * @var array
39 */
40 protected $testDirs = array();
41
42 /**
43 * @var string
44 */
45 protected $iso88591GreaterThan127 = '';
46
47 /**
48 * @var string
49 */
50 protected $utf8Latin1Supplement = '';
51
52 /**
53 * @var string
54 */
55 protected $utf8Latin1ExtendedA = '';
56
57 /**
58 * Tear down
59 */
60 protected function tearDown()
61 {
62 foreach ($this->testDirs as $dir) {
63 chmod($dir, 0777);
64 \TYPO3\CMS\Core\Utility\GeneralUtility::rmdir($dir, true);
65 }
66 parent::tearDown();
67 }
68
69 /**
70 * Creates a "real" directory for doing tests. This is necessary because some file system properties (e.g. permissions)
71 * cannot be reflected by vfsStream, and some methods (like touch()) don't work there either.
72 *
73 * Created directories are automatically destroyed during tearDown()
74 *
75 * @return string
76 */
77 protected function createRealTestdir()
78 {
79 $basedir = PATH_site . 'typo3temp/' . $this->getUniqueId('fal-test-');
80 mkdir($basedir);
81 $this->testDirs[] = $basedir;
82 return $basedir;
83 }
84
85 /**
86 * Create a "real" directory together with a driver configured
87 * for this directory.
88 *
89 * @return array With path to base directory and driver
90 */
91 protected function prepareRealTestEnvironment()
92 {
93 $basedir = $this->createRealTestdir();
94 $subject = $this->createDriver(array(
95 'basePath' => $basedir
96 ));
97 return array($basedir, $subject);
98 }
99
100 /**
101 * Creates a mocked driver object as test subject, optionally using a given mount object.
102 *
103 * IMPORTANT: Call this only after setting up the virtual file system (with the addTo* methods)!
104 *
105 * @param array $driverConfiguration
106 * @param array $mockedDriverMethods
107 * @return \TYPO3\CMS\Core\Resource\Driver\LocalDriver
108 */
109 protected function createDriver($driverConfiguration = array(), $mockedDriverMethods = array())
110 {
111 // it's important to do that here, so vfsContents could have been set before
112 if (!isset($driverConfiguration['basePath'])) {
113 $this->initializeVfs();
114 $driverConfiguration['basePath'] = $this->getMountRootUrl();
115 }
116 /** @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver $driver */
117 $mockedDriverMethods[] = 'isPathValid';
118 $driver = $this->getAccessibleMock(\TYPO3\CMS\Core\Resource\Driver\LocalDriver::class, $mockedDriverMethods, array($driverConfiguration));
119 $driver->expects($this->any())
120 ->method('isPathValid')
121 ->will(
122 $this->returnValue(true)
123 );
124
125 $driver->setStorageUid(5);
126 $driver->processConfiguration();
127 $driver->initialize();
128 return $driver;
129 }
130
131 /**
132 * @test
133 */
134 public function calculatedBasePathRelativeIsSane()
135 {
136 $subject = $this->createDriver();
137
138 // This would cause problems if you fill "/fileadmin/" into the base path field of a sys_file_storage record and select "relative" as path type
139 $relativeDriverConfiguration = array(
140 'pathType' => 'relative',
141 'basePath' => '/typo3temp/',
142 );
143 $basePath = $subject->_call('calculateBasePath', $relativeDriverConfiguration);
144
145 $this->assertNotContains('//', $basePath);
146 }
147
148 /**
149 * @test
150 */
151 public function calculatedBasePathAbsoluteIsSane()
152 {
153 $subject = $this->createDriver();
154
155 // This test checks if "/../" are properly filtered out (i.e. from "Base path" field of sys_file_storage)
156 $relativeDriverConfiguration = array(
157 'basePath' => PATH_site . 'typo3temp/../typo3temp/',
158 );
159 $basePath = $subject->_call('calculateBasePath', $relativeDriverConfiguration);
160
161 $this->assertNotContains('/../', $basePath);
162 }
163
164 /**
165 * @test
166 */
167 public function createFolderRecursiveSanitizesFilename()
168 {
169 /** @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $driver */
170 $driver = $this->createDriver(array(), array('sanitizeFilename'));
171 $driver->expects($this->exactly(2))
172 ->method('sanitizeFileName')
173 ->will(
174 $this->returnValue('sanitized')
175 );
176 $driver->createFolder('newFolder/andSubfolder', '/', true);
177 $this->assertFileExists($this->getUrlInMount('/sanitized/sanitized/'));
178 }
179
180 /**
181 * @test
182 */
183 public function determineBaseUrlUrlEncodesUriParts()
184 {
185 /** @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface $driver */
186 $driver = $this->getAccessibleMock(\TYPO3\CMS\Core\Resource\Driver\LocalDriver::class, array('hasCapability'), array(), '', false);
187 $driver->expects($this->once())
188 ->method('hasCapability')
189 ->with(\TYPO3\CMS\Core\Resource\ResourceStorage::CAPABILITY_PUBLIC)
190 ->will(
191 $this->returnValue(true)
192 );
193 $driver->_set('absoluteBasePath', PATH_site . 'un encö/ded %path/');
194 $driver->_call('determineBaseUrl');
195 $baseUri = $driver->_get('baseUri');
196 $this->assertEquals(rawurlencode('un encö') . '/' . rawurlencode('ded %path') . '/', $baseUri);
197 }
198
199 /**
200 * @test
201 */
202 public function getDefaultFolderReturnsFolderForUserUploadPath()
203 {
204 $subject = $this->createDriver();
205 $folderIdentifier = $subject->getDefaultFolder();
206 $this->assertEquals('/user_upload/', $folderIdentifier);
207 }
208
209 /**
210 * @test
211 */
212 public function defaultLevelFolderFolderIsCreatedIfItDoesntExist()
213 {
214 $subject = $this->createDriver();
215 $this->assertFileExists($this->getUrlInMount($subject->getDefaultFolder()));
216 }
217
218 /**
219 * @test
220 */
221 public function getFolderInFolderReturnsCorrectFolderObject()
222 {
223 $this->addToMount(array(
224 'someDir' => array(
225 'someSubdir' => array()
226 )
227 ));
228 $subject = $this->createDriver();
229 $folder = $subject->getFolderInFolder('someSubdir', '/someDir/');
230 $this->assertEquals('/someDir/someSubdir/', $folder);
231 }
232
233 /**
234 * @test
235 */
236 public function createFolderCreatesFolderOnDisk()
237 {
238 $this->addToMount(array('some' => array('folder' => array())));
239 $subject = $this->createDriver();
240 $subject->createFolder('path', '/some/folder/');
241 $this->assertFileExists($this->getUrlInMount('/some/folder/'));
242 $this->assertFileExists($this->getUrlInMount('/some/folder/path'));
243 }
244
245 /**
246 * @test
247 */
248 public function createFolderReturnsFolderObject()
249 {
250 $this->addToMount(array('some' => array('folder' => array())));
251 $subject = $this->createDriver();
252 $createdFolder = $subject->createFolder('path', '/some/folder/');
253 $this->assertEquals('/some/folder/path/', $createdFolder);
254 }
255
256 public static function createFolderSanitizesFolderNameBeforeCreationDataProvider()
257 {
258 return array(
259 'folder name with NULL character' => array(
260 'some' . chr(0) . 'Folder',
261 'some_Folder'
262 ),
263 'folder name with directory part' => array(
264 '../someFolder',
265 '.._someFolder'
266 )
267 );
268 }
269
270 /**
271 * @test
272 * @dataProvider createFolderSanitizesFolderNameBeforeCreationDataProvider
273 */
274 public function createFolderSanitizesFolderNameBeforeCreation($newFolderName, $expectedFolderName)
275 {
276 $this->addToMount(array('some' => array('folder' => array())));
277 $subject = $this->createDriver();
278 $subject->createFolder($newFolderName, '/some/folder/');
279 $this->assertFileExists($this->getUrlInMount('/some/folder/' . $expectedFolderName));
280 }
281
282 /**
283 * @test
284 */
285 public function basePathIsNormalizedWithTrailingSlash()
286 {
287 $subject = $this->createDriver();
288 $this->assertEquals('/', substr($subject->_call('getAbsoluteBasePath'), -1));
289 }
290
291 /**
292 * @test
293 */
294 public function noSecondSlashIsAddedIfBasePathAlreadyHasTrailingSlash()
295 {
296 $subject = $this->createDriver();
297 $this->assertNotEquals('/', substr($subject->_call('getAbsoluteBasePath'), -2, 1));
298 }
299
300 public function getSpecificFileInformationDataProvider()
301 {
302 return array(
303 'size' => array(
304 'expectedValue' => filesize(__DIR__ . '/Fixtures/Dummy.html'),
305 'propertyName' => 'size'
306 ),
307 'atime' => array(
308 'expectedValue' => 'WILL_BE_REPLACED_BY_VFS_TIME',
309 'propertyName' => 'atime'
310 ),
311 'mtime' => array(
312 'expectedValue' => 'WILL_BE_REPLACED_BY_VFS_TIME',
313 'propertyName' => 'mtime'
314 ),
315 'ctime' => array(
316 'expectedValue' => 'WILL_BE_REPLACED_BY_VFS_TIME',
317 'propertyName' => 'ctime'
318 ),
319 'name' => array(
320 'expectedValue' => 'Dummy.html',
321 'propertyName' => 'name'
322 ),
323 'mimetype' => array(
324 'expectedValue' => 'text/html',
325 'propertyName' => 'mimetype'
326 ),
327 'identifier' => array(
328 'expectedValue' => '/Dummy.html',
329 'propertyName' => 'identifier'
330 ),
331 'storage' => array(
332 'expectedValue' => 5,
333 'propertyName' => 'storage'
334 ),
335 'identifier_hash' => array(
336 'expectedValue' => 'b11efa5d7c0556a65c6aa261343b9807cac993bc',
337 'propertyName' => 'identifier_hash'
338 ),
339 'folder_hash' => array(
340 'expectedValue' => '42099b4af021e53fd8fd4e056c2568d7c2e3ffa8',
341 'propertyName' => 'folder_hash'
342 )
343 );
344 }
345
346 /**
347 * @test
348 * @dataProvider getSpecificFileInformationDataProvider
349 */
350 public function getSpecificFileInformationReturnsRequestedFileInformation($expectedValue, $property)
351 {
352 $root = vfsStream::setup();
353 $subFolder = vfsStream::newDirectory('fileadmin');
354 $root->addChild($subFolder);
355 // Load fixture files and folders from disk
356 $directory = vfsStream::copyFromFileSystem(__DIR__ . '/Fixtures/', $subFolder, 1024*1024);
357 if (in_array($property, array('mtime', 'ctime', 'atime'))) {
358 $expectedValue = $directory->getChild('Dummy.html')->filemtime();
359 }
360 FileStreamWrapper::init(PATH_site);
361 FileStreamWrapper::registerOverlayPath('fileadmin', 'vfs://root/fileadmin', false);
362
363 $subject = $this->createDriver(array('basePath' => PATH_site . 'fileadmin'));
364 $this->assertSame(
365 $expectedValue,
366 $subject->getSpecificFileInformation(PATH_site . 'fileadmin/Dummy.html', '/', $property)
367 );
368
369 FileStreamWrapper::destroy();
370 }
371
372 /**
373 * @test
374 */
375 public function getAbsolutePathReturnsCorrectPath()
376 {
377 $this->addToMount(array(
378 'someFolder' => array(
379 'file1.ext' => 'asdfg'
380 )
381 ));
382 $subject = $this->createDriver();
383 $path = $subject->_call('getAbsolutePath', '/someFolder/file1.ext');
384 $this->assertTrue(file_exists($path));
385 $this->assertEquals($this->getUrlInMount('/someFolder/file1.ext'), $path);
386 }
387
388 /**
389 * @test
390 */
391 public function addFileMovesFileToCorrectLocation()
392 {
393 $this->addToMount(array('targetFolder' => array()));
394 $this->addToVfs(array(
395 'sourceFolder' => array(
396 'file' => 'asdf'
397 )
398 ));
399 $subject = $this->createDriver(
400 array(),
401 array('getMimeTypeOfFile')
402 );
403 $this->assertTrue(file_exists($this->getUrl('sourceFolder/file')));
404 $subject->addFile($this->getUrl('sourceFolder/file'), '/targetFolder/', 'file');
405 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/file')));
406 }
407
408 /**
409 * @test
410 */
411 public function addFileUsesFilenameIfGiven()
412 {
413 $this->addToMount(array('targetFolder' => array()));
414 $this->addToVfs(array(
415 'sourceFolder' => array(
416 'file' => 'asdf'
417 )
418 ));
419 $subject = $this->createDriver(
420 array(),
421 array('getMimeTypeOfFile')
422 );
423 $this->assertTrue(file_exists($this->getUrl('sourceFolder/file')));
424 $subject->addFile($this->getUrl('sourceFolder/file'), '/targetFolder/', 'targetFile');
425 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/targetFile')));
426 }
427
428 /**
429 * @test
430 */
431 public function addFileFailsIfFileIsInDriverStorage()
432 {
433 $this->setExpectedException('InvalidArgumentException', '', 1314778269);
434 $this->addToMount(array(
435 'targetFolder' => array(
436 'file' => 'asdf'
437 )
438 ));
439 $subject = $this->createDriver();
440 $subject->addFile($this->getUrlInMount('/targetFolder/file'), '/targetFolder/', 'file');
441 }
442
443 /**
444 * @test
445 */
446 public function addFileReturnsFileIdentifier()
447 {
448 $this->addToMount(array('targetFolder' => array()));
449 $this->addToVfs(array(
450 'sourceFolder' => array(
451 'file' => 'asdf'
452 )
453 ));
454 $subject = $this->createDriver(
455 array(),
456 array('getMimeTypeOfFile')
457 );
458 $this->assertTrue(file_exists($this->getUrl('sourceFolder/file')));
459 $fileIdentifier = $subject->addFile($this->getUrl('sourceFolder/file'), '/targetFolder/', 'file');
460 $this->assertEquals('file', basename($fileIdentifier));
461 $this->assertEquals('/targetFolder/file', $fileIdentifier);
462 }
463
464 /**
465 * @test
466 */
467 public function existenceChecksWorkForFilesAndFolders()
468 {
469 $this->addToMount(array(
470 'file' => 'asdf',
471 'folder' => array()
472 ));
473 $subject = $this->createDriver();
474 // Using slashes at the beginning of paths because they will be stored in the DB this way.
475 $this->assertTrue($subject->fileExists('/file'));
476 $this->assertTrue($subject->folderExists('/folder/'));
477 $this->assertFalse($subject->fileExists('/nonexistingFile'));
478 $this->assertFalse($subject->folderExists('/nonexistingFolder/'));
479 }
480
481 /**
482 * @test
483 */
484 public function existenceChecksInFolderWorkForFilesAndFolders()
485 {
486 $this->addToMount(array(
487 'subfolder' => array(
488 'file' => 'asdf',
489 'folder' => array()
490 )
491 ));
492 $subject = $this->createDriver();
493 $this->assertTrue($subject->fileExistsInFolder('file', '/subfolder/'));
494 $this->assertTrue($subject->folderExistsInFolder('folder', '/subfolder/'));
495 $this->assertFalse($subject->fileExistsInFolder('nonexistingFile', '/subfolder/'));
496 $this->assertFalse($subject->folderExistsInFolder('nonexistingFolder', '/subfolder/'));
497 }
498
499 /**
500 * @test
501 */
502 public function getPublicUrlReturnsCorrectUriForConfiguredBaseUri()
503 {
504 $baseUri = 'http://example.org/foobar/' . $this->getUniqueId();
505 $this->addToMount(array(
506 'file.ext' => 'asdf',
507 'subfolder' => array(
508 'file2.ext' => 'asdf'
509 )
510 ));
511 $subject = $this->createDriver(array(
512 'baseUri' => $baseUri
513 ));
514 $this->assertEquals($baseUri . '/file.ext', $subject->getPublicUrl('/file.ext'));
515 $this->assertEquals($baseUri . '/subfolder/file2.ext', $subject->getPublicUrl('/subfolder/file2.ext'));
516 }
517
518 /**
519 * Data provider for getPublicUrlReturnsValidUrlContainingSpecialCharacters().
520 *
521 * @return array
522 */
523 public function getPublicUrlReturnsValidUrlContainingSpecialCharacters_dataProvider()
524 {
525 return array(
526 array('/single file with some special chars äüö!.txt'),
527 array('/on subfolder/with special chars äüö!.ext'),
528 array('/who names a file like !"§$%&()=?*+~"#\'´`<>-.ext'),
529 array('no leading slash !"§$%&()=?*+~#\'"´`"<>-.txt')
530 );
531 }
532
533 /**
534 * @test
535 * @dataProvider getPublicUrlReturnsValidUrlContainingSpecialCharacters_dataProvider
536 */
537 public function getPublicUrlReturnsValidUrlContainingSpecialCharacters($fileIdentifier)
538 {
539 $baseUri = 'http://example.org/foobar/' . $this->getUniqueId();
540 $subject = $this->createDriver(array(
541 'baseUri' => $baseUri
542 ));
543 $publicUrl = $subject->getPublicUrl($fileIdentifier);
544 $this->assertTrue(GeneralUtility::isValidUrl($publicUrl), 'getPublicUrl did not return a valid URL:' . $publicUrl);
545 }
546
547 /**
548 * @test
549 */
550 public function fileContentsCanBeWrittenAndRead()
551 {
552 $fileContents = 'asdf';
553 $this->addToMount(array(
554 'file.ext' => $fileContents
555 ));
556 $subject = $this->createDriver();
557 $this->assertEquals($fileContents, $subject->getFileContents('/file.ext'), 'File contents could not be read');
558 $newFileContents = 'asdfgh';
559 $subject->setFileContents('/file.ext', $newFileContents);
560 $this->assertEquals($newFileContents, $subject->getFileContents('/file.ext'), 'New file contents could not be read.');
561 }
562
563 /**
564 * @test
565 */
566 public function setFileContentsReturnsNumberOfBytesWrittenToFile()
567 {
568 $fileContents = 'asdf';
569 $this->addToMount(array(
570 'file.ext' => $fileContents
571 ));
572 $subject = $this->createDriver();
573 $newFileContents = 'asdfgh';
574 $bytesWritten = $subject->setFileContents('/file.ext', $newFileContents);
575 $this->assertEquals(strlen($newFileContents), $bytesWritten);
576 }
577
578 /**
579 * @test
580 * @see http://phpmagazin.de/vfsStream-1.1.0-nutzt-PHP-5.4-M%C3%B6glichkeiten-064406.html
581 */
582 public function newFilesCanBeCreated()
583 {
584 $subject = $this->createDriver();
585 $subject->createFile('testfile.txt', '/');
586 $this->assertTrue($subject->fileExists('/testfile.txt'));
587 }
588
589 /**
590 * @test
591 * @see http://phpmagazin.de/vfsStream-1.1.0-nutzt-PHP-5.4-M%C3%B6glichkeiten-064406.html
592 */
593 public function createdFilesAreEmpty()
594 {
595 $subject = $this->createDriver();
596 $subject->createFile('testfile.txt', '/');
597 $this->assertTrue($subject->fileExists('/testfile.txt'));
598 $fileData = $subject->getFileContents('/testfile.txt');
599 $this->assertEquals(0, strlen($fileData));
600 }
601
602 /**
603 * @test
604 */
605 public function createFileFixesPermissionsOnCreatedFile()
606 {
607 if (TYPO3_OS == 'WIN') {
608 $this->markTestSkipped('createdFilesHaveCorrectRights() tests not available on Windows');
609 }
610
611 // No one will use this as his default file create mask so we hopefully don't get any false positives
612 $testpattern = '0646';
613 $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = $testpattern;
614
615 $this->addToMount(
616 array(
617 'someDir' => array()
618 )
619 );
620 /** @var $subject \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
621 list($basedir, $subject) = $this->prepareRealTestEnvironment();
622 mkdir($basedir . '/someDir');
623 $subject->createFile('testfile.txt', '/someDir');
624 $this->assertEquals($testpattern, decoct(fileperms($basedir . '/someDir/testfile.txt') & 0777));
625 }
626
627 /**********************************
628 * File and directory listing
629 **********************************/
630 /**
631 * @test
632 */
633 public function getFileReturnsCorrectIdentifier()
634 {
635 $root = vfsStream::setup();
636 $subFolder = vfsStream::newDirectory('fileadmin');
637 $root->addChild($subFolder);
638 // Load fixture files and folders from disk
639 $directory = vfsStream::copyFromFileSystem(__DIR__ . '/Fixtures/', $subFolder, 1024*1024);
640 FileStreamWrapper::init(PATH_site);
641 FileStreamWrapper::registerOverlayPath('fileadmin/', 'vfs://root/fileadmin/', false);
642
643 $subject = $this->createDriver(array('basePath' => PATH_site . 'fileadmin'));
644
645 $subdirFileInfo = $subject->getFileInfoByIdentifier('Dummy.html');
646 $this->assertEquals('/Dummy.html', $subdirFileInfo['identifier']);
647 $rootFileInfo = $subject->getFileInfoByIdentifier('LocalDriverFilenameFilter.php');
648 $this->assertEquals('/LocalDriverFilenameFilter.php', $rootFileInfo['identifier']);
649
650 FileStreamWrapper::destroy();
651 }
652
653 /**
654 * @test
655 */
656 public function getFileThrowsExceptionIfFileDoesNotExist()
657 {
658 $this->setExpectedException('InvalidArgumentException', '', 1314516809);
659 $subject = $this->createDriver();
660 $subject->getFileInfoByIdentifier('/some/file/at/a/random/path');
661 }
662
663 /**
664 * @test
665 */
666 public function getFilesInFolderReturnsEmptyArrayForEmptyDirectory()
667 {
668 $subject = $this->createDriver();
669 $fileList = $subject->getFilesInFolder('/');
670 $this->assertEmpty($fileList);
671 }
672
673 /**
674 * @test
675 */
676 public function getFileListReturnsAllFilesInDirectory()
677 {
678 $dirStructure = array(
679 'aDir' => array(),
680 'file1' => 'asdfg',
681 'file2' => 'fdsa'
682 );
683 $this->addToMount($dirStructure);
684 $subject = $this->createDriver(
685 array(),
686 // Mocked because finfo() can not deal with vfs streams and throws warnings
687 array('getMimeTypeOfFile')
688 );
689 $fileList = $subject->getFilesInFolder('/');
690 $this->assertEquals(array('/file1', '/file2'), array_keys($fileList));
691 }
692
693 /**
694 * @test
695 */
696 public function getFileListReturnsAllFilesInSubdirectoryIfRecursiveParameterIsSet()
697 {
698 $dirStructure = array(
699 'aDir' => array(
700 'file3' => 'asdfgh',
701 'subdir' => array(
702 'file4' => 'asklfjklasjkl'
703 )
704 ),
705 'file1' => 'asdfg',
706 'file2' => 'fdsa'
707 );
708 $this->addToMount($dirStructure);
709 $subject = $this->createDriver(
710 array(),
711 // Mocked because finfo() can not deal with vfs streams and throws warnings
712 array('getMimeTypeOfFile')
713 );
714 $fileList = $subject->getFilesInFolder('/', 0, 0, true);
715 $this->assertEquals(array('/file1', '/file2', '/aDir/file3', '/aDir/subdir/file4'), array_keys($fileList));
716 }
717
718 /**
719 * @test
720 */
721 public function getFileListFailsIfDirectoryDoesNotExist()
722 {
723 $this->setExpectedException('InvalidArgumentException', '', 1314349666);
724 $this->addToMount(array('somefile' => ''));
725 $subject = $this->createDriver();
726 $subject->getFilesInFolder('somedir/');
727 }
728
729 /**
730 * @test
731 */
732 public function getFileInFolderCallsConfiguredCallbackFunctionWithGivenItemName()
733 {
734 $dirStructure = array(
735 'file2' => 'fdsa'
736 );
737 // register static callback to self
738 $callback = array(
739 array(
740 get_class($this),
741 'callbackStaticTestFunction'
742 )
743 );
744 $this->addToMount($dirStructure);
745 $subject = $this->createDriver();
746 // the callback function will throw an exception used to check if it was called with correct $itemName
747 $this->setExpectedException('InvalidArgumentException', '$itemName', 1336159604);
748 $subject->getFilesInFolder('/', 0, 0, false, $callback);
749 }
750
751 /**
752 * Static callback function used to test if the filter callbacks work
753 * As it is static we are using an exception to test if it is really called and works
754 *
755 * @static
756 * @throws \InvalidArgumentException
757 * @see getFileListCallsConfiguredCallbackFunction
758 */
759 public static function callbackStaticTestFunction()
760 {
761 list($itemName) = func_get_args();
762 if ($itemName === 'file2') {
763 throw new \InvalidArgumentException('$itemName', 1336159604);
764 }
765 }
766
767 /**
768 * @test
769 */
770 public function getFileListFiltersItemsWithGivenFilterMethods()
771 {
772 $dirStructure = array(
773 'fileA' => 'asdfg',
774 'fileB' => 'fdsa'
775 );
776 $this->addToMount($dirStructure);
777 $subject = $this->createDriver(
778 array(),
779 // Mocked because finfo() can not deal with vfs streams and throws warnings
780 array('getMimeTypeOfFile')
781 );
782 $filterCallbacks = array(
783 array(
784 \TYPO3\CMS\Core\Tests\Unit\Resource\Driver\Fixtures\LocalDriverFilenameFilter::class,
785 'filterFilename',
786 ),
787 );
788 $fileList = $subject->getFilesInFolder('/', 0, 0, false, $filterCallbacks);
789 $this->assertNotContains('/fileA', array_keys($fileList));
790 }
791
792 /**
793 * @test
794 */
795 public function getFolderListReturnsAllDirectoriesInDirectory()
796 {
797 $dirStructure = array(
798 'dir1' => array(),
799 'dir2' => array(),
800 'file' => 'asdfg'
801 );
802 $this->addToMount($dirStructure);
803 $subject = $this->createDriver();
804 $fileList = $subject->getFoldersInFolder('/');
805 $this->assertEquals(array('/dir1/', '/dir2/'), array_keys($fileList));
806 }
807
808 /**
809 * @test
810 */
811 public function getFolderListReturnsHiddenFoldersByDefault()
812 {
813 $dirStructure = array(
814 '.someHiddenDir' => array(),
815 'aDir' => array(),
816 'file1' => ''
817 );
818 $this->addToMount($dirStructure);
819 $subject = $this->createDriver();
820
821 $fileList = $subject->getFoldersInFolder('/');
822
823 $this->assertEquals(array('/.someHiddenDir/', '/aDir/'), array_keys($fileList));
824 }
825
826 /**
827 * Checks if the folder names . and .. are ignored when listing subdirectories
828 *
829 * @test
830 */
831 public function getFolderListLeavesOutNavigationalEntries()
832 {
833 // we have to add .. and . manually, as these are not included in vfsStream directory listings (as opposed
834 // to normal filelistings)
835 $this->addToMount(array(
836 '..' => array(),
837 '.' => array()
838 ));
839 $subject = $this->createDriver();
840 $fileList = $subject->getFoldersInFolder('/');
841 $this->assertEmpty($fileList);
842 }
843
844 /**
845 * @test
846 */
847 public function getFolderListFiltersItemsWithGivenFilterMethods()
848 {
849 $dirStructure = array(
850 'folderA' => array(),
851 'folderB' => array()
852 );
853 $this->addToMount($dirStructure);
854 $subject = $this->createDriver();
855 $filterCallbacks = array(
856 array(
857 \TYPO3\CMS\Core\Tests\Unit\Resource\Driver\Fixtures\LocalDriverFilenameFilter::class,
858 'filterFilename',
859 ),
860 );
861 $folderList = $subject->getFoldersInFolder('/', 0, 0, $filterCallbacks);
862 $this->assertNotContains('folderA', array_keys($folderList));
863 }
864
865 /**
866 * @test
867 */
868 public function getFolderListFailsIfDirectoryDoesNotExist()
869 {
870 $this->setExpectedException('InvalidArgumentException', '', 1314349666);
871 $subject = $this->createDriver();
872 vfsStream::create(array($this->basedir => array('somefile' => '')));
873 $subject->getFoldersInFolder('somedir/');
874 }
875
876 /**
877 * @test
878 */
879 public function hashReturnsCorrectHashes()
880 {
881 $contents = '68b329da9893e34099c7d8ad5cb9c940';
882 $expectedMd5Hash = '8c67dbaf0ba22f2e7fbc26413b86051b';
883 $expectedSha1Hash = 'a60cd808ba7a0bcfa37fa7f3fb5998e1b8dbcd9d';
884 $this->addToMount(array('hashFile' => $contents));
885 $subject = $this->createDriver();
886 $this->assertEquals($expectedSha1Hash, $subject->hash('/hashFile', 'sha1'));
887 $this->assertEquals($expectedMd5Hash, $subject->hash('/hashFile', 'md5'));
888 }
889
890 /**
891 * @test
892 */
893 public function hashingWithUnsupportedAlgorithmFails()
894 {
895 $this->setExpectedException('InvalidArgumentException', '', 1304964032);
896 $subject = $this->createDriver();
897 $subject->hash('/hashFile', $this->getUniqueId());
898 }
899
900 /**
901 * @test
902 * @covers TYPO3\CMS\Core\Resource\Driver\LocalDriver::getFileForLocalProcessing
903 */
904 public function getFileForLocalProcessingCreatesCopyOfFileByDefault()
905 {
906 $fileContents = 'asdfgh';
907 $this->addToMount(array(
908 'someDir' => array(
909 'someFile' => $fileContents
910 )
911 ));
912 $subject = $this->createDriver(array(), array('copyFileToTemporaryPath'));
913 $subject->expects($this->once())->method('copyFileToTemporaryPath');
914 $subject->getFileForLocalProcessing('/someDir/someFile');
915 }
916
917 /**
918 * @test
919 */
920 public function getFileForLocalProcessingReturnsOriginalFilepathForReadonlyAccess()
921 {
922 $fileContents = 'asdfgh';
923 $this->addToMount(array(
924 'someDir' => array(
925 'someFile' => $fileContents
926 )
927 ));
928 $subject = $this->createDriver();
929 $filePath = $subject->getFileForLocalProcessing('/someDir/someFile', false);
930 $this->assertEquals($filePath, $this->getUrlInMount('someDir/someFile'));
931 }
932
933 /**
934 * @test
935 */
936 public function filesCanBeCopiedToATemporaryPath()
937 {
938 $fileContents = 'asdfgh';
939 $this->addToMount(array(
940 'someDir' => array(
941 'someFile' => $fileContents
942 )
943 ));
944 $subject = $this->createDriver();
945 $filePath = GeneralUtility::fixWindowsFilePath($subject->_call('copyFileToTemporaryPath', '/someDir/someFile'));
946 $this->testFilesToDelete[] = $filePath;
947 $this->assertContains('/typo3temp/', $filePath);
948 $this->assertEquals($fileContents, file_get_contents($filePath));
949 }
950
951 /**
952 * @test
953 */
954 public function permissionsAreCorrectlyRetrievedForAllowedFile()
955 {
956 /** @var $subject \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
957 list($basedir, $subject) = $this->prepareRealTestEnvironment();
958 touch($basedir . '/someFile');
959 chmod($basedir . '/someFile', 448);
960 clearstatcache();
961 $this->assertEquals(array('r' => true, 'w' => true), $subject->getPermissions('/someFile'));
962 }
963
964 /**
965 * @test
966 */
967 public function permissionsAreCorrectlyRetrievedForForbiddenFile()
968 {
969 if (function_exists('posix_getegid') && posix_getegid() === 0) {
970 $this->markTestSkipped('Test skipped if run on linux as root');
971 } elseif (TYPO3_OS === 'WIN') {
972 $this->markTestSkipped('Test skipped if run on Windows system');
973 }
974 /** @var $subject \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
975 list($basedir, $subject) = $this->prepareRealTestEnvironment();
976 touch($basedir . '/someForbiddenFile');
977 chmod($basedir . '/someForbiddenFile', 0);
978 clearstatcache();
979 $this->assertEquals(array('r' => false, 'w' => false), $subject->getPermissions('/someForbiddenFile'));
980 }
981
982 /**
983 * @test
984 */
985 public function permissionsAreCorrectlyRetrievedForAllowedFolder()
986 {
987 /** @var $subject \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
988 list($basedir, $subject) = $this->prepareRealTestEnvironment();
989 mkdir($basedir . '/someFolder');
990 chmod($basedir . '/someFolder', 448);
991 clearstatcache();
992 $this->assertEquals(array('r' => true, 'w' => true), $subject->getPermissions('/someFolder'));
993 }
994
995 /**
996 * @test
997 */
998 public function permissionsAreCorrectlyRetrievedForForbiddenFolder()
999 {
1000 if (function_exists('posix_getegid') && posix_getegid() === 0) {
1001 $this->markTestSkipped('Test skipped if run on linux as root');
1002 } elseif (TYPO3_OS === 'WIN') {
1003 $this->markTestSkipped('Test skipped if run on Windows system');
1004 }
1005 /** @var $subject \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
1006 list($basedir, $subject) = $this->prepareRealTestEnvironment();
1007 mkdir($basedir . '/someForbiddenFolder');
1008 chmod($basedir . '/someForbiddenFolder', 0);
1009 clearstatcache();
1010 $result = $subject->getPermissions('/someForbiddenFolder');
1011 // Change permissions back to writable, so the sub-folder can be removed in tearDown
1012 chmod($basedir . '/someForbiddenFolder', 0777);
1013 $this->assertEquals(array('r' => false, 'w' => false), $result);
1014 }
1015
1016 /**
1017 * Dataprovider for getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser test
1018 *
1019 * @return array group, filemode and expected result
1020 */
1021 public function getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser_dataProvider()
1022 {
1023 $data = array();
1024 // On some OS, the posix_* functions do not exits
1025 if (function_exists('posix_getgid')) {
1026 $data = array(
1027 'current group, readable/writable' => array(
1028 posix_getgid(),
1029 48,
1030 array('r' => true, 'w' => true)
1031 ),
1032 'current group, readable/not writable' => array(
1033 posix_getgid(),
1034 32,
1035 array('r' => true, 'w' => false)
1036 ),
1037 'current group, not readable/not writable' => array(
1038 posix_getgid(),
1039 0,
1040 array('r' => false, 'w' => false)
1041 )
1042 );
1043 }
1044 $data = array_merge_recursive($data, array(
1045 'arbitrary group, readable/writable' => array(
1046 vfsStream::GROUP_USER_1,
1047 6,
1048 array('r' => true, 'w' => true)
1049 ),
1050 'arbitrary group, readable/not writable' => array(
1051 vfsStream::GROUP_USER_1,
1052 436,
1053 array('r' => true, 'w' => false)
1054 ),
1055 'arbitrary group, not readable/not writable' => array(
1056 vfsStream::GROUP_USER_1,
1057 432,
1058 array('r' => false, 'w' => false)
1059 )
1060 ));
1061 return $data;
1062 }
1063
1064 /**
1065 * @test
1066 * @dataProvider getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser_dataProvider
1067 */
1068 public function getFilePermissionsReturnsCorrectPermissionsForFilesNotOwnedByCurrentUser($group, $permissions, $expectedResult)
1069 {
1070 if (TYPO3_OS === 'WIN') {
1071 $this->markTestSkipped('Test skipped if run on Windows system');
1072 }
1073 $this->addToMount(array(
1074 'testfile' => 'asdfg'
1075 ));
1076 $subject = $this->createDriver();
1077 /** @var $fileObject vfsStreamContent */
1078 $fileObject = vfsStreamWrapper::getRoot()->getChild($this->mountDir)->getChild('testfile');
1079 // just use an "arbitrary" user here - it is only important that
1080 $fileObject->chown(vfsStream::OWNER_USER_1);
1081 $fileObject->chgrp($group);
1082 $fileObject->chmod($permissions);
1083 $this->assertEquals($expectedResult, $subject->getPermissions('/testfile'));
1084 }
1085
1086 /**
1087 * @test
1088 */
1089 public function isWithinRecognizesFilesWithinFolderAndInOtherFolders()
1090 {
1091 $subject = $this->createDriver();
1092 $this->assertTrue($subject->isWithin('/someFolder/', '/someFolder/test.jpg'));
1093 $this->assertTrue($subject->isWithin('/someFolder/', '/someFolder/subFolder/test.jpg'));
1094 $this->assertFalse($subject->isWithin('/someFolder/', '/someFolderWithALongName/test.jpg'));
1095 }
1096
1097 /**
1098 * @test
1099 */
1100 public function isWithinAcceptsFileAndFolderObjectsAsContent()
1101 {
1102 $subject = $this->createDriver();
1103 $this->assertTrue($subject->isWithin('/someFolder/', '/someFolder/test.jpg'));
1104 $this->assertTrue($subject->isWithin('/someFolder/', '/someFolder/subfolder/'));
1105 }
1106
1107 /**********************************
1108 * Copy/move file
1109 **********************************/
1110
1111 /**
1112 * @test
1113 */
1114 public function filesCanBeCopiedWithinStorage()
1115 {
1116 $fileContents = $this->getUniqueId();
1117 $this->addToMount(array(
1118 'someFile' => $fileContents,
1119 'targetFolder' => array()
1120 ));
1121 $subject = $this->createDriver(
1122 array(),
1123 array('getMimeTypeOfFile')
1124 );
1125 $subject->copyFileWithinStorage('/someFile', '/targetFolder/', 'someFile');
1126 $this->assertFileEquals($this->getUrlInMount('/someFile'), $this->getUrlInMount('/targetFolder/someFile'));
1127 }
1128
1129 /**
1130 * @test
1131 */
1132 public function filesCanBeMovedWithinStorage()
1133 {
1134 $fileContents = $this->getUniqueId();
1135 $this->addToMount(array(
1136 'targetFolder' => array(),
1137 'someFile' => $fileContents
1138 ));
1139 $subject = $this->createDriver();
1140 $newIdentifier = $subject->moveFileWithinStorage('/someFile', '/targetFolder/', 'file');
1141 $this->assertEquals($fileContents, file_get_contents($this->getUrlInMount('/targetFolder/file')));
1142 $this->assertFileNotExists($this->getUrlInMount('/someFile'));
1143 $this->assertEquals('/targetFolder/file', $newIdentifier);
1144 }
1145
1146 /**
1147 * @test
1148 */
1149 public function fileMetadataIsChangedAfterMovingFile()
1150 {
1151 $fileContents = $this->getUniqueId();
1152 $this->addToMount(array(
1153 'targetFolder' => array(),
1154 'someFile' => $fileContents
1155 ));
1156 $subject = $this->createDriver(
1157 array(),
1158 // Mocked because finfo() can not deal with vfs streams and throws warnings
1159 array('getMimeTypeOfFile')
1160 );
1161 $newIdentifier = $subject->moveFileWithinStorage('/someFile', '/targetFolder/', 'file');
1162 $fileMetadata = $subject->getFileInfoByIdentifier($newIdentifier);
1163 $this->assertEquals($newIdentifier, $fileMetadata['identifier']);
1164 }
1165
1166 public function renamingFiles_dataProvider()
1167 {
1168 return array(
1169 'file in subfolder' => array(
1170 array(
1171 'targetFolder' => array('file' => '')
1172 ),
1173 '/targetFolder/file',
1174 'newFile',
1175 '/targetFolder/newFile'
1176 ),
1177 'file in rootfolder' => array(
1178 array(
1179 'fileInRoot' => ''
1180 ),
1181 '/fileInRoot',
1182 'newFile',
1183 '/newFile'
1184 )
1185 );
1186 }
1187
1188 /**
1189 * @test
1190 * @dataProvider renamingFiles_dataProvider
1191 */
1192 public function renamingFilesChangesFilenameOnDisk(array $filesystemStructure, $oldFileIdentifier, $newFileName, $expectedNewIdentifier)
1193 {
1194 $this->addToMount($filesystemStructure);
1195 $subject = $this->createDriver();
1196 $newIdentifier = $subject->renameFile($oldFileIdentifier, $newFileName);
1197 $this->assertFalse($subject->fileExists($oldFileIdentifier));
1198 $this->assertTrue($subject->fileExists($newIdentifier));
1199 $this->assertEquals($expectedNewIdentifier, $newIdentifier);
1200 }
1201
1202 /**
1203 * @test
1204 */
1205 public function renamingFilesFailsIfTargetFileExists()
1206 {
1207 $this->setExpectedException(\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException::class, '', 1320291063);
1208 $this->addToMount(array(
1209 'targetFolder' => array('file' => '', 'newFile' => '')
1210 ));
1211 $subject = $this->createDriver();
1212 $subject->renameFile('/targetFolder/file', 'newFile');
1213 }
1214
1215 /**
1216 * We use this data provider for testing move methods because there are some issues with the
1217 *
1218 * @return array
1219 */
1220 public function renamingFolders_dataProvider()
1221 {
1222 return array(
1223 'folder in root folder' => array(
1224 array(
1225 'someFolder' => array()
1226 ),
1227 '/someFolder/',
1228 'newFolder',
1229 '/newFolder/'
1230 ),
1231 'file in subfolder' => array(
1232 array(
1233 'subfolder' => array(
1234 'someFolder' => array()
1235 )
1236 ),
1237 '/subfolder/someFolder/',
1238 'newFolder',
1239 '/subfolder/newFolder/'
1240 )
1241 );
1242 }
1243
1244 /**
1245 * @test
1246 * @dataProvider renamingFolders_dataProvider
1247 */
1248 public function renamingFoldersChangesFolderNameOnDisk(array $filesystemStructure, $oldFolderIdentifier, $newFolderName, $expectedNewIdentifier)
1249 {
1250 $this->addToMount($filesystemStructure);
1251 $subject = $this->createDriver();
1252 $mapping = $subject->renameFolder($oldFolderIdentifier, $newFolderName);
1253 $this->assertFalse($subject->folderExists($oldFolderIdentifier));
1254 $this->assertTrue($subject->folderExists($expectedNewIdentifier));
1255 $this->assertEquals($expectedNewIdentifier, $mapping[$oldFolderIdentifier]);
1256 }
1257
1258 /**
1259 * @test
1260 */
1261 public function renameFolderReturnsCorrectMappingInformationForAllFiles()
1262 {
1263 $fileContents = 'asdfg';
1264 $this->addToMount(array(
1265 'sourceFolder' => array(
1266 'subFolder' => array('file' => $fileContents),
1267 'file2' => 'asdfg'
1268 )
1269 ));
1270 $subject = $this->createDriver();
1271 $mappingInformation = $subject->renameFolder('/sourceFolder/', 'newFolder');
1272 $this->isTrue(is_array($mappingInformation));
1273 $this->assertEquals('/newFolder/', $mappingInformation['/sourceFolder/']);
1274 $this->assertEquals('/newFolder/file2', $mappingInformation['/sourceFolder/file2']);
1275 $this->assertEquals('/newFolder/subFolder/file', $mappingInformation['/sourceFolder/subFolder/file']);
1276 $this->assertEquals('/newFolder/subFolder/', $mappingInformation['/sourceFolder/subFolder/']);
1277 }
1278
1279 /**
1280 * @test
1281 */
1282 public function renameFolderRevertsRenamingIfFilenameMapCannotBeCreated()
1283 {
1284 $this->setExpectedException('\\RuntimeException', '', 1334160746);
1285 $this->addToMount(array(
1286 'sourceFolder' => array(
1287 'file' => 'asdfg'
1288 )
1289 ));
1290 $subject = $this->createDriver(array(), array('createIdentifierMap'));
1291 $subject->expects($this->atLeastOnce())->method('createIdentifierMap')->will($this->throwException(new \TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException()));
1292 $subject->renameFolder('/sourceFolder/', 'newFolder');
1293 $this->assertFileExists($this->getUrlInMount('/sourceFolder/file'));
1294 }
1295
1296 /**
1297 * @test
1298 */
1299 public function isFolderEmptyReturnsTrueForEmptyFolder()
1300 {
1301 // This also prepares the next few tests, so add more info than required for this test
1302 $this->addToMount(array(
1303 'emptyFolder' => array()
1304 ));
1305 $subject = $this->createDriver();
1306 $this->assertTrue($subject->isFolderEmpty('/emptyFolder/'));
1307 return $subject;
1308 }
1309
1310 /**
1311 * @test
1312 */
1313 public function isFolderEmptyReturnsFalseIfFolderHasFile()
1314 {
1315 $this->addToMount(array(
1316 'folderWithFile' => array(
1317 'someFile' => ''
1318 )
1319 ));
1320 $subject = $this->createDriver();
1321 $this->assertFalse($subject->isFolderEmpty('/folderWithFile/'));
1322 }
1323
1324 /**
1325 * @test
1326 */
1327 public function isFolderEmptyReturnsFalseIfFolderHasSubfolder()
1328 {
1329 $this->addToMount(array(
1330 'folderWithSubfolder' => array(
1331 'someFolder' => array()
1332 )
1333 ));
1334 $subject = $this->createDriver();
1335 $this->assertFalse($subject->isFolderEmpty('/folderWithSubfolder/'));
1336 }
1337
1338 /**********************************
1339 * Copy/move folder
1340 **********************************/
1341 /**
1342 * @test
1343 */
1344 public function foldersCanBeMovedWithinStorage()
1345 {
1346 $fileContents = $this->getUniqueId();
1347 $this->addToMount(array(
1348 'sourceFolder' => array(
1349 'file' => $fileContents,
1350 ),
1351 'targetFolder' => array(),
1352 ));
1353 $subject = $this->createDriver();
1354 /** @var \TYPO3\CMS\Core\Resource\Driver\LocalDriver $subject */
1355 $subject->moveFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'someFolder');
1356 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/someFolder/')));
1357 $this->assertEquals($fileContents, file_get_contents($this->getUrlInMount('/targetFolder/someFolder/file')));
1358 $this->assertFileNotExists($this->getUrlInMount('/sourceFolder'));
1359 }
1360
1361 /**
1362 * @test
1363 */
1364 public function moveFolderWithinStorageReturnsCorrectMappingInformationForAllFiles()
1365 {
1366 $fileContents = 'asdfg';
1367 $this->addToMount(array(
1368 'targetFolder' => array(),
1369 'sourceFolder' => array(
1370 'subFolder' => array('file' => $fileContents),
1371 'file' => 'asdfg'
1372 )
1373 ));
1374 $subject = $this->createDriver();
1375 $mappingInformation = $subject->moveFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'sourceFolder');
1376 $this->assertEquals('/targetFolder/sourceFolder/file', $mappingInformation['/sourceFolder/file']);
1377 $this->assertEquals('/targetFolder/sourceFolder/subFolder/file', $mappingInformation['/sourceFolder/subFolder/file']);
1378 $this->assertEquals('/targetFolder/sourceFolder/subFolder/', $mappingInformation['/sourceFolder/subFolder/']);
1379 }
1380
1381 /**
1382 * @test
1383 */
1384 public function folderCanBeRenamedWhenMoving()
1385 {
1386 $this->addToMount(array(
1387 'sourceFolder' => array(
1388 'file' => $this->getUniqueId(),
1389 ),
1390 'targetFolder' => array(),
1391 ));
1392 $subject = $this->createDriver();
1393 $subject->moveFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolder');
1394 $this->assertTrue(file_exists($this->getUrlInMount('/targetFolder/newFolder/')));
1395 }
1396
1397 /**
1398 * @test
1399 */
1400 public function copyFolderWithinStorageCopiesSingleFileToNewFolderName()
1401 {
1402 $this->addToMount(array(
1403 'sourceFolder' => array(
1404 'file' => $this->getUniqueId(),
1405 ),
1406 'targetFolder' => array(),
1407 ));
1408 $subject = $this->createDriver();
1409 $subject->copyFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolderName');
1410 $this->assertTrue(is_file($this->getUrlInMount('/targetFolder/newFolderName/file')));
1411 }
1412
1413 /**
1414 * @test
1415 */
1416 public function copyFolderWithinStorageCopiesSingleSubFolderToNewFolderName()
1417 {
1418 list($basePath, $subject) = $this->prepareRealTestEnvironment();
1419 GeneralUtility::mkdir_deep($basePath, '/sourceFolder/subFolder');
1420 GeneralUtility::mkdir_deep($basePath, '/targetFolder');
1421
1422 $subject->copyFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolderName');
1423 $this->isTrue(is_dir($basePath . '/targetFolder/newFolderName/subFolder'));
1424 }
1425
1426 /**
1427 * @test
1428 */
1429 public function copyFolderWithinStorageCopiesFileInSingleSubFolderToNewFolderName()
1430 {
1431 list($basePath, $subject) = $this->prepareRealTestEnvironment();
1432 GeneralUtility::mkdir_deep($basePath, '/sourceFolder/subFolder');
1433 GeneralUtility::mkdir_deep($basePath, '/targetFolder');
1434 file_put_contents($basePath . '/sourceFolder/subFolder/file', $this->getUniqueId());
1435 GeneralUtility::fixPermissions($basePath . '/sourceFolder/subFolder/file');
1436
1437 $subject->copyFolderWithinStorage('/sourceFolder/', '/targetFolder/', 'newFolderName');
1438 $this->assertTrue(is_file($basePath . '/targetFolder/newFolderName/subFolder/file'));
1439 }
1440
1441 ///////////////////////
1442 // Tests concerning sanitizeFileName
1443 ///////////////////////
1444
1445 /**
1446 * Set up data for sanitizeFileName tests
1447 */
1448 public function setUpCharacterStrings()
1449 {
1450 // Generate string containing all characters for the iso8859-1 charset, charcode greater than 127
1451 $this->iso88591GreaterThan127 = '';
1452 for ($i = 0xA0; $i <= 0xFF; $i++) {
1453 $this->iso88591GreaterThan127 .= chr($i);
1454 }
1455
1456 // Generate string containing all characters for the utf-8 Latin-1 Supplement (U+0080 to U+00FF)
1457 // without U+0080 to U+009F: control characters
1458 // Based on http://www.utf8-chartable.de/unicode-utf8-table.pl
1459 $this->utf8Latin1Supplement = '';
1460 for ($i = 0xA0; $i <= 0xBF; $i++) {
1461 $this->utf8Latin1Supplement .= chr(0xC2) . chr($i);
1462 }
1463 for ($i = 0x80; $i <= 0xBF; $i++) {
1464 $this->utf8Latin1Supplement .= chr(0xC3) . chr($i);
1465 }
1466
1467 // Generate string containing all characters for the utf-8 Latin-1 Extended-A (U+0100 to U+017F)
1468 $this->utf8Latin1ExtendedA = '';
1469 for ($i = 0x80; $i <= 0xBF; $i++) {
1470 $this->utf8Latin1ExtendedA .= chr(0xC4) . chr($i);
1471 }
1472 for ($i = 0x80; $i <= 0xBF; $i++) {
1473 $this->utf8Latin1ExtendedA .= chr(0xC5) . chr($i);
1474 }
1475 }
1476
1477 /**
1478 * Data provider for sanitizeFileNameUTF8FilesystemDataProvider
1479 *
1480 * Every array splits into:
1481 * - String value fileName
1482 * - String value charset (none = '', utf-8, latin1, etc.)
1483 * - Expected result (cleaned fileName)
1484 *
1485 * @return array
1486 */
1487 public function sanitizeFileNameUTF8FilesystemDataProvider()
1488 {
1489 $this->setUpCharacterStrings();
1490 return array(
1491 // Characters ordered by ASCII table
1492 'allowed characters utf-8 (ASCII part)' => array(
1493 '-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz',
1494 '-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
1495 ),
1496 // Characters ordered by ASCII table (except for space-character, because space-character ist trimmed)
1497 'replace special characters with _ (not allowed characters) utf-8 (ASCII part)' => array(
1498 '! "#$%&\'()*+,/:;<=>?[\\]^`{|}~',
1499 '_____________________________'
1500 ),
1501 'utf-8 (Latin-1 Supplement)' => array(
1502 $this->utf8Latin1Supplement,
1503 '________________________________ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
1504 ),
1505 'trim leading and tailing spaces utf-8' => array(
1506 ' test.txt ',
1507 'test.txt'
1508 ),
1509 'remove tailing dot' => array(
1510 'test.txt.',
1511 'test.txt'
1512 ),
1513 );
1514 }
1515
1516 /**
1517 * @test
1518 * @dataProvider sanitizeFileNameUTF8FilesystemDataProvider
1519 */
1520 public function sanitizeFileNameUTF8Filesystem($fileName, $expectedResult)
1521 {
1522 $GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem'] = 1;
1523 $this->assertEquals(
1524 $expectedResult,
1525 $this->createDriver()->sanitizeFileName($fileName)
1526 );
1527 }
1528
1529
1530 /**
1531 * Data provider for sanitizeFileNameNonUTF8Filesystem
1532 *
1533 * Every array splits into:
1534 * - String value fileName
1535 * - String value charset (none = '', utf-8, latin1, etc.)
1536 * - Expected result (cleaned fileName)
1537 *
1538 * @return array
1539 */
1540 public function sanitizeFileNameNonUTF8FilesystemDataProvider()
1541 {
1542 $this->setUpCharacterStrings();
1543 return array(
1544 // Characters ordered by ASCII table
1545 'allowed characters iso-8859-1' => array(
1546 '-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz',
1547 'iso-8859-1',
1548 '-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
1549 ),
1550 // Characters ordered by ASCII table
1551 'allowed characters utf-8' => array(
1552 '-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz',
1553 'utf-8',
1554 '-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
1555 ),
1556 // Characters ordered by ASCII table (except for space-character, because space-character ist trimmed)
1557 'replace special characters with _ (not allowed characters) iso-8859-1' => array(
1558 '! "#$%&\'()*+,/:;<=>?[\\]^`{|}~',
1559 'iso-8859-1',
1560 '_____________________________'
1561 ),
1562 // Characters ordered by ASCII table (except for space-character, because space-character ist trimmed)
1563 'replace special characters with _ (not allowed characters) utf-8' => array(
1564 '! "#$%&\'()*+,/:;<=>?[\\]^`{|}~',
1565 'utf-8',
1566 '_____________________________'
1567 ),
1568 'iso-8859-1 (code > 127)' => array(
1569 // http://de.wikipedia.org/wiki/ISO_8859-1
1570 // chr(0xA0) = NBSP (no-break space) => gets trimmed
1571 $this->iso88591GreaterThan127,
1572 'iso-8859-1',
1573 '_centpound_yen____c_a_____R_____-23_u___1o__1_41_23_4_AAAAAEAAAECEEEEIIIIDNOOOOOExOEUUUUEYTHssaaaaaeaaaeceeeeiiiidnoooooe_oeuuuueythy'
1574 ),
1575 'utf-8 (Latin-1 Supplement)' => array(
1576 // chr(0xC2) . chr(0x0A) = NBSP (no-break space) => gets trimmed
1577 $this->utf8Latin1Supplement,
1578 'utf-8',
1579 '_centpound__yen______c_a_______R_______-23__u_____1o__1_41_23_4_AAAAAEAAAECEEEEIIIIDNOOOOOExOEUUUUEYTHssaaaaaeaaaeceeeeiiiidnoooooe_oeuuuueythy'
1580 ),
1581 'utf-8 (Latin-1 Extended A)' => array(
1582 $this->utf8Latin1ExtendedA,
1583 'utf-8',
1584 'AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIJijJjKk__LlLlLlL_l_LlNnNnNn_n____OOooOoOoOEoeRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzs'
1585 ),
1586 'trim leading and tailing spaces iso-8859-1' => array(
1587 ' test.txt ',
1588 'iso-8859-1',
1589 'test.txt'
1590 ),
1591 'trim leading and tailing spaces utf-8' => array(
1592 ' test.txt ',
1593 'utf-8',
1594 'test.txt'
1595 ),
1596 'remove tailing dot iso-8859-1' => array(
1597 'test.txt.',
1598 'iso-8859-1',
1599 'test.txt'
1600 ),
1601 'remove tailing dot utf-8' => array(
1602 'test.txt.',
1603 'utf-8',
1604 'test.txt'
1605 ),
1606 );
1607 }
1608
1609 /**
1610 * @test
1611 * @dataProvider sanitizeFileNameNonUTF8FilesystemDataProvider
1612 */
1613 public function sanitizeFileNameNonUTF8Filesystem($fileName, $charset, $expectedResult)
1614 {
1615 $GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem'] = 0;
1616 $this->assertEquals(
1617 $expectedResult,
1618 $this->createDriver()->sanitizeFileName($fileName, $charset)
1619 );
1620 }
1621
1622 /**
1623 * @test
1624 * @expectedException \TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException
1625 */
1626 public function sanitizeFileNameThrowsExceptionOnInvalidFileName()
1627 {
1628 $GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem'] = 1;
1629 $this->createDriver()->sanitizeFileName('');
1630 }
1631
1632 /**
1633 * @test
1634 */
1635 public function applyFilterMethodsToDirectoryItemCallsFilterMethodIfClosure()
1636 {
1637 $this->setExpectedException('Exception', 'I was called!');
1638 $closure = function () {
1639 throw new \Exception('I was called!');
1640 };
1641
1642 $filterMethods = array(
1643 $closure,
1644 );
1645
1646 $this->createDriver()->_call('applyFilterMethodsToDirectoryItem', $filterMethods, '', '', '');
1647 }
1648
1649 /**
1650 * @test
1651 */
1652 public function applyFilterMethodsToDirectoryItemCallsFilterMethodIfName()
1653 {
1654 $dummyObject = $this
1655 ->getMockBuilder('\TYPO3\CMS\Core\Resource\Driver\LocalDriver')
1656 ->setMethods(array('dummy'))
1657 ->disableOriginalConstructor()
1658 ->getMock();
1659 $method = array(
1660 $dummyObject,
1661 'dummy',
1662 );
1663 $dummyObject->expects($this->once())->method('dummy');
1664 $filterMethods = array(
1665 $method,
1666 );
1667 $this->createDriver()->_call('applyFilterMethodsToDirectoryItem', $filterMethods, '', '', '');
1668 }
1669 }