Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
<?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_collator;
use Moodle\H5PCore;
use Moodle\H5PDisplayOptionBehaviour;

// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod

/**
 *
 * Test class covering the H5PFrameworkInterface interface implementation.
 *
 * @package    core_h5p
 * @category   test
 * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @covers     \core_h5p\framework
 * @runTestsInSeparateProcesses
 */
class framework_test extends \advanced_testcase {

    /** @var \core_h5p\framework */
    private $framework;

    /**
     * Set up function for tests.
     */
    public function setUp(): void {
        $factory = new \core_h5p\factory();
        $this->framework = $factory->get_framework();
    }

    /**
     * Test the behaviour of getPlatformInfo().
     */
    public function test_getPlatformInfo() {
        global $CFG;

        $platforminfo = $this->framework->getPlatformInfo();

        $expected = array(
            'name' => 'Moodle',
            'version' => $CFG->version,
            'h5pVersion' => $CFG->version
        );

        $this->assertEquals($expected, $platforminfo);
    }

    /**
     * Test the behaviour of fetchExternalData() when the store path is not defined.
     *
     * This test is intensive and requires downloading content of an external file,
     * therefore it might take longer time to execute.
     * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
     */
    public function test_fetchExternalData_no_path_defined() {

        if (!PHPUNIT_LONGTEST) {
            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
        }

        $this->resetAfterTest();

        $library = 'H5P.Accordion';
        // Provide a valid URL to an external H5P content.
        $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');

        // Test fetching an external H5P content without defining a path to where the file should be stored.
        $data = $this->framework->fetchExternalData($url, null, true);

        // The response should not be empty and return true if the file was successfully downloaded.
        $this->assertNotEmpty($data);
        $this->assertTrue($data);

        $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
        // The uploaded file should exist on the filesystem.
        $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
    }

    /**
     * Test the behaviour of fetchExternalData() when the store path is defined.
     *
     * This test is intensive and requires downloading content of an external file,
     * therefore it might take longer time to execute.
     * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
     */
    public function test_fetchExternalData_path_defined() {
        global $CFG;

        if (!PHPUNIT_LONGTEST) {
            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
        }

        $this->resetAfterTest();

        $library = 'H5P.Accordion';
        // Provide a valid URL to an external H5P content.
        $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');

        $h5pfolderpath = $CFG->tempdir . uniqid('/h5p-');

        $data = $this->framework->fetchExternalData($url, null, true, $h5pfolderpath . '.h5p');

        // The response should not be empty and return true if the content has been successfully saved to a file.
        $this->assertNotEmpty($data);
        $this->assertTrue($data);

        // The uploaded file should exist on the filesystem.
        $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
    }

    /**
     * Test the behaviour of fetchExternalData() when the URL is pointing to an external file that is
     * not an h5p content.
     *
     * This test is intensive and requires downloading content of an external file,
     * therefore it might take longer time to execute.
     * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
     */
    public function test_fetchExternalData_url_not_h5p() {

        if (!PHPUNIT_LONGTEST) {
            // This test is intensive and requires downloading the content of an external file.
            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
        }

        $this->resetAfterTest();

        // Provide an URL to an external file that is not an H5P content file.
        $url = $this->getExternalTestFileUrl('/h5pcontenttypes.json');

        $data = $this->framework->fetchExternalData($url, null, true);

        // The response should not be empty and return true if the content has been successfully saved to a file.
        $this->assertNotEmpty($data);
        $this->assertTrue($data);

        // The uploaded file should exist on the filesystem with it's original extension.
        // NOTE: The file would be later validated by the H5P Validator.
        $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
        $this->assertTrue(file_exists($h5pfolderpath . '.json'));
    }

    /**
     * Test the behaviour of fetchExternalData() when the URL is invalid.
     */
    public function test_fetchExternalData_url_invalid() {
        // Provide an invalid URL to an external file.
        $url = "someprotocol://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";

        $data = $this->framework->fetchExternalData($url, null, true);

        // The response should be empty.
        $this->assertEmpty($data);
    }

    /**
     * Test the behaviour of setLibraryTutorialUrl().
     */
    public function test_setLibraryTutorialUrl() {
        global $DB;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create several libraries records.
        $lib1 = $generator->create_library_record('Library1', 'Lib1', 1, 0, 1, '', null, 'http://tutorial1.org',
            'http://example.org');
        $lib2 = $generator->create_library_record('Library2', 'Lib2', 2, 0, 1, '', null, 'http://tutorial2.org');
        $lib3 = $generator->create_library_record('Library3', 'Lib3', 3, 0);

        // Check only lib1 tutorial URL is updated.
        $url = 'https://newtutorial.cat';
        $this->framework->setLibraryTutorialUrl($lib1->machinename, $url);

        $libraries = $DB->get_records('h5p_libraries');
        $this->assertEquals($libraries[$lib1->id]->tutorial, $url);
        $this->assertNotEquals($libraries[$lib2->id]->tutorial, $url);

        // Check lib1 tutorial URL is set to null.
        $this->framework->setLibraryTutorialUrl($lib1->machinename, null);

        $libraries = $DB->get_records('h5p_libraries');
        $this->assertCount(3, $libraries);
        $this->assertNull($libraries[$lib1->id]->tutorial);

        // Check no tutorial URL is set if library name doesn't exist.
        $this->framework->setLibraryTutorialUrl('Unexisting library', $url);

        $libraries = $DB->get_records('h5p_libraries');
        $this->assertCount(3, $libraries);
        $this->assertNull($libraries[$lib1->id]->tutorial);
        $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org');
        $this->assertNull($libraries[$lib3->id]->tutorial);

        // Check tutorial is set as expected when it was null.
        $this->framework->setLibraryTutorialUrl($lib3->machinename, $url);

        $libraries = $DB->get_records('h5p_libraries');
        $this->assertEquals($libraries[$lib3->id]->tutorial, $url);
        $this->assertNull($libraries[$lib1->id]->tutorial);
        $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org');
    }

    /**
     * Test the behaviour of setErrorMessage().
     */
    public function test_setErrorMessage() {
        // Set an error message and an error code.
        $message = "Error message";
        $code = '404';

        // Set an error message.
        $this->framework->setErrorMessage($message, $code);

        // Get the error messages.
        $errormessages = $this->framework->getMessages('error');

        $expected = new \stdClass();
        $expected->code = 404;
        $expected->message = 'Error message';

        $this->assertEquals($expected, $errormessages[0]);
    }

    /**
     * Test the behaviour of setInfoMessage().
     */
    public function test_setInfoMessage() {
        $message = "Info message";

        // Set an info message.
        $this->framework->setInfoMessage($message);

        // Get the info messages.
        $infomessages = $this->framework->getMessages('info');

        $expected = 'Info message';

        $this->assertEquals($expected, $infomessages[0]);
    }

    /**
     * Test the behaviour of getMessages() when requesting the info messages.
     */
    public function test_getMessages_info() {
        // Set an info message.
        $this->framework->setInfoMessage("Info message");
        // Set an error message.
        $this->framework->setErrorMessage("Error message 1", 404);

        // Get the info messages.
        $infomessages = $this->framework->getMessages('info');

        $expected = 'Info message';

        // Make sure that only the info message has been returned.
        $this->assertCount(1, $infomessages);
        $this->assertEquals($expected, $infomessages[0]);

        $infomessages = $this->framework->getMessages('info');

        // Make sure the info messages have now been removed.
        $this->assertEmpty($infomessages);
    }

    /**
     * Test the behaviour of getMessages() when requesting the error messages.
     */
    public function test_getMessages_error() {
        // Set an info message.
        $this->framework->setInfoMessage("Info message");
        // Set an error message.
        $this->framework->setErrorMessage("Error message 1", 404);
        // Set another error message.
        $this->framework->setErrorMessage("Error message 2", 403);

        // Get the error messages.
        $errormessages = $this->framework->getMessages('error');

        // Make sure that only the error messages are being returned.
        $this->assertEquals(2, count($errormessages));

        $expected1 = (object) [
            'code' => 404,
            'message' => 'Error message 1'
        ];

        $expected2 = (object) [
            'code' => 403,
            'message' => 'Error message 2'
        ];

        $this->assertEquals($expected1, $errormessages[0]);
        $this->assertEquals($expected2, $errormessages[1]);

        $errormessages = $this->framework->getMessages('error');

        // Make sure the info messages have now been removed.
        $this->assertEmpty($errormessages);
    }

    /**
     * Test the behaviour of t() when translating existing string that does not require any arguments.
     */
    public function test_t_existing_string_no_args() {
        // Existing language string without passed arguments.
        $translation = $this->framework->t('No copyright information available for this content.');

        // Make sure the string translation has been returned.
        $this->assertEquals('No copyright information available for this content.', $translation);
    }

    /**
     * Test the behaviour of t() when translating existing string that does require parameters.
     */
    public function test_t_existing_string_args() {
        // Existing language string with passed arguments.
        $translation = $this->framework->t('Illegal option %option in %library',
            ['%option' => 'example', '%library' => 'Test library']);

        // Make sure the string translation has been returned.
        $this->assertEquals('Illegal option example in Test library', $translation);
    }

    /**
     * Test the behaviour of t() when translating non-existent string.
     */
    public function test_t_non_existent_string() {
        // Non-existing language string.
        $message = 'Random message %option';

        $translation = $this->framework->t($message);

        // Make sure a debugging message is triggered.
        $this->assertDebuggingCalled("String translation cannot be found. Please add a string definition for '" .
            $message . "' in the core_h5p component.");
        // As the string does not exist in the mapping array, make sure the passed message is returned.
        $this->assertEquals($message, $translation);
    }

    /**
     * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
     * the folder name is parsable.
     **/
    public function test_getLibraryFileUrl() {
        global $CFG;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create a library record.
        $lib = $generator->create_library_record('Library', 'Lib', 1, 1);

        $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/library.json";

        // Get the URL of a file from an existing library. The provided folder name is parsable.
        $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');

        // Make sure the expected URL is returned.
        $this->assertEquals($expected, $actual);
    }

    /**
     * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a non-existent library and
     * the folder name is parsable.
     **/
    public function test_getLibraryFileUrl_non_existent_library() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create a library record.
        $generator->create_library_record('Library', 'Lib', 1, 1);

        // Get the URL of a file from a non-existent library. The provided folder name is parsable.
        $actual = $this->framework->getLibraryFileUrl('Library2-1.1', 'library.json');

        // Make sure a debugging message is triggered.
        $this->assertDebuggingCalled('The library "Library2-1.1" does not exist.');

        // Make sure that an URL is not returned.
        $this->assertEquals(null, $actual);
    }

    /**
     * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
     * the folder name is not parsable.
     **/
    public function test_getLibraryFileUrl_not_parsable_folder_name() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create a library record.
        $generator->create_library_record('Library', 'Lib', 1, 1);

        // Get the URL of a file from an existing library. The provided folder name is not parsable.
        $actual = $this->framework->getLibraryFileUrl('Library1.1', 'library.json');

        // Make sure a debugging message is triggered.
        $this->assertDebuggingCalled(
            'The provided string value "Library1.1" is not a valid name for a library folder.');

        // Make sure that an URL is not returned.
        $this->assertEquals(null, $actual);
    }

    /**
     * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
     * versions and the folder name is parsable.
     **/
    public function test_getLibraryFileUrl_library_has_multiple_versions() {
        global $CFG;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create library records with a different minor version.
        $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1);
        $lib2 = $generator->create_library_record('Library', 'Lib', 1, 3);

        $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.3/library.json";

        // Get the URL of a file from an existing library (Library 1.3). The provided folder name is parsable.
        $actual = $this->framework->getLibraryFileUrl('Library-1.3', 'library.json');

        // Make sure the proper URL (from the requested library version) is returned.
        $this->assertEquals($expected, $actual);
    }

    /**
     * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
     * patch versions and the folder name is parsable.
     **/
    public function test_getLibraryFileUrl_library_has_multiple_patch_versions() {
        global $CFG;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create library records with a different patch version.
        $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
        $lib2 = $generator->create_library_record('Library', 'Lib', 1, 1, 4);
        $lib3 = $generator->create_library_record('Library', 'Lib', 1, 1, 3);

        $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.1/library.json";

        // Get the URL of a file from an existing library. The provided folder name is parsable.
        $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');

        // Make sure the proper URL (from the latest library patch) is returned.
        $this->assertEquals($expected, $actual);
    }

    /**
     * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a sub-folder
     * of an existing library and the folder name is parsable.
     **/
    public function test_getLibraryFileUrl_library_subfolder() {
        global $CFG;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create a library record.
        $lib = $generator->create_library_record('Library', 'Lib', 1, 1);

        $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/css/example.css";

        // Get the URL of a file from a sub-folder from an existing library. The provided folder name is parsable.
        $actual = $this->framework->getLibraryFileUrl('Library-1.1/css', 'example.css');

        // Make sure the proper URL is returned.
        $this->assertEquals($expected, $actual);
    }

    /**
     * Test the behaviour of loadAddons().
     */
    public function test_loadAddons() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create a Library addon (1.1).
        $generator->create_library_record('Library', 'Lib', 1, 1, 2,
            '', '/regex1/');
        // Create a Library addon (1.3).
        $generator->create_library_record('Library', 'Lib', 1, 3, 2,
            '', '/regex2/');
        // Create a Library addon (1.2).
        $generator->create_library_record('Library', 'Lib', 1, 2, 2,
            '', '/regex3/');
        // Create a Library1 addon (1.2)
        $generator->create_library_record('Library1', 'Lib1', 1, 2, 2,
            '', '/regex11/');

        // Load the latest version of each addon.
        $addons = $this->framework->loadAddons();

        // The addons array should return 2 results (Library and Library1 addon).
        $this->assertCount(2, $addons);

        // Ensure the addons array is consistently ordered before asserting their contents.
        core_collator::asort_array_of_arrays_by_key($addons, 'machineName');
        [$addonone, $addontwo] = array_values($addons);

        // Make sure the version 1.3 is the latest 'Library' addon version.
        $this->assertEquals('Library', $addonone['machineName']);
        $this->assertEquals(1, $addonone['majorVersion']);
        $this->assertEquals(3, $addonone['minorVersion']);

        // Make sure the version 1.2 is the latest 'Library1' addon version.
        $this->assertEquals('Library1', $addontwo['machineName']);
        $this->assertEquals(1, $addontwo['majorVersion']);
        $this->assertEquals(2, $addontwo['minorVersion']);
    }

    /**
     * Test the behaviour of loadLibraries().
     */
    public function test_loadLibraries() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Generate h5p related data.
        $generator->generate_h5p_data();

        // Load all libraries.
        $libraries = $this->framework->loadLibraries();

        // Make sure all libraries are returned.
        $this->assertNotEmpty($libraries);
        $this->assertCount(6, $libraries);
        $this->assertEquals('MainLibrary', $libraries['MainLibrary'][0]->machine_name);
        $this->assertEquals('1', $libraries['MainLibrary'][0]->major_version);
        $this->assertEquals('0', $libraries['MainLibrary'][0]->minor_version);
        $this->assertEquals('1', $libraries['MainLibrary'][0]->patch_version);
    }

    /**
     * Test the behaviour of test_getLibraryId() when requesting an existing machine name.
     */
    public function test_getLibraryId_existing_machine_name() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create a library.
        $lib = $generator->create_library_record('Library', 'Lib', 1, 1, 2);

        // Request the library ID of the library with machine name 'Library'.
        $libraryid = $this->framework->getLibraryId('Library');

        // Make sure the library ID is being returned.
        $this->assertNotFalse($libraryid);
        $this->assertEquals($lib->id, $libraryid);
    }

    /**
     * Test the behaviour of test_getLibraryId() when requesting a non-existent machine name.
     */
    public function test_getLibraryId_non_existent_machine_name() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create a library.
        $generator->create_library_record('Library', 'Lib', 1, 1, 2);

        // Request the library ID of the library with machinename => 'TestLibrary' (non-existent).
        $libraryid = $this->framework->getLibraryId('TestLibrary');

        // Make sure the library ID not being returned.
        $this->assertFalse($libraryid);
    }

    /**
     * Test the behaviour of test_getLibraryId() when requesting a non-existent major version.
     */
    public function test_getLibraryId_non_existent_major_version() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create a library.
        $generator->create_library_record('Library', 'Lib', 1, 1, 2);

        // Request the library ID of the library with machine name => 'Library', majorversion => 2 (non-existent).
        $libraryid = $this->framework->getLibraryId('Library', 2);

        // Make sure the library ID not being returned.
        $this->assertFalse($libraryid);
    }

    /**
     * Test the behaviour of test_getLibraryId() when requesting a non-existent minor version.
     */
    public function test_getLibraryId_non_existent_minor_version() {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create a library.
        $generator->create_library_record('Library', 'Lib', 1, 1, 2);

        // Request the library ID of the library with machine name => 'Library',
        // majorversion => 1,  minorversion => 2 (non-existent).
        $libraryid = $this->framework->getLibraryId('Library', 1, 2);

        // Make sure the library ID not being returned.
        $this->assertFalse($libraryid);
    }

    /**
     * Test the behaviour of isPatchedLibrary().
     *
     * @dataProvider isPatchedLibrary_provider
     * @param array $libraryrecords Array containing data for the library creation
     * @param array $testlibrary Array containing the test library data
     * @param bool $expected The expectation whether the library is patched or not
     **/
    public function test_isPatchedLibrary(array $libraryrecords, array $testlibrary, bool $expected): void {
        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        foreach ($libraryrecords as $library) {
            call_user_func_array([$generator, 'create_library_record'], $library);
        }

        $this->assertEquals($expected, $this->framework->isPatchedLibrary($testlibrary));
    }

    /**
     * Data provider for test_isPatchedLibrary().
     *
     * @return array
     */
    public function isPatchedLibrary_provider(): array {
        return [
            'Unpatched library. No different versioning' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 1,
                    'minorVersion' => 1,
                    'patchVersion' => 2
                ],
                false,
            ],
            'Major version identical; Minor version identical; Patch version newer' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 1,
                    'minorVersion' => 1,
                    'patchVersion' => 3
                ],
                true,
            ],
            'Major version identical; Minor version newer; Patch version newer' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 1,
                    'minorVersion' => 2,
                    'patchVersion' => 3
                ],
                false,
            ],
            'Major version identical; Minor version identical; Patch version older' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 1,
                    'minorVersion' => 1,
                    'patchVersion' => 1
                ],
                false,
            ],
            'Major version identical; Minor version newer; Patch version older' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 1,
                    'minorVersion' => 2,
                    'patchVersion' => 1
                ],
                false,
            ],
            'Major version newer; Minor version identical; Patch version older' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 2,
                    'minorVersion' => 1,
                    'patchVersion' => 1
                ],
                false,
            ],
            'Major version newer; Minor version identical; Patch version newer' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 2,
                    'minorVersion' => 1,
                    'patchVersion' => 3
                ],
                false,
            ],

            'Major version older; Minor version identical; Patch version older' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 0,
                    'minorVersion' => 1,
                    'patchVersion' => 1
                ],
                false,
            ],
            'Major version older; Minor version identical; Patch version newer' => [
                [
                    ['TestLibrary', 'Test', 1, 1, 2],
                ],
                [
                    'machineName' => 'TestLibrary',
                    'majorVersion' => 0,
                    'minorVersion' => 1,
                    'patchVersion' => 3
                ],
                false,
            ],
        ];
    }

    /**
     * Test the behaviour of isInDevMode().
     */
    public function test_isInDevMode() {
        $isdevmode = $this->framework->isInDevMode();

        $this->assertFalse($isdevmode);
    }

    /**
     * Test the behaviour of mayUpdateLibraries().
     */
    public function test_mayUpdateLibraries(): void {
        global $DB;

        $this->resetAfterTest();

        // Create some users.
        $contextsys = \context_system::instance();
        $user = $this->getDataGenerator()->create_user();
        $admin = get_admin();
        $managerrole = $DB->get_record('role', ['shortname' => 'manager'], '*', MUST_EXIST);
        $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
        $manager = $this->getDataGenerator()->create_user();
        role_assign($managerrole->id, $manager->id, $contextsys);

        // Create a course with a label and enrol the user.
        $course = $this->getDataGenerator()->create_course();
        $label = $this->getDataGenerator()->create_module('label', ['course' => $course->id]);
        list(, $labelcm) = get_course_and_cm_from_instance($label->id, 'label');
        $contextlabel = \context_module::instance($labelcm->id);
        $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');

        // Create the .h5p file.
        $path = __DIR__ . '/fixtures/h5ptest.zip';

        // Admin and manager should have permission to update libraries.
        $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextsys);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertTrue($mayupdatelib);

        $file = helper::create_fake_stored_file_from_path($path, $manager->id, $contextsys);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertTrue($mayupdatelib);

        // By default, normal user hasn't permission to update libraries (in both contexts, system and module label).
        $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertFalse($mayupdatelib);

        $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertFalse($mayupdatelib);

        // If the current user (admin) can update libraries, the method should return true (even if the file userid hasn't the
        // required capabilility in the file context).
        $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextlabel);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertTrue($mayupdatelib);

        // If the update capability is assigned to the user, they should be able to update the libraries (only in the context
        // where the capability has been assigned).
        $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertFalse($mayupdatelib);
        assign_capability('moodle/h5p:updatelibraries', CAP_ALLOW, $studentrole->id, $contextlabel);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertTrue($mayupdatelib);
        $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
        $this->framework->set_file($file);
        $mayupdatelib = $this->framework->mayUpdateLibraries();
        $this->assertFalse($mayupdatelib);
    }

    /**
     * Test the behaviour of get_file() and set_file().
     */
    public function test_get_file(): void {
        $this->resetAfterTest();

        // Create some users.
        $contextsys = \context_system::instance();
        $user = $this->getDataGenerator()->create_user();

        // The H5P file.
        $path = __DIR__ . '/fixtures/h5ptest.zip';

        // An error should be raised when it's called before initialitzing it.
        $this->expectException('coding_exception');
        $this->expectExceptionMessage('Using get_file() before file is set');
        $this->framework->get_file();

        // Check the value when only path and user are set.
        $file = helper::create_fake_stored_file_from_path($path, $user->id);
        $this->framework->set_file($file);
        $file = $this->framework->get_file();
        $this->assertEquals($user->id, $$file->get_userid());
        $this->assertEquals($contextsys->id, $file->get_contextid());

        // Check the value when also the context is set.
        $course = $this->getDataGenerator()->create_course();
        $contextcourse = \context_course::instance($course->id);
        $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextcourse);
        $this->framework->set_file($file);
        $file = $this->framework->get_file();
        $this->assertEquals($user->id, $$file->get_userid());
        $this->assertEquals($contextcourse->id, $file->get_contextid());
    }

    /**
     * Test the behaviour of saveLibraryData() when saving data for a new library.
     */
    public function test_saveLibraryData_new_library() {
        global $DB;

        $this->resetAfterTest();

        $librarydata = array(
            'title' => 'Test',
            'machineName' => 'TestLibrary',
            'majorVersion' => '1',
            'minorVersion' => '0',
            'patchVersion' => '2',
            'runnable' => 1,
            'fullscreen' => 1,
            'preloadedJs' => array(
                array(
                    'path' => 'js/name.min.js'
                )
            ),
            'preloadedCss' => array(
                array(
                    'path' => 'css/name.css'
                )
            ),
            'dropLibraryCss' => array(
                array(
                    'machineName' => 'Name2'
                )
            )
        );

        // Create a new library.
        $this->framework->saveLibraryData($librarydata);

        $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);

        // Make sure the library data was properly saved.
        $this->assertNotEmpty($library);
        $this->assertNotEmpty($librarydata['libraryId']);
        $this->assertEquals($librarydata['title'], $library->title);
        $this->assertEquals($librarydata['machineName'], $library->machinename);
        $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
        $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
        $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
        $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
        $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
        $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
    }

    /**
     * Test the behaviour of saveLibraryData() when saving (updating) data for an existing library.
     */
    public function test_saveLibraryData_existing_library() {
        global $DB;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');

        // Create a library record.
        $library = $generator->create_library_record('TestLibrary', 'Test', 1, 0, 2);

        $librarydata = array(
            'libraryId' => $library->id,
            'title' => 'Test1',
            'machineName' => 'TestLibrary',
            'majorVersion' => '1',
            'minorVersion' => '2',
            'patchVersion' => '2',
            'runnable' => 1,
            'fullscreen' => 1,
            'preloadedJs' => array(
                array(
                    'path' => 'js/name.min.js'
                )
            ),
            'preloadedCss' => array(
                array(
                    'path' => 'css/name.css'
                )
            ),
            'dropLibraryCss' => array(
                array(
                    'machineName' => 'Name2'
                )
            )
        );

        // Update the library.
        $this->framework->saveLibraryData($librarydata, false);

        $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);

        // Make sure the library data was properly updated.
        $this->assertNotEmpty($library);
        $this->assertNotEmpty($librarydata['libraryId']);
        $this->assertEquals($librarydata['title'], $library->title);
        $this->assertEquals($librarydata['machineName'], $library->machinename);
        $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
        $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
        $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
        $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
        $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
        $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
    }

    /**
     * Test the behaviour of insertContent().
     */
    public function test_insertContent() {
        global $DB;

        $this->resetAfterTest();

        $content = array(
            'params' => json_encode(['param1' => 'Test']),
            'library' => array(
                'libraryId' => 1
            ),
            'disable' => 8
        );

        // Insert h5p content.
        $contentid = $this->framework->insertContent($content);

        // Get the entered content from the db.
        $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);

        // Make sure the h5p content was properly inserted.
        $this->assertNotEmpty($dbcontent);
        $this->assertEquals($content['params'], $dbcontent->jsoncontent);
        $this->assertEquals($content['library']['libraryId'], $dbcontent->mainlibraryid);
        $this->assertEquals($content['disable'], $dbcontent->displayoptions);
    }

    /**
     * Test the behaviour of insertContent().
     */
    public function test_insertContent_latestlibrary() {
        global $DB;

        $this->resetAfterTest();

        $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
        // Create a library record.
        $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);

        $content = array(
            'params' => json_encode(['param1' => 'Test']),
            'library' => array(
                'libraryId' => 0,
                'machineName' => 'TestLibrary',
            ),
            'disable' => 8
        );

        // Insert h5p content.
        $contentid = $this->framework->insertContent($content);

        // Get the entered content from the db.
        $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);

        // Make sure the h5p content was properly inserted.
        $this->assertNotEmpty($dbcontent);
        $this->assertEquals($content['params'], $dbcontent->jsoncontent);
        $this->assertEquals($content['disable'], $dbcontent->displayoptions);
        // As the libraryId was empty, the latest library has been used.
        $this->assertEquals($lib->id, $dbcontent->mainlibraryid);
    }

    /**
     * Test the behaviour of updateContent().
     */
    public function test_updateContent() {
        global $DB;

        $this->resetAfterTest();

> /** @var \core_h5p_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create a library record. $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2); // Create an h5p content with 'TestLibrary' as it's main library. $contentid = $generator->create_h5p_record($lib->id); $content = array( 'id' => $contentid, 'params' => json_encode(['param2' => 'Test2']), 'library' => array( 'libraryId' => $lib->id ), 'disable' => 8 ); // Update the h5p content. $this->framework->updateContent($content); $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]); // Make sure the h5p content was properly updated. $this->assertNotEmpty($h5pcontent);
> $this->assertNotEmpty($h5pcontent->pathnamehash); $this->assertEquals($content['params'], $h5pcontent->jsoncontent); > $this->assertNotEmpty($h5pcontent->contenthash);
$this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid); $this->assertEquals($content['disable'], $h5pcontent->displayoptions); } /** * Test the behaviour of updateContent() with metadata. * * @covers ::updateContent */ public function test_updateContent_withmetadata(): void { global $DB; $this->resetAfterTest(); /** @var \core_h5p_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create a library record. $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2); // Create an h5p content with 'TestLibrary' as it's main library. $contentid = $generator->create_h5p_record($lib->id); $params = ['param2' => 'Test2']; $metadata = [ 'license' => 'CC BY', 'licenseVersion' => '4.0', 'yearFrom' => 2000, 'yearTo' => 2023, 'defaultLanguage' => 'ca', ]; $content = [ 'id' => $contentid, 'params' => json_encode($params), 'library' => [ 'libraryId' => $lib->id, ], 'disable' => 8, 'metadata' => $metadata, ]; // Update the h5p content. $this->framework->updateContent($content); $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]); // Make sure the h5p content was properly updated. $this->assertNotEmpty($h5pcontent);
> $this->assertNotEmpty($h5pcontent->pathnamehash); $this->assertEquals(json_encode(array_merge($params, ['metadata' => $metadata])), $h5pcontent->jsoncontent); > $this->assertNotEmpty($h5pcontent->contenthash);
$this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid); $this->assertEquals($content['disable'], $h5pcontent->displayoptions); } /** * Test the behaviour of saveLibraryDependencies(). */ public function test_saveLibraryDependencies() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create a library 'Library'. $library = $generator->create_library_record('Library', 'Title'); // Create a library 'DependencyLibrary1'. $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1'); // Create a library 'DependencyLibrary2'. $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2'); $dependencies = array( array( 'machineName' => $dependency1->machinename, 'majorVersion' => $dependency1->majorversion, 'minorVersion' => $dependency1->minorversion ), array( 'machineName' => $dependency2->machinename, 'majorVersion' => $dependency2->majorversion, 'minorVersion' => $dependency2->minorversion ), ); // Set 'DependencyLibrary1' and 'DependencyLibrary2' as library dependencies of 'Library'. $this->framework->saveLibraryDependencies($library->id, $dependencies, 'preloaded'); $libdependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library->id], 'id ASC'); // Make sure the library dependencies for 'Library' are properly set. $this->assertEquals(2, count($libdependencies)); $this->assertEquals($dependency1->id, reset($libdependencies)->requiredlibraryid); $this->assertEquals($dependency2->id, end($libdependencies)->requiredlibraryid); } /** * Test the behaviour of deleteContentData(). */ public function test_deleteContentData() { global $DB; $this->resetAfterTest();
> /** @var \core_h5p_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
> // For the mod_h5pactivity component, the activity needs to be created too. > $course = $this->getDataGenerator()->create_course(); // Generate some h5p related data. > $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); $data = $generator->generate_h5p_data(); > $this->setUser($user); $h5pid = $data->h5pcontent->h5pid; > $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); > $activitycontext = \context_module::instance($activity->cmid); $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]); > $filerecord = [ // Make sure the particular h5p content exists in the DB. > 'contextid' => $activitycontext->id, $this->assertNotEmpty($h5pcontent); > 'component' => 'mod_h5pactivity', > 'filearea' => 'package', // Get the h5p content libraries from the DB. > 'itemid' => 0, $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]); > 'filepath' => '/', > 'filename' => 'dummy.h5p', // Make sure the content libraries exists in the DB. > 'addxapistate' => true, $this->assertNotEmpty($h5pcontentlibraries); > ];
< $data = $generator->generate_h5p_data();
> $data = $generator->generate_h5p_data(false, $filerecord);
< $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
< $this->assertNotEmpty($h5pcontent); < < // Get the h5p content libraries from the DB. < $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]); <
> $this->assertNotEmpty($DB->get_record('h5p', ['id' => $h5pid]));
< $this->assertNotEmpty($h5pcontentlibraries); < $this->assertCount(5, $h5pcontentlibraries);
> $this->assertCount(5, $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid])); > // Make sure the particular xAPI state exists in the DB. > $records = $DB->get_records('xapi_states'); > $record = reset($records); > $this->assertCount(1, $records); > $this->assertNotNull($record->statedata);
< $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]); < $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]); <
< $this->assertEmpty($h5pcontent);
> $this->assertEmpty($DB->get_record('h5p', ['id' => $h5pid]));
< $this->assertEmpty($h5pcontentlibraries);
> $this->assertEmpty($DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid])); > // The xAPI state should be reseted. > $records = $DB->get_records('xapi_states'); > $record = reset($records); > $this->assertCount(1, $records); > $this->assertNull($record->statedata); > } > > /** > * Test the behaviour of resetContentUserData(). > */ > public function test_resetContentUserData() { > global $DB; > > $this->resetAfterTest(); > > /** @var \core_h5p_generator $generator */ > $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); > // For the mod_h5pactivity component, the activity needs to be created too. > $course = $this->getDataGenerator()->create_course(); > $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); > $this->setUser($user); > $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); > $activitycontext = \context_module::instance($activity->cmid); > $filerecord = [ > 'contextid' => $activitycontext->id, > 'component' => 'mod_h5pactivity', > 'filearea' => 'package', > 'itemid' => 0, > 'filepath' => '/', > 'filename' => 'dummy.h5p', > 'addxapistate' => true, > ]; > > // Generate some h5p related data. > $data = $generator->generate_h5p_data(false, $filerecord); > $h5pid = $data->h5pcontent->h5pid; > > // Make sure the H5P content, libraries and xAPI state exist in the DB. > $this->assertNotEmpty($DB->get_record('h5p', ['id' => $h5pid])); > $this->assertCount(5, $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid])); > $records = $DB->get_records('xapi_states'); > $record = reset($records); > $this->assertCount(1, $records); > $this->assertNotNull($record->statedata); > > // Reset the user data associated to this H5P content. > $this->framework->resetContentUserData($h5pid); > > // The H5P content should still exist in the db. > $this->assertNotEmpty($DB->get_record('h5p', ['id' => $h5pid])); > // The particular content libraries should still exist in the db. > $this->assertCount(5, $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid])); > // The xAPI state should still exist in the db, but should be reset. > $records = $DB->get_records('xapi_states'); > $record = reset($records); > $this->assertCount(1, $records); > $this->assertNull($record->statedata);
/** * Test the behaviour of deleteLibraryUsage(). */ public function test_deleteLibraryUsage() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate some h5p related data. $data = $generator->generate_h5p_data(); $h5pid = $data->h5pcontent->h5pid; // Get the h5p content libraries from the DB. $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]); // The particular h5p content should have 5 content libraries. $this->assertNotEmpty($h5pcontentlibraries); $this->assertCount(5, $h5pcontentlibraries); // Delete the h5p content and it's related data. $this->framework->deleteLibraryUsage($h5pid); // Get the h5p content libraries from the DB. $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]); // The particular h5p content libraries should no longer exist in the db. $this->assertEmpty($h5pcontentlibraries); } /** * Test the behaviour of test_saveLibraryUsage(). */ public function test_saveLibraryUsage() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create a library 'Library'. $library = $generator->create_library_record('Library', 'Title'); // Create a library 'DependencyLibrary1'. $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1'); // Create a library 'DependencyLibrary2'. $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2'); // Create an h5p content with 'Library' as it's main library. $contentid = $generator->create_h5p_record($library->id); $dependencies = array( array( 'library' => array( 'libraryId' => $dependency1->id, 'machineName' => $dependency1->machinename, 'dropLibraryCss' => $dependency1->droplibrarycss ), 'type' => 'preloaded', 'weight' => 1 ), array( 'library' => array( 'libraryId' => $dependency2->id, 'machineName' => $dependency2->machinename, 'dropLibraryCss' => $dependency2->droplibrarycss ), 'type' => 'preloaded', 'weight' => 2 ), ); // Save 'DependencyLibrary1' and 'DependencyLibrary2' as h5p content libraries. $this->framework->saveLibraryUsage($contentid, $dependencies); // Get the h5p content libraries from the DB. $libdependencies = $DB->get_records('h5p_contents_libraries', ['h5pid' => $contentid], 'id ASC'); // Make sure that 'DependencyLibrary1' and 'DependencyLibrary2' are properly set as h5p content libraries. $this->assertEquals(2, count($libdependencies)); $this->assertEquals($dependency1->id, reset($libdependencies)->libraryid); $this->assertEquals($dependency2->id, end($libdependencies)->libraryid); } /** * Test the behaviour of getLibraryUsage() without skipping a particular h5p content. */ public function test_getLibraryUsage_no_skip_content() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $generateddata = $generator->generate_h5p_data(); // The Id of the library 'Library1'. $library1id = $generateddata->lib1->data->id; // The Id of the library 'Library2'. $library2id = $generateddata->lib2->data->id; // The Id of the library 'Library5'. $library5id = $generateddata->lib5->data->id; // Get the library usage for 'Library1' (do not skip content). $data = $this->framework->getLibraryUsage($library1id); $expected = array( 'content' => 1, 'libraries' => 1 ); // Make sure 'Library1' is used by 1 content and is a dependency to 1 library. $this->assertEquals($expected, $data); // Get the library usage for 'Library2' (do not skip content). $data = $this->framework->getLibraryUsage($library2id); $expected = array( 'content' => 1, 'libraries' => 2, ); // Make sure 'Library2' is used by 1 content and is a dependency to 2 libraries. $this->assertEquals($expected, $data); // Get the library usage for 'Library5' (do not skip content). $data = $this->framework->getLibraryUsage($library5id); $expected = array( 'content' => 0, 'libraries' => 1, ); // Make sure 'Library5' is not used by any content and is a dependency to 1 library. $this->assertEquals($expected, $data); } /** * Test the behaviour of getLibraryUsage() when skipping a particular content. */ public function test_getLibraryUsage_skip_content() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $generateddata = $generator->generate_h5p_data(); // The Id of the library 'Library1'. $library1id = $generateddata->lib1->data->id; // Get the library usage for 'Library1' (skip content). $data = $this->framework->getLibraryUsage($library1id, true); $expected = array( 'content' => -1, 'libraries' => 1, ); // Make sure 'Library1' is a dependency to 1 library. $this->assertEquals($expected, $data); } /** * Test the behaviour of loadLibrary() when requesting an existing library. */ public function test_loadLibrary_existing_library() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $generateddata = $generator->generate_h5p_data(); // The library data of 'Library1'. $library1 = $generateddata->lib1->data; // The library data of 'Library5'. $library5 = $generateddata->lib5->data; // The preloaded dependencies. $preloadeddependencies = array(); foreach ($generateddata->lib1->dependencies as $preloadeddependency) { $preloadeddependencies[] = array( 'machineName' => $preloadeddependency->machinename, 'majorVersion' => $preloadeddependency->majorversion, 'minorVersion' => $preloadeddependency->minorversion ); } // Create a dynamic dependency. $generator->create_library_dependency_record($library1->id, $library5->id, 'dynamic'); $dynamicdependencies[] = array( 'machineName' => $library5->machinename, 'majorVersion' => $library5->majorversion, 'minorVersion' => $library5->minorversion ); // Load 'Library1' data. $data = $this->framework->loadLibrary($library1->machinename, $library1->majorversion, $library1->minorversion); $expected = array( 'libraryId' => $library1->id, 'title' => $library1->title, 'machineName' => $library1->machinename, 'majorVersion' => $library1->majorversion, 'minorVersion' => $library1->minorversion, 'patchVersion' => $library1->patchversion, 'runnable' => $library1->runnable, 'fullscreen' => $library1->fullscreen, 'embedTypes' => $library1->embedtypes, 'preloadedJs' => $library1->preloadedjs, 'preloadedCss' => $library1->preloadedcss, 'dropLibraryCss' => $library1->droplibrarycss, 'semantics' => $library1->semantics, 'preloadedDependencies' => $preloadeddependencies, 'dynamicDependencies' => $dynamicdependencies ); // Make sure the 'Library1' data is properly loaded. $this->assertEquals($expected, $data); } /** * Test the behaviour of loadLibrary() when requesting a non-existent library. */ public function test_loadLibrary_non_existent_library() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $generator->generate_h5p_data(); // Attempt to load a non-existent library. $data = $this->framework->loadLibrary('MissingLibrary', 1, 2); // Make sure nothing is loaded. $this->assertFalse($data); } /** * Test the behaviour of loadLibrarySemantics(). * * @dataProvider loadLibrarySemantics_provider * @param array $libraryrecords Array containing data for the library creation * @param array $testlibrary Array containing the test library data * @param string $expected The expected semantics value **/ public function test_loadLibrarySemantics(array $libraryrecords, array $testlibrary, string $expected): void { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); foreach ($libraryrecords as $library) { call_user_func_array([$generator, 'create_library_record'], $library); } $this->assertEquals($expected, $this->framework->loadLibrarySemantics( $testlibrary['machinename'], $testlibrary['majorversion'], $testlibrary['minorversion'])); } /** * Data provider for test_loadLibrarySemantics(). * * @return array */ public function loadLibrarySemantics_provider(): array { $semantics = json_encode( [ 'type' => 'text', 'name' => 'text', 'label' => 'Plain text', 'description' => 'Please add some text' ] ); return [ 'Library with semantics' => [ [ ['Library1', 'Lib1', 1, 1, 2, $semantics], ], [ 'machinename' => 'Library1', 'majorversion' => 1, 'minorversion' => 1 ], $semantics, ], 'Library without semantics' => [ [ ['Library2', 'Lib2', 1, 2, 2, ''], ], [ 'machinename' => 'Library2', 'majorversion' => 1, 'minorversion' => 2 ], '', ] ]; } /** * Test the behaviour of alterLibrarySemantics(). */ public function test_alterLibrarySemantics() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); $semantics = json_encode( array( 'type' => 'text', 'name' => 'text', 'label' => 'Plain text', 'description' => 'Please add some text' ) ); // Create a library 'Library1' with semantics. $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2, $semantics); $updatedsemantics = array( 'type' => 'text', 'name' => 'updated text', 'label' => 'Updated text', 'description' => 'Please add some text' ); // Alter the semantics of 'Library1'. $this->framework->alterLibrarySemantics($updatedsemantics, 'Library1', 1, 1); // Get the semantics of 'Library1' from the DB. $currentsemantics = $DB->get_field('h5p_libraries', 'semantics', array('id' => $library1->id)); // The semantics for Library1 shouldn't be updated. $this->assertEquals($semantics, $currentsemantics); } /** * Test the behaviour of deleteLibraryDependencies() when requesting to delete the * dependencies of an existing library. */ public function test_deleteLibraryDependencies_existing_library() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The data of the library 'Library1'. $library1 = $data->lib1->data; // Get the dependencies of 'Library1'. $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]); // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4'). $this->assertCount(3, $dependencies); // Delete the dependencies of 'Library1'. $this->framework->deleteLibraryDependencies($library1->id); $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]); // The 'Library1' should have 0 dependencies. $this->assertCount(0, $dependencies); } /** * Test the behaviour of deleteLibraryDependencies() when requesting to delete the * dependencies of a non-existent library. */ public function test_deleteLibraryDependencies_non_existent_library() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The data of the library 'Library1'. $library1 = $data->lib1->data; // Get the dependencies of 'Library1'. $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]); // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4'). $this->assertCount(3, $dependencies); // Delete the dependencies of a non-existent library. $this->framework->deleteLibraryDependencies(0); $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]); // The 'Library1' should have 3 dependencies. $this->assertCount(3, $dependencies); } /** * Test the behaviour of deleteLibrary(). */ public function test_deleteLibrary() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(true); // The data of the 'Library1' library. $library1 = $data->lib1->data; // Get the library dependencies of 'Library1'. $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]); // The 'Library1' should have 3 library dependencies ('Library2', 'Library3', 'Library4'). $this->assertCount(3, $dependencies); // Return the created 'Library1' files. $libraryfiles = $DB->get_records('files', array( 'component' => \core_h5p\file_storage::COMPONENT, 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA, 'itemid' => $library1->id ) ); // The library ('Library1') should have 7 related folders/files. $this->assertCount(7, $libraryfiles); // Delete the library. $this->framework->deleteLibrary($library1); $lib1 = $DB->get_record('h5p_libraries', ['machinename' => $library1->machinename]); $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]); $libraryfiles = $DB->get_records('files', array( 'component' => \core_h5p\file_storage::COMPONENT, 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA, 'itemid' => $library1->id ) ); // The 'Library1' should not exist. $this->assertEmpty($lib1); // The library ('Library1') should have 0 dependencies. $this->assertCount(0, $dependencies); // The library (library1) should have 0 related folders/files. $this->assertCount(0, $libraryfiles); } /** * Test the behaviour of loadContent(). */ public function test_loadContent() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The Id of the created h5p content. $h5pid = $data->h5pcontent->h5pid; // Get the h5p content data from the DB. $h5p = $DB->get_record('h5p', ['id' => $h5pid]); // The data of content's main library ('MainLibrary'). $mainlibrary = $data->mainlib->data; // Load the h5p content. $content = $this->framework->loadContent($h5pid); $expected = array( 'id' => $h5p->id, 'params' => $h5p->jsoncontent, 'embedType' => 'iframe', 'disable' => $h5p->displayoptions, 'title' => $mainlibrary->title, 'slug' => H5PCore::slugify($mainlibrary->title) . '-' . $h5p->id, 'filtered' => $h5p->filtered, 'libraryId' => $mainlibrary->id, 'libraryName' => $mainlibrary->machinename, 'libraryMajorVersion' => $mainlibrary->majorversion, 'libraryMinorVersion' => $mainlibrary->minorversion, 'libraryEmbedTypes' => $mainlibrary->embedtypes, 'libraryFullscreen' => $mainlibrary->fullscreen, 'metadata' => '', 'pathnamehash' => $h5p->pathnamehash ); $params = json_decode($h5p->jsoncontent); if (empty($params->metadata)) { $params->metadata = new \stdClass(); } $expected['metadata'] = $params->metadata; $expected['params'] = json_encode($params->params ?? $params); // The returned content should match the expected array. $this->assertEquals($expected, $content); } /** * Test the behaviour of loadContentDependencies() when requesting content dependencies * without specifying the dependency type. */ public function test_loadContentDependencies_no_type_defined() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The Id of the h5p content. $h5pid = $data->h5pcontent->h5pid; // The content dependencies. $dependencies = $data->h5pcontent->contentdependencies; // Add Library5 as a content dependency (dynamic dependency type). $library5 = $data->lib5->data; $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic'); // Get all content dependencies. $contentdependencies = $this->framework->loadContentDependencies($h5pid); $expected = array(); foreach ($dependencies as $dependency) { $expected[$dependency->machinename] = array( 'libraryId' => $dependency->id, 'machineName' => $dependency->machinename, 'majorVersion' => $dependency->majorversion, 'minorVersion' => $dependency->minorversion, 'patchVersion' => $dependency->patchversion, 'preloadedCss' => $dependency->preloadedcss, 'preloadedJs' => $dependency->preloadedjs, 'dropCss' => '0', 'dependencyType' => 'preloaded' ); } $expected = array_merge($expected, array( 'Library5' => array( 'libraryId' => $library5->id, 'machineName' => $library5->machinename, 'majorVersion' => $library5->majorversion, 'minorVersion' => $library5->minorversion, 'patchVersion' => $library5->patchversion, 'preloadedCss' => $library5->preloadedcss, 'preloadedJs' => $library5->preloadedjs, 'dropCss' => '0', 'dependencyType' => 'dynamic' ) ) ); // The loaded content dependencies should return 6 libraries. $this->assertCount(6, $contentdependencies); $this->assertEquals($expected, $contentdependencies); } /** * Test the behaviour of loadContentDependencies() when requesting content dependencies * with specifying the dependency type. */ public function test_loadContentDependencies_type_defined() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The Id of the h5p content. $h5pid = $data->h5pcontent->h5pid; // The content dependencies. $dependencies = $data->h5pcontent->contentdependencies; // Add Library5 as a content dependency (dynamic dependency type). $library5 = $data->lib5->data; $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic'); // Load all content dependencies of dependency type 'preloaded'. $preloadeddependencies = $this->framework->loadContentDependencies($h5pid, 'preloaded'); $expected = array(); foreach ($dependencies as $dependency) { $expected[$dependency->machinename] = array( 'libraryId' => $dependency->id, 'machineName' => $dependency->machinename, 'majorVersion' => $dependency->majorversion, 'minorVersion' => $dependency->minorversion, 'patchVersion' => $dependency->patchversion, 'preloadedCss' => $dependency->preloadedcss, 'preloadedJs' => $dependency->preloadedjs, 'dropCss' => '0', 'dependencyType' => 'preloaded' ); } // The loaded content dependencies should return 5 libraries. $this->assertCount(5, $preloadeddependencies); $this->assertEquals($expected, $preloadeddependencies); // Load all content dependencies of dependency type 'dynamic'. $dynamicdependencies = $this->framework->loadContentDependencies($h5pid, 'dynamic'); $expected = array( 'Library5' => array( 'libraryId' => $library5->id, 'machineName' => $library5->machinename, 'majorVersion' => $library5->majorversion, 'minorVersion' => $library5->minorversion, 'patchVersion' => $library5->patchversion, 'preloadedCss' => $library5->preloadedcss, 'preloadedJs' => $library5->preloadedjs, 'dropCss' => '0', 'dependencyType' => 'dynamic' ) ); // The loaded content dependencies should now return 1 library. $this->assertCount(1, $dynamicdependencies); $this->assertEquals($expected, $dynamicdependencies); } /** * Test the behaviour of getOption(). */ public function test_getOption(): void { $this->resetAfterTest(); // Get value for display_option_download. $value = $this->framework->getOption(H5PCore::DISPLAY_OPTION_DOWNLOAD); $expected = H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF; $this->assertEquals($expected, $value); // Get value for display_option_embed using default value (it should be ignored). $value = $this->framework->getOption(H5PCore::DISPLAY_OPTION_EMBED, H5PDisplayOptionBehaviour::NEVER_SHOW); $expected = H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF; $this->assertEquals($expected, $value); // Get value for unexisting setting without default. $value = $this->framework->getOption('unexistingsetting'); $expected = false; $this->assertEquals($expected, $value); // Get value for unexisting setting with default. $value = $this->framework->getOption('unexistingsetting', 'defaultvalue'); $expected = 'defaultvalue'; $this->assertEquals($expected, $value); } /** * Test the behaviour of setOption(). */ public function test_setOption(): void { $this->resetAfterTest(); // Set value for 'newsetting' setting. $name = 'newsetting'; $value = $this->framework->getOption($name); $this->assertEquals(false, $value); $newvalue = 'value1'; $this->framework->setOption($name, $newvalue); $value = $this->framework->getOption($name); $this->assertEquals($newvalue, $value); // Set value for display_option_download and then get it again. Check it hasn't changed. $name = H5PCore::DISPLAY_OPTION_DOWNLOAD; $newvalue = H5PDisplayOptionBehaviour::NEVER_SHOW; $this->framework->setOption($name, $newvalue); $value = $this->framework->getOption($name); $expected = H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF; $this->assertEquals($expected, $value); } /** * Test the behaviour of updateContentFields(). */ public function test_updateContentFields() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create 'Library1' library. $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2); // Create 'Library2' library. $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2); // Create an h5p content with 'Library1' as it's main library. $h5pid = $generator->create_h5p_record($library1->id, 'iframe'); $updatedata = array( 'jsoncontent' => json_encode(['value' => 'test']), 'mainlibraryid' => $library2->id ); // Update h5p content fields. $this->framework->updateContentFields($h5pid, $updatedata); // Get the h5p content from the DB. $h5p = $DB->get_record('h5p', ['id' => $h5pid]); $expected = json_encode(['value' => 'test']); // Make sure the h5p content fields are properly updated. $this->assertEquals($expected, $h5p->jsoncontent); $this->assertEquals($library2->id, $h5p->mainlibraryid); } /** * Test the behaviour of clearFilteredParameters(). */ public function test_clearFilteredParameters() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create 3 libraries. $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2); $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2); $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2); // Create h5p content with 'Library1' as a main library. $h5pcontentid1 = $generator->create_h5p_record($library1->id); // Create h5p content with 'Library1' as a main library. $h5pcontentid2 = $generator->create_h5p_record($library1->id); // Create h5p content with 'Library2' as a main library. $h5pcontentid3 = $generator->create_h5p_record($library2->id); // Create h5p content with 'Library3' as a main library. $h5pcontentid4 = $generator->create_h5p_record($library3->id); $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]); $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]); $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]); $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]); // The filtered parameters should be present in each h5p content. $this->assertNotEmpty($h5pcontent1->filtered); $this->assertNotEmpty($h5pcontent2->filtered); $this->assertNotEmpty($h5pcontent3->filtered); $this->assertNotEmpty($h5pcontent4->filtered); // Clear the filtered parameters for contents that have library1 and library3 as // their main library. $this->framework->clearFilteredParameters([$library1->id, $library3->id]); $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]); $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]); $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]); $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]); // The filtered parameters should be still present only for the content that has // library 2 as a main library. $this->assertEmpty($h5pcontent1->filtered); $this->assertEmpty($h5pcontent2->filtered); $this->assertNotEmpty($h5pcontent3->filtered); $this->assertEmpty($h5pcontent4->filtered); } /** * Test the behaviour of getNumNotFiltered(). */ public function test_getNumNotFiltered() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create 3 libraries. $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2); $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2); $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2); // Create h5p content with library1 as a main library. $h5pcontentid1 = $generator->create_h5p_record($library1->id); // Create h5p content with library1 as a main library. $h5pcontentid2 = $generator->create_h5p_record($library1->id); // Create h5p content with library2 as a main library. $h5pcontentid3 = $generator->create_h5p_record($library2->id); // Create h5p content with library3 as a main library. $h5pcontentid4 = $generator->create_h5p_record($library3->id); $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]); $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]); $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]); $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]); // The filtered parameters should be present in each h5p content. $this->assertNotEmpty($h5pcontent1->filtered); $this->assertNotEmpty($h5pcontent2->filtered); $this->assertNotEmpty($h5pcontent3->filtered); $this->assertNotEmpty($h5pcontent4->filtered); // Clear the filtered parameters for contents that have library1 and library3 as // their main library. $this->framework->clearFilteredParameters([$library1->id, $library3->id]); $countnotfiltered = $this->framework->getNumNotFiltered(); // 3 contents don't have their parameters filtered. $this->assertEquals(3, $countnotfiltered); } /** * Test the behaviour of getNumContent(). */ public function test_getNumContent() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The 'MainLibrary' library data. $mainlibrary = $data->mainlib->data; // The 'Library1' library data. $library1 = $data->lib1->data; // Create new h5p content with MainLibrary as a main library. $generator->create_h5p_record($mainlibrary->id); // Get the number of h5p contents that are using 'MainLibrary' as their main library. $countmainlib = $this->framework->getNumContent($mainlibrary->id); // Get the number of h5p contents that are using 'Library1' as their main library. $countlib1 = $this->framework->getNumContent($library1->id); // Make sure that 2 contents are using MainLibrary as their main library. $this->assertEquals(2, $countmainlib); // Make sure that 0 contents are using Library1 as their main library. $this->assertEquals(0, $countlib1); } /** * Test the behaviour of getNumContent() when certain contents are being skipped. */ public function test_getNumContent_skip_content() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The 'MainLibrary' library data. $mainlibrary = $data->mainlib->data; // Create new h5p content with MainLibrary as a main library. $h5pcontentid = $generator->create_h5p_record($mainlibrary->id); // Get the number of h5p contents that are using 'MainLibrary' as their main library. // Skip the newly created content $h5pcontentid. $countmainlib = $this->framework->getNumContent($mainlibrary->id, [$h5pcontentid]); // Make sure that 1 content is returned instead of 2 ($h5pcontentid being skipped). $this->assertEquals(1, $countmainlib); } /** * Test the behaviour of isContentSlugAvailable(). */ public function test_isContentSlugAvailable() { $this->resetAfterTest(); $slug = 'h5p-test-slug-1'; // Currently this returns always true. The slug is generated as a unique value for // each h5p content and it is not stored in the h5p content table. $isslugavailable = $this->framework->isContentSlugAvailable($slug); $this->assertTrue($isslugavailable); } /** * Test that a record is stored for cached assets. */ public function test_saveCachedAssets() { global $DB; $this->resetAfterTest(); $libraries = array( array( 'machineName' => 'H5P.TestLib', 'libraryId' => 405, ), array( 'FontAwesome' => 'FontAwesome', 'libraryId' => 406, ), array( 'machineName' => 'H5P.SecondLib', 'libraryId' => 407, ), ); $key = 'testhashkey'; $this->framework->saveCachedAssets($key, $libraries); $records = $DB->get_records('h5p_libraries_cachedassets'); $this->assertCount(3, $records); } /** * Test that the correct libraries are removed from the cached assets table */ public function test_deleteCachedAssets() { global $DB; $this->resetAfterTest(); $libraries = array( array( 'machineName' => 'H5P.TestLib', 'libraryId' => 405, ), array( 'FontAwesome' => 'FontAwesome', 'libraryId' => 406, ), array( 'machineName' => 'H5P.SecondLib', 'libraryId' => 407, ), ); $key1 = 'testhashkey'; $this->framework->saveCachedAssets($key1, $libraries); $libraries = array( array( 'machineName' => 'H5P.DiffLib', 'libraryId' => 408, ), array( 'FontAwesome' => 'FontAwesome', 'libraryId' => 406, ), array( 'machineName' => 'H5P.ThirdLib', 'libraryId' => 409, ), ); $key2 = 'secondhashkey'; $this->framework->saveCachedAssets($key2, $libraries); $libraries = array( array( 'machineName' => 'H5P.AnotherDiffLib', 'libraryId' => 410, ), array( 'FontAwesome' => 'NotRelated', 'libraryId' => 411, ), array( 'machineName' => 'H5P.ForthLib', 'libraryId' => 412, ), ); $key3 = 'threeforthewin'; $this->framework->saveCachedAssets($key3, $libraries); $records = $DB->get_records('h5p_libraries_cachedassets'); $this->assertCount(9, $records); // Selecting one library id will result in all related library entries also being deleted. // Going to use the FontAwesome library id. The first two hashes should be returned. $hashes = $this->framework->deleteCachedAssets(406); $this->assertCount(2, $hashes); $index = array_search($key1, $hashes); $this->assertEquals($key1, $hashes[$index]); $index = array_search($key2, $hashes); $this->assertEquals($key2, $hashes[$index]); $index = array_search($key3, $hashes); $this->assertFalse($index); // Check that the records have been removed as well. $records = $DB->get_records('h5p_libraries_cachedassets'); $this->assertCount(3, $records); } /** * Test the behaviour of getLibraryContentCount(). */ public function test_getLibraryContentCount() { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Generate h5p related data. $data = $generator->generate_h5p_data(); // The 'MainLibrary' library data. $mainlibrary = $data->mainlib->data; // The 'Library2' library data. $library2 = $data->lib2->data; // Create new h5p content with Library2 as it's main library. $generator->create_h5p_record($library2->id); // Create new h5p content with MainLibrary as it's main library. $generator->create_h5p_record($mainlibrary->id); $countlibrarycontent = $this->framework->getLibraryContentCount(); $expected = array( "{$mainlibrary->machinename} {$mainlibrary->majorversion}.{$mainlibrary->minorversion}" => 2, "{$library2->machinename} {$library2->majorversion}.{$library2->minorversion}" => 1, ); // MainLibrary and Library1 are currently main libraries to the existing h5p contents. // Should return the number of cases where MainLibrary and Library1 are main libraries to an h5p content. $this->assertEquals($expected, $countlibrarycontent); } /** * Test the behaviour of test_libraryHasUpgrade(). * * @dataProvider libraryHasUpgrade_provider * @param array $libraryrecords Array containing data for the library creation * @param array $testlibrary Array containing the test library data * @param bool $expected The expectation whether the library is patched or not **/ public function test_libraryHasUpgrade(array $libraryrecords, array $testlibrary, bool $expected): void { $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); foreach ($libraryrecords as $library) { call_user_func_array([$generator, 'create_library_record'], $library); } $this->assertEquals($expected, $this->framework->libraryHasUpgrade($testlibrary)); } /** * Data provider for test_libraryHasUpgrade(). * * @return array */ public function libraryHasUpgrade_provider(): array { return [ 'Lower major version; Identical lower version' => [ [ ['Library', 'Lib', 2, 2], ], [ 'machineName' => 'Library', 'majorVersion' => 1, 'minorVersion' => 2 ], true, ], 'Major version identical; Lower minor version' => [ [ ['Library', 'Lib', 2, 2], ], [ 'machineName' => 'Library', 'majorVersion' => 2, 'minorVersion' => 1 ], true, ], 'Major version identical; Minor version identical' => [ [ ['Library', 'Lib', 2, 2], ], [ 'machineName' => 'Library', 'majorVersion' => 2, 'minorVersion' => 2 ], false, ], 'Major version higher; Minor version identical' => [ [ ['Library', 'Lib', 2, 2], ], [ 'machineName' => 'Library', 'majorVersion' => 3, 'minorVersion' => 2 ], false, ], 'Major version identical; Minor version newer' => [ [ ['Library', 'Lib', 2, 2], ], [ 'machineName' => 'Library', 'majorVersion' => 2, 'minorVersion' => 4 ], false, ] ]; } /** * Test the behaviour of get_latest_library_version(). */ public function test_get_latest_library_version() { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); // Create a library record. $machinename = 'TestLibrary'; $lib1 = $generator->create_library_record($machinename, 'Test', 1, 1, 2); $lib2 = $generator->create_library_record($machinename, 'Test', 1, 2, 1); $content = array( 'params' => json_encode(['param1' => 'Test']), 'library' => array( 'libraryId' => 0, 'machineName' => 'TestLibrary', ), 'disable' => 8 ); // Get the latest id (at this point, should be lib2). $latestlib = $this->framework->get_latest_library_version($machinename); $this->assertEquals($lib2->id, $latestlib->id); // Get the latest id (at this point, should be lib3). $lib3 = $generator->create_library_record($machinename, 'Test', 2, 1, 0); $latestlib = $this->framework->get_latest_library_version($machinename); $this->assertEquals($lib3->id, $latestlib->id); // Get the latest id (at this point, should be still lib3). $lib4 = $generator->create_library_record($machinename, 'Test', 1, 1, 3); $latestlib = $this->framework->get_latest_library_version($machinename); $this->assertEquals($lib3->id, $latestlib->id); // Get the latest id (at this point, should be lib5). $lib5 = $generator->create_library_record($machinename, 'Test', 2, 1, 6); $latestlib = $this->framework->get_latest_library_version($machinename); $this->assertEquals($lib5->id, $latestlib->id); } }