MDL-41022 cleanup core_files_zip_packer_testcase
[moodle.git] / lib / filestorage / tests / zip_packer_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Unit tests for /lib/filestorage/zip_packer.php and zip_archive.php
19  *
20  * @package   core_files
21  * @category  phpunit
22  * @copyright 2012 Petr Skoda
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 class core_files_zip_packer_testcase extends advanced_testcase {
30     protected $testfile;
31     protected $files;
33     protected function setUp() {
34         parent::setUp();
36         $this->testfile = __DIR__.'/fixtures/test.txt';
38         $fs = get_file_storage();
39         $context = context_system::instance();
40         if (!$file = $fs->get_file($context->id, 'phpunit', 'data', 0, '/', 'test.txt')) {
41             $file = $fs->create_file_from_pathname(
42                 array('contextid'=>$context->id, 'component'=>'phpunit', 'filearea'=>'data', 'itemid'=>0, 'filepath'=>'/', 'filename'=>'test.txt'),
43                 $this->testfile);
44         }
46         $this->files = array(
47             'test.test' => $this->testfile,
48             'testíček.txt' => $this->testfile,
49             'Prüfung.txt' => $this->testfile,
50             '测试.txt' => $this->testfile,
51             '試験.txt' => $this->testfile,
52             'Žluťoučký/Koníček.txt' => $file,
53         );
54     }
56     public function test_get_packer() {
57         $this->resetAfterTest(false);
58         $packer = get_file_packer();
59         $this->assertInstanceOf('zip_packer', $packer);
61         $packer = get_file_packer('application/zip');
62         $this->assertInstanceOf('zip_packer', $packer);
63     }
65     /**
66      * @depends test_get_packer
67      */
68     public function test_list_files() {
69         $this->resetAfterTest(false);
71         $files = array(
72             __DIR__.'/fixtures/test_moodle_22.zip',
73             __DIR__.'/fixtures/test_moodle.zip',
74             __DIR__.'/fixtures/test_tc_8.zip',
75             __DIR__.'/fixtures/test_7zip_927.zip',
76             __DIR__.'/fixtures/test_winzip_165.zip',
77             __DIR__.'/fixtures/test_winrar_421.zip',
78             __DIR__.'/fixtures/test_thumbsdb.zip',
79         );
81         if (function_exists('normalizer_normalize')) {
82             // Unfortunately there is no way to standardise UTF-8 strings without INTL extension.
83             $files[] = __DIR__.'/fixtures/test_infozip_3.zip';
84             $files[] = __DIR__.'/fixtures/test_osx_1074.zip';
85             $files[] = __DIR__.'/fixtures/test_osx_compress.zip';
86         }
88         $packer = get_file_packer('application/zip');
90         foreach ($files as $archive) {
91             $archivefiles = $packer->list_files($archive);
92             $this->assertTrue(is_array($archivefiles), "Archive not extracted properly: ".basename($archive).' ');
93             $this->assertTrue(count($this->files) === count($archivefiles) or count($this->files) === count($archivefiles) - 1); // Some zippers create empty dirs.
94             foreach ($archivefiles as $file) {
95                 if ($file->pathname === 'Žluťoučký/') {
96                     // Some zippers create empty dirs.
97                     continue;
98                 }
99                 $this->assertArrayHasKey($file->pathname, $this->files, "File $file->pathname not extracted properly: ".basename($archive).' ');
100             }
101         }
103         // Windows packer supports only DOS encoding.
104         $archive = __DIR__.'/fixtures/test_win8_de.zip';
105         $archivefiles = $packer->list_files($archive);
106         $this->assertTrue(is_array($archivefiles), "Archive not extracted properly: ".basename($archive).' ');
107         $this->assertEquals(2, count($archivefiles));
108         foreach ($archivefiles as $file) {
109             $this->assertTrue($file->pathname === 'Prüfung.txt' or $file->pathname === 'test.test');
110         }
112         $zip_archive = new zip_archive();
113         $zip_archive->open(__DIR__.'/fixtures/test_win8_cz.zip', file_archive::OPEN, 'cp852');
114         $archivefiles = $zip_archive->list_files();
115         $this->assertTrue(is_array($archivefiles), "Archive not extracted properly: ".basename($archive).' ');
116         $this->assertEquals(3, count($archivefiles));
117         foreach ($archivefiles as $file) {
118             $this->assertTrue($file->pathname === 'Žluťoučký/Koníček.txt' or $file->pathname === 'testíček.txt' or $file->pathname === 'test.test');
119         }
120         $zip_archive->close();
122         // Empty archive extraction.
123         $archive = __DIR__.'/fixtures/empty.zip';
124         $archivefiles = $packer->list_files($archive);
125         $this->assertSame(array(), $archivefiles);
126     }
128     /**
129      * @depends test_list_files
130      */
131     public function test_archive_to_pathname() {
132         global $CFG;
134         $this->resetAfterTest(false);
136         $packer = get_file_packer('application/zip');
137         $archive = "$CFG->tempdir/archive.zip";
139         $this->assertFileNotExists($archive);
140         $result = $packer->archive_to_pathname($this->files, $archive);
141         $this->assertTrue($result);
142         $this->assertFileExists($archive);
144         $archivefiles = $packer->list_files($archive);
145         $this->assertTrue(is_array($archivefiles));
146         $this->assertEquals(count($this->files), count($archivefiles));
147         foreach ($archivefiles as $file) {
148             $this->assertArrayHasKey($file->pathname, $this->files);
149         }
151         // Test invalid files parameter.
152         $archive = "$CFG->tempdir/archive2.zip";
153         $this->assertFileNotExists($archive);
155         $this->assertFileNotExists(__DIR__.'/xx/yy/ee.txt');
156         $files = array('xtest.txt'=>__DIR__.'/xx/yy/ee.txt');
158         $result = $packer->archive_to_pathname($files, $archive, false);
159         $this->assertFalse($result);
160         $this->assertDebuggingCalled();
161         $this->assertFileNotExists($archive);
163         $result = $packer->archive_to_pathname($files, $archive);
164         $this->assertTrue($result);
165         $this->assertFileExists($archive);
166         $this->assertDebuggingCalled();
167         $archivefiles = $packer->list_files($archive);
168         $this->assertSame(array(), $archivefiles);
169         unlink($archive);
171         $this->assertFileNotExists(__DIR__.'/xx/yy/ee.txt');
172         $this->assertFileExists(__DIR__.'/fixtures/test.txt');
173         $files = array('xtest.txt'=>__DIR__.'/xx/yy/ee.txt', 'test.txt'=>__DIR__.'/fixtures/test.txt', 'ytest.txt'=>__DIR__.'/xx/yy/yy.txt');
174         $result = $packer->archive_to_pathname($files, $archive);
175         $this->assertTrue($result);
176         $this->assertFileExists($archive);
177         $archivefiles = $packer->list_files($archive);
178         $this->assertCount(1, $archivefiles);
179         $this->assertEquals('test.txt', $archivefiles[0]->pathname);
180         $dms = $this->getDebuggingMessages();
181         $this->assertCount(2, $dms);
182         $this->resetDebugging();
183         unlink($archive);
184     }
186     /**
187      * @depends test_archive_to_pathname
188      */
189     public function test_archive_to_storage() {
190         $this->resetAfterTest(false);
192         $packer = get_file_packer('application/zip');
193         $fs = get_file_storage();
194         $context = context_system::instance();
196         $this->assertFalse($fs->file_exists($context->id, 'phpunit', 'test', 0, '/', 'archive.zip'));
197         $result = $packer->archive_to_storage($this->files, $context->id, 'phpunit', 'test', 0, '/', 'archive.zip');
198         $this->assertInstanceOf('stored_file', $result);
199         $this->assertTrue($fs->file_exists($context->id, 'phpunit', 'test', 0, '/', 'archive.zip'));
201         $archivefiles = $result->list_files($packer);
202         $this->assertTrue(is_array($archivefiles));
203         $this->assertEquals(count($this->files), count($archivefiles));
204         foreach ($archivefiles as $file) {
205             $this->assertArrayHasKey($file->pathname, $this->files);
206         }
207     }
209     /**
210      * @depends test_archive_to_storage
211      */
212     public function test_extract_to_pathname() {
213         global $CFG;
215         $this->resetAfterTest(false);
217         $packer = get_file_packer('application/zip');
218         $fs = get_file_storage();
219         $context = context_system::instance();
221         $target = "$CFG->tempdir/test/";
222         $testcontent = file_get_contents($this->testfile);
224         @mkdir($target, $CFG->directorypermissions);
225         $this->assertTrue(is_dir($target));
227         $archive = "$CFG->tempdir/archive.zip";
228         $this->assertFileExists($archive);
229         $result = $packer->extract_to_pathname($archive, $target);
230         $this->assertTrue(is_array($result));
231         $this->assertEquals(count($this->files), count($result));
232         foreach ($this->files as $file => $unused) {
233             $this->assertTrue($result[$file]);
234             $this->assertFileExists($target.$file);
235             $this->assertSame($testcontent, file_get_contents($target.$file));
236         }
238         $archive = $fs->get_file($context->id, 'phpunit', 'test', 0, '/', 'archive.zip');
239         $this->assertNotEmpty($archive);
240         $result = $packer->extract_to_pathname($archive, $target);
241         $this->assertTrue(is_array($result));
242         $this->assertEquals(count($this->files), count($result));
243         foreach ($this->files as $file => $unused) {
244             $this->assertTrue($result[$file]);
245             $this->assertFileExists($target.$file);
246             $this->assertSame($testcontent, file_get_contents($target.$file));
247         }
248     }
250     /**
251      * @depends test_archive_to_storage
252      */
253     public function test_extract_to_pathname_onlyfiles() {
254         global $CFG;
256         $this->resetAfterTest(false);
258         $packer = get_file_packer('application/zip');
259         $fs = get_file_storage();
260         $context = context_system::instance();
262         $target = "$CFG->tempdir/onlyfiles/";
263         $testcontent = file_get_contents($this->testfile);
265         @mkdir($target, $CFG->directorypermissions);
266         $this->assertTrue(is_dir($target));
268         $onlyfiles = array('test', 'test.test', 'Žluťoučký/Koníček.txt', 'Idontexist');
269         $willbeextracted = array_intersect(array_keys($this->files), $onlyfiles);
270         $donotextract = array_diff(array_keys($this->files), $onlyfiles);
272         $archive = "$CFG->tempdir/archive.zip";
273         $this->assertFileExists($archive);
274         $result = $packer->extract_to_pathname($archive, $target, $onlyfiles);
275         $this->assertTrue(is_array($result));
276         $this->assertEquals(count($willbeextracted), count($result));
278         foreach ($willbeextracted as $file) {
279             $this->assertTrue($result[$file]);
280             $this->assertFileExists($target.$file);
281             $this->assertSame($testcontent, file_get_contents($target.$file));
282         }
283         foreach ($donotextract as $file) {
284             $this->assertFalse(isset($result[$file]));
285             $this->assertFileNotExists($target.$file);
286         }
288     }
290     /**
291      * @depends test_archive_to_storage
292      */
293     public function test_extract_to_storage() {
294         global $CFG;
296         $this->resetAfterTest(false);
298         $packer = get_file_packer('application/zip');
299         $fs = get_file_storage();
300         $context = context_system::instance();
302         $testcontent = file_get_contents($this->testfile);
304         $archive = $fs->get_file($context->id, 'phpunit', 'test', 0, '/', 'archive.zip');
305         $this->assertNotEmpty($archive);
306         $result = $packer->extract_to_storage($archive, $context->id, 'phpunit', 'target', 0, '/');
307         $this->assertTrue(is_array($result));
308         $this->assertEquals(count($this->files), count($result));
309         foreach ($this->files as $file => $unused) {
310             $this->assertTrue($result[$file]);
311             $stored_file = $fs->get_file_by_hash(sha1("/$context->id/phpunit/target/0/$file"));
312             $this->assertInstanceOf('stored_file', $stored_file);
313             $this->assertSame($testcontent, $stored_file->get_content());
314         }
316         $archive = "$CFG->tempdir/archive.zip";
317         $this->assertFileExists($archive);
318         $result = $packer->extract_to_storage($archive, $context->id, 'phpunit', 'target', 0, '/');
319         $this->assertTrue(is_array($result));
320         $this->assertEquals(count($this->files), count($result));
321         foreach ($this->files as $file => $unused) {
322             $this->assertTrue($result[$file]);
323             $stored_file = $fs->get_file_by_hash(sha1("/$context->id/phpunit/target/0/$file"));
324             $this->assertInstanceOf('stored_file', $stored_file);
325             $this->assertSame($testcontent, $stored_file->get_content());
326         }
327         unlink($archive);
328     }
330     /**
331      * @depends test_extract_to_storage
332      */
333     public function test_add_files() {
334         global $CFG;
336         $this->resetAfterTest(false);
338         $packer = get_file_packer('application/zip');
339         $archive = "$CFG->tempdir/archive.zip";
341         $this->assertFileNotExists($archive);
342         $packer->archive_to_pathname(array(), $archive);
343         $this->assertFileExists($archive);
345         $zip_archive = new zip_archive();
346         $zip_archive->open($archive, file_archive::OPEN);
347         $this->assertEquals(0, $zip_archive->count());
349         $zip_archive->add_file_from_string('test.txt', 'test');
350         $zip_archive->close();
351         $zip_archive->open($archive, file_archive::OPEN);
352         $this->assertEquals(1, $zip_archive->count());
354         $zip_archive->add_directory('test2');
355         $zip_archive->close();
356         $zip_archive->open($archive, file_archive::OPEN);
357         $files = $zip_archive->list_files();
358         $this->assertCount(2, $files);
359         $this->assertEquals('test.txt', $files[0]->pathname);
360         $this->assertEquals('test2/', $files[1]->pathname);
362         $result = $zip_archive->add_file_from_pathname('test.txt', __DIR__.'/nonexistent/file.txt');
363         $this->assertFalse($result);
364         $zip_archive->close();
365         $zip_archive->open($archive, file_archive::OPEN);
366         $this->assertEquals(2, $zip_archive->count());
367         $zip_archive->close();
369         unlink($archive);
370     }
372     /**
373      * @depends test_add_files
374      */
375     public function test_open_archive() {
376         global $CFG;
378         $this->resetAfterTest(true);
380         $archive = "$CFG->tempdir/archive.zip";
382         $this->assertFileNotExists($archive);
384         $zip_archive = new zip_archive();
385         $result = $zip_archive->open($archive, file_archive::OPEN);
386         $this->assertFalse($result);
387         $this->assertDebuggingCalled();
389         $zip_archive = new zip_archive();
390         $result = $zip_archive->open($archive, file_archive::CREATE);
391         $this->assertTrue($result);
392         $zip_archive->add_file_from_string('test.txt', 'test');
393         $zip_archive->close();
394         $zip_archive->open($archive, file_archive::OPEN);
395         $this->assertEquals(1, $zip_archive->count());
397         $zip_archive = new zip_archive();
398         $result = $zip_archive->open($archive, file_archive::OVERWRITE);
399         $this->assertTrue($result);
400         $zip_archive->add_file_from_string('test2.txt', 'test');
401         $zip_archive->close();
402         $zip_archive->open($archive, file_archive::OPEN);
403         $this->assertEquals(1, $zip_archive->count());
404         $zip_archive->close();
406         unlink($archive);
407         $zip_archive = new zip_archive();
408         $result = $zip_archive->open($archive, file_archive::OVERWRITE);
409         $this->assertTrue($result);
410         $zip_archive->add_file_from_string('test2.txt', 'test');
411         $zip_archive->close();
412         $zip_archive->open($archive, file_archive::OPEN);
413         $this->assertEquals(1, $zip_archive->count());
414         $zip_archive->close();
416         unlink($archive);
417     }