MDL-41022 cleanup core_files_file_storage_testcase
[moodle.git] / lib / filestorage / tests / file_storage_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/file_storage.php
19  *
20  * @package   core_files
21  * @category  phpunit
22  * @copyright 2012 David Mudrak <david@moodle.com>
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir . '/filelib.php');
30 require_once($CFG->dirroot . '/repository/lib.php');
31 require_once($CFG->libdir . '/filestorage/stored_file.php');
33 class core_files_file_storage_testcase extends advanced_testcase {
35     /**
36      * Files can be created from strings.
37      */
38     public function test_create_file_from_string() {
39         global $DB;
41         $this->resetAfterTest(true);
43         $this->assertEquals(0, $DB->count_records('files', array()));
45         $content = 'abcd';
46         $syscontext = context_system::instance();
47         $filerecord = array(
48             'contextid' => $syscontext->id,
49             'component' => 'core',
50             'filearea'  => 'unittest',
51             'itemid'    => 0,
52             'filepath'  => '/images/',
53             'filename'  => 'testfile.txt',
54         );
55         $pathhash = sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].$filerecord['filename']);
57         $fs = get_file_storage();
58         $file = $fs->create_file_from_string($filerecord, $content);
60         $this->assertInstanceOf('stored_file', $file);
61         $this->assertSame(sha1($content), $file->get_contenthash());
62         $this->assertSame($pathhash, $file->get_pathnamehash());
64         $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>$pathhash)));
66         $location = test_stored_file_inspection::get_pretected_pathname($file);
68         $this->assertFileExists($location);
70         // Verify the dir placeholder files are created.
71         $this->assertEquals(3, $DB->count_records('files', array()));
72         $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].'/.'))));
73         $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].'.'))));
75         // Tests that missing content file is recreated.
77         unlink($location);
78         $this->assertFileNotExists($location);
80         $filerecord['filename'] = 'testfile2.txt';
81         $file2 = $fs->create_file_from_string($filerecord, $content);
82         $this->assertInstanceOf('stored_file', $file2);
83         $this->assertSame($file->get_contenthash(), $file2->get_contenthash());
84         $this->assertFileExists($location);
86         $this->assertEquals(4, $DB->count_records('files', array()));
88         // Test that borked content file is recreated.
90         $this->assertSame(2, file_put_contents($location, 'xx'));
92         $filerecord['filename'] = 'testfile3.txt';
93         $file3 = $fs->create_file_from_string($filerecord, $content);
94         $this->assertInstanceOf('stored_file', $file3);
95         $this->assertSame($file->get_contenthash(), $file3->get_contenthash());
96         $this->assertFileExists($location);
98         $this->assertSame($content, file_get_contents($location));
99         $this->assertDebuggingCalled();
101         $this->assertEquals(5, $DB->count_records('files', array()));
102     }
104     /**
105      * Local files can be added to the filepool
106      */
107     public function test_create_file_from_pathname() {
108         global $CFG, $DB;
110         $this->resetAfterTest(true);
112         $filecount = $DB->count_records('files', array());
113         $this->assertEquals(0, $filecount);
115         $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
116         $syscontext = context_system::instance();
117         $filerecord = array(
118             'contextid' => $syscontext->id,
119             'component' => 'core',
120             'filearea'  => 'unittest',
121             'itemid'    => 0,
122             'filepath'  => '/images/',
123             'filename'  => 'testimage.jpg',
124         );
125         $pathhash = sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].$filerecord['filename']);
127         $fs = get_file_storage();
128         $file = $fs->create_file_from_pathname($filerecord, $filepath);
130         $this->assertInstanceOf('stored_file', $file);
131         $this->assertSame(sha1_file($filepath), $file->get_contenthash());
133         $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>$pathhash)));
135         $location = test_stored_file_inspection::get_pretected_pathname($file);
137         $this->assertFileExists($location);
139         // Verify the dir placeholder files are created.
140         $this->assertEquals(3, $DB->count_records('files', array()));
141         $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].'/.'))));
142         $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].'.'))));
144         // Tests that missing content file is recreated.
146         unlink($location);
147         $this->assertFileNotExists($location);
149         $filerecord['filename'] = 'testfile2.jpg';
150         $file2 = $fs->create_file_from_pathname($filerecord, $filepath);
151         $this->assertInstanceOf('stored_file', $file2);
152         $this->assertSame($file->get_contenthash(), $file2->get_contenthash());
153         $this->assertFileExists($location);
155         $this->assertEquals(4, $DB->count_records('files', array()));
157         // Test that borked content file is recreated.
159         $this->assertSame(2, file_put_contents($location, 'xx'));
161         $filerecord['filename'] = 'testfile3.jpg';
162         $file3 = $fs->create_file_from_pathname($filerecord, $filepath);
163         $this->assertInstanceOf('stored_file', $file3);
164         $this->assertSame($file->get_contenthash(), $file3->get_contenthash());
165         $this->assertFileExists($location);
167         $this->assertSame(file_get_contents($filepath), file_get_contents($location));
168         $this->assertDebuggingCalled();
170         $this->assertEquals(5, $DB->count_records('files', array()));
172         // Test invalid file creation.
174         $filerecord['filename'] = 'testfile4.jpg';
175         try {
176             $fs->create_file_from_pathname($filerecord, $filepath.'nonexistent');
177             $this->fail('Exception expected when trying to add non-existent stored file.');
178         } catch (Exception $e) {
179             $this->assertInstanceOf('file_exception', $e);
180         }
181     }
183     /**
184      * Tests get get file.
185      */
186     public function test_get_file() {
187         global $CFG;
189         $this->resetAfterTest(false);
191         $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
192         $syscontext = context_system::instance();
193         $filerecord = array(
194             'contextid' => $syscontext->id,
195             'component' => 'core',
196             'filearea'  => 'unittest',
197             'itemid'    => 0,
198             'filepath'  => '/images/',
199             'filename'  => 'testimage.jpg',
200         );
201         $pathhash = sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].$filerecord['filename']);
203         $fs = get_file_storage();
204         $file = $fs->create_file_from_pathname($filerecord, $filepath);
206         $this->assertInstanceOf('stored_file', $file);
207         $this->assertEquals($syscontext->id, $file->get_contextid());
208         $this->assertEquals('core', $file->get_component());
209         $this->assertEquals('unittest', $file->get_filearea());
210         $this->assertEquals(0, $file->get_itemid());
211         $this->assertEquals('/images/', $file->get_filepath());
212         $this->assertEquals('testimage.jpg', $file->get_filename());
213         $this->assertEquals(filesize($filepath), $file->get_filesize());
214         $this->assertEquals($pathhash, $file->get_pathnamehash());
216         return $file;
217     }
219     /**
220      * Local images can be added to the filepool and their preview can be obtained
221      *
222      * @depends test_get_file
223      */
224     public function test_get_file_preview(stored_file $file) {
225         global $CFG;
227         $this->resetAfterTest();
228         $fs = get_file_storage();
230         $previewtinyicon = $fs->get_file_preview($file, 'tinyicon');
231         $this->assertInstanceOf('stored_file', $previewtinyicon);
232         $this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
234         $previewtinyicon = $fs->get_file_preview($file, 'thumb');
235         $this->assertInstanceOf('stored_file', $previewtinyicon);
236         $this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
238         $this->setExpectedException('file_exception');
239         $fs->get_file_preview($file, 'amodewhichdoesntexist');
240     }
242     public function test_get_file_preview_nonimage() {
243         $this->resetAfterTest(true);
244         $syscontext = context_system::instance();
245         $filerecord = array(
246             'contextid' => $syscontext->id,
247             'component' => 'core',
248             'filearea'  => 'unittest',
249             'itemid'    => 0,
250             'filepath'  => '/textfiles/',
251             'filename'  => 'testtext.txt',
252         );
254         $fs = get_file_storage();
255         $fs->create_file_from_string($filerecord, 'text contents');
256         $textfile = $fs->get_file($syscontext->id, $filerecord['component'], $filerecord['filearea'],
257             $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename']);
259         $preview = $fs->get_file_preview($textfile, 'thumb');
260         $this->assertFalse($preview);
261     }
263     /**
264      * Make sure renaming is working
265      *
266      * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
267      */
268     public function test_file_renaming() {
269         global $CFG;
271         $this->resetAfterTest();
272         $fs = get_file_storage();
273         $syscontext = context_system::instance();
274         $component = 'core';
275         $filearea  = 'unittest';
276         $itemid    = 0;
277         $filepath  = '/';
278         $filename  = 'test.txt';
280         $filerecord = array(
281             'contextid' => $syscontext->id,
282             'component' => $component,
283             'filearea'  => $filearea,
284             'itemid'    => $itemid,
285             'filepath'  => $filepath,
286             'filename'  => $filename,
287         );
289         $originalfile = $fs->create_file_from_string($filerecord, 'Test content');
290         $this->assertInstanceOf('stored_file', $originalfile);
291         $contenthash = $originalfile->get_contenthash();
292         $newpath = '/test/';
293         $newname = 'newtest.txt';
295         // This should work.
296         $originalfile->rename($newpath, $newname);
297         $file = $fs->get_file($syscontext->id, $component, $filearea, $itemid, $newpath, $newname);
298         $this->assertInstanceOf('stored_file', $file);
299         $this->assertEquals($contenthash, $file->get_contenthash());
301         // Try break it.
302         $this->setExpectedException('file_exception');
303         // This shall throw exception.
304         $originalfile->rename($newpath, $newname);
305     }
307     /**
308      * Create file from reference tests
309      *
310      * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
311      */
312     public function test_create_file_from_reference() {
313         global $CFG, $DB;
315         $this->resetAfterTest();
316         // Create user.
317         $generator = $this->getDataGenerator();
318         $user = $generator->create_user();
319         $this->setUser($user);
320         $usercontext = context_user::instance($user->id);
321         $syscontext = context_system::instance();
323         $fs = get_file_storage();
325         $repositorypluginname = 'user';
326         // Override repository permission.
327         $capability = 'repository/' . $repositorypluginname . ':view';
328         $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
329         assign_capability($capability, CAP_ALLOW, $allroles['guest'], $syscontext->id, true);
331         $args = array();
332         $args['type'] = $repositorypluginname;
333         $repos = repository::get_instances($args);
334         $userrepository = reset($repos);
335         $this->assertInstanceOf('repository', $userrepository);
337         $component = 'user';
338         $filearea  = 'private';
339         $itemid    = 0;
340         $filepath  = '/';
341         $filename  = 'userfile.txt';
343         $filerecord = array(
344             'contextid' => $usercontext->id,
345             'component' => $component,
346             'filearea'  => $filearea,
347             'itemid'    => $itemid,
348             'filepath'  => $filepath,
349             'filename'  => $filename,
350         );
352         $content = 'Test content';
353         $originalfile = $fs->create_file_from_string($filerecord, $content);
354         $this->assertInstanceOf('stored_file', $originalfile);
356         $newfilerecord = array(
357             'contextid' => $syscontext->id,
358             'component' => 'core',
359             'filearea'  => 'phpunit',
360             'itemid'    => 0,
361             'filepath'  => $filepath,
362             'filename'  => $filename,
363         );
364         $ref = $fs->pack_reference($filerecord);
365         $newstoredfile = $fs->create_file_from_reference($newfilerecord, $userrepository->id, $ref);
366         $this->assertInstanceOf('stored_file', $newstoredfile);
367         $this->assertEquals($userrepository->id, $newstoredfile->get_repository_id());
368         $this->assertEquals($originalfile->get_contenthash(), $newstoredfile->get_contenthash());
369         $this->assertEquals($originalfile->get_filesize(), $newstoredfile->get_filesize());
370         $this->assertRegExp('#' . $filename. '$#', $newstoredfile->get_reference_details());
372         // Test looking for references.
373         $count = $fs->get_references_count_by_storedfile($originalfile);
374         $this->assertEquals(1, $count);
375         $files = $fs->get_references_by_storedfile($originalfile);
376         $file = reset($files);
377         $this->assertEquals($file, $newstoredfile);
379         // Look for references by repository ID.
380         $files = $fs->get_external_files($userrepository->id);
381         $file = reset($files);
382         $this->assertEquals($file, $newstoredfile);
384         // Try convert reference to local file.
385         $importedfile = $fs->import_external_file($newstoredfile);
386         $this->assertFalse($importedfile->is_external_file());
387         $this->assertInstanceOf('stored_file', $importedfile);
388         // Still readable?
389         $this->assertEquals($content, $importedfile->get_content());
390     }
392     private function setup_three_private_files() {
394         $this->resetAfterTest();
396         $generator = $this->getDataGenerator();
397         $user = $generator->create_user();
398         $this->setUser($user->id);
399         $usercontext = context_user::instance($user->id);
400         // Create a user private file.
401         $file1 = new stdClass;
402         $file1->contextid = $usercontext->id;
403         $file1->component = 'user';
404         $file1->filearea  = 'private';
405         $file1->itemid    = 0;
406         $file1->filepath  = '/';
407         $file1->filename  = '1.txt';
408         $file1->source    = 'test';
410         $fs = get_file_storage();
411         $userfile1 = $fs->create_file_from_string($file1, 'file1 content');
412         $this->assertInstanceOf('stored_file', $userfile1);
414         $file2 = clone($file1);
415         $file2->filename = '2.txt';
416         $userfile2 = $fs->create_file_from_string($file2, 'file2 content');
417         $this->assertInstanceOf('stored_file', $userfile2);
419         $file3 = clone($file1);
420         $file3->filename = '3.txt';
421         $userfile3 = $fs->create_file_from_storedfile($file3, $userfile2);
422         $this->assertInstanceOf('stored_file', $userfile3);
424         $user->ctxid = $usercontext->id;
426         return $user;
427     }
429     public function test_get_area_files() {
430         $user = $this->setup_three_private_files();
431         $fs = get_file_storage();
433         // Get area files with default options.
434         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
436         // Should be the two files we added plus the folder.
437         $this->assertEquals(4, count($areafiles));
439         // Verify structure.
440         foreach ($areafiles as $key => $file) {
441             $this->assertInstanceOf('stored_file', $file);
442             $this->assertEquals($key, $file->get_pathnamehash());
443         }
445         // Get area files without a folder.
446         $folderlessfiles = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'sortorder', false);
447         // Should be the two files without folder.
448         $this->assertEquals(3, count($folderlessfiles));
450         // Verify structure.
451         foreach ($folderlessfiles as $key => $file) {
452             $this->assertInstanceOf('stored_file', $file);
453             $this->assertEquals($key, $file->get_pathnamehash());
454         }
456         // Get area files ordered by id.
457         $filesbyid  = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'id', false);
458         // Should be the two files without folder.
459         $this->assertEquals(3, count($filesbyid));
461         // Verify structure.
462         foreach ($filesbyid as $key => $file) {
463             $this->assertInstanceOf('stored_file', $file);
464             $this->assertEquals($key, $file->get_pathnamehash());
465         }
467         // Test with an itemid with no files.
468         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private', 666, 'sortorder', false);
469         // Should be none.
470         $this->assertEmpty($areafiles);
471     }
473     public function test_get_area_tree() {
474         $user = $this->setup_three_private_files();
475         $fs = get_file_storage();
477         // Get area files with default options.
478         $areatree = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
479         $this->assertEmpty($areatree['subdirs']);
480         $this->assertNotEmpty($areatree['files']);
481         $this->assertCount(3, $areatree['files']);
483         // Ensure an empty try with a fake itemid.
484         $emptytree = $fs->get_area_tree($user->ctxid, 'user', 'private', 666);
485         $this->assertEmpty($emptytree['subdirs']);
486         $this->assertEmpty($emptytree['files']);
488         // Create a subdir.
489         $dir = $fs->create_directory($user->ctxid, 'user', 'private', 0, '/testsubdir/');
490         $this->assertInstanceOf('stored_file', $dir);
492         // Add a file to the subdir.
493         $filerecord = array(
494             'contextid' => $user->ctxid,
495             'component' => 'user',
496             'filearea'  => 'private',
497             'itemid'    => 0,
498             'filepath'  => '/testsubdir/',
499             'filename'  => 'test-get-area-tree.txt',
500         );
502         $directoryfile = $fs->create_file_from_string($filerecord, 'Test content');
503         $this->assertInstanceOf('stored_file', $directoryfile);
505         $areatree = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
507         // At the top level there should still be 3 files.
508         $this->assertCount(3, $areatree['files']);
510         // There should now be a subdirectory.
511         $this->assertCount(1, $areatree['subdirs']);
513         // The test subdir is named testsubdir.
514         $subdir = $areatree['subdirs']['testsubdir'];
515         $this->assertNotEmpty($subdir);
516         // It should have one file we added.
517         $this->assertCount(1, $subdir['files']);
518         // And no subdirs itself.
519         $this->assertCount(0, $subdir['subdirs']);
521         // Verify the file is the one we added.
522         $subdirfile = reset($subdir['files']);
523         $this->assertInstanceOf('stored_file', $subdirfile);
524         $this->assertEquals($filerecord['filename'], $subdirfile->get_filename());
525     }
527     public function test_get_file_by_id() {
528         $user = $this->setup_three_private_files();
529         $fs = get_file_storage();
531         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
533         // Test get_file_by_id.
534         $filebyid = reset($areafiles);
535         $shouldbesame = $fs->get_file_by_id($filebyid->get_id());
536         $this->assertEquals($filebyid->get_contenthash(), $shouldbesame->get_contenthash());
538         // Test an id which doens't exist.
539         $doesntexist = $fs->get_file_by_id(99999);
540         $this->assertFalse($doesntexist);
541     }
543     public function test_get_file_by_hash() {
544         $user = $this->setup_three_private_files();
545         $fs = get_file_storage();
547         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
548         // Test get_file_by_hash.
549         $filebyhash = reset($areafiles);
550         $shouldbesame = $fs->get_file_by_hash($filebyhash->get_pathnamehash());
551         $this->assertEquals($filebyhash->get_id(), $shouldbesame->get_id());
553         // Test an hash which doens't exist.
554         $doesntexist = $fs->get_file_by_hash('DOESNTEXIST');
555         $this->assertFalse($doesntexist);
556     }
558     public function test_get_external_files() {
559         $user = $this->setup_three_private_files();
560         $fs = get_file_storage();
562         $repos = repository::get_instances(array('type'=>'user'));
563         $userrepository = reset($repos);
564         $this->assertInstanceOf('repository', $userrepository);
566         // No aliases yet.
567         $exfiles = $fs->get_external_files($userrepository->id, 'id');
568         $this->assertEquals(array(), $exfiles);
570         // Create three aliases linking the same original: $aliasfile1 and $aliasfile2 are
571         // created via create_file_from_reference(), $aliasfile3 created from $aliasfile2.
572         $originalfile = null;
573         foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
574             if (!$areafile->is_directory()) {
575                 $originalfile = $areafile;
576                 break;
577             }
578         }
579         $this->assertInstanceOf('stored_file', $originalfile);
580         $originalrecord = array(
581             'contextid' => $originalfile->get_contextid(),
582             'component' => $originalfile->get_component(),
583             'filearea'  => $originalfile->get_filearea(),
584             'itemid'    => $originalfile->get_itemid(),
585             'filepath'  => $originalfile->get_filepath(),
586             'filename'  => $originalfile->get_filename(),
587         );
589         $aliasrecord = $this->generate_file_record();
590         $aliasrecord->filepath = '/foo/';
591         $aliasrecord->filename = 'one.txt';
593         $ref = $fs->pack_reference($originalrecord);
594         $aliasfile1 = $fs->create_file_from_reference($aliasrecord, $userrepository->id, $ref);
596         $aliasrecord->filepath = '/bar/';
597         $aliasrecord->filename = 'uno.txt';
598         // Change the order of the items in the array to make sure that it does not matter.
599         ksort($originalrecord);
600         $ref = $fs->pack_reference($originalrecord);
601         $aliasfile2 = $fs->create_file_from_reference($aliasrecord, $userrepository->id, $ref);
603         $aliasrecord->filepath = '/bar/';
604         $aliasrecord->filename = 'jedna.txt';
605         $aliasfile3 = $fs->create_file_from_storedfile($aliasrecord, $aliasfile2);
607         // Make sure we get three aliases now.
608         $exfiles = $fs->get_external_files($userrepository->id, 'id');
609         $this->assertEquals(3, count($exfiles));
610         foreach ($exfiles as $exfile) {
611             $this->assertTrue($exfile->is_external_file());
612         }
613         // Make sure they all link the same original (thence that all are linked with the same
614         // record in {files_reference}).
615         $this->assertEquals($aliasfile1->get_referencefileid(), $aliasfile2->get_referencefileid());
616         $this->assertEquals($aliasfile3->get_referencefileid(), $aliasfile2->get_referencefileid());
617     }
619     public function test_create_directory_contextid_negative() {
620         $fs = get_file_storage();
622         $this->setExpectedException('file_exception');
623         $fs->create_directory(-1, 'core', 'unittest', 0, '/');
624     }
626     public function test_create_directory_contextid_invalid() {
627         $fs = get_file_storage();
629         $this->setExpectedException('file_exception');
630         $fs->create_directory('not an int', 'core', 'unittest', 0, '/');
631     }
633     public function test_create_directory_component_invalid() {
634         $fs = get_file_storage();
635         $syscontext = context_system::instance();
637         $this->setExpectedException('file_exception');
638         $fs->create_directory($syscontext->id, 'bad/component', 'unittest', 0, '/');
639     }
641     public function test_create_directory_filearea_invalid() {
642         $fs = get_file_storage();
643         $syscontext = context_system::instance();
645         $this->setExpectedException('file_exception');
646         $fs->create_directory($syscontext->id, 'core', 'bad-filearea', 0, '/');
647     }
649     public function test_create_directory_itemid_negative() {
650         $fs = get_file_storage();
651         $syscontext = context_system::instance();
653         $this->setExpectedException('file_exception');
654         $fs->create_directory($syscontext->id, 'core', 'unittest', -1, '/');
655     }
657     public function test_create_directory_itemid_invalid() {
658         $fs = get_file_storage();
659         $syscontext = context_system::instance();
661         $this->setExpectedException('file_exception');
662         $fs->create_directory($syscontext->id, 'core', 'unittest', 'notanint', '/');
663     }
665     public function test_create_directory_filepath_invalid() {
666         $fs = get_file_storage();
667         $syscontext = context_system::instance();
669         $this->setExpectedException('file_exception');
670         $fs->create_directory($syscontext->id, 'core', 'unittest', 0, '/not-with-trailing/or-leading-slash');
671     }
673     public function test_get_directory_files() {
674         $user = $this->setup_three_private_files();
675         $fs = get_file_storage();
677         $dir = $fs->create_directory($user->ctxid, 'user', 'private', 0, '/testsubdir/');
678         $this->assertInstanceOf('stored_file', $dir);
680         // Add a file to the subdir.
681         $filerecord = array(
682             'contextid' => $user->ctxid,
683             'component' => 'user',
684             'filearea'  => 'private',
685             'itemid'    => 0,
686             'filepath'  => '/testsubdir/',
687             'filename'  => 'test-get-area-tree.txt',
688         );
690         $directoryfile = $fs->create_file_from_string($filerecord, 'Test content');
691         $this->assertInstanceOf('stored_file', $directoryfile);
693         // Don't recurse without dirs.
694         $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, false, 'id');
695         // 3 files only.
696         $this->assertCount(3, $files);
697         foreach ($files as $key => $file) {
698             $this->assertInstanceOf('stored_file', $file);
699             $this->assertEquals($key, $file->get_pathnamehash());
700         }
702         // Don't recurse with dirs.
703         $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, true, 'id');
704         // 3 files + 1 directory.
705         $this->assertCount(4, $files);
706         foreach ($files as $key => $file) {
707             $this->assertInstanceOf('stored_file', $file);
708             $this->assertEquals($key, $file->get_pathnamehash());
709         }
711         // Recurse with dirs.
712         $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, true, 'id');
713         // 3 files + 1 directory +  1 subdir file.
714         $this->assertCount(5, $files);
715         foreach ($files as $key => $file) {
716             $this->assertInstanceOf('stored_file', $file);
717             $this->assertEquals($key, $file->get_pathnamehash());
718         }
720         // Recurse without dirs.
721         $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, false, 'id');
722         // 3 files +  1 subdir file.
723         $this->assertCount(4, $files);
724         foreach ($files as $key => $file) {
725             $this->assertInstanceOf('stored_file', $file);
726             $this->assertEquals($key, $file->get_pathnamehash());
727         }
728     }
730     public function test_search_references() {
731         $user = $this->setup_three_private_files();
732         $fs = get_file_storage();
733         $repos = repository::get_instances(array('type'=>'user'));
734         $repo = reset($repos);
736         $alias1 = array(
737             'contextid' => $user->ctxid,
738             'component' => 'user',
739             'filearea'  => 'private',
740             'itemid'    => 0,
741             'filepath'  => '/aliases/',
742             'filename'  => 'alias-to-1.txt'
743         );
745         $alias2 = array(
746             'contextid' => $user->ctxid,
747             'component' => 'user',
748             'filearea'  => 'private',
749             'itemid'    => 0,
750             'filepath'  => '/aliases/',
751             'filename'  => 'another-alias-to-1.txt'
752         );
754         $reference = file_storage::pack_reference(array(
755             'contextid' => $user->ctxid,
756             'component' => 'user',
757             'filearea'  => 'private',
758             'itemid'    => 0,
759             'filepath'  => '/',
760             'filename'  => '1.txt'
761         ));
763         // There are no aliases now.
764         $result = $fs->search_references($reference);
765         $this->assertEquals(array(), $result);
767         $result = $fs->search_references_count($reference);
768         $this->assertSame($result, 0);
770         // Create two aliases and make sure they are returned.
771         $fs->create_file_from_reference($alias1, $repo->id, $reference);
772         $fs->create_file_from_reference($alias2, $repo->id, $reference);
774         $result = $fs->search_references($reference);
775         $this->assertTrue(is_array($result));
776         $this->assertEquals(count($result), 2);
777         foreach ($result as $alias) {
778             $this->assertTrue($alias instanceof stored_file);
779         }
781         $result = $fs->search_references_count($reference);
782         $this->assertSame($result, 2);
784         // The method can't be used for references to files outside the filepool.
785         $exceptionthrown = false;
786         try {
787             $fs->search_references('http://dl.dropbox.com/download/1234567/naked-dougiamas.jpg');
788         } catch (file_reference_exception $e) {
789             $exceptionthrown = true;
790         }
791         $this->assertTrue($exceptionthrown);
793         $exceptionthrown = false;
794         try {
795             $fs->search_references_count('http://dl.dropbox.com/download/1234567/naked-dougiamas.jpg');
796         } catch (file_reference_exception $e) {
797             $exceptionthrown = true;
798         }
799         $this->assertTrue($exceptionthrown);
800     }
802     public function test_delete_area_files() {
803         $user = $this->setup_three_private_files();
804         $fs = get_file_storage();
806         // Get area files with default options.
807         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
808         // Should be the two files we added plus the folder.
809         $this->assertEquals(4, count($areafiles));
810         $fs->delete_area_files($user->ctxid, 'user', 'private');
812         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
813         // Should be the two files we added plus the folder.
814         $this->assertEquals(0, count($areafiles));
815     }
817     public function test_delete_area_files_itemid() {
818         $user = $this->setup_three_private_files();
819         $fs = get_file_storage();
821         // Get area files with default options.
822         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
823         // Should be the two files we added plus the folder.
824         $this->assertEquals(4, count($areafiles));
825         $fs->delete_area_files($user->ctxid, 'user', 'private', 9999);
827         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
828         $this->assertEquals(4, count($areafiles));
829     }
831     public function test_delete_area_files_select() {
832         $user = $this->setup_three_private_files();
833         $fs = get_file_storage();
835         // Get area files with default options.
836         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
837         // Should be the two files we added plus the folder.
838         $this->assertEquals(4, count($areafiles));
839         $fs->delete_area_files_select($user->ctxid, 'user', 'private', '!= :notitemid', array('notitemid'=>9999));
841         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
842         // Should be the two files we added plus the folder.
843         $this->assertEquals(0, count($areafiles));
844     }
846     public function test_delete_component_files() {
847         $user = $this->setup_three_private_files();
848         $fs = get_file_storage();
850         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
851         $this->assertEquals(4, count($areafiles));
852         $fs->delete_component_files('user');
853         $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
854         $this->assertEquals(0, count($areafiles));
855     }
857     public function test_create_file_from_url() {
858         $this->resetAfterTest(true);
860         $syscontext = context_system::instance();
861         $filerecord = array(
862             'contextid' => $syscontext->id,
863             'component' => 'core',
864             'filearea'  => 'unittest',
865             'itemid'    => 0,
866             'filepath'  => '/downloadtest/',
867         );
868         $url = 'http://download.moodle.org/unittest/test.html';
870         $fs = get_file_storage();
872         // Test creating file without filename.
873         $file1 = $fs->create_file_from_url($filerecord, $url);
874         $this->assertInstanceOf('stored_file', $file1);
876         // Set filename.
877         $filerecord['filename'] = 'unit-test-filename.html';
878         $file2 = $fs->create_file_from_url($filerecord, $url);
879         $this->assertInstanceOf('stored_file', $file2);
881         // Use temporary file.
882         $filerecord['filename'] = 'unit-test-with-temp-file.html';
883         $file3 = $fs->create_file_from_url($filerecord, $url, null, true);
884         $file3 = $this->assertInstanceOf('stored_file', $file3);
885     }
887     public function test_cron() {
888         $this->resetAfterTest(true);
890         // Note: this is only testing DB compatibility atm, rather than
891         // that work is done.
892         $fs = get_file_storage();
894         $this->expectOutputRegex('/Cleaning up/');
895         $fs->cron();
896     }
898     public function test_is_area_empty() {
899         $user = $this->setup_three_private_files();
900         $fs = get_file_storage();
902         $this->assertFalse($fs->is_area_empty($user->ctxid, 'user', 'private'));
904         // File area with madeup itemid should be empty.
905         $this->assertTrue($fs->is_area_empty($user->ctxid, 'user', 'private', 9999));
906         // Still empty with dirs included.
907         $this->assertTrue($fs->is_area_empty($user->ctxid, 'user', 'private', 9999, false));
908     }
910     public function test_move_area_files_to_new_context() {
911         $this->resetAfterTest(true);
913         // Create a course with a page resource.
914         $course = $this->getDataGenerator()->create_course();
915         $page1 = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
916         $page1context = context_module::instance($page1->cmid);
918         // Add a file to the page.
919         $fs = get_file_storage();
920         $filerecord = array(
921             'contextid' => $page1context->id,
922             'component' => 'mod_page',
923             'filearea'  => 'content',
924             'itemid'    => 0,
925             'filepath'  => '/',
926             'filename'  => 'unit-test-file.txt',
927         );
929         $originalfile = $fs->create_file_from_string($filerecord, 'Test content');
930         $this->assertInstanceOf('stored_file', $originalfile);
932         $pagefiles = $fs->get_area_files($page1context->id, 'mod_page', 'content', 0, 'sortorder', false);
933         // Should be one file in filearea.
934         $this->assertFalse($fs->is_area_empty($page1context->id, 'mod_page', 'content'));
936         // Create a new page.
937         $page2 = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
938         $page2context = context_module::instance($page2->cmid);
940         // Newly created page area is empty.
941         $this->assertTrue($fs->is_area_empty($page2context->id, 'mod_page', 'content'));
943         // Move the files.
944         $fs->move_area_files_to_new_context($page1context->id, $page2context->id, 'mod_page', 'content');
946         // Page2 filearea should no longer be empty.
947         $this->assertFalse($fs->is_area_empty($page2context->id, 'mod_page', 'content'));
949         // Page1 filearea should now be empty.
950         $this->assertTrue($fs->is_area_empty($page1context->id, 'mod_page', 'content'));
952         $page2files = $fs->get_area_files($page2context->id, 'mod_page', 'content', 0, 'sortorder', false);
953         $movedfile = reset($page2files);
955         // The two files should have the same content hash.
956         $this->assertEquals($movedfile->get_contenthash(), $originalfile->get_contenthash());
957     }
959     public function test_convert_image() {
960         global $CFG;
962         $this->resetAfterTest(false);
964         $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
965         $syscontext = context_system::instance();
966         $filerecord = array(
967             'contextid' => $syscontext->id,
968             'component' => 'core',
969             'filearea'  => 'unittest',
970             'itemid'    => 0,
971             'filepath'  => '/images/',
972             'filename'  => 'testimage.jpg',
973         );
975         $fs = get_file_storage();
976         $original = $fs->create_file_from_pathname($filerecord, $filepath);
978         $filerecord['filename'] = 'testimage-converted-10x10.jpg';
979         $converted = $fs->convert_image($filerecord, $original, 10, 10, true, 100);
980         $this->assertInstanceOf('stored_file', $converted);
982         $filerecord['filename'] = 'testimage-convereted-nosize.jpg';
983         $converted = $fs->convert_image($filerecord, $original);
984         $this->assertInstanceOf('stored_file', $converted);
985     }
987     private function generate_file_record() {
988         $syscontext = context_system::instance();
989         $filerecord = new stdClass();
990         $filerecord->contextid = $syscontext->id;
991         $filerecord->component = 'core';
992         $filerecord->filearea = 'phpunit';
993         $filerecord->filepath = '/';
994         $filerecord->filename = 'testfile.txt';
995         $filerecord->itemid = 0;
997         return $filerecord;
998     }
1000     public function test_create_file_from_storedfile_file_invalid() {
1001         $this->resetAfterTest(true);
1003         $filerecord = $this->generate_file_record();
1005         $fs = get_file_storage();
1006         $this->setExpectedException('file_exception');
1007         // Create a file from a file id which doesn't exist.
1008         $fs->create_file_from_storedfile($filerecord,  9999);
1009     }
1011     public function test_create_file_from_storedfile_contextid_invalid() {
1012         $this->resetAfterTest(true);
1014         $filerecord = $this->generate_file_record();
1016         $fs = get_file_storage();
1017         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1018         $this->assertInstanceOf('stored_file', $file1);
1020         $filerecord->filename = 'invalid.txt';
1021         $filerecord->contextid = 'invalid';
1023         $this->setExpectedException('file_exception', 'Invalid contextid');
1024         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1025     }
1027     public function test_create_file_from_storedfile_component_invalid() {
1028         $this->resetAfterTest(true);
1030         $filerecord = $this->generate_file_record();
1032         $fs = get_file_storage();
1033         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1034         $this->assertInstanceOf('stored_file', $file1);
1036         $filerecord->filename = 'invalid.txt';
1037         $filerecord->component = 'bad/component';
1039         $this->setExpectedException('file_exception', 'Invalid component');
1040         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1041     }
1043     public function test_create_file_from_storedfile_filearea_invalid() {
1044         $this->resetAfterTest(true);
1046         $filerecord = $this->generate_file_record();
1048         $fs = get_file_storage();
1049         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1050         $this->assertInstanceOf('stored_file', $file1);
1052         $filerecord->filename = 'invalid.txt';
1053         $filerecord->filearea = 'bad-filearea';
1055         $this->setExpectedException('file_exception', 'Invalid filearea');
1056         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1057     }
1059     public function test_create_file_from_storedfile_itemid_invalid() {
1060         $this->resetAfterTest(true);
1062         $filerecord = $this->generate_file_record();
1064         $fs = get_file_storage();
1065         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1066         $this->assertInstanceOf('stored_file', $file1);
1068         $filerecord->filename = 'invalid.txt';
1069         $filerecord->itemid = 'bad-itemid';
1071         $this->setExpectedException('file_exception', 'Invalid itemid');
1072         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1073     }
1075     public function test_create_file_from_storedfile_filepath_invalid() {
1076         $this->resetAfterTest(true);
1078         $filerecord = $this->generate_file_record();
1080         $fs = get_file_storage();
1081         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1082         $this->assertInstanceOf('stored_file', $file1);
1084         $filerecord->filename = 'invalid.txt';
1085         $filerecord->filepath = 'a-/bad/-filepath';
1087         $this->setExpectedException('file_exception', 'Invalid file path');
1088         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1089     }
1091     public function test_create_file_from_storedfile_filename_invalid() {
1092         $this->resetAfterTest(true);
1094         $filerecord = $this->generate_file_record();
1096         $fs = get_file_storage();
1097         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1098         $this->assertInstanceOf('stored_file', $file1);
1100         $filerecord->filename = '';
1102         $this->setExpectedException('file_exception', 'Invalid file name');
1103         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1104     }
1106     public function test_create_file_from_storedfile_timecreated_invalid() {
1107         $this->resetAfterTest(true);
1109         $filerecord = $this->generate_file_record();
1111         $fs = get_file_storage();
1112         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1113         $this->assertInstanceOf('stored_file', $file1);
1115         $filerecord->filename = 'invalid.txt';
1116         $filerecord->timecreated = 'today';
1118         $this->setExpectedException('file_exception', 'Invalid file timecreated');
1119         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1120     }
1122     public function test_create_file_from_storedfile_timemodified_invalid() {
1123         $this->resetAfterTest(true);
1125         $filerecord = $this->generate_file_record();
1127         $fs = get_file_storage();
1128         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1129         $this->assertInstanceOf('stored_file', $file1);
1131         $filerecord->filename = 'invalid.txt';
1132         $filerecord->timemodified  = 'today';
1134         $this->setExpectedException('file_exception', 'Invalid file timemodified');
1135         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1136     }
1138     public function test_create_file_from_storedfile_duplicate() {
1139         $this->resetAfterTest(true);
1141         $filerecord = $this->generate_file_record();
1143         $fs = get_file_storage();
1144         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1145         $this->assertInstanceOf('stored_file', $file1);
1147         // Creating a file validating unique constraint.
1148         $this->setExpectedException('stored_file_creation_exception');
1149         $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1150     }
1152     public function test_create_file_from_storedfile() {
1153         $this->resetAfterTest(true);
1155         $syscontext = context_system::instance();
1157         $filerecord = new stdClass();
1158         $filerecord->contextid = $syscontext->id;
1159         $filerecord->component = 'core';
1160         $filerecord->filearea = 'phpunit';
1161         $filerecord->filepath = '/';
1162         $filerecord->filename = 'testfile.txt';
1163         $filerecord->itemid = 0;
1165         $fs = get_file_storage();
1167         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1168         $this->assertInstanceOf('stored_file', $file1);
1170         $filerecord->filename = 'test-create-file-from-storedfile.txt';
1171         $file2 = $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1172         $this->assertInstanceOf('stored_file', $file2);
1174         // These will be normalised to current time..
1175         $filerecord->timecreated = -100;
1176         $filerecord->timemodified= -100;
1177         $filerecord->filename = 'test-create-file-from-storedfile-bad-dates.txt';
1179         $file3 = $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1180         $this->assertInstanceOf('stored_file', $file3);
1182         $this->assertNotEquals($file3->get_timemodified(), $filerecord->timemodified);
1183         $this->assertNotEquals($file3->get_timecreated(), $filerecord->timecreated);
1184     }
1186     public function test_create_file_from_string_contextid_invalid() {
1187         $this->resetAfterTest(true);
1189         $filerecord = $this->generate_file_record();
1190         $fs = get_file_storage();
1192         $filerecord->contextid = 'invalid';
1194         $this->setExpectedException('file_exception', 'Invalid contextid');
1195         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1196     }
1198     public function test_create_file_from_string_component_invalid() {
1199         $this->resetAfterTest(true);
1201         $filerecord = $this->generate_file_record();
1202         $fs = get_file_storage();
1204         $filerecord->component = 'bad/component';
1206         $this->setExpectedException('file_exception', 'Invalid component');
1207         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1208     }
1210     public function test_create_file_from_string_filearea_invalid() {
1211         $this->resetAfterTest(true);
1213         $filerecord = $this->generate_file_record();
1214         $fs = get_file_storage();
1216         $filerecord->filearea = 'bad-filearea';
1218         $this->setExpectedException('file_exception', 'Invalid filearea');
1219         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1220     }
1222     public function test_create_file_from_string_itemid_invalid() {
1223         $this->resetAfterTest(true);
1225         $filerecord = $this->generate_file_record();
1226         $fs = get_file_storage();
1228         $filerecord->itemid = 'bad-itemid';
1230         $this->setExpectedException('file_exception', 'Invalid itemid');
1231         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1232     }
1234     public function test_create_file_from_string_filepath_invalid() {
1235         $this->resetAfterTest(true);
1237         $filerecord = $this->generate_file_record();
1238         $fs = get_file_storage();
1240         $filerecord->filepath = 'a-/bad/-filepath';
1242         $this->setExpectedException('file_exception', 'Invalid file path');
1243         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1244     }
1246     public function test_create_file_from_string_filename_invalid() {
1247         $this->resetAfterTest(true);
1249         $filerecord = $this->generate_file_record();
1250         $fs = get_file_storage();
1252         $filerecord->filename = '';
1254         $this->setExpectedException('file_exception', 'Invalid file name');
1255         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1256     }
1258     public function test_create_file_from_string_timecreated_invalid() {
1259         $this->resetAfterTest(true);
1261         $filerecord = $this->generate_file_record();
1262         $fs = get_file_storage();
1264         $filerecord->timecreated = 'today';
1266         $this->setExpectedException('file_exception', 'Invalid file timecreated');
1267         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1268     }
1270     public function test_create_file_from_string_timemodified_invalid() {
1271         $this->resetAfterTest(true);
1273         $filerecord = $this->generate_file_record();
1274         $fs = get_file_storage();
1276         $filerecord->timemodified  = 'today';
1278         $this->setExpectedException('file_exception', 'Invalid file timemodified');
1279         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1280     }
1282     public function test_create_file_from_string_duplicate() {
1283         $this->resetAfterTest(true);
1285         $filerecord = $this->generate_file_record();
1286         $fs = get_file_storage();
1288         $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1290         // Creating a file validating unique constraint.
1291         $this->setExpectedException('stored_file_creation_exception');
1292         $file2 = $fs->create_file_from_string($filerecord, 'text contents');
1293     }
1295     public function test_create_file_from_pathname_contextid_invalid() {
1296         global $CFG;
1297         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1299         $this->resetAfterTest(true);
1301         $filerecord = $this->generate_file_record();
1302         $fs = get_file_storage();
1304         $filerecord->contextid = 'invalid';
1306         $this->setExpectedException('file_exception', 'Invalid contextid');
1307         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1308     }
1310     public function test_create_file_from_pathname_component_invalid() {
1311         global $CFG;
1312         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1314         $this->resetAfterTest(true);
1316         $filerecord = $this->generate_file_record();
1317         $fs = get_file_storage();
1319         $filerecord->component = 'bad/component';
1321         $this->setExpectedException('file_exception', 'Invalid component');
1322         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1323     }
1325     public function test_create_file_from_pathname_filearea_invalid() {
1326         global $CFG;
1327         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1329         $this->resetAfterTest(true);
1331         $filerecord = $this->generate_file_record();
1332         $fs = get_file_storage();
1334         $filerecord->filearea = 'bad-filearea';
1336         $this->setExpectedException('file_exception', 'Invalid filearea');
1337         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1338     }
1340     public function test_create_file_from_pathname_itemid_invalid() {
1341         global $CFG;
1342         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1344         $this->resetAfterTest(true);
1346         $filerecord = $this->generate_file_record();
1347         $fs = get_file_storage();
1349         $filerecord->itemid = 'bad-itemid';
1351         $this->setExpectedException('file_exception', 'Invalid itemid');
1352         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1353     }
1355     public function test_create_file_from_pathname_filepath_invalid() {
1356         global $CFG;
1357         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1359         $this->resetAfterTest(true);
1361         $filerecord = $this->generate_file_record();
1362         $fs = get_file_storage();
1364         $filerecord->filepath = 'a-/bad/-filepath';
1366         $this->setExpectedException('file_exception', 'Invalid file path');
1367         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1368     }
1370     public function test_create_file_from_pathname_filename_invalid() {
1371         global $CFG;
1372         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1374         $this->resetAfterTest(true);
1376         $filerecord = $this->generate_file_record();
1377         $fs = get_file_storage();
1379         $filerecord->filename = '';
1381         $this->setExpectedException('file_exception', 'Invalid file name');
1382         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1383     }
1385     public function test_create_file_from_pathname_timecreated_invalid() {
1386         global $CFG;
1387         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1389         $this->resetAfterTest(true);
1391         $filerecord = $this->generate_file_record();
1392         $fs = get_file_storage();
1394         $filerecord->timecreated = 'today';
1396         $this->setExpectedException('file_exception', 'Invalid file timecreated');
1397         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1398     }
1400     public function test_create_file_from_pathname_timemodified_invalid() {
1401         global $CFG;
1402         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1404         $this->resetAfterTest(true);
1406         $filerecord = $this->generate_file_record();
1407         $fs = get_file_storage();
1409         $filerecord->timemodified  = 'today';
1411         $this->setExpectedException('file_exception', 'Invalid file timemodified');
1412         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1413     }
1415     public function test_create_file_from_pathname_duplicate_file() {
1416         global $CFG;
1417         $this->resetAfterTest(true);
1419         $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1421         $filerecord = $this->generate_file_record();
1422         $fs = get_file_storage();
1424         $file1 = $fs->create_file_from_pathname($filerecord, $path);
1425         $this->assertInstanceOf('stored_file', $file1);
1427         // Creating a file validating unique constraint.
1428         $this->setExpectedException('stored_file_creation_exception');
1429         $file2 = $fs->create_file_from_pathname($filerecord, $path);
1430     }
1432     /**
1433      * Calling stored_file::delete_reference() on a non-reference file throws coding_exception
1434      */
1435     public function test_delete_reference_on_nonreference() {
1437         $this->resetAfterTest(true);
1438         $user = $this->setup_three_private_files();
1439         $fs = get_file_storage();
1440         $repos = repository::get_instances(array('type'=>'user'));
1441         $repo = reset($repos);
1443         $file = null;
1444         foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
1445             if (!$areafile->is_directory()) {
1446                 $file = $areafile;
1447                 break;
1448             }
1449         }
1450         $this->assertInstanceOf('stored_file', $file);
1451         $this->assertFalse($file->is_external_file());
1453         $this->setExpectedException('coding_exception');
1454         $file->delete_reference();
1455     }
1457     /**
1458      * Calling stored_file::delete_reference() on a reference file does not affect other
1459      * symlinks to the same original
1460      */
1461     public function test_delete_reference_one_symlink_does_not_rule_them_all() {
1463         $this->resetAfterTest(true);
1464         $user = $this->setup_three_private_files();
1465         $fs = get_file_storage();
1466         $repos = repository::get_instances(array('type'=>'user'));
1467         $repo = reset($repos);
1469         // Create two aliases linking the same original.
1471         $originalfile = null;
1472         foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
1473             if (!$areafile->is_directory()) {
1474                 $originalfile = $areafile;
1475                 break;
1476             }
1477         }
1478         $this->assertInstanceOf('stored_file', $originalfile);
1480         // Calling delete_reference() on a non-reference file.
1482         $originalrecord = array(
1483             'contextid' => $originalfile->get_contextid(),
1484             'component' => $originalfile->get_component(),
1485             'filearea'  => $originalfile->get_filearea(),
1486             'itemid'    => $originalfile->get_itemid(),
1487             'filepath'  => $originalfile->get_filepath(),
1488             'filename'  => $originalfile->get_filename(),
1489         );
1491         $aliasrecord = $this->generate_file_record();
1492         $aliasrecord->filepath = '/A/';
1493         $aliasrecord->filename = 'symlink.txt';
1495         $ref = $fs->pack_reference($originalrecord);
1496         $aliasfile1 = $fs->create_file_from_reference($aliasrecord, $repo->id, $ref);
1498         $aliasrecord->filepath = '/B/';
1499         $aliasrecord->filename = 'symlink.txt';
1500         $ref = $fs->pack_reference($originalrecord);
1501         $aliasfile2 = $fs->create_file_from_reference($aliasrecord, $repo->id, $ref);
1503         // Refetch A/symlink.txt file.
1504         $symlink1 = $fs->get_file($aliasrecord->contextid, $aliasrecord->component,
1505             $aliasrecord->filearea, $aliasrecord->itemid, '/A/', 'symlink.txt');
1506         $this->assertTrue($symlink1->is_external_file());
1508         // Unlink the A/symlink.txt file.
1509         $symlink1->delete_reference();
1510         $this->assertFalse($symlink1->is_external_file());
1512         // Make sure that B/symlink.txt has not been affected.
1513         $symlink2 = $fs->get_file($aliasrecord->contextid, $aliasrecord->component,
1514             $aliasrecord->filearea, $aliasrecord->itemid, '/B/', 'symlink.txt');
1515         $this->assertTrue($symlink2->is_external_file());
1516     }
1518     public function test_get_unused_filename() {
1519         global $USER;
1520         $this->resetAfterTest(true);
1522         $fs = get_file_storage();
1523         $this->setAdminUser();
1524         $contextid = context_user::instance($USER->id)->id;
1525         $component = 'user';
1526         $filearea = 'private';
1527         $itemid = 0;
1528         $filepath = '/';
1530         // Create some private files.
1531         $file = new stdClass;
1532         $file->contextid = $contextid;
1533         $file->component = 'user';
1534         $file->filearea  = 'private';
1535         $file->itemid    = 0;
1536         $file->filepath  = '/';
1537         $file->source    = 'test';
1538         $filenames = array('foo.txt', 'foo (1).txt', 'foo (20).txt', 'foo (999)', 'bar.jpg', 'What (a cool file).jpg',
1539                 'Hurray! (1).php', 'Hurray! (2).php', 'Hurray! (9a).php', 'Hurray! (abc).php');
1540         foreach ($filenames as $key => $filename) {
1541             $file->filename = $filename;
1542             $userfile = $fs->create_file_from_string($file, "file $key $filename content");
1543             $this->assertInstanceOf('stored_file', $userfile);
1544         }
1546         // Asserting new generated names.
1547         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'unused.txt');
1548         $this->assertEquals('unused.txt', $newfilename);
1549         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo.txt');
1550         $this->assertEquals('foo (21).txt', $newfilename);
1551         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (1).txt');
1552         $this->assertEquals('foo (21).txt', $newfilename);
1553         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (2).txt');
1554         $this->assertEquals('foo (2).txt', $newfilename);
1555         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (20).txt');
1556         $this->assertEquals('foo (21).txt', $newfilename);
1557         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo');
1558         $this->assertEquals('foo', $newfilename);
1559         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (123)');
1560         $this->assertEquals('foo (123)', $newfilename);
1561         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (999)');
1562         $this->assertEquals('foo (1000)', $newfilename);
1563         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar.png');
1564         $this->assertEquals('bar.png', $newfilename);
1565         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar (12).png');
1566         $this->assertEquals('bar (12).png', $newfilename);
1567         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar.jpg');
1568         $this->assertEquals('bar (1).jpg', $newfilename);
1569         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar (1).jpg');
1570         $this->assertEquals('bar (1).jpg', $newfilename);
1571         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'What (a cool file).jpg');
1572         $this->assertEquals('What (a cool file) (1).jpg', $newfilename);
1573         $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'Hurray! (1).php');
1574         $this->assertEquals('Hurray! (3).php', $newfilename);
1576         $this->setExpectedException('coding_exception');
1577         $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, '');
1578     }
1581 class test_stored_file_inspection extends stored_file {
1582     public static function get_pretected_pathname(stored_file $file) {
1583         return $file->get_pathname_by_contenthash();
1584     }