FileHandlingUtilityTest.php 13.9 KB
Newer Older
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
9
10
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
11
 *
12
13
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
16
 * The TYPO3 project - inspiring people to share!
 */
17
18
19

namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Utility;

20
use TYPO3\CMS\Core\Core\Environment;
21
22
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
23
use TYPO3\CMS\Core\Utility\StringUtility;
24
use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
25
26
27
use TYPO3\CMS\Extensionmanager\Utility\EmConfUtility;
use TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility;
use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
28

29
/**
30
 * Testcase
31
 */
32
class FileHandlingUtilityTest extends UnitTestCase
33
34
35
36
{
    /**
     * @var array List of created fake extensions to be deleted in tearDown() again
     */
37
    protected $fakedExtensions = [];
38
39
40
41
42
43
44
45
46
47

    /**
     * Creates a fake extension inside typo3temp/. No configuration is created,
     * just the folder
     *
     * @param bool $extkeyOnly
     * @return string The extension key
     */
    protected function createFakeExtension($extkeyOnly = false)
    {
48
        $extKey = strtolower(StringUtility::getUniqueId('testing'));
49
        $absExtPath = Environment::getVarPath() . '/tests/ext-' . $extKey . '/';
50
        $this->fakedExtensions[$extKey] = [
51
            'packagePath' => $absExtPath
52
        ];
53
54
55
        if ($extkeyOnly === true) {
            return $extKey;
        }
56
        GeneralUtility::mkdir($absExtPath);
57
        $this->testFilesToDelete[] = Environment::getVarPath() . '/tests/ext-' . $extKey;
58
59
60
61
62
63
64
65
66
        return $extKey;
    }

    /**
     * @test
     */
    public function makeAndClearExtensionDirRemovesExtensionDirIfAlreadyExists()
    {
        $extKey = $this->createFakeExtension();
67
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['removeDirectory', 'addDirectory', 'getExtensionDir'], [], '', false);
68
        $fileHandlerMock->expects(self::once())
69
            ->method('removeDirectory')
70
            ->with(Environment::getVarPath() . '/tests/ext-' . $extKey . '/');
71
        $fileHandlerMock->expects(self::any())
72
            ->method('getExtensionDir')
73
            ->willReturn(Environment::getVarPath() . '/tests/ext-' . $extKey . '/');
74
75
76
77
78
79
80
81
82
        $fileHandlerMock->_call('makeAndClearExtensionDir', $extKey);
    }

    /**
     * @test
     */
    public function makeAndClearExtensionDirAddsDir()
    {
        $extKey = $this->createFakeExtension();
83
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['removeDirectory', 'addDirectory', 'getExtensionDir']);
84
        $fileHandlerMock->expects(self::once())
85
            ->method('addDirectory')
86
            ->with(Environment::getVarPath() . '/tests/ext-' . $extKey . '/');
87
        $fileHandlerMock->expects(self::any())
88
            ->method('getExtensionDir')
89
            ->willReturn(Environment::getVarPath() . '/tests/ext-' . $extKey . '/');
90
91
92
93
94
95
96
97
        $fileHandlerMock->_call('makeAndClearExtensionDir', $extKey);
    }

    /**
     * @test
     */
    public function makeAndClearExtensionDirThrowsExceptionOnInvalidPath()
    {
98
99
        $this->expectException(ExtensionManagerException::class);
        $this->expectExceptionCode(1337280417);
100
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['removeDirectory', 'addDirectory']);
101
        $languageServiceMock = $this->getMockBuilder(LanguageService::class)->disableOriginalConstructor()->getMock();
102
        $fileHandlerMock->injectLanguageService($languageServiceMock);
103
104
105
106
107
108
109
110
        $fileHandlerMock->_call('makeAndClearExtensionDir', 'testing123', 'fakepath');
    }

    /**
     * @test
     */
    public function addDirectoryAddsDirectory()
    {
111
        $extDirPath = Environment::getVarPath() . '/tests/' . StringUtility::getUniqueId('test-extensions-');
112
        $this->testFilesToDelete[] = $extDirPath;
113
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['dummy']);
114
        $fileHandlerMock->_call('addDirectory', $extDirPath);
115
        self::assertTrue(is_dir($extDirPath));
116
117
118
119
120
121
122
    }

    /**
     * @test
     */
    public function removeDirectoryRemovesDirectory()
    {
123
        $extDirPath = Environment::getVarPath() . '/tests/' . StringUtility::getUniqueId('test-extensions-');
124
        @mkdir($extDirPath);
125
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['dummy']);
126
        $fileHandlerMock->_call('removeDirectory', $extDirPath);
127
        self::assertFalse(is_dir($extDirPath));
128
129
130
131
132
133
134
    }

    /**
     * @test
     */
    public function removeDirectoryRemovesSymlink()
    {
135
136
        $absoluteSymlinkPath = Environment::getVarPath() . '/tests/' . StringUtility::getUniqueId('test_symlink_');
        $absoluteFilePath = Environment::getVarPath() . '/tests/' . StringUtility::getUniqueId('test_file_');
137
138
139
        touch($absoluteFilePath);
        $this->testFilesToDelete[] = $absoluteFilePath;
        symlink($absoluteFilePath, $absoluteSymlinkPath);
140
        $fileHandler = new FileHandlingUtility();
141
        $fileHandler->removeDirectory($absoluteSymlinkPath);
142
        self::assertFalse(is_link($absoluteSymlinkPath));
143
144
145
146
147
148
149
    }

    /**
     * @test
     */
    public function removeDirectoryDoesNotRemoveContentOfSymlinkedTargetDirectory()
    {
150
151
152
        $absoluteSymlinkPath = Environment::getVarPath() . '/tests/' . StringUtility::getUniqueId('test_symlink_');
        $absoluteDirectoryPath = Environment::getVarPath() . '/tests/' . StringUtility::getUniqueId('test_dir_') . '/';
        $relativeFilePath = StringUtility::getUniqueId('test_file_');
153
154
155
156
157
158
159
160
161

        mkdir($absoluteDirectoryPath);
        touch($absoluteDirectoryPath . $relativeFilePath);

        $this->testFilesToDelete[] = $absoluteDirectoryPath . $relativeFilePath;
        $this->testFilesToDelete[] = $absoluteDirectoryPath;

        symlink($absoluteDirectoryPath, $absoluteSymlinkPath);

162
        $fileHandler = new FileHandlingUtility();
163
        $fileHandler->removeDirectory($absoluteSymlinkPath);
164
        self::assertTrue(is_file($absoluteDirectoryPath . $relativeFilePath));
165
166
167
168
169
170
171
    }

    /**
     * @test
     */
    public function unpackExtensionFromExtensionDataArrayCreatesTheExtensionDirectory()
    {
172
        $extensionKey = 'test';
173
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, [
174
175
176
177
178
179
            'makeAndClearExtensionDir',
            'writeEmConfToFile',
            'extractDirectoriesFromExtensionData',
            'createDirectoriesForExtensionFiles',
            'writeExtensionFiles',
            'reloadPackageInformation',
180
        ]);
181
        $fileHandlerMock->expects(self::once())->method('extractDirectoriesFromExtensionData')->willReturn([]);
182
183
        $fileHandlerMock->expects(self::once())->method('makeAndClearExtensionDir')->with($extensionKey)->willReturn('my_path');
        $fileHandlerMock->unpackExtensionFromExtensionDataArray($extensionKey, []);
184
185
186
187
188
189
190
    }

    /**
     * @test
     */
    public function unpackExtensionFromExtensionDataArrayStripsDirectoriesFromFilesArray()
    {
191
        $extensionData = [
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
            'extKey' => 'test',
            'FILES' => [
                'ChangeLog' => [
                    'name' => 'ChangeLog',
                    'size' => 4559,
                    'mtime' => 1219448527,
                    'is_executable' => false,
                    'content' => 'some content to write'
                ],
                'doc/' => [
                    'name' => 'doc/',
                    'size' => 0,
                    'mtime' => 1219448527,
                    'is_executable' => false,
                    'content' => ''
                ],
                'doc/ChangeLog' => [
                    'name' => 'ChangeLog',
                    'size' => 4559,
                    'mtime' => 1219448527,
                    'is_executable' => false,
                    'content' => 'some content to write'
                ],
            ]
216
217
218
        ];
        $cleanedFiles = [
            'ChangeLog' => [
219
220
221
222
223
                'name' => 'ChangeLog',
                'size' => 4559,
                'mtime' => 1219448527,
                'is_executable' => false,
                'content' => 'some content to write'
224
225
            ],
            'doc/ChangeLog' => [
226
227
228
229
230
                'name' => 'ChangeLog',
                'size' => 4559,
                'mtime' => 1219448527,
                'is_executable' => false,
                'content' => 'some content to write'
231
232
233
            ],
        ];
        $directories = [
234
235
            'doc/',
            'mod/doc/'
236
        ];
237

238
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, [
239
240
241
242
243
244
            'makeAndClearExtensionDir',
            'writeEmConfToFile',
            'extractDirectoriesFromExtensionData',
            'createDirectoriesForExtensionFiles',
            'writeExtensionFiles',
            'reloadPackageInformation',
245
        ]);
246
        $fileHandlerMock->expects(self::once())->method('extractDirectoriesFromExtensionData')->willReturn($directories);
247
        $fileHandlerMock->expects(self::once())->method('createDirectoriesForExtensionFiles')->with($directories);
248
        $fileHandlerMock->expects(self::once())->method('makeAndClearExtensionDir')->with($extensionData['extKey'])->willReturn('my_path');
249
250
        $fileHandlerMock->expects(self::once())->method('writeExtensionFiles')->with($cleanedFiles);
        $fileHandlerMock->expects(self::once())->method('reloadPackageInformation')->with('test');
251
        $fileHandlerMock->unpackExtensionFromExtensionDataArray('test', $extensionData);
252
253
254
255
256
257
258
    }

    /**
     * @test
     */
    public function writeExtensionFilesWritesFiles()
    {
259
260
        $files = [
            'ChangeLog' => [
261
262
263
264
265
                'name' => 'ChangeLog',
                'size' => 4559,
                'mtime' => 1219448527,
                'is_executable' => false,
                'content' => 'some content to write'
266
267
            ],
            'README' => [
268
269
270
271
272
                'name' => 'README',
                'size' => 4566,
                'mtime' => 1219448533,
                'is_executable' => false,
                'content' => 'FEEL FREE TO ADD SOME DOCUMENTATION HERE'
273
274
            ]
        ];
275
        $rootPath = ($extDirPath = $this->fakedExtensions[$this->createFakeExtension()]['packagePath']);
276
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['makeAndClearExtensionDir']);
277
        $fileHandlerMock->_call('writeExtensionFiles', $files, $rootPath);
278
        self::assertTrue(file_exists($rootPath . 'ChangeLog'));
279
280
281
282
283
284
285
    }

    /**
     * @test
     */
    public function extractDirectoriesFromExtensionDataExtractsDirectories()
    {
286
287
        $files = [
            'ChangeLog' => [
288
289
290
291
292
                'name' => 'ChangeLog',
                'size' => 4559,
                'mtime' => 1219448527,
                'is_executable' => false,
                'content' => 'some content to write'
293
294
            ],
            'doc/' => [
295
296
297
298
299
                'name' => 'doc/',
                'size' => 0,
                'mtime' => 1219448527,
                'is_executable' => false,
                'content' => ''
300
301
            ],
            'doc/ChangeLog' => [
302
303
304
305
306
                'name' => 'ChangeLog',
                'size' => 4559,
                'mtime' => 1219448527,
                'is_executable' => false,
                'content' => 'some content to write'
307
308
            ],
            'doc/README' => [
309
310
311
312
313
                'name' => 'README',
                'size' => 4566,
                'mtime' => 1219448533,
                'is_executable' => false,
                'content' => 'FEEL FREE TO ADD SOME DOCUMENTATION HERE'
314
315
            ],
            'mod/doc/README' => [
316
317
318
319
320
                'name' => 'README',
                'size' => 4566,
                'mtime' => 1219448533,
                'is_executable' => false,
                'content' => 'FEEL FREE TO ADD SOME DOCUMENTATION HERE'
321
322
            ]
        ];
323
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['makeAndClearExtensionDir']);
324
        $extractedDirectories = $fileHandlerMock->_call('extractDirectoriesFromExtensionData', $files);
325
        $expected = [
326
327
            'doc/',
            'mod/doc/'
328
        ];
329
        self::assertSame($expected, array_values($extractedDirectories));
330
331
332
333
334
335
336
    }

    /**
     * @test
     */
    public function createDirectoriesForExtensionFilesCreatesDirectories()
    {
337
        $rootPath = $this->fakedExtensions[$this->createFakeExtension()]['packagePath'];
338
        $directories = [
339
340
            'doc/',
            'mod/doc/'
341
        ];
342
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['makeAndClearExtensionDir']);
343
344
        self::assertFalse(is_dir($rootPath . 'doc/'));
        self::assertFalse(is_dir($rootPath . 'mod/doc/'));
345
        $fileHandlerMock->_call('createDirectoriesForExtensionFiles', $directories, $rootPath);
346
347
        self::assertTrue(is_dir($rootPath . 'doc/'));
        self::assertTrue(is_dir($rootPath . 'mod/doc/'));
348
349
350
351
352
353
354
355
    }

    /**
     * @test
     */
    public function writeEmConfWritesEmConfFile()
    {
        $extKey = $this->createFakeExtension();
356
357
358
359
        $emConfData = [
            'title' => 'Plugin cache engine',
            'description' => 'Provides an interface to cache plugin content elements based on 4.3 caching framework',
            'category' => 'Frontend',
360
        ];
361
        $rootPath = $this->fakedExtensions[$extKey]['packagePath'];
362
        /** @var FileHandlingUtility $fileHandlerMock */
363
        $fileHandlerMock = $this->getAccessibleMock(FileHandlingUtility::class, ['makeAndClearExtensionDir']);
364
365
        $fileHandlerMock->injectEmConfUtility(new EmConfUtility());
        $fileHandlerMock->_call('writeEmConfToFile', $extKey, $emConfData, $rootPath);
366
        self::assertTrue(file_exists($rootPath . 'ext_emconf.php'));
367
    }
368
}