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