Rev 1 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>.namespace core_h5p;use core_h5p\file_storage;use core_h5p\local\library\autoloader;use core_h5p\helper;use file_archive;use moodle_exception;use ReflectionMethod;use stored_file;use zip_archive;/*** Test class covering the H5PFileStorage interface implementation.** @package core_h5p* @category test* @copyright 2019 Victor Deniz <victor@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later* @runTestsInSeparateProcesses*/class file_storage_test extends \advanced_testcase {/** @var \core_h5p\file_storage H5P file storage instance */protected $h5p_file_storage;/** @var \file_storage Core Moodle file_storage associated to the H5P file_storage */protected $h5p_fs_fs;/** @var \context Moodle context of the H5P file_storage */protected $h5p_fs_context;/** @var string Path to temp directory */protected $h5p_tempath;/** @var \core_h5p_generator H5P generator instance */protected $h5p_generator;/** @var array $files an array used in the cache tests. */protected $files = ['scripts' => [], 'styles' => []];/** @var int $libraryid an id for the library. */protected $libraryid = 1;protected function setUp(): void {parent::setUp();$this->resetAfterTest(true);autoloader::register();// Fetch generator.$generator = \testing_util::get_data_generator();$this->h5p_generator = $generator->get_plugin_generator('core_h5p');// Create file_storage_instance and create H5P temp directory.$this->h5p_file_storage = new file_storage();$this->h5p_tempath = $this->h5p_file_storage->getTmpPath();check_dir_exists($this->h5p_tempath);// Get value of protected properties.$h5p_fs_rc = new \ReflectionClass(file_storage::class);$h5p_file_storage_context = $h5p_fs_rc->getProperty('context');$this->h5p_fs_context = $h5p_file_storage_context->getValue($this->h5p_file_storage);$h5p_file_storage_fs = $h5p_fs_rc->getProperty('fs');$this->h5p_fs_fs = $h5p_file_storage_fs->getValue($this->h5p_file_storage);}/*** Test that given the main directory of a library that all files are saved* into the file system.*/public function test_saveLibrary(): void {$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $files] = $this->h5p_generator->create_library($this->h5p_tempath, $this->libraryid, $machinename, $majorversion,$minorversion);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);// Check that files are in the Moodle file system.$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/", 'library.json');$filepath = "/{$machinename}-{$majorversion}.{$minorversion}/";$this->assertEquals($filepath, $file->get_filepath());$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/scripts/", 'testlib.min.js');$jsfilepath = "{$filepath}scripts/";$this->assertEquals($jsfilepath, $file->get_filepath());$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/styles/", 'testlib.min.css');$cssfilepath = "{$filepath}styles/";$this->assertEquals($cssfilepath, $file->get_filepath());}/*** Test that a content file can be saved.*/public function test_saveContent(): void {$source = $this->h5p_tempath . '/' . 'content.json';$this->h5p_generator->create_file($source);$this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');$this->assertEquals(file_storage::CONTENT_FILEAREA, $file->get_filearea());$this->assertEquals('content.json', $file->get_filename());$this->assertEquals(5, $file->get_itemid());}/*** Test that content files located on the file system can be deleted.*/public function test_deleteContent(): void {$source = $this->h5p_tempath . '/' . 'content.json';$this->h5p_generator->create_file($source);$this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');$this->assertEquals('content.json', $file->get_filename());// Now to delete the record.$this->h5p_file_storage->deleteContent(['id' => 5]);$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');$this->assertFalse($file);}/*** Test that returning a temp path returns what is expected by the h5p library.*/public function test_getTmpPath(): void {$temparray = explode('/', $this->h5p_tempath);$h5pdirectory = array_pop($temparray);$this->assertTrue(stripos($h5pdirectory, 'h5p-') === 0);}/*** Test that the content files can be exported to a specified location.*/public function test_exportContent(): void {// Create a file to store.$source = $this->h5p_tempath . '/' . 'content.json';$this->h5p_generator->create_file($source);$this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');$this->assertEquals('content.json', $file->get_filename());// Now export it.$destinationdirectory = $this->h5p_tempath . '/' . 'testdir';check_dir_exists($destinationdirectory);$this->h5p_file_storage->exportContent(5, $destinationdirectory);// Check that there is a file now in that directory.$contents = scandir($destinationdirectory);$value = array_search('content.json', $contents);$this->assertEquals('content.json', $contents[$value]);}/*** Test that libraries on the file system can be exported to a specified location.*/public function test_exportLibrary(): void {$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $files] = $this->h5p_generator->create_library($this->h5p_tempath, $this->libraryid, $machinename, $majorversion,$minorversion);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);$destinationdirectory = $this->h5p_tempath . '/' . 'testdir';check_dir_exists($destinationdirectory);$this->h5p_file_storage->exportLibrary($lib, $destinationdirectory);$filepath = "/{$machinename}-{$majorversion}.{$minorversion}/";// There should be at least three items here (but could be more with . and ..).$this->assertFileExists($destinationdirectory . $filepath . 'library.json');$this->assertFileExists($destinationdirectory . $filepath . 'scripts/' . 'testlib.min.js');$this->assertFileExists($destinationdirectory . $filepath . 'styles/' . 'testlib.min.css');}/*** Test that an export file can be saved into the file system.*/public function test_saveExport(): void {$filename = 'someexportedfile.h5p';$source = $this->h5p_tempath . '/' . $filename;$this->h5p_generator->create_file($source);$this->h5p_file_storage->saveExport($source, $filename);// Check out if the file is there.$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::EXPORT_FILEAREA, '0', '/', $filename);$this->assertEquals(file_storage::EXPORT_FILEAREA, $file->get_filearea());}/*** Test that an exort file can be deleted from the file system.* @return [type] [description]*/public function test_deleteExport(): void {$filename = 'someexportedfile.h5p';$source = $this->h5p_tempath . '/' . $filename;$this->h5p_generator->create_file($source);$this->h5p_file_storage->saveExport($source, $filename);// Check out if the file is there.$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::EXPORT_FILEAREA, '0', '/', $filename);$this->assertEquals(file_storage::EXPORT_FILEAREA, $file->get_filearea());// Time to delete.$this->h5p_file_storage->deleteExport($filename);// Check out if the file is there.$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::EXPORT_FILEAREA, '0', '/', $filename);$this->assertFalse($file);}/*** Test to check if an export file already exists on the file system.*/public function test_hasExport(): void {$filename = 'someexportedfile.h5p';$source = $this->h5p_tempath . '/' . $filename;$this->h5p_generator->create_file($source);// Check that it doesn't exist in the file system.$this->assertFalse($this->h5p_file_storage->hasExport($filename));$this->h5p_file_storage->saveExport($source, $filename);// Now it should be present.$this->assertTrue($this->h5p_file_storage->hasExport($filename));}/*** Test that all the library files for an H5P activity can be concatenated into "cache" files. One for js and another for css.*/public function test_cacheAssets(): void {$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);// Second library.$basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';$this->libraryid++;$machinename = 'SuperTest';$majorversion = 2;$minorversion = 4;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);$this->h5p_file_storage->saveLibrary($lib);$this->assertCount(2, $this->files['scripts']);$this->assertCount(2, $this->files['styles']);$key = 'testhashkey';$this->h5p_file_storage->cacheAssets($this->files, $key);$this->assertCount(1, $this->files['scripts']);$this->assertCount(1, $this->files['styles']);$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.js';$this->assertEquals($expectedfile, $this->files['scripts'][0]->path);$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.css';$this->assertEquals($expectedfile, $this->files['styles'][0]->path);}/*** Test that cached files can be retrieved via a key.*/public function test_getCachedAssets(): void {$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);// Second library.$basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';$this->libraryid++;$machinename = 'SuperTest';$majorversion = 2;$minorversion = 4;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);$this->h5p_file_storage->saveLibrary($lib);$this->assertCount(2, $this->files['scripts']);$this->assertCount(2, $this->files['styles']);$key = 'testhashkey';$this->h5p_file_storage->cacheAssets($this->files, $key);$testarray = $this->h5p_file_storage->getCachedAssets($key);$this->assertCount(1, $testarray['scripts']);$this->assertCount(1, $testarray['styles']);$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.js';$this->assertEquals($expectedfile, $testarray['scripts'][0]->path);$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.css';$this->assertEquals($expectedfile, $testarray['styles'][0]->path);}/*** Test that cache files in the files system can be removed.*/public function test_deleteCachedAssets(): void {$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);// Second library.$basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';$this->libraryid++;$machinename = 'SuperTest';$majorversion = 2;$minorversion = 4;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);$this->h5p_file_storage->saveLibrary($lib);$this->assertCount(2, $this->files['scripts']);$this->assertCount(2, $this->files['styles']);$key = 'testhashkey';$this->h5p_file_storage->cacheAssets($this->files, $key);$testarray = $this->h5p_file_storage->getCachedAssets($key);$this->assertCount(1, $testarray['scripts']);$this->assertCount(1, $testarray['styles']);// Time to delete.$this->h5p_file_storage->deleteCachedAssets([$key]);$testarray = $this->h5p_file_storage->getCachedAssets($key);$this->assertNull($testarray);}/*** Retrieve content from a file given a specific path.*/public function test_getContent(): void {$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);array_push($this->files['scripts'], ...$libfiles['scripts']);array_push($this->files['styles'], ...$libfiles['styles']);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);$content = $this->h5p_file_storage->getContent($this->files['scripts'][0]->path);// The file content is created based on the file system path (\core_h5p_generator::create_file).$expectedcontent = hash("md5", $basedirectory. '/' . 'scripts' . '/' . 'testlib.min.js');$this->assertEquals($expectedcontent, $content);}/*** Test that an upgrade script can be found on the file system.*/public function test_getUpgradeScript(): void {// Upload an upgrade file.$machinename = 'TestLib';$majorversion = 3;$minorversion = 1;$filepath = '/' . "{$machinename}-{$majorversion}.{$minorversion}" . '/';$fs = get_file_storage();$filerecord = ['contextid' => \context_system::instance()->id,'component' => file_storage::COMPONENT,'filearea' => file_storage::LIBRARY_FILEAREA,'itemid' => 15,'filepath' => $filepath,'filename' => 'upgrade.js'];$filestorage = new file_storage();$fs->create_file_from_string($filerecord, 'test string info');$expectedfilepath = '/' . file_storage::LIBRARY_FILEAREA . $filepath . 'upgrade.js';$this->assertEquals($expectedfilepath, $filestorage->getUpgradeScript($machinename, $majorversion, $minorversion));$this->assertNull($filestorage->getUpgradeScript($machinename, $majorversion, 7));}/*** Test that information from a source can be saved to the specified path.* The zip file has the following contents* - h5ptest* |- content* | |- content.json* |- testFont* | |- testfont.min.css* |- testJavaScript* | |- testscript.min.js* |- h5p.json*/public function test_saveFileFromZip(): void {$ziparchive = new zip_archive();$path = __DIR__ . '/fixtures/h5ptest.zip';$result = $ziparchive->open($path, file_archive::OPEN);$files = $ziparchive->list_files();foreach ($files as $file) {if (!$file->is_directory) {$stream = $ziparchive->get_stream($file->index);$items = explode('/', $file->pathname);array_shift($items);$path = implode('/', $items);$this->h5p_file_storage->saveFileFromZip($this->h5p_tempath, $path, $stream);$filestocheck[] = $path;}}$ziparchive->close();foreach ($filestocheck as $filetocheck) {$pathtocheck = $this->h5p_tempath .'/'. $filetocheck;$this->assertFileExists($pathtocheck);}}/*** Test that a library is fully deleted from the file system*/public function test_delete_library(): void {$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';$machinename = 'TestLib';$majorversion = 1;$minorversion = 0;[$lib, $files] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib);// Save a second library to ensure we aren't deleting all libraries, but just the one specified.$basedirectory = $this->h5p_tempath . '/' . 'awesomelib-2.1';$this->libraryid++;$machinename = 'AwesomeLib';$majorversion = 2;$minorversion = 1;[$lib2, $files2] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,$minorversion);// Now run the API call.$this->h5p_file_storage->saveLibrary($lib2);$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::LIBRARY_FILEAREA);$this->assertCount(14, $files);$this->h5p_file_storage->delete_library($lib);// Let's look at the records.$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::LIBRARY_FILEAREA);$this->assertCount(7, $files);// Check that the db count is still the same after setting the libraryId to false.$lib['libraryId'] = false;$this->h5p_file_storage->delete_library($lib);$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::LIBRARY_FILEAREA);$this->assertCount(7, $files);}/*** Test get_icon_url() function behaviour.** @dataProvider get_icon_url_provider* @param string $filename The name of the H5P file to load.* @param bool $expected Whether the icon should exist or not.*/public function test_get_icon_url(string $filename, bool $expected): void {global $DB;$this->resetAfterTest();$factory = new \core_h5p\factory();$admin = get_admin();// Prepare a valid .H5P file.$path = __DIR__ . '/fixtures/'.$filename;// Libraries can be updated when the file has been created by admin, even when the current user is not the admin.$this->setUser($admin);$file = helper::create_fake_stored_file_from_path($path, (int)$admin->id);$factory->get_framework()->set_file($file);$config = (object)['frame' => 1,'export' => 1,'embed' => 0,'copyright' => 0,];$h5pid = helper::save_h5p($factory, $file, $config);$h5p = $DB->get_record('h5p', ['id' => $h5pid]);$h5plib = $DB->get_record('h5p_libraries', ['id' => $h5p->mainlibraryid]);$iconurl = $this->h5p_file_storage->get_icon_url($h5plib->id,$h5plib->machinename,$h5plib->majorversion,$h5plib->minorversion);if ($expected) {$this->assertStringContainsString(file_storage::ICON_FILENAME, $iconurl);} else {$this->assertFalse($iconurl);}}/*** Data provider for test_get_icon_url().** @return array*/public function get_icon_url_provider(): array {return ['Icon included' => ['filltheblanks.h5p',true,],'Icon not included' => ['greeting-card.h5p',false,],];}/*** Test the private method get_file, a wrapper for getting an H5P content file.*/public function test_get_file(): void {$this->setAdminUser();$file = 'img/fake.png';$h5pcontentid = 3;// Add a file to a H5P content.$this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $h5pcontentid);// Set get_file method accessibility.$method = new ReflectionMethod(file_storage::class, 'get_file');$contentfile = $method->invoke(new file_storage(), file_storage::CONTENT_FILEAREA, $h5pcontentid, $file);// Check that it returns an instance of store_file.$this->assertInstanceOf('stored_file', $contentfile);// Add a file to editor.$this->h5p_generator->create_content_file($file, 'draft', $h5pcontentid);$editorfile = $method->invoke(new file_storage(), 'draft', $h5pcontentid, $file);// Check that it returns an instance of store_file.$this->assertInstanceOf('stored_file', $editorfile);}/*** Test that a single file is added to Moodle files.*/public function test_move_file(): void {// Create temp folder.$tempfolder = make_request_directory(false);// Create H5P content folder.$filepath = '/img/';$filename = 'fake.png';$h5pcontentfolder = $tempfolder . '/fakeH5Pcontent/content' . $filepath;if (!check_dir_exists($h5pcontentfolder, true, true)) {throw new moodle_exception('error_creating_temp_dir', 'error', $h5pcontentfolder);}$file = $h5pcontentfolder . $filename;touch($file);$h5pcontentid = 3;// Check the file doesn't exist in Moodle files.$this->assertFalse($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));// Set get_file method accessibility.$method = new ReflectionMethod(file_storage::class, 'move_file');$method->invoke(new file_storage(), $file, $h5pcontentid);// Check the file exist in Moodle files.$this->assertTrue($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));}/*** Test that a file is copied from another H5P content or the H5P editor.** @return void*/public function test_cloneContentFile(): void {$admin = get_admin();$usercontext = \context_user::instance($admin->id);$this->setUser($admin);// Upload a file to the editor.$file = 'images/fake.jpg';$filepath = '/'.dirname($file).'/';$filename = basename($file);$content = 'abcd';$filerecord = array('contextid' => $usercontext->id,'component' => 'user','filearea' => 'draft','itemid' => 0,'filepath' => $filepath,'filename' => $filename,);$this->h5p_fs_fs->create_file_from_string($filerecord, $content);// Target H5P content, where the file will be cloned.$targetcontent = new \stdClass();$targetcontent->id = 999;// Check the file doesn't exists before cloning.$this->assertFalse($this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));// Copy file from the editor.$this->h5p_file_storage->cloneContentFile($file, 'editor', $targetcontent);// Check the file exists after cloning.$this->assertInstanceOf(\stored_file::class, $this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));// Simulate that an H5P content, with id $sourcecontentid, has a file.$file = 'images/fake2.jpg';$filepath = '/'.dirname($file).'/';$filename = basename($file);$sourcecontentid = 111;$filerecord['contextid'] = $this->h5p_fs_context->id;$filerecord['component'] = file_storage::COMPONENT;$filerecord['filearea'] = file_storage::CONTENT_FILEAREA;$filerecord['itemid'] = $sourcecontentid;$filerecord['filepath'] = $filepath;$filerecord['filename'] = $filename;$this->h5p_fs_fs->create_file_from_string($filerecord, $content);// Check the file doesn't exists before cloning.$this->assertFalse($this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));// Copy file from another H5P content.$this->h5p_file_storage->cloneContentFile($file, $sourcecontentid, $targetcontent);// Check the file exists after cloning.$this->assertInstanceOf(\stored_file::class, $this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));}/*** Test that a given file exists in an H5P content.** @return void*/public function test_getContentFile(): void {$file = 'img/fake.png';$contentid = 3;// Add a file to a H5P content.$this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $contentid);// Get an existing file id.$fileid = $this->h5p_file_storage->getContentFile($file, $contentid);$this->assertNotNull($fileid);// Try to get a nonexistent file.$fileid = $this->h5p_file_storage->getContentFile($file, 5);$this->assertNull($fileid);}/*** Tests that the content folder of an H5P content is imported in the Moodle filesystem.*/public function test_moveContentDiretory(): void {// Create temp folder.$tempfolder = make_request_directory(false);// Create H5P content folder.$h5pcontentfolder = $tempfolder . '/fakeH5Pcontent';$contentfolder = $h5pcontentfolder . '/content';if (!check_dir_exists($contentfolder, true, true)) {throw new moodle_exception('error_creating_temp_dir', 'error', $contentfolder);}// Add content.json file.touch($contentfolder . 'content.json');// Create several folders and files inside content folder.$filesexpected = array();$numfolders = random_int(2, 5);for ($numfolder = 1; $numfolder < $numfolders; $numfolder++) {$foldername = '/folder' . $numfolder;$newfolder = $contentfolder . $foldername;if (!check_dir_exists($newfolder, true, true)) {throw new moodle_exception('error_creating_temp_dir', 'error', $newfolder);}$numfiles = random_int(2, 5);for ($numfile = 1; $numfile < $numfiles; $numfile++) {$filename = '/file' . $numfile . '.ext';touch($newfolder . $filename);$filesexpected[] = $foldername . $filename;}}$targeth5pcontentid = 111;$this->h5p_file_storage->moveContentDirectory($h5pcontentfolder, $targeth5pcontentid);// Get database records.$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id,file_storage::COMPONENT,file_storage::CONTENT_FILEAREA,$targeth5pcontentid,'filepath, filename',false);$filepaths = array_map(static function(stored_file $file): string {return $file->get_filepath() . $file->get_filename();}, $files);// Check that created files match with database records.$this->assertEquals($filesexpected, array_values($filepaths));}/*** Test that an H5P content file is removed.*/public function test_removeContentFile(): void {$file = 'img/fake.png';$filepath = '/' . dirname($file) . '/';$filename = basename($file);$h5pcontentid = 3;// Add a file to a H5P content.$this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $h5pcontentid);// Check the file exists.$this->assertTrue($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));$this->h5p_file_storage->removeContentFile($file, $h5pcontentid);// Check the file doesn't exists.$this->assertFalse($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));}/*** Test H5P custom styles generation.** @covers ::generate_custom_styles*/public function test_generate_custom_styles(): void {\set_config('h5pcustomcss', '.debug { color: #fab; }', 'core_h5p');$h5pfsrc = new \ReflectionClass(file_storage::class);$customcssfilename = $h5pfsrc->getConstant('CUSTOM_CSS_FILENAME');// Test 'h5pcustomcss' with data.file_storage::generate_custom_styles();$this->assertTrue($this->h5p_fs_fs->file_exists(\context_system::instance()->id,file_storage::COMPONENT,file_storage::CSS_FILEAREA,0,'/',$customcssfilename));$cssfile = $this->h5p_fs_fs->get_file(\context_system::instance()->id,file_storage::COMPONENT,file_storage::CSS_FILEAREA,0,'/',$customcssfilename);$this->assertInstanceOf('stored_file', $cssfile);$csscontents = $cssfile->get_content();$this->assertEquals($csscontents, '.debug { color: #fab; }');// Test 'h5pcustomcss' without data.\set_config('h5pcustomcss', '', 'core_h5p');file_storage::generate_custom_styles();$this->assertFalse($this->h5p_fs_fs->file_exists(\context_system::instance()->id,file_storage::COMPONENT,file_storage::CSS_FILEAREA,0,'/',$customcssfilename));}/*** Test H5P custom styles retrieval.** @covers ::get_custom_styles*/public function test_get_custom_styles(): void {global $CFG;$css = '.debug { color: #fab; }';$cssurl = $CFG->wwwroot . '/pluginfile.php/1/core_h5p/css/custom_h5p.css';\set_config('h5pcustomcss', $css, 'core_h5p');$h5pfsrc = new \ReflectionClass(file_storage::class);$customcssfilename = $h5pfsrc->getConstant('CUSTOM_CSS_FILENAME');// Normal operation without data.\set_config('h5pcustomcss', '', 'core_h5p');file_storage::generate_custom_styles();$style = file_storage::get_custom_styles();$this->assertNull($style);// Normal operation with data.\set_config('h5pcustomcss', $css, 'core_h5p');file_storage::generate_custom_styles();$style = file_storage::get_custom_styles();$this->assertNotEmpty($style);$this->assertEquals($style['cssurl']->out(), $cssurl);$this->assertEquals($style['cssversion'], md5($css));// No CSS set when there is a file.\set_config('h5pcustomcss', '', 'core_h5p');try {$style = file_storage::get_custom_styles();$this->fail('moodle_exception for when there is no CSS and yet there is a file, was not thrown');} catch (\moodle_exception $me) {$this->assertEquals('The H5P \'h5pcustomcss\' setting is empty and yet the custom CSS file \''.$customcssfilename.'\' exists.',$me->errorcode);}\set_config('h5pcustomcss', $css, 'core_h5p'); // Reset for next assertion.// No CSS file when there is CSS.$cssfile = $this->h5p_fs_fs->get_file(\context_system::instance()->id,file_storage::COMPONENT,file_storage::CSS_FILEAREA,0,'/',$customcssfilename);$cssfile->delete();try {$style = file_storage::get_custom_styles();$this->fail('moodle_exception for when there is CSS and yet there is a file, was not thrown');} catch (\moodle_exception $me) {$this->assertEquals('The H5P custom CSS file \''.$customcssfilename.'\' does not exist and yet there is CSS in the \'h5pcustomcss\' setting.',$me->errorcode);}}}