3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * Unit tests for /lib/filestorage/file_storage.php
23 * @copyright 2012 David Mudrak <david@moodle.com>
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die();
30 require_once($CFG->libdir . '/filelib.php');
31 require_once($CFG->dirroot . '/repository/lib.php');
32 require_once($CFG->libdir . '/filestorage/stored_file.php');
34 class core_files_file_storage_testcase extends advanced_testcase {
37 * Files can be created from strings.
39 public function test_create_file_from_string() {
42 $this->resetAfterTest(true);
44 $this->assertEquals(0, $DB->count_records('files', array()));
47 $syscontext = context_system::instance();
49 'contextid' => $syscontext->id,
50 'component' => 'core',
51 'filearea' => 'unittest',
53 'filepath' => '/images/',
54 'filename' => 'testfile.txt',
56 $pathhash = sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].$filerecord['filename']);
58 $fs = get_file_storage();
59 $file = $fs->create_file_from_string($filerecord, $content);
61 $this->assertInstanceOf('stored_file', $file);
62 $this->assertSame(sha1($content), $file->get_contenthash());
63 $this->assertSame($pathhash, $file->get_pathnamehash());
65 $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>$pathhash)));
67 $location = test_stored_file_inspection::get_pretected_pathname($file);
69 $this->assertFileExists($location);
72 // Verify the dir placeholder files are created.
73 $this->assertEquals(3, $DB->count_records('files', array()));
74 $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].'/.'))));
75 $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].'.'))));
78 // Tests that missing content file is recreated.
81 $this->assertFileNotExists($location);
83 $filerecord['filename'] = 'testfile2.txt';
84 $file2 = $fs->create_file_from_string($filerecord, $content);
85 $this->assertInstanceOf('stored_file', $file2);
86 $this->assertSame($file->get_contenthash(), $file2->get_contenthash());
87 $this->assertFileExists($location);
89 $this->assertEquals(4, $DB->count_records('files', array()));
92 // Test that borked content file is recreated.
94 $this->assertSame(2, file_put_contents($location, 'xx'));
96 $filerecord['filename'] = 'testfile3.txt';
97 $file3 = $fs->create_file_from_string($filerecord, $content);
98 $this->assertInstanceOf('stored_file', $file3);
99 $this->assertSame($file->get_contenthash(), $file3->get_contenthash());
100 $this->assertFileExists($location);
102 $this->assertSame($content, file_get_contents($location));
103 $this->assertDebuggingCalled();
105 $this->assertEquals(5, $DB->count_records('files', array()));
109 * Local files can be added to the filepool
111 public function test_create_file_from_pathname() {
114 $this->resetAfterTest(true);
116 $filecount = $DB->count_records('files', array());
117 $this->assertEquals(0, $filecount);
119 $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
120 $syscontext = context_system::instance();
122 'contextid' => $syscontext->id,
123 'component' => 'core',
124 'filearea' => 'unittest',
126 'filepath' => '/images/',
127 'filename' => 'testimage.jpg',
129 $pathhash = sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].$filerecord['filename']);
131 $fs = get_file_storage();
132 $file = $fs->create_file_from_pathname($filerecord, $filepath);
134 $this->assertInstanceOf('stored_file', $file);
135 $this->assertSame(sha1_file($filepath), $file->get_contenthash());
137 $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>$pathhash)));
139 $location = test_stored_file_inspection::get_pretected_pathname($file);
141 $this->assertFileExists($location);
144 // Verify the dir placeholder files are created.
145 $this->assertEquals(3, $DB->count_records('files', array()));
146 $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].'/.'))));
147 $this->assertTrue($DB->record_exists('files', array('pathnamehash'=>sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].'.'))));
150 // Tests that missing content file is recreated.
153 $this->assertFileNotExists($location);
155 $filerecord['filename'] = 'testfile2.jpg';
156 $file2 = $fs->create_file_from_pathname($filerecord, $filepath);
157 $this->assertInstanceOf('stored_file', $file2);
158 $this->assertSame($file->get_contenthash(), $file2->get_contenthash());
159 $this->assertFileExists($location);
161 $this->assertEquals(4, $DB->count_records('files', array()));
164 // Test that borked content file is recreated.
166 $this->assertSame(2, file_put_contents($location, 'xx'));
168 $filerecord['filename'] = 'testfile3.jpg';
169 $file3 = $fs->create_file_from_pathname($filerecord, $filepath);
170 $this->assertInstanceOf('stored_file', $file3);
171 $this->assertSame($file->get_contenthash(), $file3->get_contenthash());
172 $this->assertFileExists($location);
174 $this->assertSame(file_get_contents($filepath), file_get_contents($location));
175 $this->assertDebuggingCalled();
177 $this->assertEquals(5, $DB->count_records('files', array()));
179 // Test invalid file creation.
181 $filerecord['filename'] = 'testfile4.jpg';
183 $fs->create_file_from_pathname($filerecord, $filepath.'nonexistent');
184 $this->fail('Exception expected when trying to add non-existent stored file.');
185 } catch (Exception $e) {
186 $this->assertInstanceOf('file_exception', $e);
191 * Tests get get file.
193 public function test_get_file() {
196 $this->resetAfterTest(false);
198 $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
199 $syscontext = context_system::instance();
201 'contextid' => $syscontext->id,
202 'component' => 'core',
203 'filearea' => 'unittest',
205 'filepath' => '/images/',
206 'filename' => 'testimage.jpg',
208 $pathhash = sha1('/'.$filerecord['contextid'].'/'.$filerecord['component'].'/'.$filerecord['filearea'].'/'.$filerecord['itemid'].$filerecord['filepath'].$filerecord['filename']);
210 $fs = get_file_storage();
211 $file = $fs->create_file_from_pathname($filerecord, $filepath);
213 $this->assertInstanceOf('stored_file', $file);
214 $this->assertEquals($syscontext->id, $file->get_contextid());
215 $this->assertEquals('core', $file->get_component());
216 $this->assertEquals('unittest', $file->get_filearea());
217 $this->assertEquals(0, $file->get_itemid());
218 $this->assertEquals('/images/', $file->get_filepath());
219 $this->assertEquals('testimage.jpg', $file->get_filename());
220 $this->assertEquals(filesize($filepath), $file->get_filesize());
221 $this->assertEquals($pathhash, $file->get_pathnamehash());
227 * Local images can be added to the filepool and their preview can be obtained
229 * @depends test_get_file
231 public function test_get_file_preview(stored_file $file) {
234 $this->resetAfterTest(true);
235 $fs = get_file_storage();
237 $previewtinyicon = $fs->get_file_preview($file, 'tinyicon');
238 $this->assertInstanceOf('stored_file', $previewtinyicon);
239 $this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
241 $previewtinyicon = $fs->get_file_preview($file, 'thumb');
242 $this->assertInstanceOf('stored_file', $previewtinyicon);
243 $this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
245 $this->setExpectedException('file_exception');
246 $fs->get_file_preview($file, 'amodewhichdoesntexist');
249 public function test_get_file_preview_nonimage() {
250 $this->resetAfterTest(true);
251 $syscontext = context_system::instance();
253 'contextid' => $syscontext->id,
254 'component' => 'core',
255 'filearea' => 'unittest',
257 'filepath' => '/textfiles/',
258 'filename' => 'testtext.txt',
261 $fs = get_file_storage();
262 $fs->create_file_from_string($filerecord, 'text contents');
263 $textfile = $fs->get_file($syscontext->id, $filerecord['component'], $filerecord['filearea'],
264 $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename']);
266 $preview = $fs->get_file_preview($textfile, 'thumb');
267 $this->assertFalse($preview);
271 * Make sure renaming is working
273 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
275 public function test_file_renaming() {
278 $this->resetAfterTest(true);
279 $fs = get_file_storage();
280 $syscontext = context_system::instance();
282 $filearea = 'unittest';
285 $filename = 'test.txt';
288 'contextid' => $syscontext->id,
289 'component' => $component,
290 'filearea' => $filearea,
292 'filepath' => $filepath,
293 'filename' => $filename,
296 $originalfile = $fs->create_file_from_string($filerecord, 'Test content');
297 $this->assertInstanceOf('stored_file', $originalfile);
298 $contenthash = $originalfile->get_contenthash();
300 $newname = 'newtest.txt';
303 $originalfile->rename($newpath, $newname);
304 $file = $fs->get_file($syscontext->id, $component, $filearea, $itemid, $newpath, $newname);
305 $this->assertInstanceOf('stored_file', $file);
306 $this->assertEquals($contenthash, $file->get_contenthash());
309 $this->setExpectedException('file_exception');
310 // this shall throw exception
311 $originalfile->rename($newpath, $newname);
315 * Create file from reference tests
317 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
319 public function test_create_file_from_reference() {
322 $this->resetAfterTest(true);
324 $generator = $this->getDataGenerator();
325 $user = $generator->create_user();
326 $this->setUser($user);
327 $usercontext = context_user::instance($user->id);
328 $syscontext = context_system::instance();
330 $fs = get_file_storage();
332 $repositorypluginname = 'user';
333 // override repository permission
334 $capability = 'repository/' . $repositorypluginname . ':view';
335 $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
336 assign_capability($capability, CAP_ALLOW, $allroles['guest'], $syscontext->id, true);
340 $args['type'] = $repositorypluginname;
341 $repos = repository::get_instances($args);
342 $userrepository = reset($repos);
343 $this->assertInstanceOf('repository', $userrepository);
346 $filearea = 'private';
349 $filename = 'userfile.txt';
352 'contextid' => $usercontext->id,
353 'component' => $component,
354 'filearea' => $filearea,
356 'filepath' => $filepath,
357 'filename' => $filename,
360 $content = 'Test content';
361 $originalfile = $fs->create_file_from_string($filerecord, $content);
362 $this->assertInstanceOf('stored_file', $originalfile);
364 $newfilerecord = array(
365 'contextid' => $syscontext->id,
366 'component' => 'core',
367 'filearea' => 'phpunit',
369 'filepath' => $filepath,
370 'filename' => $filename,
372 $ref = $fs->pack_reference($filerecord);
373 $newstoredfile = $fs->create_file_from_reference($newfilerecord, $userrepository->id, $ref);
374 $this->assertInstanceOf('stored_file', $newstoredfile);
375 $this->assertEquals($userrepository->id, $newstoredfile->get_repository_id());
376 $this->assertEquals($originalfile->get_contenthash(), $newstoredfile->get_contenthash());
377 $this->assertEquals($originalfile->get_filesize(), $newstoredfile->get_filesize());
378 $this->assertRegExp('#' . $filename. '$#', $newstoredfile->get_reference_details());
380 // Test looking for references
381 $count = $fs->get_references_count_by_storedfile($originalfile);
382 $this->assertEquals(1, $count);
383 $files = $fs->get_references_by_storedfile($originalfile);
384 $file = reset($files);
385 $this->assertEquals($file, $newstoredfile);
387 // Look for references by repository ID
388 $files = $fs->get_external_files($userrepository->id);
389 $file = reset($files);
390 $this->assertEquals($file, $newstoredfile);
392 // Try convert reference to local file
393 $importedfile = $fs->import_external_file($newstoredfile);
394 $this->assertFalse($importedfile->is_external_file());
395 $this->assertInstanceOf('stored_file', $importedfile);
397 $this->assertEquals($content, $importedfile->get_content());
400 private function setup_three_private_files() {
402 $this->resetAfterTest(true);
404 $generator = $this->getDataGenerator();
405 $user = $generator->create_user();
406 $this->setUser($user->id);
407 $usercontext = context_user::instance($user->id);
408 // create a user private file
409 $file1 = new stdClass;
410 $file1->contextid = $usercontext->id;
411 $file1->component = 'user';
412 $file1->filearea = 'private';
414 $file1->filepath = '/';
415 $file1->filename = '1.txt';
416 $file1->source = 'test';
418 $fs = get_file_storage();
419 $userfile1 = $fs->create_file_from_string($file1, 'file1 content');
420 $this->assertInstanceOf('stored_file', $userfile1);
422 $file2 = clone($file1);
423 $file2->filename = '2.txt';
424 $userfile2 = $fs->create_file_from_string($file2, 'file2 content');
425 $this->assertInstanceOf('stored_file', $userfile2);
427 $file3 = clone($file1);
428 $file3->filename = '3.txt';
429 $userfile3 = $fs->create_file_from_storedfile($file3, $userfile2);
430 $this->assertInstanceOf('stored_file', $userfile3);
432 $user->ctxid = $usercontext->id;
437 public function test_get_area_files() {
438 $user = $this->setup_three_private_files();
439 $fs = get_file_storage();
441 // Get area files with default options.
442 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
444 // Should be the two files we added plus the folder.
445 $this->assertEquals(4, count($areafiles));
448 foreach ($areafiles as $key => $file) {
449 $this->assertInstanceOf('stored_file', $file);
450 $this->assertEquals($key, $file->get_pathnamehash());
453 // Get area files without a folder.
454 $folderlessfiles = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'sortorder', false);
455 // Should be the two files without folder.
456 $this->assertEquals(3, count($folderlessfiles));
459 foreach ($folderlessfiles as $key => $file) {
460 $this->assertInstanceOf('stored_file', $file);
461 $this->assertEquals($key, $file->get_pathnamehash());
464 // Get area files ordered by id.
465 $filesbyid = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'id', false);
466 // Should be the two files without folder.
467 $this->assertEquals(3, count($filesbyid));
470 foreach ($filesbyid as $key => $file) {
471 $this->assertInstanceOf('stored_file', $file);
472 $this->assertEquals($key, $file->get_pathnamehash());
475 // Test with an itemid with no files
476 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private', 666, 'sortorder', false);
478 $this->assertEmpty($areafiles);
481 public function test_get_area_tree() {
482 $user = $this->setup_three_private_files();
483 $fs = get_file_storage();
486 // Get area files with default options.
487 $areatree = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
488 $this->assertEmpty($areatree['subdirs']);
489 $this->assertNotEmpty($areatree['files']);
490 $this->assertCount(3, $areatree['files']);
492 // Ensure an empty try with a fake itemid.
493 $emptytree = $fs->get_area_tree($user->ctxid, 'user', 'private', 666);
494 $this->assertEmpty($emptytree['subdirs']);
495 $this->assertEmpty($emptytree['files']);
498 $dir = $fs->create_directory($user->ctxid, 'user', 'private', 0, '/testsubdir/');
499 $this->assertInstanceOf('stored_file', $dir);
501 // Add a file to the subdir.
503 'contextid' => $user->ctxid,
504 'component' => 'user',
505 'filearea' => 'private',
507 'filepath' => '/testsubdir/',
508 'filename' => 'test-get-area-tree.txt',
511 $directoryfile = $fs->create_file_from_string($filerecord, 'Test content');
512 $this->assertInstanceOf('stored_file', $directoryfile);
514 $areatree = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
516 // At the top level there should still be 3 files.
517 $this->assertCount(3, $areatree['files']);
519 // There should now be a subdirectory.
520 $this->assertCount(1, $areatree['subdirs']);
522 // The test subdir is named testsubdir.
523 $subdir = $areatree['subdirs']['testsubdir'];
524 $this->assertNotEmpty($subdir);
525 // It should have one file we added.
526 $this->assertCount(1, $subdir['files']);
527 // And no subdirs itself.
528 $this->assertCount(0, $subdir['subdirs']);
530 // Verify the file is the one we added.
531 $subdirfile = reset($subdir['files']);
532 $this->assertInstanceOf('stored_file', $subdirfile);
533 $this->assertEquals($filerecord['filename'], $subdirfile->get_filename());
536 public function test_get_file_by_id() {
537 $user = $this->setup_three_private_files();
538 $fs = get_file_storage();
540 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
542 // Test get_file_by_id.
543 $filebyid = reset($areafiles);
544 $shouldbesame = $fs->get_file_by_id($filebyid->get_id());
545 $this->assertEquals($filebyid->get_contenthash(), $shouldbesame->get_contenthash());
547 // Test an id which doens't exist.
548 $doesntexist = $fs->get_file_by_id(99999);
549 $this->assertFalse($doesntexist);
552 public function test_get_file_by_hash() {
553 $user = $this->setup_three_private_files();
554 $fs = get_file_storage();
556 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
557 // Test get_file_by_hash
558 $filebyhash = reset($areafiles);
559 $shouldbesame = $fs->get_file_by_hash($filebyhash->get_pathnamehash());
560 $this->assertEquals($filebyhash->get_id(), $shouldbesame->get_id());
562 // Test an hash which doens't exist.
563 $doesntexist = $fs->get_file_by_hash('DOESNTEXIST');
564 $this->assertFalse($doesntexist);
567 public function test_get_external_files() {
568 $user = $this->setup_three_private_files();
569 $fs = get_file_storage();
571 $repos = repository::get_instances(array('type'=>'user'));
572 $userrepository = reset($repos);
573 $this->assertInstanceOf('repository', $userrepository);
576 $exfiles = $fs->get_external_files($userrepository->id, 'id');
577 $this->assertEquals(array(), $exfiles);
579 // create three aliases linking the same original: $aliasfile1 and $aliasfile2 are
580 // created via create_file_from_reference(), $aliasfile3 created from $aliasfile2
581 $originalfile = null;
582 foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
583 if (!$areafile->is_directory()) {
584 $originalfile = $areafile;
588 $this->assertInstanceOf('stored_file', $originalfile);
589 $originalrecord = array(
590 'contextid' => $originalfile->get_contextid(),
591 'component' => $originalfile->get_component(),
592 'filearea' => $originalfile->get_filearea(),
593 'itemid' => $originalfile->get_itemid(),
594 'filepath' => $originalfile->get_filepath(),
595 'filename' => $originalfile->get_filename(),
598 $aliasrecord = $this->generate_file_record();
599 $aliasrecord->filepath = '/foo/';
600 $aliasrecord->filename = 'one.txt';
602 $ref = $fs->pack_reference($originalrecord);
603 $aliasfile1 = $fs->create_file_from_reference($aliasrecord, $userrepository->id, $ref);
605 $aliasrecord->filepath = '/bar/';
606 $aliasrecord->filename = 'uno.txt';
607 // change the order of the items in the array to make sure that it does not matter
608 ksort($originalrecord);
609 $ref = $fs->pack_reference($originalrecord);
610 $aliasfile2 = $fs->create_file_from_reference($aliasrecord, $userrepository->id, $ref);
612 $aliasrecord->filepath = '/bar/';
613 $aliasrecord->filename = 'jedna.txt';
614 $aliasfile3 = $fs->create_file_from_storedfile($aliasrecord, $aliasfile2);
616 // make sure we get three aliases now
617 $exfiles = $fs->get_external_files($userrepository->id, 'id');
618 $this->assertEquals(3, count($exfiles));
619 foreach ($exfiles as $exfile) {
620 $this->assertTrue($exfile->is_external_file());
622 // make sure they all link the same original (thence that all are linked with the same
623 // record in {files_reference})
624 $this->assertEquals($aliasfile1->get_referencefileid(), $aliasfile2->get_referencefileid());
625 $this->assertEquals($aliasfile3->get_referencefileid(), $aliasfile2->get_referencefileid());
628 public function test_create_directory_contextid_negative() {
629 $fs = get_file_storage();
631 $this->setExpectedException('file_exception');
632 $fs->create_directory(-1, 'core', 'unittest', 0, '/');
635 public function test_create_directory_contextid_invalid() {
636 $fs = get_file_storage();
638 $this->setExpectedException('file_exception');
639 $fs->create_directory('not an int', 'core', 'unittest', 0, '/');
642 public function test_create_directory_component_invalid() {
643 $fs = get_file_storage();
644 $syscontext = context_system::instance();
646 $this->setExpectedException('file_exception');
647 $fs->create_directory($syscontext->id, 'bad/component', 'unittest', 0, '/');
650 public function test_create_directory_filearea_invalid() {
651 $fs = get_file_storage();
652 $syscontext = context_system::instance();
654 $this->setExpectedException('file_exception');
655 $fs->create_directory($syscontext->id, 'core', 'bad-filearea', 0, '/');
658 public function test_create_directory_itemid_negative() {
659 $fs = get_file_storage();
660 $syscontext = context_system::instance();
662 $this->setExpectedException('file_exception');
663 $fs->create_directory($syscontext->id, 'core', 'unittest', -1, '/');
666 public function test_create_directory_itemid_invalid() {
667 $fs = get_file_storage();
668 $syscontext = context_system::instance();
670 $this->setExpectedException('file_exception');
671 $fs->create_directory($syscontext->id, 'core', 'unittest', 'notanint', '/');
674 public function test_create_directory_filepath_invalid() {
675 $fs = get_file_storage();
676 $syscontext = context_system::instance();
678 $this->setExpectedException('file_exception');
679 $fs->create_directory($syscontext->id, 'core', 'unittest', 0, '/not-with-trailing/or-leading-slash');
682 public function test_get_directory_files() {
683 $user = $this->setup_three_private_files();
684 $fs = get_file_storage();
686 $dir = $fs->create_directory($user->ctxid, 'user', 'private', 0, '/testsubdir/');
687 $this->assertInstanceOf('stored_file', $dir);
689 // Add a file to the subdir.
691 'contextid' => $user->ctxid,
692 'component' => 'user',
693 'filearea' => 'private',
695 'filepath' => '/testsubdir/',
696 'filename' => 'test-get-area-tree.txt',
699 $directoryfile = $fs->create_file_from_string($filerecord, 'Test content');
700 $this->assertInstanceOf('stored_file', $directoryfile);
702 // Don't recurse without dirs
703 $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, false, 'id');
705 $this->assertCount(3, $files);
706 foreach ($files as $key => $file) {
707 $this->assertInstanceOf('stored_file', $file);
708 $this->assertEquals($key, $file->get_pathnamehash());
711 // Don't recurse with dirs.
712 $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, true, 'id');
713 // 3 files + 1 directory.
714 $this->assertCount(4, $files);
715 foreach ($files as $key => $file) {
716 $this->assertInstanceOf('stored_file', $file);
717 $this->assertEquals($key, $file->get_pathnamehash());
720 // Recurse with dirs.
721 $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, true, 'id');
722 // 3 files + 1 directory + 1 subdir file.
723 $this->assertCount(5, $files);
724 foreach ($files as $key => $file) {
725 $this->assertInstanceOf('stored_file', $file);
726 $this->assertEquals($key, $file->get_pathnamehash());
729 // Recurse without dirs.
730 $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, false, 'id');
731 // 3 files + 1 subdir file.
732 $this->assertCount(4, $files);
733 foreach ($files as $key => $file) {
734 $this->assertInstanceOf('stored_file', $file);
735 $this->assertEquals($key, $file->get_pathnamehash());
739 public function test_search_references() {
740 $user = $this->setup_three_private_files();
741 $fs = get_file_storage();
742 $repos = repository::get_instances(array('type'=>'user'));
743 $repo = reset($repos);
746 'contextid' => $user->ctxid,
747 'component' => 'user',
748 'filearea' => 'private',
750 'filepath' => '/aliases/',
751 'filename' => 'alias-to-1.txt'
755 'contextid' => $user->ctxid,
756 'component' => 'user',
757 'filearea' => 'private',
759 'filepath' => '/aliases/',
760 'filename' => 'another-alias-to-1.txt'
763 $reference = file_storage::pack_reference(array(
764 'contextid' => $user->ctxid,
765 'component' => 'user',
766 'filearea' => 'private',
769 'filename' => '1.txt'
772 // There are no aliases now.
773 $result = $fs->search_references($reference);
774 $this->assertEquals(array(), $result);
776 $result = $fs->search_references_count($reference);
777 $this->assertSame($result, 0);
779 // Create two aliases and make sure they are returned.
780 $fs->create_file_from_reference($alias1, $repo->id, $reference);
781 $fs->create_file_from_reference($alias2, $repo->id, $reference);
783 $result = $fs->search_references($reference);
784 $this->assertTrue(is_array($result));
785 $this->assertEquals(count($result), 2);
786 foreach ($result as $alias) {
787 $this->assertTrue($alias instanceof stored_file);
790 $result = $fs->search_references_count($reference);
791 $this->assertSame($result, 2);
793 // The method can't be used for references to files outside the filepool
794 $exceptionthrown = false;
796 $fs->search_references('http://dl.dropbox.com/download/1234567/naked-dougiamas.jpg');
797 } catch (file_reference_exception $e) {
798 $exceptionthrown = true;
800 $this->assertTrue($exceptionthrown);
802 $exceptionthrown = false;
804 $fs->search_references_count('http://dl.dropbox.com/download/1234567/naked-dougiamas.jpg');
805 } catch (file_reference_exception $e) {
806 $exceptionthrown = true;
808 $this->assertTrue($exceptionthrown);
811 public function test_delete_area_files() {
812 $user = $this->setup_three_private_files();
813 $fs = get_file_storage();
815 // Get area files with default options.
816 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
817 // Should be the two files we added plus the folder.
818 $this->assertEquals(4, count($areafiles));
819 $fs->delete_area_files($user->ctxid, 'user', 'private');
821 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
822 // Should be the two files we added plus the folder.
823 $this->assertEquals(0, count($areafiles));
826 public function test_delete_area_files_itemid() {
827 $user = $this->setup_three_private_files();
828 $fs = get_file_storage();
830 // Get area files with default options.
831 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
832 // Should be the two files we added plus the folder.
833 $this->assertEquals(4, count($areafiles));
834 $fs->delete_area_files($user->ctxid, 'user', 'private', 9999);
836 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
837 $this->assertEquals(4, count($areafiles));
840 public function test_delete_area_files_select() {
841 $user = $this->setup_three_private_files();
842 $fs = get_file_storage();
844 // Get area files with default options.
845 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
846 // Should be the two files we added plus the folder.
847 $this->assertEquals(4, count($areafiles));
848 $fs->delete_area_files_select($user->ctxid, 'user', 'private', '!= :notitemid', array('notitemid'=>9999));
850 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
851 // Should be the two files we added plus the folder.
852 $this->assertEquals(0, count($areafiles));
855 public function test_delete_component_files() {
856 $user = $this->setup_three_private_files();
857 $fs = get_file_storage();
859 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
860 $this->assertEquals(4, count($areafiles));
861 $fs->delete_component_files('user');
862 $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
863 $this->assertEquals(0, count($areafiles));
866 public function test_create_file_from_url() {
867 $this->resetAfterTest(true);
869 $syscontext = context_system::instance();
871 'contextid' => $syscontext->id,
872 'component' => 'core',
873 'filearea' => 'unittest',
875 'filepath' => '/downloadtest/',
877 $url = 'http://download.moodle.org/unittest/test.html';
879 $fs = get_file_storage();
881 // Test creating file without filename.
882 $file1 = $fs->create_file_from_url($filerecord, $url);
883 $this->assertInstanceOf('stored_file', $file1);
886 $filerecord['filename'] = 'unit-test-filename.html';
887 $file2 = $fs->create_file_from_url($filerecord, $url);
888 $this->assertInstanceOf('stored_file', $file2);
890 // Use temporary file.
891 $filerecord['filename'] = 'unit-test-with-temp-file.html';
892 $file3 = $fs->create_file_from_url($filerecord, $url, null, true);
893 $file3 = $this->assertInstanceOf('stored_file', $file3);
896 public function test_cron() {
897 $this->resetAfterTest(true);
899 // Note: this is only testing DB compatibility atm, rather than
900 // that work is done.
901 $fs = get_file_storage();
903 $this->expectOutputRegex('/Cleaning up/');
907 public function test_is_area_empty() {
908 $user = $this->setup_three_private_files();
909 $fs = get_file_storage();
911 $this->assertFalse($fs->is_area_empty($user->ctxid, 'user', 'private'));
913 // File area with madeup itemid should be empty.
914 $this->assertTrue($fs->is_area_empty($user->ctxid, 'user', 'private', 9999));
915 // Still empty with dirs included.
916 $this->assertTrue($fs->is_area_empty($user->ctxid, 'user', 'private', 9999, false));
919 public function test_move_area_files_to_new_context() {
920 $this->resetAfterTest(true);
922 // Create a course with a page resource.
923 $course = $this->getDataGenerator()->create_course();
924 $page1 = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
925 $page1context = context_module::instance($page1->cmid);
927 // Add a file to the page.
928 $fs = get_file_storage();
930 'contextid' => $page1context->id,
931 'component' => 'mod_page',
932 'filearea' => 'content',
935 'filename' => 'unit-test-file.txt',
938 $originalfile = $fs->create_file_from_string($filerecord, 'Test content');
939 $this->assertInstanceOf('stored_file', $originalfile);
941 $pagefiles = $fs->get_area_files($page1context->id, 'mod_page', 'content', 0, 'sortorder', false);
942 // Should be one file in filearea.
943 $this->assertFalse($fs->is_area_empty($page1context->id, 'mod_page', 'content'));
945 // Create a new page.
946 $page2 = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
947 $page2context = context_module::instance($page2->cmid);
949 // Newly created page area is empty.
950 $this->assertTrue($fs->is_area_empty($page2context->id, 'mod_page', 'content'));
953 $fs->move_area_files_to_new_context($page1context->id, $page2context->id, 'mod_page', 'content');
955 // Page2 filearea should no longer be empty.
956 $this->assertFalse($fs->is_area_empty($page2context->id, 'mod_page', 'content'));
958 // Page1 filearea should now be empty.
959 $this->assertTrue($fs->is_area_empty($page1context->id, 'mod_page', 'content'));
961 $page2files = $fs->get_area_files($page2context->id, 'mod_page', 'content', 0, 'sortorder', false);
962 $movedfile = reset($page2files);
964 // The two files should have the same content hash.
965 $this->assertEquals($movedfile->get_contenthash(), $originalfile->get_contenthash());
968 public function test_convert_image() {
971 $this->resetAfterTest(false);
973 $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
974 $syscontext = context_system::instance();
976 'contextid' => $syscontext->id,
977 'component' => 'core',
978 'filearea' => 'unittest',
980 'filepath' => '/images/',
981 'filename' => 'testimage.jpg',
984 $fs = get_file_storage();
985 $original = $fs->create_file_from_pathname($filerecord, $filepath);
987 $filerecord['filename'] = 'testimage-converted-10x10.jpg';
988 $converted = $fs->convert_image($filerecord, $original, 10, 10, true, 100);
989 $this->assertInstanceOf('stored_file', $converted);
991 $filerecord['filename'] = 'testimage-convereted-nosize.jpg';
992 $converted = $fs->convert_image($filerecord, $original);
993 $this->assertInstanceOf('stored_file', $converted);
996 private function generate_file_record() {
997 $syscontext = context_system::instance();
998 $filerecord = new stdClass();
999 $filerecord->contextid = $syscontext->id;
1000 $filerecord->component = 'core';
1001 $filerecord->filearea = 'phpunit';
1002 $filerecord->filepath = '/';
1003 $filerecord->filename = 'testfile.txt';
1004 $filerecord->itemid = 0;
1009 public function test_create_file_from_storedfile_file_invalid() {
1010 $this->resetAfterTest(true);
1012 $filerecord = $this->generate_file_record();
1014 $fs = get_file_storage();
1015 $this->setExpectedException('file_exception');
1016 // Create a file from a file id which doesn't exist.
1017 $fs->create_file_from_storedfile($filerecord, 9999);
1020 public function test_create_file_from_storedfile_contextid_invalid() {
1021 $this->resetAfterTest(true);
1023 $filerecord = $this->generate_file_record();
1025 $fs = get_file_storage();
1026 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1027 $this->assertInstanceOf('stored_file', $file1);
1029 $filerecord->filename = 'invalid.txt';
1030 $filerecord->contextid = 'invalid';
1032 $this->setExpectedException('file_exception', 'Invalid contextid');
1033 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1036 public function test_create_file_from_storedfile_component_invalid() {
1037 $this->resetAfterTest(true);
1039 $filerecord = $this->generate_file_record();
1041 $fs = get_file_storage();
1042 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1043 $this->assertInstanceOf('stored_file', $file1);
1045 $filerecord->filename = 'invalid.txt';
1046 $filerecord->component = 'bad/component';
1048 $this->setExpectedException('file_exception', 'Invalid component');
1049 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1052 public function test_create_file_from_storedfile_filearea_invalid() {
1053 $this->resetAfterTest(true);
1055 $filerecord = $this->generate_file_record();
1057 $fs = get_file_storage();
1058 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1059 $this->assertInstanceOf('stored_file', $file1);
1061 $filerecord->filename = 'invalid.txt';
1062 $filerecord->filearea = 'bad-filearea';
1064 $this->setExpectedException('file_exception', 'Invalid filearea');
1065 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1068 public function test_create_file_from_storedfile_itemid_invalid() {
1069 $this->resetAfterTest(true);
1071 $filerecord = $this->generate_file_record();
1073 $fs = get_file_storage();
1074 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1075 $this->assertInstanceOf('stored_file', $file1);
1077 $filerecord->filename = 'invalid.txt';
1078 $filerecord->itemid = 'bad-itemid';
1080 $this->setExpectedException('file_exception', 'Invalid itemid');
1081 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1084 public function test_create_file_from_storedfile_filepath_invalid() {
1085 $this->resetAfterTest(true);
1087 $filerecord = $this->generate_file_record();
1089 $fs = get_file_storage();
1090 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1091 $this->assertInstanceOf('stored_file', $file1);
1093 $filerecord->filename = 'invalid.txt';
1094 $filerecord->filepath = 'a-/bad/-filepath';
1096 $this->setExpectedException('file_exception', 'Invalid file path');
1097 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1100 public function test_create_file_from_storedfile_filename_invalid() {
1101 $this->resetAfterTest(true);
1103 $filerecord = $this->generate_file_record();
1105 $fs = get_file_storage();
1106 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1107 $this->assertInstanceOf('stored_file', $file1);
1109 $filerecord->filename = '';
1111 $this->setExpectedException('file_exception', 'Invalid file name');
1112 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1115 public function test_create_file_from_storedfile_timecreated_invalid() {
1116 $this->resetAfterTest(true);
1118 $filerecord = $this->generate_file_record();
1120 $fs = get_file_storage();
1121 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1122 $this->assertInstanceOf('stored_file', $file1);
1124 $filerecord->filename = 'invalid.txt';
1125 $filerecord->timecreated = 'today';
1127 $this->setExpectedException('file_exception', 'Invalid file timecreated');
1128 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1131 public function test_create_file_from_storedfile_timemodified_invalid() {
1132 $this->resetAfterTest(true);
1134 $filerecord = $this->generate_file_record();
1136 $fs = get_file_storage();
1137 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1138 $this->assertInstanceOf('stored_file', $file1);
1140 $filerecord->filename = 'invalid.txt';
1141 $filerecord->timemodified = 'today';
1143 $this->setExpectedException('file_exception', 'Invalid file timemodified');
1144 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1147 public function test_create_file_from_storedfile_duplicate() {
1148 $this->resetAfterTest(true);
1150 $filerecord = $this->generate_file_record();
1152 $fs = get_file_storage();
1153 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1154 $this->assertInstanceOf('stored_file', $file1);
1156 // Creating a file validating unique constraint.
1157 $this->setExpectedException('stored_file_creation_exception');
1158 $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1161 public function test_create_file_from_storedfile() {
1162 $this->resetAfterTest(true);
1164 $syscontext = context_system::instance();
1166 $filerecord = new stdClass();
1167 $filerecord->contextid = $syscontext->id;
1168 $filerecord->component = 'core';
1169 $filerecord->filearea = 'phpunit';
1170 $filerecord->filepath = '/';
1171 $filerecord->filename = 'testfile.txt';
1172 $filerecord->itemid = 0;
1174 $fs = get_file_storage();
1176 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1177 $this->assertInstanceOf('stored_file', $file1);
1179 $filerecord->filename = 'test-create-file-from-storedfile.txt';
1180 $file2 = $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1181 $this->assertInstanceOf('stored_file', $file2);
1183 // These will be normalised to current time..
1184 $filerecord->timecreated = -100;
1185 $filerecord->timemodified= -100;
1186 $filerecord->filename = 'test-create-file-from-storedfile-bad-dates.txt';
1188 $file3 = $fs->create_file_from_storedfile($filerecord, $file1->get_id());
1189 $this->assertInstanceOf('stored_file', $file3);
1191 $this->assertNotEquals($file3->get_timemodified(), $filerecord->timemodified);
1192 $this->assertNotEquals($file3->get_timecreated(), $filerecord->timecreated);
1195 public function test_create_file_from_string_contextid_invalid() {
1196 $this->resetAfterTest(true);
1198 $filerecord = $this->generate_file_record();
1199 $fs = get_file_storage();
1201 $filerecord->contextid = 'invalid';
1203 $this->setExpectedException('file_exception', 'Invalid contextid');
1204 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1207 public function test_create_file_from_string_component_invalid() {
1208 $this->resetAfterTest(true);
1210 $filerecord = $this->generate_file_record();
1211 $fs = get_file_storage();
1213 $filerecord->component = 'bad/component';
1215 $this->setExpectedException('file_exception', 'Invalid component');
1216 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1219 public function test_create_file_from_string_filearea_invalid() {
1220 $this->resetAfterTest(true);
1222 $filerecord = $this->generate_file_record();
1223 $fs = get_file_storage();
1225 $filerecord->filearea = 'bad-filearea';
1227 $this->setExpectedException('file_exception', 'Invalid filearea');
1228 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1231 public function test_create_file_from_string_itemid_invalid() {
1232 $this->resetAfterTest(true);
1234 $filerecord = $this->generate_file_record();
1235 $fs = get_file_storage();
1237 $filerecord->itemid = 'bad-itemid';
1239 $this->setExpectedException('file_exception', 'Invalid itemid');
1240 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1243 public function test_create_file_from_string_filepath_invalid() {
1244 $this->resetAfterTest(true);
1246 $filerecord = $this->generate_file_record();
1247 $fs = get_file_storage();
1249 $filerecord->filepath = 'a-/bad/-filepath';
1251 $this->setExpectedException('file_exception', 'Invalid file path');
1252 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1255 public function test_create_file_from_string_filename_invalid() {
1256 $this->resetAfterTest(true);
1258 $filerecord = $this->generate_file_record();
1259 $fs = get_file_storage();
1261 $filerecord->filename = '';
1263 $this->setExpectedException('file_exception', 'Invalid file name');
1264 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1267 public function test_create_file_from_string_timecreated_invalid() {
1268 $this->resetAfterTest(true);
1270 $filerecord = $this->generate_file_record();
1271 $fs = get_file_storage();
1273 $filerecord->timecreated = 'today';
1275 $this->setExpectedException('file_exception', 'Invalid file timecreated');
1276 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1279 public function test_create_file_from_string_timemodified_invalid() {
1280 $this->resetAfterTest(true);
1282 $filerecord = $this->generate_file_record();
1283 $fs = get_file_storage();
1285 $filerecord->timemodified = 'today';
1287 $this->setExpectedException('file_exception', 'Invalid file timemodified');
1288 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1291 public function test_create_file_from_string_duplicate() {
1292 $this->resetAfterTest(true);
1294 $filerecord = $this->generate_file_record();
1295 $fs = get_file_storage();
1297 $file1 = $fs->create_file_from_string($filerecord, 'text contents');
1299 // Creating a file validating unique constraint.
1300 $this->setExpectedException('stored_file_creation_exception');
1301 $file2 = $fs->create_file_from_string($filerecord, 'text contents');
1304 public function test_create_file_from_pathname_contextid_invalid() {
1306 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1308 $this->resetAfterTest(true);
1310 $filerecord = $this->generate_file_record();
1311 $fs = get_file_storage();
1313 $filerecord->contextid = 'invalid';
1315 $this->setExpectedException('file_exception', 'Invalid contextid');
1316 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1319 public function test_create_file_from_pathname_component_invalid() {
1321 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1323 $this->resetAfterTest(true);
1325 $filerecord = $this->generate_file_record();
1326 $fs = get_file_storage();
1328 $filerecord->component = 'bad/component';
1330 $this->setExpectedException('file_exception', 'Invalid component');
1331 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1334 public function test_create_file_from_pathname_filearea_invalid() {
1336 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1338 $this->resetAfterTest(true);
1340 $filerecord = $this->generate_file_record();
1341 $fs = get_file_storage();
1343 $filerecord->filearea = 'bad-filearea';
1345 $this->setExpectedException('file_exception', 'Invalid filearea');
1346 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1349 public function test_create_file_from_pathname_itemid_invalid() {
1351 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1353 $this->resetAfterTest(true);
1355 $filerecord = $this->generate_file_record();
1356 $fs = get_file_storage();
1358 $filerecord->itemid = 'bad-itemid';
1360 $this->setExpectedException('file_exception', 'Invalid itemid');
1361 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1364 public function test_create_file_from_pathname_filepath_invalid() {
1366 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1368 $this->resetAfterTest(true);
1370 $filerecord = $this->generate_file_record();
1371 $fs = get_file_storage();
1373 $filerecord->filepath = 'a-/bad/-filepath';
1375 $this->setExpectedException('file_exception', 'Invalid file path');
1376 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1379 public function test_create_file_from_pathname_filename_invalid() {
1381 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1383 $this->resetAfterTest(true);
1385 $filerecord = $this->generate_file_record();
1386 $fs = get_file_storage();
1388 $filerecord->filename = '';
1390 $this->setExpectedException('file_exception', 'Invalid file name');
1391 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1394 public function test_create_file_from_pathname_timecreated_invalid() {
1396 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1398 $this->resetAfterTest(true);
1400 $filerecord = $this->generate_file_record();
1401 $fs = get_file_storage();
1403 $filerecord->timecreated = 'today';
1405 $this->setExpectedException('file_exception', 'Invalid file timecreated');
1406 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1409 public function test_create_file_from_pathname_timemodified_invalid() {
1411 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1413 $this->resetAfterTest(true);
1415 $filerecord = $this->generate_file_record();
1416 $fs = get_file_storage();
1418 $filerecord->timemodified = 'today';
1420 $this->setExpectedException('file_exception', 'Invalid file timemodified');
1421 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1424 public function test_create_file_from_pathname_duplicate_file() {
1426 $this->resetAfterTest(true);
1428 $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
1430 $filerecord = $this->generate_file_record();
1431 $fs = get_file_storage();
1433 $file1 = $fs->create_file_from_pathname($filerecord, $path);
1434 $this->assertInstanceOf('stored_file', $file1);
1436 // Creating a file validating unique constraint.
1437 $this->setExpectedException('stored_file_creation_exception');
1438 $file2 = $fs->create_file_from_pathname($filerecord, $path);
1442 * Calling stored_file::delete_reference() on a non-reference file throws coding_exception
1444 public function test_delete_reference_on_nonreference() {
1446 $this->resetAfterTest(true);
1447 $user = $this->setup_three_private_files();
1448 $fs = get_file_storage();
1449 $repos = repository::get_instances(array('type'=>'user'));
1450 $repo = reset($repos);
1453 foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
1454 if (!$areafile->is_directory()) {
1459 $this->assertInstanceOf('stored_file', $file);
1460 $this->assertFalse($file->is_external_file());
1462 $this->setExpectedException('coding_exception');
1463 $file->delete_reference();
1467 * Calling stored_file::delete_reference() on a reference file does not affect other
1468 * symlinks to the same original
1470 public function test_delete_reference_one_symlink_does_not_rule_them_all() {
1472 $this->resetAfterTest(true);
1473 $user = $this->setup_three_private_files();
1474 $fs = get_file_storage();
1475 $repos = repository::get_instances(array('type'=>'user'));
1476 $repo = reset($repos);
1478 // create two aliases linking the same original
1480 $originalfile = null;
1481 foreach ($fs->get_area_files($user->ctxid, 'user', 'private') as $areafile) {
1482 if (!$areafile->is_directory()) {
1483 $originalfile = $areafile;
1487 $this->assertInstanceOf('stored_file', $originalfile);
1489 // calling delete_reference() on a non-reference file
1491 $originalrecord = array(
1492 'contextid' => $originalfile->get_contextid(),
1493 'component' => $originalfile->get_component(),
1494 'filearea' => $originalfile->get_filearea(),
1495 'itemid' => $originalfile->get_itemid(),
1496 'filepath' => $originalfile->get_filepath(),
1497 'filename' => $originalfile->get_filename(),
1500 $aliasrecord = $this->generate_file_record();
1501 $aliasrecord->filepath = '/A/';
1502 $aliasrecord->filename = 'symlink.txt';
1504 $ref = $fs->pack_reference($originalrecord);
1505 $aliasfile1 = $fs->create_file_from_reference($aliasrecord, $repo->id, $ref);
1507 $aliasrecord->filepath = '/B/';
1508 $aliasrecord->filename = 'symlink.txt';
1509 $ref = $fs->pack_reference($originalrecord);
1510 $aliasfile2 = $fs->create_file_from_reference($aliasrecord, $repo->id, $ref);
1512 // refetch A/symlink.txt
1513 $symlink1 = $fs->get_file($aliasrecord->contextid, $aliasrecord->component,
1514 $aliasrecord->filearea, $aliasrecord->itemid, '/A/', 'symlink.txt');
1515 $this->assertTrue($symlink1->is_external_file());
1517 // unlink the A/symlink.txt
1518 $symlink1->delete_reference();
1519 $this->assertFalse($symlink1->is_external_file());
1521 // make sure that B/symlink.txt has not been affected
1522 $symlink2 = $fs->get_file($aliasrecord->contextid, $aliasrecord->component,
1523 $aliasrecord->filearea, $aliasrecord->itemid, '/B/', 'symlink.txt');
1524 $this->assertTrue($symlink2->is_external_file());
1527 public function test_get_unused_filename() {
1529 $this->resetAfterTest(true);
1531 $fs = get_file_storage();
1532 $this->setAdminUser();
1533 $contextid = context_user::instance($USER->id)->id;
1534 $component = 'user';
1535 $filearea = 'private';
1539 // Create some private files.
1540 $file = new stdClass;
1541 $file->contextid = $contextid;
1542 $file->component = 'user';
1543 $file->filearea = 'private';
1545 $file->filepath = '/';
1546 $file->source = 'test';
1547 $filenames = array('foo.txt', 'foo (1).txt', 'foo (20).txt', 'foo (999)', 'bar.jpg', 'What (a cool file).jpg',
1548 'Hurray! (1).php', 'Hurray! (2).php', 'Hurray! (9a).php', 'Hurray! (abc).php');
1549 foreach ($filenames as $key => $filename) {
1550 $file->filename = $filename;
1551 $userfile = $fs->create_file_from_string($file, "file $key $filename content");
1552 $this->assertInstanceOf('stored_file', $userfile);
1555 // Asserting new generated names.
1556 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'unused.txt');
1557 $this->assertEquals('unused.txt', $newfilename);
1558 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo.txt');
1559 $this->assertEquals('foo (21).txt', $newfilename);
1560 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (1).txt');
1561 $this->assertEquals('foo (21).txt', $newfilename);
1562 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (2).txt');
1563 $this->assertEquals('foo (2).txt', $newfilename);
1564 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (20).txt');
1565 $this->assertEquals('foo (21).txt', $newfilename);
1566 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo');
1567 $this->assertEquals('foo', $newfilename);
1568 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (123)');
1569 $this->assertEquals('foo (123)', $newfilename);
1570 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'foo (999)');
1571 $this->assertEquals('foo (1000)', $newfilename);
1572 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar.png');
1573 $this->assertEquals('bar.png', $newfilename);
1574 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar (12).png');
1575 $this->assertEquals('bar (12).png', $newfilename);
1576 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar.jpg');
1577 $this->assertEquals('bar (1).jpg', $newfilename);
1578 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'bar (1).jpg');
1579 $this->assertEquals('bar (1).jpg', $newfilename);
1580 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'What (a cool file).jpg');
1581 $this->assertEquals('What (a cool file) (1).jpg', $newfilename);
1582 $newfilename = $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, 'Hurray! (1).php');
1583 $this->assertEquals('Hurray! (3).php', $newfilename);
1585 $this->setExpectedException('coding_exception');
1586 $fs->get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, '');
1590 class test_stored_file_inspection extends stored_file {
1591 public static function get_pretected_pathname(stored_file $file) {
1592 return $file->get_pathname_by_contenthash();