See Release Notes
Long Term Support Release
<?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/>. /** * Testing the H5P API. * * @package core_h5p * @category test * @copyright 2020 Sara Arjona <sara@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ declare(strict_types = 1); namespace core_h5p;> use stdClass; defined('MOODLE_INTERNAL') || die(); >/** * Test class covering the H5P API. * * @package core_h5p * @copyright 2020 Sara Arjona <sara@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @coversDefaultClass \core_h5p\api */ class api_test extends \advanced_testcase { /** * Test the behaviour of delete_library(). * * @dataProvider delete_library_provider * @param string $libraryname Machine name of the library to delete. * @param int $expectedh5p Total of H5P contents expected after deleting the library. * @param int $expectedlibraries Total of H5P libraries expected after deleting the library. * @param int $expectedcontents Total of H5P content_libraries expected after deleting the library. * @param int $expecteddependencies Total of H5P library dependencies expected after deleting the library. */ public function test_delete_library(string $libraryname, int $expectedh5p, int $expectedlibraries, int $expectedcontents, int $expecteddependencies): void { global $DB; $this->setRunTestInSeparateProcess(true); $this->resetAfterTest(); // Generate h5p related data. $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); $generator->generate_h5p_data(); $generator->create_library_record('H5P.TestingLibrary', 'TestingLibrary', 1, 0); // Check the current content in H5P tables is the expected. $counth5p = $DB->count_records('h5p'); $counth5plibraries = $DB->count_records('h5p_libraries'); $counth5pcontents = $DB->count_records('h5p_contents_libraries'); $counth5pdependencies = $DB->count_records('h5p_library_dependencies'); $this->assertSame(1, $counth5p); $this->assertSame(7, $counth5plibraries); $this->assertSame(5, $counth5pcontents); $this->assertSame(7, $counth5pdependencies); // Delete this library. $factory = new factory(); $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname]); if ($library) { api::delete_library($factory, $library); } // Check the expected libraries and content have been removed. $counth5p = $DB->count_records('h5p'); $counth5plibraries = $DB->count_records('h5p_libraries'); $counth5pcontents = $DB->count_records('h5p_contents_libraries'); $counth5pdependencies = $DB->count_records('h5p_library_dependencies'); $this->assertSame($expectedh5p, $counth5p); $this->assertSame($expectedlibraries, $counth5plibraries); $this->assertSame($expectedcontents, $counth5pcontents); $this->assertSame($expecteddependencies, $counth5pdependencies); } /** * Data provider for test_delete_library(). * * @return array */ public function delete_library_provider(): array { return [ 'Delete MainLibrary' => [ 'MainLibrary', 0, 6, 0, 4, ], 'Delete Library1' => [ 'Library1', 0, 5, 0, 1, ], 'Delete Library2' => [ 'Library2', 0, 4, 0, 1, ], 'Delete Library3' => [ 'Library3', 0, 4, 0, 0, ], 'Delete Library4' => [ 'Library4', 0, 4, 0, 1, ], 'Delete Library5' => [ 'Library5', 0, 3, 0, 0, ], 'Delete a library without dependencies' => [ 'H5P.TestingLibrary', 1, 6, 5, 7, ], 'Delete unexisting library' => [ 'LibraryX', 1, 7, 5, 7, ], ]; } /** * Test the behaviour of get_dependent_libraries(). * * @dataProvider get_dependent_libraries_provider * @param string $libraryname Machine name of the library to delete. * @param int $expectedvalue Total of H5P required libraries expected. */ public function test_get_dependent_libraries(string $libraryname, int $expectedvalue): void { global $DB; $this->resetAfterTest(); // Generate h5p related data. $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); $generator->generate_h5p_data(); $generator->create_library_record('H5P.TestingLibrary', 'TestingLibrary', 1, 0); // Get required libraries. $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname], 'id'); if ($library) { $libraries = api::get_dependent_libraries((int)$library->id); } else { $libraries = []; } $this->assertCount($expectedvalue, $libraries); } /** * Data provider for test_get_dependent_libraries(). * * @return array */ public function get_dependent_libraries_provider(): array { return [ 'Main library of a content' => [ 'MainLibrary', 0, ], 'Library1' => [ 'Library1', 1, ], 'Library2' => [ 'Library2', 2, ], 'Library without dependencies' => [ 'H5P.TestingLibrary', 0, ], 'Unexisting library' => [ 'LibraryX', 0, ], ]; } /** * Test the behaviour of get_library(). * * @dataProvider get_library_provider * @param string $libraryname Machine name of the library to delete. * @param bool $emptyexpected Wether the expected result is empty or not. */ public function test_get_library(string $libraryname, bool $emptyexpected): void { global $DB; $this->resetAfterTest(); // Generate h5p related data. $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); $generator->generate_h5p_data(); $generator->create_library_record('H5P.TestingLibrary', 'TestingLibrary', 1, 0); // Get the library identifier. $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname], 'id'); if ($library) { $result = api::get_library((int)$library->id); } else { $result = null; } if ($emptyexpected) { $this->assertEmpty($result); } else { $this->assertEquals($library->id, $result->id); $this->assertEquals($libraryname, $result->machinename); } } /** * Data provider for test_get_library(). * * @return array */ public function get_library_provider(): array { return [ 'Main library of a content' => [ 'MainLibrary', false, ], 'Library1' => [ 'Library1', false, ], 'Library without dependencies' => [ 'H5P.TestingLibrary', false, ], 'Unexisting library' => [ 'LibraryX', true, ], ]; } /** * Test the behaviour of get_content_from_pluginfile_url(). */ public function test_get_content_from_pluginfile_url(): void { $this->setRunTestInSeparateProcess(true); $this->resetAfterTest(); $factory = new factory(); // Create the H5P data. $filename = 'find-the-words.h5p'; $path = __DIR__ . '/fixtures/' . $filename; $fakefile = helper::create_fake_stored_file_from_path($path); $config = (object)[ 'frame' => 1, 'export' => 1, 'embed' => 0, 'copyright' => 0, ]; // Get URL for this H5P content file. $syscontext = \context_system::instance(); $url = \moodle_url::make_pluginfile_url( $syscontext->id, \core_h5p\file_storage::COMPONENT, 'unittest', $fakefile->get_itemid(), '/', $filename ); // Scenario 1: Get the H5P for this URL and check there isn't any existing H5P (because it hasn't been saved). list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out()); $this->assertEquals($fakefile->get_pathnamehash(), $newfile->get_pathnamehash()); $this->assertEquals($fakefile->get_contenthash(), $newfile->get_contenthash()); $this->assertFalse($h5p); // Scenario 2: Save the H5P and check now the H5P is exactly the same as the original one. $h5pid = helper::save_h5p($factory, $fakefile, $config); list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out()); $this->assertEquals($h5pid, $h5p->id); $this->assertEquals($fakefile->get_pathnamehash(), $h5p->pathnamehash); $this->assertEquals($fakefile->get_contenthash(), $h5p->contenthash); // Scenario 3: Get the H5P for an unexisting H5P file. $url = \moodle_url::make_pluginfile_url( $syscontext->id, \core_h5p\file_storage::COMPONENT, 'unittest', $fakefile->get_itemid(), '/', 'unexisting.h5p' ); list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out()); $this->assertFalse($newfile); $this->assertFalse($h5p); } /**> * Test the behaviour of get_original_content_from_pluginfile_url(). * Test the behaviour of create_content_from_pluginfile_url(). > * */ > * @covers ::get_original_content_from_pluginfile_url public function test_create_content_from_pluginfile_url(): void { > */ global $DB; > public function test_get_original_content_from_pluginfile_url(): void { > $this->setRunTestInSeparateProcess(true); $this->setRunTestInSeparateProcess(true); > $this->resetAfterTest(); $this->resetAfterTest(); > $this->setAdminUser(); $factory = new factory(); > > $factory = new factory(); // Create the H5P data. > $syscontext = \context_system::instance(); $filename = 'find-the-words.h5p'; > $path = __DIR__ . '/fixtures/' . $filename; > // Create the original file. $fakefile = helper::create_fake_stored_file_from_path($path); > $filename = 'greeting-card.h5p'; $config = (object)[ > $path = __DIR__ . '/fixtures/' . $filename; 'frame' => 1, > $originalfile = helper::create_fake_stored_file_from_path($path); 'export' => 1, > $originalfilerecord = [ 'embed' => 0, > 'contextid' => $originalfile->get_contextid(), 'copyright' => 0, > 'component' => $originalfile->get_component(), ]; > 'filearea' => $originalfile->get_filearea(), > 'itemid' => $originalfile->get_itemid(), // Get URL for this H5P content file. > 'filepath' => $originalfile->get_filepath(), $syscontext = \context_system::instance(); > 'filename' => $originalfile->get_filename(), $url = \moodle_url::make_pluginfile_url( > ]; $syscontext->id, > \core_h5p\file_storage::COMPONENT, > $config = (object)[ 'unittest', > 'frame' => 1, $fakefile->get_itemid(), > 'export' => 1, '/', > 'embed' => 0, $filename > 'copyright' => 0, ); > ]; > // Scenario 1: Create the H5P from this URL and check the content is exactly the same as the fake file. > $originalurl = \moodle_url::make_pluginfile_url( $messages = new \stdClass(); > $originalfile->get_contextid(), list($newfile, $h5pid) = api::create_content_from_pluginfile_url($url->out(), $config, $factory, $messages); > $originalfile->get_component(), $this->assertNotFalse($h5pid); > $originalfile->get_filearea(), $h5p = $DB->get_record('h5p', ['id' => $h5pid]); > $originalfile->get_itemid(), $this->assertEquals($fakefile->get_pathnamehash(), $h5p->pathnamehash); > $originalfile->get_filepath(), $this->assertEquals($fakefile->get_contenthash(), $h5p->contenthash); > $originalfile->get_filename() $this->assertTrue(empty($messages->error)); > ); $this->assertTrue(empty($messages->info)); > > // Create a reference to the original file. // Scenario 2: Create the H5P for an unexisting H5P file. > $reffilerecord = [ $url = \moodle_url::make_pluginfile_url( > 'contextid' => $syscontext->id, $syscontext->id, > 'component' => 'core', \core_h5p\file_storage::COMPONENT, > 'filearea' => 'phpunit', 'unittest', > 'itemid' => 0, $fakefile->get_itemid(), > 'filepath' => '/', '/', > 'filename' => $filename 'unexisting.h5p' > ]; ); > list($newfile, $h5p) = api::create_content_from_pluginfile_url($url->out(), $config, $factory, $messages); > $fs = get_file_storage(); $this->assertFalse($newfile); > $ref = $fs->pack_reference($originalfilerecord); $this->assertFalse($h5p); > $repos = \repository::get_instances(['type' => 'user']); $this->assertTrue(empty($messages->error)); > $userrepository = reset($repos); $this->assertTrue(empty($messages->info)); > $referencedfile = $fs->create_file_from_reference($reffilerecord, $userrepository->id, $ref); } > $this->assertEquals($referencedfile->get_contenthash(), $originalfile->get_contenthash()); > /** > $referencedurl = \moodle_url::make_pluginfile_url( * Test the behaviour of delete_content_from_pluginfile_url(). > $syscontext->id, */ > 'core', public function test_delete_content_from_pluginfile_url(): void { > 'phpunit', global $DB; > 0, > '/', $this->setRunTestInSeparateProcess(true); > $filename $this->resetAfterTest(); > ); $factory = new factory(); > > // Scenario 1: Original file (without any reference). // Create the H5P data. > $originalh5pid = helper::save_h5p($factory, $originalfile, $config); $filename = 'find-the-words.h5p'; > list($source, $h5p, $file) = api::get_original_content_from_pluginfile_url($originalurl->out()); $path = __DIR__ . '/fixtures/' . $filename; > $this->assertEquals($originalfile->get_pathnamehash(), $source->get_pathnamehash()); $fakefile = helper::create_fake_stored_file_from_path($path); > $this->assertEquals($originalfile->get_contenthash(), $source->get_contenthash()); $config = (object)[ > $this->assertEquals($originalh5pid, $h5p->id); 'frame' => 1, > $this->assertFalse($file); 'export' => 1, > 'embed' => 0, > // Scenario 2: Referenced file (alias to originalfile). 'copyright' => 0, > list($source, $h5p, $file) = api::get_original_content_from_pluginfile_url($referencedurl->out()); ]; > $this->assertEquals($originalfile->get_pathnamehash(), $source->get_pathnamehash()); > $this->assertEquals($originalfile->get_contenthash(), $source->get_contenthash()); // Get URL for this H5P content file. > $this->assertEquals($originalfile->get_contenthash(), $source->get_contenthash()); $syscontext = \context_system::instance(); > $this->assertEquals($originalh5pid, $h5p->id); $url = \moodle_url::make_pluginfile_url( > $this->assertEquals($referencedfile->get_pathnamehash(), $file->get_pathnamehash()); $syscontext->id, > $this->assertEquals($referencedfile->get_contenthash(), $file->get_contenthash()); \core_h5p\file_storage::COMPONENT, > $this->assertEquals($referencedfile->get_contenthash(), $file->get_contenthash()); 'unittest', > $fakefile->get_itemid(), > // Scenario 3: Unexisting file. '/', > $unexistingurl = \moodle_url::make_pluginfile_url( $filename > $syscontext->id, ); > 'core', > 'phpunit', // Scenario 1: Try to remove the H5P content for an undeployed file. > 0, list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out()); > '/', $this->assertEquals(0, $DB->count_records('h5p')); > 'unexisting.h5p' api::delete_content_from_pluginfile_url($url->out(), $factory); > ); $this->assertEquals(0, $DB->count_records('h5p')); > list($source, $h5p, $file) = api::get_original_content_from_pluginfile_url($unexistingurl->out()); > $this->assertFalse($source); // Scenario 2: Deploy an H5P from this URL, check it's created, remove it and check it has been removed as expected. > $this->assertFalse($h5p); $this->assertEquals(0, $DB->count_records('h5p')); > $this->assertFalse($file); > } $messages = new \stdClass(); > list($newfile, $h5pid) = api::create_content_from_pluginfile_url($url->out(), $config, $factory, $messages); > /** $this->assertEquals(1, $DB->count_records('h5p')); > * Test the behaviour of can_edit_content(). > * api::delete_content_from_pluginfile_url($url->out(), $factory); > * @covers ::can_edit_content $this->assertEquals(0, $DB->count_records('h5p')); > * @dataProvider can_edit_content_provider > * // Scenario 3: Try to remove the H5P for an unexisting H5P URL. > * @param string $currentuser User who will call the method. $url = \moodle_url::make_pluginfile_url( > * @param string $fileauthor Author of the file to check. $syscontext->id, > * @param string $filecomponent Component of the file to check. \core_h5p\file_storage::COMPONENT, > * @param bool $expected Expected result after calling the can_edit_content method. 'unittest', > * @param string $filearea Area of the file to check. $fakefile->get_itemid(), > * '/', > * @return void 'unexisting.h5p' > */ ); > public function test_can_edit_content(string $currentuser, string $fileauthor, string $filecomponent, bool $expected, $this->assertEquals(0, $DB->count_records('h5p')); > $filearea = 'unittest'): void { api::delete_content_from_pluginfile_url($url->out(), $factory); > global $USER, $DB; $this->assertEquals(0, $DB->count_records('h5p')); > } > $this->setRunTestInSeparateProcess(true); > $this->resetAfterTest(); /** > * Test the behaviour of get_export_info_from_context_id(). > // Create course. */ > $course = $this->getDataGenerator()->create_course(); public function test_get_export_info_from_context_id(): void { > $context = \context_course::instance($course->id); global $DB; > > // Create some users. $this->setRunTestInSeparateProcess(true); > $this->setAdminUser(); $this->resetAfterTest(); > $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); $factory = new factory(); > $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); > $users = [ // Create the H5P data. > 'admin' => $USER, $filename = 'find-the-words.h5p'; > 'teacher' => $teacher, $syscontext = \context_system::instance(); > 'student' => $student, > ]; // Test scenario 1: H5P exists and deployed. > $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); > // Set current user. $fakeexportfile = $generator->create_export_file($filename, > if ($currentuser !== 'admin') { $syscontext->id, > $this->setUser($users[$currentuser]); \core_h5p\file_storage::COMPONENT, > } \core_h5p\file_storage::EXPORT_FILEAREA); > > $itemid = rand(); $exportfile = api::get_export_info_from_context_id($syscontext->id, > if ($filearea === 'post') { $factory, > // Create a forum and add a discussion. \core_h5p\file_storage::COMPONENT, > $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); \core_h5p\file_storage::EXPORT_FILEAREA); > $this->assertEquals($fakeexportfile['filename'], $exportfile['filename']); > $record = new stdClass(); $this->assertEquals($fakeexportfile['filepath'], $exportfile['filepath']); > $record->course = $course->id; $this->assertEquals($fakeexportfile['filesize'], $exportfile['filesize']); > $record->userid = $users[$fileauthor]->id; $this->assertEquals($fakeexportfile['timemodified'], $exportfile['timemodified']); > $record->forum = $forum->id; $this->assertEquals($fakeexportfile['fileurl'], $exportfile['fileurl']); > $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); > $post = $DB->get_record('forum_posts', ['discussion' => $discussion->id]); // Test scenario 2: H5P exist, deployed but the content has changed. > $itemid = $post->id; // We need to change the contenthash to simulate the H5P file was changed. > } $h5pfile = $DB->get_record('h5p', []); > $h5pfile->contenthash = sha1('testedit'); > // Create the file. $DB->update_record('h5p', $h5pfile); > $filename = 'greeting-card.h5p'; $exportfile = api::get_export_info_from_context_id($syscontext->id, > $path = __DIR__ . '/fixtures/' . $filename; $factory, > if ($filecomponent === 'contentbank') { \core_h5p\file_storage::COMPONENT, > $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); \core_h5p\file_storage::EXPORT_FILEAREA); > $contents = $generator->generate_contentbank_data( $this->assertNull($exportfile); > 'contenttype_h5p', > 1, // Tests scenario 3: H5P is not deployed. > (int)$users[$fileauthor]->id, // We need to delete the H5P record to simulate the H5P was not deployed. > $context, $DB->delete_records('h5p', ['id' => $h5pfile->id]); > true, $exportfile = api::get_export_info_from_context_id($syscontext->id, > $path $factory, > ); \core_h5p\file_storage::COMPONENT, > $content = array_shift($contents); \core_h5p\file_storage::EXPORT_FILEAREA); > $file = $content->get_file(); $this->assertNull($exportfile); > } else { } > $filerecord = [ > 'contextid' => $context->id, /** > 'component' => $filecomponent, * Test the behaviour of set_library_enabled(). > 'filearea' => $filearea, * > 'itemid' => $itemid, * @covers ::set_library_enabled > 'filepath' => '/', * @dataProvider set_library_enabled_provider > 'filename' => basename($path), * > 'userid' => $users[$fileauthor]->id, * @param string $libraryname Library name to enable/disable. > ]; * @param string $action Action to be done with the library. Supported values: enable, disable. > $fs = get_file_storage(); * @param int $expected Expected value for the enabled library field. -1 will be passed if the library doesn't exist. > $file = $fs->create_file_from_pathname($filerecord, $path); */ > } public function test_set_library_enabled(string $libraryname, string $action, int $expected): void { > global $DB; > // Check if the currentuser can edit the file. > $result = api::can_edit_content($file); $this->resetAfterTest(); > $this->assertEquals($expected, $result); > } // Create libraries. > $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); > /** $generator->generate_h5p_data(); > * Data provider for test_can_edit_content(). > * // Check by default the library is enabled. > * @return array $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname]); > */ if ($expected >= 0) { > public function can_edit_content_provider(): array { $this->assertEquals(1, $library->enabled); > return [ $libraryid = (int) $library->id; > // Component = user. } else { > 'user: Admin user is author' => [ // Unexisting library. Set libraryid to some unexisting id. > 'currentuser' => 'admin', $libraryid = -1; > 'fileauthor' => 'admin', $this->expectException('dml_missing_record_exception'); > 'filecomponent' => 'user', } > 'expected' => true, > ], \core_h5p\api::set_library_enabled($libraryid, ($action == 'enable')); > 'user: Admin user, teacher is author' => [ > 'currentuser' => 'admin', // Check the value of the "enabled" field after calling enable/disable method. > 'fileauthor' => 'teacher', $libraries = $DB->get_records('h5p_libraries'); > 'filecomponent' => 'user', foreach ($libraries as $libraryid => $library) { > 'expected' => false, if ($library->machinename == $libraryname) { > ], $this->assertEquals($expected, $library->enabled); > 'user: Teacher user, teacher is author' => [ } else { > 'currentuser' => 'teacher', // Check that only $libraryname has been enabled/disabled. > 'fileauthor' => 'teacher', $this->assertEquals(1, $library->enabled); > 'filecomponent' => 'user', } > 'expected' => true, } > ], } > 'user: Teacher user, admin is author' => [ > 'currentuser' => 'teacher', /** > 'fileauthor' => 'admin', * Data provider for test_set_library_enabled(). > 'filecomponent' => 'user', * > 'expected' => false, * @return array > ], */ > 'user: Student user, student is author' => [ public function set_library_enabled_provider(): array { > 'currentuser' => 'student', return [ > 'fileauthor' => 'student', 'Disable existing library' => [ > 'filecomponent' => 'user', 'libraryname' => 'MainLibrary', > 'expected' => true, 'action' => 'disable', > ], 'expected' => 0, > 'user: Student user, teacher is author' => [ ], > 'currentuser' => 'student', 'Enable existing library' => [ > 'fileauthor' => 'teacher', 'libraryname' => 'MainLibrary', > 'filecomponent' => 'user', 'action' => 'enable', > 'expected' => false, 'expected' => 1, > ], ], > 'Disable existing library (not main)' => [ > // Component = mod_h5pactivity. 'libraryname' => 'Library1', > 'mod_h5pactivity: Admin user is author' => [ 'action' => 'disable', > 'currentuser' => 'admin', 'expected' => 0, > 'fileauthor' => 'admin', ], > 'filecomponent' => 'mod_h5pactivity', 'Enable existing library (not main)' => [ > 'expected' => true, 'libraryname' => 'Library1', > ], 'action' => 'enable', > 'mod_h5pactivity: Admin user, teacher is author' => [ 'expected' => 1, > 'currentuser' => 'admin', ], > 'fileauthor' => 'teacher', 'Disable existing library (not runnable)' => [ > 'filecomponent' => 'mod_h5pactivity', 'libraryname' => 'Library3', > 'expected' => true, 'action' => 'disable', > ], 'expected' => 1, // Not runnable libraries can't be disabled. > 'mod_h5pactivity: Teacher user, teacher is author' => [ ], > 'currentuser' => 'teacher', 'Enable existing library (not runnable)' => [ > 'fileauthor' => 'teacher', 'libraryname' => 'Library3', > 'filecomponent' => 'mod_h5pactivity', 'action' => 'enable', > 'expected' => true, 'expected' => 1, > ], ], > 'mod_h5pactivity: Teacher user, admin is author' => [ 'Enable unexisting library' => [ > 'currentuser' => 'teacher', 'libraryname' => 'Unexisting library', > 'fileauthor' => 'admin', 'action' => 'enable', > 'filecomponent' => 'mod_h5pactivity', 'expected' => -1, > 'expected' => true, ], > ], 'Disable unexisting library' => [ > 'mod_h5pactivity: Student user, student is author' => [ 'libraryname' => 'Unexisting library', > 'currentuser' => 'student', 'action' => 'disable', > 'fileauthor' => 'student', 'expected' => -1, > 'filecomponent' => 'mod_h5pactivity', ], > 'expected' => false, ]; > ], } > 'mod_h5pactivity: Student user, teacher is author' => [ > 'currentuser' => 'student', /** > 'fileauthor' => 'teacher', * Test the behaviour of is_library_enabled(). > 'filecomponent' => 'mod_h5pactivity', * > 'expected' => false, * @covers ::is_library_enabled > ], * @dataProvider is_library_enabled_provider > * > // Component = mod_book. * @param string $libraryname Library name to check. > 'mod_book: Admin user is author' => [ * @param bool $expected Expected result after calling the method. > 'currentuser' => 'admin', * @param bool $exception Exception expected or not. > 'fileauthor' => 'admin', * @param bool $useid Whether to use id for calling is_library_enabled method. > 'filecomponent' => 'mod_book', * @param bool $uselibraryname Whether to use libraryname for calling is_library_enabled method. > 'expected' => true, */ > ], public function test_is_library_enabled(string $libraryname, bool $expected, bool $exception = false, > 'mod_book: Admin user, teacher is author' => [ bool $useid = false, bool $uselibraryname = true): void { > 'currentuser' => 'admin', global $DB; > 'fileauthor' => 'teacher', > 'filecomponent' => 'mod_book', $this->resetAfterTest(); > 'expected' => true, > ], // Create the following libraries: > // - H5P.Lib1: 1 version enabled, 1 version disabled. > // Component = mod_forum. // - H5P.Lib2: 2 versions enabled. > 'mod_forum: Admin user is author' => [ // - H5P.Lib3: 2 versions disabled. > 'currentuser' => 'admin', // - H5P.Lib4: 1 version disabled. > 'fileauthor' => 'admin', // - H5P.Lib5: 1 version enabled. > 'filecomponent' => 'mod_forum', $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); > 'expected' => true, $libraries = [ > ], 'H5P.Lib1.1' => $generator->create_library_record('H5P.Lib1', 'Lib1', 1, 1, 0, '', null, null, null, false), > 'mod_forum: Admin user, teacher is author' => [ 'H5P.Lib1.2' => $generator->create_library_record('H5P.Lib1', 'Lib1', 1, 2), > 'currentuser' => 'admin', 'H5P.Lib2.1' => $generator->create_library_record('H5P.Lib2', 'Lib2', 2, 1), > 'fileauthor' => 'teacher', 'H5P.Lib2.2' => $generator->create_library_record('H5P.Lib2', 'Lib2', 2, 2), > 'filecomponent' => 'mod_forum', 'H5P.Lib3.1' => $generator->create_library_record('H5P.Lib3', 'Lib3', 3, 1, 0, '', null, null, null, false), > 'expected' => true, 'H5P.Lib3.2' => $generator->create_library_record('H5P.Lib3', 'Lib3', 3, 2, 0, '', null, null, null, false), > ], 'H5P.Lib4.1' => $generator->create_library_record('H5P.Lib4', 'Lib4', 4, 1, 0, '', null, null, null, false), > 'mod_forum: Teacher user, admin is author' => [ 'H5P.Lib5.1' => $generator->create_library_record('H5P.Lib5', 'Lib5', 5, 1), > 'currentuser' => 'teacher', ]; > 'fileauthor' => 'admin', > 'filecomponent' => 'mod_forum', $countenabledlibraries = $DB->count_records('h5p_libraries', ['enabled' => 1]); > 'expected' => true, $this->assertEquals(4, $countenabledlibraries); > ], > 'mod_forum: Student user, teacher is author' => [ if ($useid) { > 'currentuser' => 'student', $librarydata = ['id' => $libraries[$libraryname]->id]; > 'fileauthor' => 'teacher', } else if ($uselibraryname) { > 'filecomponent' => 'mod_forum', $librarydata = ['machinename' => $libraryname]; > 'expected' => false, } else { > ], $librarydata = ['invalid' => true]; > 'mod_forum/post: Admin user is author' => [ } > 'currentuser' => 'admin', > 'fileauthor' => 'admin', if ($exception) { > 'filecomponent' => 'mod_forum', $this->expectException(\moodle_exception::class); > 'expected' => true, } > 'filearea' => 'post', > ], $result = api::is_library_enabled((object) $librarydata); > 'mod_forum/post: Teacher user, admin is author' => [ $this->assertEquals($expected, $result); > 'currentuser' => 'teacher', } > 'fileauthor' => 'admin', > 'filecomponent' => 'mod_forum', /** > 'expected' => true, * Data provider for test_is_library_enabled(). > 'filearea' => 'post', * > ], * @return array > 'mod_forum/post: Student user, teacher is author' => [ */ > 'currentuser' => 'student', public function is_library_enabled_provider(): array { > 'fileauthor' => 'teacher', return [ > 'filecomponent' => 'mod_forum', 'Library with 2 versions, one of them disabled' => [ > 'expected' => false, 'libraryname' => 'H5P.Lib1', > 'filearea' => 'post', 'expected' => false, > ], ], > 'Library with 2 versions, all enabled' => [ > // Component = block_html. 'libraryname' => 'H5P.Lib2', > 'block_html: Admin user is author' => [ 'expected' => true, > 'currentuser' => 'admin', ], > 'fileauthor' => 'admin', 'Library with 2 versions, all disabled' => [ > 'filecomponent' => 'block_html', 'libraryname' => 'H5P.Lib3', > 'expected' => true, 'expected' => false, > ], ], > 'block_html: Admin user, teacher is author' => [ 'Library with only one version, disabled' => [ > 'currentuser' => 'admin', 'libraryname' => 'H5P.Lib4', > 'fileauthor' => 'teacher', 'expected' => false, > 'filecomponent' => 'block_html', ], > 'expected' => true, 'Library with only one version, enabled' => [ > ], 'libraryname' => 'H5P.Lib5', > 'expected' => true, > // Component = contentbank. ], > 'contentbank: Admin user is author' => [ 'Library with 2 versions, one of them disabled (using id) - 1.1 (disabled)' => [ > 'currentuser' => 'admin', 'libraryname' => 'H5P.Lib1.1', > 'fileauthor' => 'admin', 'expected' => false, > 'filecomponent' => 'contentbank', 'exception' => false, > 'expected' => true, 'useid' => true, > ], ], > 'contentbank: Admin user, teacher is author' => [ 'Library with 2 versions, one of them disabled (using id) - 1.2 (enabled)' => [ > 'currentuser' => 'admin', 'libraryname' => 'H5P.Lib1.2', > 'fileauthor' => 'teacher', 'expected' => true, > 'filecomponent' => 'contentbank', 'exception' => false, > 'expected' => true, 'useid' => true, > ], ], > 'contentbank: Teacher user, teacher is author' => [ 'Library with 2 versions, all enabled (using id) - 2.1' => [ > 'currentuser' => 'teacher', 'libraryname' => 'H5P.Lib2.1', > 'fileauthor' => 'teacher', 'expected' => true, > 'filecomponent' => 'contentbank', 'exception' => false, > 'expected' => true, 'useid' => true, > ], ], > 'contentbank: Teacher user, admin is author' => [ 'Library with 2 versions, all enabled (using id) - 2.2' => [ > 'currentuser' => 'teacher', 'libraryname' => 'H5P.Lib2.2', > 'fileauthor' => 'admin', 'expected' => true, > 'filecomponent' => 'contentbank', 'exception' => false, > 'expected' => false, 'useid' => true, > ], ], > 'contentbank: Student user, student is author' => [ 'Library with 2 versions, all disabled (using id) - 3.1' => [ > 'currentuser' => 'student', 'libraryname' => 'H5P.Lib3.1', > 'fileauthor' => 'student', 'expected' => false, > 'filecomponent' => 'contentbank', 'exception' => false, > 'expected' => false, 'useid' => true, > ], ], > 'contentbank: Student user, teacher is author' => [ 'Library with 2 versions, all disabled (using id) - 3.2' => [ > 'currentuser' => 'student', 'libraryname' => 'H5P.Lib3.2', > 'fileauthor' => 'teacher', 'expected' => false, > 'filecomponent' => 'contentbank', 'exception' => false, > 'expected' => false, 'useid' => true, > ], ], > 'Library with only one version, disabled (using id)' => [ > // Unexisting components. 'libraryname' => 'H5P.Lib4.1', > 'Unexisting component' => [ 'expected' => false, > 'currentuser' => 'admin', 'exception' => false, > 'fileauthor' => 'admin', 'useid' => true, > 'filecomponent' => 'unexisting_component', ], > 'expected' => false, 'Library with only one version, enabled (using id)' => [ > ], 'libraryname' => 'H5P.Lib5.1', > 'Unexisting module activity' => [ 'expected' => true, > 'currentuser' => 'admin', 'exception' => false, > 'fileauthor' => 'admin', 'useid' => true, > 'filecomponent' => 'mod_unexisting', ], > 'expected' => false, 'Unexisting library' => [ > ], 'libraryname' => 'H5P.Unexisting', > 'Unexisting block' => [ 'expected' => true, > 'currentuser' => 'admin', ], > 'fileauthor' => 'admin', 'Missing required parameters' => [ > 'filecomponent' => 'block_unexisting', 'libraryname' => 'H5P.Unexisting', > 'expected' => false, 'expected' => false, > ], 'exception' => true, > ]; 'useid' => false, > } 'uselibraryname' => false, > ], > /**]; } /** * Test the behaviour of is_valid_package(). * @runInSeparateProcess * * @covers ::is_valid_package * @dataProvider is_valid_package_provider * * @param string $filename The H5P content to validate. * @param bool $expected Expected result after calling the method. * @param bool $isadmin Whether the user calling the method will be admin or not. * @param bool $onlyupdatelibs Whether new libraries can be installed or only the existing ones can be updated. * @param bool $skipcontent Should the content be skipped (so only the libraries will be saved)? */ public function test_is_valid_package(string $filename, bool $expected, bool $isadmin = false, bool $onlyupdatelibs = false, bool $skipcontent = false): void { global $USER; $this->resetAfterTest(); if ($isadmin) { $this->setAdminUser(); $user = $USER; } else { // Create a user. $user = $this->getDataGenerator()->create_user(); $this->setUser($user); } // Prepare the file. $path = __DIR__ . $filename; $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); // Check if the H5P content is valid or not. $result = api::is_valid_package($file, $onlyupdatelibs, $skipcontent); $this->assertEquals($expected, $result); } /** * Data provider for test_is_valid_package(). * * @return array */ public function is_valid_package_provider(): array { return [ 'Valid H5P file (as admin)' => [< 'filename' => '/fixtures/greeting-card-887.h5p',> 'filename' => '/fixtures/greeting-card.h5p','expected' => true, 'isadmin' => true, ], 'Valid H5P file (as user) without library update and checking content' => [< 'filename' => '/fixtures/greeting-card-887.h5p',> 'filename' => '/fixtures/greeting-card.h5p','expected' => false, // Libraries are missing and user hasn't the right permissions to upload them. 'isadmin' => false, 'onlyupdatelibs' => false, 'skipcontent' => false, ], 'Valid H5P file (as user) with library update and checking content' => [< 'filename' => '/fixtures/greeting-card-887.h5p',> 'filename' => '/fixtures/greeting-card.h5p','expected' => false, // Libraries are missing and user hasn't the right permissions to upload them. 'isadmin' => false, 'onlyupdatelibs' => true, 'skipcontent' => false, ], 'Valid H5P file (as user) without library update and skipping content' => [< 'filename' => '/fixtures/greeting-card-887.h5p',> 'filename' => '/fixtures/greeting-card.h5p','expected' => true, // Content check is skipped so the package will be considered valid. 'isadmin' => false, 'onlyupdatelibs' => false, 'skipcontent' => true, ], 'Valid H5P file (as user) with library update and skipping content' => [< 'filename' => '/fixtures/greeting-card-887.h5p',> 'filename' => '/fixtures/greeting-card.h5p','expected' => true, // Content check is skipped so the package will be considered valid. 'isadmin' => false, 'onlyupdatelibs' => true, 'skipcontent' => true, ], 'Invalid H5P file (as admin)' => [ 'filename' => '/fixtures/h5ptest.zip', 'expected' => false, 'isadmin' => true, ], 'Invalid H5P file (as user)' => [ 'filename' => '/fixtures/h5ptest.zip', 'expected' => false, 'isadmin' => false, ], 'Invalid H5P file (as user) skipping content' => [ 'filename' => '/fixtures/h5ptest.zip', 'expected' => true, // Content check is skipped so the package will be considered valid. 'isadmin' => false, 'onlyupdatelibs' => false, 'skipcontent' => true, ], ]; } }