[BUGFIX] Reload ext_emconf.php after extension update
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Tests / Unit / Utility / FileHandlingUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Utility;
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 /**
18 * Testcase
19 *
20 */
21 class FileHandlingUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
22
23 /**
24 * @var array List of created fake extensions to be deleted in tearDown() again
25 */
26 protected $fakedExtensions = array();
27
28 /**
29 * Creates a fake extension inside typo3temp/. No configuration is created,
30 * just the folder
31 *
32 * @param bool $extkeyOnly
33 * @return string The extension key
34 */
35 protected function createFakeExtension($extkeyOnly = FALSE) {
36 $extKey = strtolower($this->getUniqueId('testing'));
37 $absExtPath = PATH_site . 'typo3temp/ext-' . $extKey . '/';
38 $relPath = 'typo3temp/ext-' . $extKey . '/';
39 $this->fakedExtensions[$extKey] = array(
40 'siteRelPath' => $relPath,
41 'siteAbsPath' => $absExtPath
42 );
43 if ($extkeyOnly === TRUE) {
44 return $extKey;
45 }
46 \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir($absExtPath);
47 $this->testFilesToDelete[] = PATH_site . 'typo3temp/ext-' . $extKey;
48 return $extKey;
49 }
50
51 /**
52 * @test
53 * @return void
54 */
55 public function makeAndClearExtensionDirRemovesExtensionDirIfAlreadyExists() {
56 $extKey = $this->createFakeExtension();
57 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('removeDirectory', 'addDirectory', 'getExtensionDir'), array(), '', FALSE);
58 $fileHandlerMock->expects($this->once())
59 ->method('removeDirectory')
60 ->with(PATH_site . 'typo3temp/ext-' . $extKey . '/');
61 $fileHandlerMock->expects($this->any())
62 ->method('getExtensionDir')
63 ->willReturn(PATH_site . 'typo3temp/ext-' . $extKey . '/');
64 $fileHandlerMock->_call('makeAndClearExtensionDir', $extKey);
65 }
66
67 /**
68 * @return array
69 */
70 public function invalidRelativePathDataProvider() {
71 return array(
72 array('../../'),
73 array('/foo/bar'),
74 array('foo//bar'),
75 array('foo/bar' . chr(0)),
76 );
77 }
78
79 /**
80 * @param string $invalidRelativePath
81 * @test
82 * @dataProvider invalidRelativePathDataProvider
83 * @expectedException \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
84 */
85 public function getAbsolutePathThrowsExceptionForInvalidRelativePaths($invalidRelativePath) {
86 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('dummy'), array());
87 $fileHandlerMock->_call('getAbsolutePath', $invalidRelativePath);
88 }
89
90 /**
91 * @return array
92 */
93 public function validRelativePathDataProvider() {
94 return array(
95 array('foo/../bar', PATH_site . 'bar'),
96 array('bas', PATH_site . 'bas'),
97 );
98 }
99
100 /**
101 * @param string $validRelativePath
102 * @param string $expectedAbsolutePath
103 * @test
104 * @dataProvider validRelativePathDataProvider
105 */
106 public function getAbsolutePathReturnsAbsolutePathForValidRelativePaths($validRelativePath, $expectedAbsolutePath) {
107 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('dummy'));
108 $this->assertSame($expectedAbsolutePath, $fileHandlerMock->_call('getAbsolutePath', $validRelativePath));
109 }
110
111 /**
112 * @test
113 * @return void
114 */
115 public function makeAndClearExtensionDirAddsDir() {
116 $extKey = $this->createFakeExtension();
117 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('removeDirectory', 'addDirectory', 'getExtensionDir'));
118 $fileHandlerMock->expects($this->once())
119 ->method('addDirectory')
120 ->with(PATH_site . 'typo3temp/ext-' . $extKey . '/');
121 $fileHandlerMock->expects($this->any())
122 ->method('getExtensionDir')
123 ->willReturn(PATH_site . 'typo3temp/ext-' . $extKey . '/');
124 $fileHandlerMock->_call('makeAndClearExtensionDir', $extKey);
125 }
126
127 /**
128 * @test
129 * @expectedException \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
130 * @return void
131 */
132 public function makeAndClearExtensionDirThrowsExceptionOnInvalidPath() {
133 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('removeDirectory', 'addDirectory'));
134 $languageServiceMock = $this->getMock(\TYPO3\CMS\Lang\LanguageService::class);
135 $fileHandlerMock->_set('languageService', $languageServiceMock);
136 $fileHandlerMock->_call('makeAndClearExtensionDir', 'testing123', 'fakepath');
137 }
138
139 /**
140 * @test
141 * @return void
142 */
143 public function addDirectoryAddsDirectory() {
144 $extDirPath = PATH_site . '/typo3temp/' . $this->getUniqueId('test-extensions-');
145 $this->testFilesToDelete[] = $extDirPath;
146 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('dummy'));
147 $fileHandlerMock->_call('addDirectory', $extDirPath);
148 $this->assertTrue(is_dir($extDirPath));
149 }
150
151 /**
152 * @test
153 * @return void
154 */
155 public function removeDirectoryRemovesDirectory() {
156 $extDirPath = PATH_site . '/typo3temp/' . $this->getUniqueId('test-extensions-');
157 @mkdir($extDirPath);
158 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('dummy'));
159 $fileHandlerMock->_call('removeDirectory', $extDirPath);
160 $this->assertFalse(is_dir($extDirPath));
161 }
162
163 /**
164 * @test
165 * @return void
166 */
167 public function removeDirectoryRemovesSymlink() {
168 $absoluteSymlinkPath = PATH_site . 'typo3temp/' . $this->getUniqueId('test_symlink_');
169 $absoluteFilePath = PATH_site . 'typo3temp/' . $this->getUniqueId('test_file_');
170 touch($absoluteFilePath);
171 $this->testFilesToDelete[] = $absoluteFilePath;
172 symlink($absoluteFilePath, $absoluteSymlinkPath);
173 $fileHandler = new \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility();
174 $fileHandler->removeDirectory($absoluteSymlinkPath);
175 $this->assertFalse(is_link($absoluteSymlinkPath));
176 }
177
178 /**
179 * @test
180 * @return void
181 */
182 public function removeDirectoryDoesNotRemoveContentOfSymlinkedTargetDirectory() {
183 $absoluteSymlinkPath = PATH_site . 'typo3temp/' . $this->getUniqueId('test_symlink_');
184 $absoluteDirectoryPath = PATH_site . 'typo3temp/' . $this->getUniqueId('test_dir_') . '/';
185 $relativeFilePath = $this->getUniqueId('test_file_');
186
187 mkdir($absoluteDirectoryPath);
188 touch($absoluteDirectoryPath . $relativeFilePath);
189
190 $this->testFilesToDelete[] = $absoluteDirectoryPath . $relativeFilePath;
191 $this->testFilesToDelete[] = $absoluteDirectoryPath;
192
193 symlink($absoluteDirectoryPath, $absoluteSymlinkPath);
194
195 $fileHandler = new \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility();
196 $fileHandler->removeDirectory($absoluteSymlinkPath);
197 $this->assertTrue(is_file($absoluteDirectoryPath . $relativeFilePath));
198 }
199
200 /**
201 * @test
202 * @return void
203 */
204 public function unpackExtensionFromExtensionDataArrayCreatesTheExtensionDirectory() {
205 $extensionData = array(
206 'extKey' => 'test'
207 );
208 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array(
209 'makeAndClearExtensionDir',
210 'writeEmConfToFile',
211 'extractFilesArrayFromExtensionData',
212 'extractDirectoriesFromExtensionData',
213 'createDirectoriesForExtensionFiles',
214 'writeExtensionFiles',
215 'reloadPackageInformation',
216 ));
217 $fileHandlerMock->expects($this->once())->method('extractFilesArrayFromExtensionData')->will($this->returnValue(array()));
218 $fileHandlerMock->expects($this->once())->method('extractDirectoriesFromExtensionData')->will($this->returnValue(array()));
219 $fileHandlerMock->expects($this->once())->method('makeAndClearExtensionDir')->with($extensionData['extKey']);
220 $fileHandlerMock->_call('unpackExtensionFromExtensionDataArray', $extensionData);
221 }
222
223 /**
224 * @test
225 * @return void
226 */
227 public function unpackExtensionFromExtensionDataArrayStripsDirectoriesFromFilesArray() {
228 $extensionData = array(
229 'extKey' => 'test'
230 );
231 $files = array(
232 'ChangeLog' => array(
233 'name' => 'ChangeLog',
234 'size' => 4559,
235 'mtime' => 1219448527,
236 'is_executable' => FALSE,
237 'content' => 'some content to write'
238 ),
239 'doc/' => array(
240 'name' => 'doc/',
241 'size' => 0,
242 'mtime' => 1219448527,
243 'is_executable' => FALSE,
244 'content' => ''
245 ),
246 'doc/ChangeLog' => array(
247 'name' => 'ChangeLog',
248 'size' => 4559,
249 'mtime' => 1219448527,
250 'is_executable' => FALSE,
251 'content' => 'some content to write'
252 ),
253 );
254 $cleanedFiles = array(
255 'ChangeLog' => array(
256 'name' => 'ChangeLog',
257 'size' => 4559,
258 'mtime' => 1219448527,
259 'is_executable' => FALSE,
260 'content' => 'some content to write'
261 ),
262 'doc/ChangeLog' => array(
263 'name' => 'ChangeLog',
264 'size' => 4559,
265 'mtime' => 1219448527,
266 'is_executable' => FALSE,
267 'content' => 'some content to write'
268 ),
269 );
270 $directories = array(
271 'doc/',
272 'mod/doc/'
273 );
274
275 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array(
276 'makeAndClearExtensionDir',
277 'writeEmConfToFile',
278 'extractFilesArrayFromExtensionData',
279 'extractDirectoriesFromExtensionData',
280 'createDirectoriesForExtensionFiles',
281 'writeExtensionFiles',
282 'reloadPackageInformation',
283 ));
284 $fileHandlerMock->expects($this->once())->method('extractFilesArrayFromExtensionData')->will($this->returnValue($files));
285 $fileHandlerMock->expects($this->once())->method('extractDirectoriesFromExtensionData')->will($this->returnValue($directories));
286 $fileHandlerMock->expects($this->once())->method('createDirectoriesForExtensionFiles')->with($directories);
287 $fileHandlerMock->expects($this->once())->method('writeExtensionFiles')->with($cleanedFiles);
288 $fileHandlerMock->expects($this->once())->method('reloadPackageInformation')->with('test');
289 $fileHandlerMock->_call('unpackExtensionFromExtensionDataArray', $extensionData);
290 }
291
292 /**
293 * @test
294 * @return void
295 */
296 public function extractFilesArrayFromExtensionDataReturnsFileArray() {
297 $extensionData = array(
298 'key' => 'test',
299 'FILES' => array(
300 'filename1' => 'dummycontent',
301 'filename2' => 'dummycontent2'
302 )
303 );
304 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('makeAndClearExtensionDir'));
305 $extractedFiles = $fileHandlerMock->_call('extractFilesArrayFromExtensionData', $extensionData);
306 $this->assertArrayHasKey('filename1', $extractedFiles);
307 $this->assertArrayHasKey('filename2', $extractedFiles);
308 }
309
310 /**
311 * @test
312 * @return void
313 */
314 public function writeExtensionFilesWritesFiles() {
315 $files = array(
316 'ChangeLog' => array(
317 'name' => 'ChangeLog',
318 'size' => 4559,
319 'mtime' => 1219448527,
320 'is_executable' => FALSE,
321 'content' => 'some content to write'
322 ),
323 'README' => array(
324 'name' => 'README',
325 'size' => 4566,
326 'mtime' => 1219448533,
327 'is_executable' => FALSE,
328 'content' => 'FEEL FREE TO ADD SOME DOCUMENTATION HERE'
329 )
330 );
331 $rootPath = ($extDirPath = $this->fakedExtensions[$this->createFakeExtension()]['siteAbsPath']);
332 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('makeAndClearExtensionDir'));
333 $fileHandlerMock->_call('writeExtensionFiles', $files, $rootPath);
334 $this->assertTrue(file_exists($rootPath . 'ChangeLog'));
335 }
336
337 /**
338 * @test
339 * @return void
340 */
341 public function extractDirectoriesFromExtensionDataExtractsDirectories() {
342 $files = array(
343 'ChangeLog' => array(
344 'name' => 'ChangeLog',
345 'size' => 4559,
346 'mtime' => 1219448527,
347 'is_executable' => FALSE,
348 'content' => 'some content to write'
349 ),
350 'doc/' => array(
351 'name' => 'doc/',
352 'size' => 0,
353 'mtime' => 1219448527,
354 'is_executable' => FALSE,
355 'content' => ''
356 ),
357 'doc/ChangeLog' => array(
358 'name' => 'ChangeLog',
359 'size' => 4559,
360 'mtime' => 1219448527,
361 'is_executable' => FALSE,
362 'content' => 'some content to write'
363 ),
364 'doc/README' => array(
365 'name' => 'README',
366 'size' => 4566,
367 'mtime' => 1219448533,
368 'is_executable' => FALSE,
369 'content' => 'FEEL FREE TO ADD SOME DOCUMENTATION HERE'
370 ),
371 'mod/doc/README' => array(
372 'name' => 'README',
373 'size' => 4566,
374 'mtime' => 1219448533,
375 'is_executable' => FALSE,
376 'content' => 'FEEL FREE TO ADD SOME DOCUMENTATION HERE'
377 )
378 );
379 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('makeAndClearExtensionDir'));
380 $extractedDirectories = $fileHandlerMock->_call('extractDirectoriesFromExtensionData', $files);
381 $expected = array(
382 'doc/',
383 'mod/doc/'
384 );
385 $this->assertSame($expected, array_values($extractedDirectories));
386 }
387
388 /**
389 * @test
390 * @return void
391 */
392 public function createDirectoriesForExtensionFilesCreatesDirectories() {
393 $rootPath = $this->fakedExtensions[$this->createFakeExtension()]['siteAbsPath'];
394 $directories = array(
395 'doc/',
396 'mod/doc/'
397 );
398 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('makeAndClearExtensionDir'));
399 $this->assertFalse(is_dir($rootPath . 'doc/'));
400 $this->assertFalse(is_dir($rootPath . 'mod/doc/'));
401 $fileHandlerMock->_call('createDirectoriesForExtensionFiles', $directories, $rootPath);
402 $this->assertTrue(is_dir($rootPath . 'doc/'));
403 $this->assertTrue(is_dir($rootPath . 'mod/doc/'));
404 }
405
406 /**
407 * @test
408 * @return void
409 */
410 public function writeEmConfWritesEmConfFile() {
411 $extKey = $this->createFakeExtension();
412 $extensionData = array(
413 'extKey' => $extKey,
414 'EM_CONF' => array(
415 'title' => 'Plugin cache engine',
416 'description' => 'Provides an interface to cache plugin content elements based on 4.3 caching framework',
417 'category' => 'Frontend',
418 )
419 );
420 $rootPath = $this->fakedExtensions[$extKey]['siteAbsPath'];
421 $emConfUtilityMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\EmConfUtility::class, array('constructEmConf'));
422 $emConfUtilityMock->expects($this->once())->method('constructEmConf')->with($extensionData)->will($this->returnValue(var_export($extensionData['EM_CONF'], TRUE)));
423 $fileHandlerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('makeAndClearExtensionDir'));
424 $fileHandlerMock->_set('emConfUtility', $emConfUtilityMock);
425 $fileHandlerMock->_call('writeEmConfToFile', $extensionData, $rootPath);
426 $this->assertTrue(file_exists($rootPath . 'ext_emconf.php'));
427 }
428
429 /**
430 * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
431 */
432 protected function getPreparedFileHandlingMockForDirectoryCreationTests() {
433 /** @var $fileHandlerMock \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility|\PHPUnit_Framework_MockObject_MockObject */
434 $fileHandlerMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class, array('createNestedDirectory', 'getAbsolutePath', 'directoryExists'));
435 $fileHandlerMock->expects($this->any())
436 ->method('getAbsolutePath')
437 ->will($this->returnArgument(0));
438 return $fileHandlerMock;
439 }
440
441 /**
442 * @test
443 */
444 public function uploadFolderIsNotCreatedIfNotRequested() {
445 $fileHandlerMock = $this->getPreparedFileHandlingMockForDirectoryCreationTests();
446 $fileHandlerMock->expects($this->never())
447 ->method('createNestedDirectory');
448 $fileHandlerMock->ensureConfiguredDirectoriesExist(array(
449 'key' => 'foo_bar',
450 'uploadfolder' => 0,
451 )
452 );
453 }
454
455 /**
456 * @test
457 */
458 public function additionalFoldersAreNotCreatedIfNotRequested() {
459 $fileHandlerMock = $this->getPreparedFileHandlingMockForDirectoryCreationTests();
460 $fileHandlerMock->expects($this->never())
461 ->method('createNestedDirectory');
462 $fileHandlerMock->ensureConfiguredDirectoriesExist(array(
463 'key' => 'foo_bar',
464 'createDirs' => '',
465 )
466 );
467 }
468
469 /**
470 * @test
471 */
472 public function configuredUploadFolderIsCreatedIfRequested() {
473 $fileHandlerMock = $this->getPreparedFileHandlingMockForDirectoryCreationTests();
474 $fileHandlerMock->expects($this->once())
475 ->method('createNestedDirectory')
476 ->with('uploads/tx_foobar/');
477 $fileHandlerMock->ensureConfiguredDirectoriesExist(array(
478 'key' => 'foo_bar',
479 'uploadfolder' => 1,
480 )
481 );
482 }
483
484 /**
485 * @test
486 */
487 public function configuredAdditionalDirectoriesAreCreatedIfRequested() {
488 $fileHandlerMock = $this->getPreparedFileHandlingMockForDirectoryCreationTests();
489 $fileHandlerMock->expects($this->exactly(2))
490 ->method('createNestedDirectory')
491 ->will($this->returnCallback(function($path) {
492 if (!in_array($path, array('foo/bar', 'baz/foo'))) {
493 throw new \Exception('Path "' . $path . '" is not expected to be created');
494 }
495
496 })
497 );
498 $fileHandlerMock->ensureConfiguredDirectoriesExist(array(
499 'key' => 'foo_bar',
500 'createDirs' => 'foo/bar, baz/foo',
501 )
502 );
503 }
504
505 /**
506 * @test
507 */
508 public function configuredDirectoriesAreNotCreatedIfTheyAlreadyExist() {
509 $fileHandlerMock = $this->getPreparedFileHandlingMockForDirectoryCreationTests();
510 $fileHandlerMock->expects($this->exactly(3))
511 ->method('directoryExists')
512 ->will($this->returnValue(TRUE));
513 $fileHandlerMock->expects($this->never())
514 ->method('createNestedDirectory');
515 $fileHandlerMock->ensureConfiguredDirectoriesExist(array(
516 'key' => 'foo_bar',
517 'uploadfolder' => 1,
518 'createDirs' => 'foo/bar, baz/foo',
519 )
520 );
521 }
522
523 /**
524 * Warning: This test asserts multiple things at once to keep the setup short.
525 *
526 * @test
527 */
528 public function createZipFileFromExtensionGeneratesCorrectArchive() {
529 // 42 second of first day in 1970 - used to have achieve stable file names
530 $GLOBALS['EXEC_TIME'] = 42;
531
532 // Create extension for testing:
533 $extKey = $this->createFakeExtension();
534 $extensionRoot = $this->fakedExtensions[$extKey]['siteAbsPath'];
535
536 // Build mocked fileHandlingUtility:
537 $fileHandlerMock = $this->getAccessibleMock(
538 \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility::class,
539 array('getAbsoluteExtensionPath', 'getExtensionVersion')
540 );
541 $fileHandlerMock->expects($this->any())
542 ->method('getAbsoluteExtensionPath')
543 ->will($this->returnValue($extensionRoot));
544 $fileHandlerMock->expects($this->any())
545 ->method('getExtensionVersion')
546 ->will($this->returnValue('0.0.0'));
547
548 // Add files and directories to extension:
549 touch($extensionRoot . 'emptyFile.txt');
550 file_put_contents($extensionRoot . 'notEmptyFile.txt', 'content');
551 touch($extensionRoot . '.hiddenFile');
552 mkdir($extensionRoot . 'emptyDir');
553 mkdir($extensionRoot . 'notEmptyDir');
554 touch($extensionRoot . 'notEmptyDir/file.txt');
555
556 // Create zip-file from extension
557 $filename = $fileHandlerMock->_call('createZipFileFromExtension', $extKey);
558
559 $expectedFilename = PATH_site . 'typo3temp/ExtensionManager/' . $extKey . '_0.0.0_' . date('YmdHi', 42) . '.zip';
560 $this->testFilesToDelete[] = $filename;
561 $this->assertEquals($expectedFilename, $filename, 'Archive file name differs from expectation');
562
563 // File was created
564 $this->assertTrue(file_exists($filename), 'Zip file not created');
565
566 // Read archive and check its contents
567 $archive = new \ZipArchive();
568 $this->assertTrue($archive->open($filename), 'Unable to open archive');
569 $this->assertEquals($archive->statName('emptyFile.txt')->size, 0, 'Empty file not in archive');
570 $this->assertEquals($archive->getFromName('notEmptyFile.txt'), 'content', 'Expected content not found');
571 $this->assertFalse($archive->statName('.hiddenFile'), 'Hidden file not in archive');
572 $this->assertTrue(is_array($archive->statName('emptyDir/')), 'Empty directory not in archive');
573 $this->assertTrue(is_array($archive->statName('notEmptyDir/')), 'Not empty directory not in archive');
574 $this->assertTrue(is_array($archive->statName('notEmptyDir/file.txt')), 'File within directory not in archive');
575
576 // Check that the archive has no additional content
577 $this->assertEquals($archive->numFiles, 5, 'Too many or too less files in archive');
578 }
579
580 }