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.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core_h5p;
  18  
  19  use core_collator;
  20  use Moodle\H5PCore;
  21  use Moodle\H5PDisplayOptionBehaviour;
  22  
  23  // phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
  24  
  25  /**
  26   *
  27   * Test class covering the H5PFrameworkInterface interface implementation.
  28   *
  29   * @package    core_h5p
  30   * @category   test
  31   * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   * @covers     \core_h5p\framework
  34   * @runTestsInSeparateProcesses
  35   */
  36  class framework_test extends \advanced_testcase {
  37  
  38      /** @var \core_h5p\framework */
  39      private $framework;
  40  
  41      /**
  42       * Set up function for tests.
  43       */
  44      public function setUp(): void {
  45          $factory = new \core_h5p\factory();
  46          $this->framework = $factory->get_framework();
  47      }
  48  
  49      /**
  50       * Test the behaviour of getPlatformInfo().
  51       */
  52      public function test_getPlatformInfo() {
  53          global $CFG;
  54  
  55          $platforminfo = $this->framework->getPlatformInfo();
  56  
  57          $expected = array(
  58              'name' => 'Moodle',
  59              'version' => $CFG->version,
  60              'h5pVersion' => $CFG->version
  61          );
  62  
  63          $this->assertEquals($expected, $platforminfo);
  64      }
  65  
  66      /**
  67       * Test the behaviour of fetchExternalData() when the store path is not defined.
  68       *
  69       * This test is intensive and requires downloading content of an external file,
  70       * therefore it might take longer time to execute.
  71       * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
  72       */
  73      public function test_fetchExternalData_no_path_defined() {
  74  
  75          if (!PHPUNIT_LONGTEST) {
  76              $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
  77          }
  78  
  79          $this->resetAfterTest();
  80  
  81          $library = 'H5P.Accordion';
  82          // Provide a valid URL to an external H5P content.
  83          $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');
  84  
  85          // Test fetching an external H5P content without defining a path to where the file should be stored.
  86          $data = $this->framework->fetchExternalData($url, null, true);
  87  
  88          // The response should not be empty and return true if the file was successfully downloaded.
  89          $this->assertNotEmpty($data);
  90          $this->assertTrue($data);
  91  
  92          $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
  93          // The uploaded file should exist on the filesystem.
  94          $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
  95      }
  96  
  97      /**
  98       * Test the behaviour of fetchExternalData() when the store path is defined.
  99       *
 100       * This test is intensive and requires downloading content of an external file,
 101       * therefore it might take longer time to execute.
 102       * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
 103       */
 104      public function test_fetchExternalData_path_defined() {
 105          global $CFG;
 106  
 107          if (!PHPUNIT_LONGTEST) {
 108              $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
 109          }
 110  
 111          $this->resetAfterTest();
 112  
 113          $library = 'H5P.Accordion';
 114          // Provide a valid URL to an external H5P content.
 115          $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');
 116  
 117          $h5pfolderpath = $CFG->tempdir . uniqid('/h5p-');
 118  
 119          $data = $this->framework->fetchExternalData($url, null, true, $h5pfolderpath . '.h5p');
 120  
 121          // The response should not be empty and return true if the content has been successfully saved to a file.
 122          $this->assertNotEmpty($data);
 123          $this->assertTrue($data);
 124  
 125          // The uploaded file should exist on the filesystem.
 126          $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
 127      }
 128  
 129      /**
 130       * Test the behaviour of fetchExternalData() when the URL is pointing to an external file that is
 131       * not an h5p content.
 132       *
 133       * This test is intensive and requires downloading content of an external file,
 134       * therefore it might take longer time to execute.
 135       * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
 136       */
 137      public function test_fetchExternalData_url_not_h5p() {
 138  
 139          if (!PHPUNIT_LONGTEST) {
 140              // This test is intensive and requires downloading the content of an external file.
 141              $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
 142          }
 143  
 144          $this->resetAfterTest();
 145  
 146          // Provide an URL to an external file that is not an H5P content file.
 147          $url = $this->getExternalTestFileUrl('/h5pcontenttypes.json');
 148  
 149          $data = $this->framework->fetchExternalData($url, null, true);
 150  
 151          // The response should not be empty and return true if the content has been successfully saved to a file.
 152          $this->assertNotEmpty($data);
 153          $this->assertTrue($data);
 154  
 155          // The uploaded file should exist on the filesystem with it's original extension.
 156          // NOTE: The file would be later validated by the H5P Validator.
 157          $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
 158          $this->assertTrue(file_exists($h5pfolderpath . '.json'));
 159      }
 160  
 161      /**
 162       * Test the behaviour of fetchExternalData() when the URL is invalid.
 163       */
 164      public function test_fetchExternalData_url_invalid() {
 165          // Provide an invalid URL to an external file.
 166          $url = "someprotocol://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
 167  
 168          $data = $this->framework->fetchExternalData($url, null, true);
 169  
 170          // The response should be empty.
 171          $this->assertEmpty($data);
 172      }
 173  
 174      /**
 175       * Test the behaviour of setLibraryTutorialUrl().
 176       */
 177      public function test_setLibraryTutorialUrl() {
 178          global $DB;
 179  
 180          $this->resetAfterTest();
 181  
 182          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 183  
 184          // Create several libraries records.
 185          $lib1 = $generator->create_library_record('Library1', 'Lib1', 1, 0, 1, '', null, 'http://tutorial1.org',
 186              'http://example.org');
 187          $lib2 = $generator->create_library_record('Library2', 'Lib2', 2, 0, 1, '', null, 'http://tutorial2.org');
 188          $lib3 = $generator->create_library_record('Library3', 'Lib3', 3, 0);
 189  
 190          // Check only lib1 tutorial URL is updated.
 191          $url = 'https://newtutorial.cat';
 192          $this->framework->setLibraryTutorialUrl($lib1->machinename, $url);
 193  
 194          $libraries = $DB->get_records('h5p_libraries');
 195          $this->assertEquals($libraries[$lib1->id]->tutorial, $url);
 196          $this->assertNotEquals($libraries[$lib2->id]->tutorial, $url);
 197  
 198          // Check lib1 tutorial URL is set to null.
 199          $this->framework->setLibraryTutorialUrl($lib1->machinename, null);
 200  
 201          $libraries = $DB->get_records('h5p_libraries');
 202          $this->assertCount(3, $libraries);
 203          $this->assertNull($libraries[$lib1->id]->tutorial);
 204  
 205          // Check no tutorial URL is set if library name doesn't exist.
 206          $this->framework->setLibraryTutorialUrl('Unexisting library', $url);
 207  
 208          $libraries = $DB->get_records('h5p_libraries');
 209          $this->assertCount(3, $libraries);
 210          $this->assertNull($libraries[$lib1->id]->tutorial);
 211          $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org');
 212          $this->assertNull($libraries[$lib3->id]->tutorial);
 213  
 214          // Check tutorial is set as expected when it was null.
 215          $this->framework->setLibraryTutorialUrl($lib3->machinename, $url);
 216  
 217          $libraries = $DB->get_records('h5p_libraries');
 218          $this->assertEquals($libraries[$lib3->id]->tutorial, $url);
 219          $this->assertNull($libraries[$lib1->id]->tutorial);
 220          $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org');
 221      }
 222  
 223      /**
 224       * Test the behaviour of setErrorMessage().
 225       */
 226      public function test_setErrorMessage() {
 227          // Set an error message and an error code.
 228          $message = "Error message";
 229          $code = '404';
 230  
 231          // Set an error message.
 232          $this->framework->setErrorMessage($message, $code);
 233  
 234          // Get the error messages.
 235          $errormessages = $this->framework->getMessages('error');
 236  
 237          $expected = new \stdClass();
 238          $expected->code = 404;
 239          $expected->message = 'Error message';
 240  
 241          $this->assertEquals($expected, $errormessages[0]);
 242      }
 243  
 244      /**
 245       * Test the behaviour of setInfoMessage().
 246       */
 247      public function test_setInfoMessage() {
 248          $message = "Info message";
 249  
 250          // Set an info message.
 251          $this->framework->setInfoMessage($message);
 252  
 253          // Get the info messages.
 254          $infomessages = $this->framework->getMessages('info');
 255  
 256          $expected = 'Info message';
 257  
 258          $this->assertEquals($expected, $infomessages[0]);
 259      }
 260  
 261      /**
 262       * Test the behaviour of getMessages() when requesting the info messages.
 263       */
 264      public function test_getMessages_info() {
 265          // Set an info message.
 266          $this->framework->setInfoMessage("Info message");
 267          // Set an error message.
 268          $this->framework->setErrorMessage("Error message 1", 404);
 269  
 270          // Get the info messages.
 271          $infomessages = $this->framework->getMessages('info');
 272  
 273          $expected = 'Info message';
 274  
 275          // Make sure that only the info message has been returned.
 276          $this->assertCount(1, $infomessages);
 277          $this->assertEquals($expected, $infomessages[0]);
 278  
 279          $infomessages = $this->framework->getMessages('info');
 280  
 281          // Make sure the info messages have now been removed.
 282          $this->assertEmpty($infomessages);
 283      }
 284  
 285      /**
 286       * Test the behaviour of getMessages() when requesting the error messages.
 287       */
 288      public function test_getMessages_error() {
 289          // Set an info message.
 290          $this->framework->setInfoMessage("Info message");
 291          // Set an error message.
 292          $this->framework->setErrorMessage("Error message 1", 404);
 293          // Set another error message.
 294          $this->framework->setErrorMessage("Error message 2", 403);
 295  
 296          // Get the error messages.
 297          $errormessages = $this->framework->getMessages('error');
 298  
 299          // Make sure that only the error messages are being returned.
 300          $this->assertEquals(2, count($errormessages));
 301  
 302          $expected1 = (object) [
 303              'code' => 404,
 304              'message' => 'Error message 1'
 305          ];
 306  
 307          $expected2 = (object) [
 308              'code' => 403,
 309              'message' => 'Error message 2'
 310          ];
 311  
 312          $this->assertEquals($expected1, $errormessages[0]);
 313          $this->assertEquals($expected2, $errormessages[1]);
 314  
 315          $errormessages = $this->framework->getMessages('error');
 316  
 317          // Make sure the info messages have now been removed.
 318          $this->assertEmpty($errormessages);
 319      }
 320  
 321      /**
 322       * Test the behaviour of t() when translating existing string that does not require any arguments.
 323       */
 324      public function test_t_existing_string_no_args() {
 325          // Existing language string without passed arguments.
 326          $translation = $this->framework->t('No copyright information available for this content.');
 327  
 328          // Make sure the string translation has been returned.
 329          $this->assertEquals('No copyright information available for this content.', $translation);
 330      }
 331  
 332      /**
 333       * Test the behaviour of t() when translating existing string that does require parameters.
 334       */
 335      public function test_t_existing_string_args() {
 336          // Existing language string with passed arguments.
 337          $translation = $this->framework->t('Illegal option %option in %library',
 338              ['%option' => 'example', '%library' => 'Test library']);
 339  
 340          // Make sure the string translation has been returned.
 341          $this->assertEquals('Illegal option example in Test library', $translation);
 342      }
 343  
 344      /**
 345       * Test the behaviour of t() when translating non-existent string.
 346       */
 347      public function test_t_non_existent_string() {
 348          // Non-existing language string.
 349          $message = 'Random message %option';
 350  
 351          $translation = $this->framework->t($message);
 352  
 353          // Make sure a debugging message is triggered.
 354          $this->assertDebuggingCalled("String translation cannot be found. Please add a string definition for '" .
 355              $message . "' in the core_h5p component.");
 356          // As the string does not exist in the mapping array, make sure the passed message is returned.
 357          $this->assertEquals($message, $translation);
 358      }
 359  
 360      /**
 361       * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
 362       * the folder name is parsable.
 363       **/
 364      public function test_getLibraryFileUrl() {
 365          global $CFG;
 366  
 367          $this->resetAfterTest();
 368  
 369          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 370          // Create a library record.
 371          $lib = $generator->create_library_record('Library', 'Lib', 1, 1);
 372  
 373          $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/library.json";
 374  
 375          // Get the URL of a file from an existing library. The provided folder name is parsable.
 376          $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');
 377  
 378          // Make sure the expected URL is returned.
 379          $this->assertEquals($expected, $actual);
 380      }
 381  
 382      /**
 383       * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a non-existent library and
 384       * the folder name is parsable.
 385       **/
 386      public function test_getLibraryFileUrl_non_existent_library() {
 387          $this->resetAfterTest();
 388  
 389          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 390          // Create a library record.
 391          $generator->create_library_record('Library', 'Lib', 1, 1);
 392  
 393          // Get the URL of a file from a non-existent library. The provided folder name is parsable.
 394          $actual = $this->framework->getLibraryFileUrl('Library2-1.1', 'library.json');
 395  
 396          // Make sure a debugging message is triggered.
 397          $this->assertDebuggingCalled('The library "Library2-1.1" does not exist.');
 398  
 399          // Make sure that an URL is not returned.
 400          $this->assertEquals(null, $actual);
 401      }
 402  
 403      /**
 404       * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
 405       * the folder name is not parsable.
 406       **/
 407      public function test_getLibraryFileUrl_not_parsable_folder_name() {
 408          $this->resetAfterTest();
 409  
 410          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 411          // Create a library record.
 412          $generator->create_library_record('Library', 'Lib', 1, 1);
 413  
 414          // Get the URL of a file from an existing library. The provided folder name is not parsable.
 415          $actual = $this->framework->getLibraryFileUrl('Library1.1', 'library.json');
 416  
 417          // Make sure a debugging message is triggered.
 418          $this->assertDebuggingCalled(
 419              'The provided string value "Library1.1" is not a valid name for a library folder.');
 420  
 421          // Make sure that an URL is not returned.
 422          $this->assertEquals(null, $actual);
 423      }
 424  
 425      /**
 426       * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
 427       * versions and the folder name is parsable.
 428       **/
 429      public function test_getLibraryFileUrl_library_has_multiple_versions() {
 430          global $CFG;
 431  
 432          $this->resetAfterTest();
 433  
 434          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 435          // Create library records with a different minor version.
 436          $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1);
 437          $lib2 = $generator->create_library_record('Library', 'Lib', 1, 3);
 438  
 439          $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.3/library.json";
 440  
 441          // Get the URL of a file from an existing library (Library 1.3). The provided folder name is parsable.
 442          $actual = $this->framework->getLibraryFileUrl('Library-1.3', 'library.json');
 443  
 444          // Make sure the proper URL (from the requested library version) is returned.
 445          $this->assertEquals($expected, $actual);
 446      }
 447  
 448      /**
 449       * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
 450       * patch versions and the folder name is parsable.
 451       **/
 452      public function test_getLibraryFileUrl_library_has_multiple_patch_versions() {
 453          global $CFG;
 454  
 455          $this->resetAfterTest();
 456  
 457          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 458          // Create library records with a different patch version.
 459          $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
 460          $lib2 = $generator->create_library_record('Library', 'Lib', 1, 1, 4);
 461          $lib3 = $generator->create_library_record('Library', 'Lib', 1, 1, 3);
 462  
 463          $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.1/library.json";
 464  
 465          // Get the URL of a file from an existing library. The provided folder name is parsable.
 466          $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');
 467  
 468          // Make sure the proper URL (from the latest library patch) is returned.
 469          $this->assertEquals($expected, $actual);
 470      }
 471  
 472      /**
 473       * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a sub-folder
 474       * of an existing library and the folder name is parsable.
 475       **/
 476      public function test_getLibraryFileUrl_library_subfolder() {
 477          global $CFG;
 478  
 479          $this->resetAfterTest();
 480  
 481          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 482          // Create a library record.
 483          $lib = $generator->create_library_record('Library', 'Lib', 1, 1);
 484  
 485          $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/css/example.css";
 486  
 487          // Get the URL of a file from a sub-folder from an existing library. The provided folder name is parsable.
 488          $actual = $this->framework->getLibraryFileUrl('Library-1.1/css', 'example.css');
 489  
 490          // Make sure the proper URL is returned.
 491          $this->assertEquals($expected, $actual);
 492      }
 493  
 494      /**
 495       * Test the behaviour of loadAddons().
 496       */
 497      public function test_loadAddons() {
 498          $this->resetAfterTest();
 499  
 500          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 501  
 502          // Create a Library addon (1.1).
 503          $generator->create_library_record('Library', 'Lib', 1, 1, 2,
 504              '', '/regex1/');
 505          // Create a Library addon (1.3).
 506          $generator->create_library_record('Library', 'Lib', 1, 3, 2,
 507              '', '/regex2/');
 508          // Create a Library addon (1.2).
 509          $generator->create_library_record('Library', 'Lib', 1, 2, 2,
 510              '', '/regex3/');
 511          // Create a Library1 addon (1.2)
 512          $generator->create_library_record('Library1', 'Lib1', 1, 2, 2,
 513              '', '/regex11/');
 514  
 515          // Load the latest version of each addon.
 516          $addons = $this->framework->loadAddons();
 517  
 518          // The addons array should return 2 results (Library and Library1 addon).
 519          $this->assertCount(2, $addons);
 520  
 521          // Ensure the addons array is consistently ordered before asserting their contents.
 522          core_collator::asort_array_of_arrays_by_key($addons, 'machineName');
 523          [$addonone, $addontwo] = array_values($addons);
 524  
 525          // Make sure the version 1.3 is the latest 'Library' addon version.
 526          $this->assertEquals('Library', $addonone['machineName']);
 527          $this->assertEquals(1, $addonone['majorVersion']);
 528          $this->assertEquals(3, $addonone['minorVersion']);
 529  
 530          // Make sure the version 1.2 is the latest 'Library1' addon version.
 531          $this->assertEquals('Library1', $addontwo['machineName']);
 532          $this->assertEquals(1, $addontwo['majorVersion']);
 533          $this->assertEquals(2, $addontwo['minorVersion']);
 534      }
 535  
 536      /**
 537       * Test the behaviour of loadLibraries().
 538       */
 539      public function test_loadLibraries() {
 540          $this->resetAfterTest();
 541  
 542          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 543  
 544          // Generate h5p related data.
 545          $generator->generate_h5p_data();
 546  
 547          // Load all libraries.
 548          $libraries = $this->framework->loadLibraries();
 549  
 550          // Make sure all libraries are returned.
 551          $this->assertNotEmpty($libraries);
 552          $this->assertCount(6, $libraries);
 553          $this->assertEquals('MainLibrary', $libraries['MainLibrary'][0]->machine_name);
 554          $this->assertEquals('1', $libraries['MainLibrary'][0]->major_version);
 555          $this->assertEquals('0', $libraries['MainLibrary'][0]->minor_version);
 556          $this->assertEquals('1', $libraries['MainLibrary'][0]->patch_version);
 557      }
 558  
 559      /**
 560       * Test the behaviour of test_getLibraryId() when requesting an existing machine name.
 561       */
 562      public function test_getLibraryId_existing_machine_name() {
 563          $this->resetAfterTest();
 564  
 565          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 566  
 567          // Create a library.
 568          $lib = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
 569  
 570          // Request the library ID of the library with machine name 'Library'.
 571          $libraryid = $this->framework->getLibraryId('Library');
 572  
 573          // Make sure the library ID is being returned.
 574          $this->assertNotFalse($libraryid);
 575          $this->assertEquals($lib->id, $libraryid);
 576      }
 577  
 578      /**
 579       * Test the behaviour of test_getLibraryId() when requesting a non-existent machine name.
 580       */
 581      public function test_getLibraryId_non_existent_machine_name() {
 582          $this->resetAfterTest();
 583  
 584          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 585  
 586          // Create a library.
 587          $generator->create_library_record('Library', 'Lib', 1, 1, 2);
 588  
 589          // Request the library ID of the library with machinename => 'TestLibrary' (non-existent).
 590          $libraryid = $this->framework->getLibraryId('TestLibrary');
 591  
 592          // Make sure the library ID not being returned.
 593          $this->assertFalse($libraryid);
 594      }
 595  
 596      /**
 597       * Test the behaviour of test_getLibraryId() when requesting a non-existent major version.
 598       */
 599      public function test_getLibraryId_non_existent_major_version() {
 600          $this->resetAfterTest();
 601  
 602          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 603  
 604          // Create a library.
 605          $generator->create_library_record('Library', 'Lib', 1, 1, 2);
 606  
 607          // Request the library ID of the library with machine name => 'Library', majorversion => 2 (non-existent).
 608          $libraryid = $this->framework->getLibraryId('Library', 2);
 609  
 610          // Make sure the library ID not being returned.
 611          $this->assertFalse($libraryid);
 612      }
 613  
 614      /**
 615       * Test the behaviour of test_getLibraryId() when requesting a non-existent minor version.
 616       */
 617      public function test_getLibraryId_non_existent_minor_version() {
 618          $this->resetAfterTest();
 619  
 620          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 621  
 622          // Create a library.
 623          $generator->create_library_record('Library', 'Lib', 1, 1, 2);
 624  
 625          // Request the library ID of the library with machine name => 'Library',
 626          // majorversion => 1,  minorversion => 2 (non-existent).
 627          $libraryid = $this->framework->getLibraryId('Library', 1, 2);
 628  
 629          // Make sure the library ID not being returned.
 630          $this->assertFalse($libraryid);
 631      }
 632  
 633      /**
 634       * Test the behaviour of isPatchedLibrary().
 635       *
 636       * @dataProvider isPatchedLibrary_provider
 637       * @param array $libraryrecords Array containing data for the library creation
 638       * @param array $testlibrary Array containing the test library data
 639       * @param bool $expected The expectation whether the library is patched or not
 640       **/
 641      public function test_isPatchedLibrary(array $libraryrecords, array $testlibrary, bool $expected): void {
 642          $this->resetAfterTest();
 643  
 644          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 645  
 646          foreach ($libraryrecords as $library) {
 647              call_user_func_array([$generator, 'create_library_record'], $library);
 648          }
 649  
 650          $this->assertEquals($expected, $this->framework->isPatchedLibrary($testlibrary));
 651      }
 652  
 653      /**
 654       * Data provider for test_isPatchedLibrary().
 655       *
 656       * @return array
 657       */
 658      public function isPatchedLibrary_provider(): array {
 659          return [
 660              'Unpatched library. No different versioning' => [
 661                  [
 662                      ['TestLibrary', 'Test', 1, 1, 2],
 663                  ],
 664                  [
 665                      'machineName' => 'TestLibrary',
 666                      'majorVersion' => 1,
 667                      'minorVersion' => 1,
 668                      'patchVersion' => 2
 669                  ],
 670                  false,
 671              ],
 672              'Major version identical; Minor version identical; Patch version newer' => [
 673                  [
 674                      ['TestLibrary', 'Test', 1, 1, 2],
 675                  ],
 676                  [
 677                      'machineName' => 'TestLibrary',
 678                      'majorVersion' => 1,
 679                      'minorVersion' => 1,
 680                      'patchVersion' => 3
 681                  ],
 682                  true,
 683              ],
 684              'Major version identical; Minor version newer; Patch version newer' => [
 685                  [
 686                      ['TestLibrary', 'Test', 1, 1, 2],
 687                  ],
 688                  [
 689                      'machineName' => 'TestLibrary',
 690                      'majorVersion' => 1,
 691                      'minorVersion' => 2,
 692                      'patchVersion' => 3
 693                  ],
 694                  false,
 695              ],
 696              'Major version identical; Minor version identical; Patch version older' => [
 697                  [
 698                      ['TestLibrary', 'Test', 1, 1, 2],
 699                  ],
 700                  [
 701                      'machineName' => 'TestLibrary',
 702                      'majorVersion' => 1,
 703                      'minorVersion' => 1,
 704                      'patchVersion' => 1
 705                  ],
 706                  false,
 707              ],
 708              'Major version identical; Minor version newer; Patch version older' => [
 709                  [
 710                      ['TestLibrary', 'Test', 1, 1, 2],
 711                  ],
 712                  [
 713                      'machineName' => 'TestLibrary',
 714                      'majorVersion' => 1,
 715                      'minorVersion' => 2,
 716                      'patchVersion' => 1
 717                  ],
 718                  false,
 719              ],
 720              'Major version newer; Minor version identical; Patch version older' => [
 721                  [
 722                      ['TestLibrary', 'Test', 1, 1, 2],
 723                  ],
 724                  [
 725                      'machineName' => 'TestLibrary',
 726                      'majorVersion' => 2,
 727                      'minorVersion' => 1,
 728                      'patchVersion' => 1
 729                  ],
 730                  false,
 731              ],
 732              'Major version newer; Minor version identical; Patch version newer' => [
 733                  [
 734                      ['TestLibrary', 'Test', 1, 1, 2],
 735                  ],
 736                  [
 737                      'machineName' => 'TestLibrary',
 738                      'majorVersion' => 2,
 739                      'minorVersion' => 1,
 740                      'patchVersion' => 3
 741                  ],
 742                  false,
 743              ],
 744  
 745              'Major version older; Minor version identical; Patch version older' => [
 746                  [
 747                      ['TestLibrary', 'Test', 1, 1, 2],
 748                  ],
 749                  [
 750                      'machineName' => 'TestLibrary',
 751                      'majorVersion' => 0,
 752                      'minorVersion' => 1,
 753                      'patchVersion' => 1
 754                  ],
 755                  false,
 756              ],
 757              'Major version older; Minor version identical; Patch version newer' => [
 758                  [
 759                      ['TestLibrary', 'Test', 1, 1, 2],
 760                  ],
 761                  [
 762                      'machineName' => 'TestLibrary',
 763                      'majorVersion' => 0,
 764                      'minorVersion' => 1,
 765                      'patchVersion' => 3
 766                  ],
 767                  false,
 768              ],
 769          ];
 770      }
 771  
 772      /**
 773       * Test the behaviour of isInDevMode().
 774       */
 775      public function test_isInDevMode() {
 776          $isdevmode = $this->framework->isInDevMode();
 777  
 778          $this->assertFalse($isdevmode);
 779      }
 780  
 781      /**
 782       * Test the behaviour of mayUpdateLibraries().
 783       */
 784      public function test_mayUpdateLibraries(): void {
 785          global $DB;
 786  
 787          $this->resetAfterTest();
 788  
 789          // Create some users.
 790          $contextsys = \context_system::instance();
 791          $user = $this->getDataGenerator()->create_user();
 792          $admin = get_admin();
 793          $managerrole = $DB->get_record('role', ['shortname' => 'manager'], '*', MUST_EXIST);
 794          $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
 795          $manager = $this->getDataGenerator()->create_user();
 796          role_assign($managerrole->id, $manager->id, $contextsys);
 797  
 798          // Create a course with a label and enrol the user.
 799          $course = $this->getDataGenerator()->create_course();
 800          $label = $this->getDataGenerator()->create_module('label', ['course' => $course->id]);
 801          list(, $labelcm) = get_course_and_cm_from_instance($label->id, 'label');
 802          $contextlabel = \context_module::instance($labelcm->id);
 803          $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
 804  
 805          // Create the .h5p file.
 806          $path = __DIR__ . '/fixtures/h5ptest.zip';
 807  
 808          // Admin and manager should have permission to update libraries.
 809          $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextsys);
 810          $this->framework->set_file($file);
 811          $mayupdatelib = $this->framework->mayUpdateLibraries();
 812          $this->assertTrue($mayupdatelib);
 813  
 814          $file = helper::create_fake_stored_file_from_path($path, $manager->id, $contextsys);
 815          $this->framework->set_file($file);
 816          $mayupdatelib = $this->framework->mayUpdateLibraries();
 817          $this->assertTrue($mayupdatelib);
 818  
 819          // By default, normal user hasn't permission to update libraries (in both contexts, system and module label).
 820          $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
 821          $this->framework->set_file($file);
 822          $mayupdatelib = $this->framework->mayUpdateLibraries();
 823          $this->assertFalse($mayupdatelib);
 824  
 825          $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
 826          $this->framework->set_file($file);
 827          $mayupdatelib = $this->framework->mayUpdateLibraries();
 828          $this->assertFalse($mayupdatelib);
 829  
 830          // If the current user (admin) can update libraries, the method should return true (even if the file userid hasn't the
 831          // required capabilility in the file context).
 832          $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextlabel);
 833          $this->framework->set_file($file);
 834          $mayupdatelib = $this->framework->mayUpdateLibraries();
 835          $this->assertTrue($mayupdatelib);
 836  
 837          // If the update capability is assigned to the user, they should be able to update the libraries (only in the context
 838          // where the capability has been assigned).
 839          $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
 840          $this->framework->set_file($file);
 841          $mayupdatelib = $this->framework->mayUpdateLibraries();
 842          $this->assertFalse($mayupdatelib);
 843          assign_capability('moodle/h5p:updatelibraries', CAP_ALLOW, $studentrole->id, $contextlabel);
 844          $mayupdatelib = $this->framework->mayUpdateLibraries();
 845          $this->assertTrue($mayupdatelib);
 846          $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
 847          $this->framework->set_file($file);
 848          $mayupdatelib = $this->framework->mayUpdateLibraries();
 849          $this->assertFalse($mayupdatelib);
 850      }
 851  
 852      /**
 853       * Test the behaviour of get_file() and set_file().
 854       */
 855      public function test_get_file(): void {
 856          $this->resetAfterTest();
 857  
 858          // Create some users.
 859          $contextsys = \context_system::instance();
 860          $user = $this->getDataGenerator()->create_user();
 861  
 862          // The H5P file.
 863          $path = __DIR__ . '/fixtures/h5ptest.zip';
 864  
 865          // An error should be raised when it's called before initialitzing it.
 866          $this->expectException('coding_exception');
 867          $this->expectExceptionMessage('Using get_file() before file is set');
 868          $this->framework->get_file();
 869  
 870          // Check the value when only path and user are set.
 871          $file = helper::create_fake_stored_file_from_path($path, $user->id);
 872          $this->framework->set_file($file);
 873          $file = $this->framework->get_file();
 874          $this->assertEquals($user->id, $$file->get_userid());
 875          $this->assertEquals($contextsys->id, $file->get_contextid());
 876  
 877          // Check the value when also the context is set.
 878          $course = $this->getDataGenerator()->create_course();
 879          $contextcourse = \context_course::instance($course->id);
 880          $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextcourse);
 881          $this->framework->set_file($file);
 882          $file = $this->framework->get_file();
 883          $this->assertEquals($user->id, $$file->get_userid());
 884          $this->assertEquals($contextcourse->id, $file->get_contextid());
 885      }
 886  
 887      /**
 888       * Test the behaviour of saveLibraryData() when saving data for a new library.
 889       */
 890      public function test_saveLibraryData_new_library() {
 891          global $DB;
 892  
 893          $this->resetAfterTest();
 894  
 895          $librarydata = array(
 896              'title' => 'Test',
 897              'machineName' => 'TestLibrary',
 898              'majorVersion' => '1',
 899              'minorVersion' => '0',
 900              'patchVersion' => '2',
 901              'runnable' => 1,
 902              'fullscreen' => 1,
 903              'preloadedJs' => array(
 904                  array(
 905                      'path' => 'js/name.min.js'
 906                  )
 907              ),
 908              'preloadedCss' => array(
 909                  array(
 910                      'path' => 'css/name.css'
 911                  )
 912              ),
 913              'dropLibraryCss' => array(
 914                  array(
 915                      'machineName' => 'Name2'
 916                  )
 917              )
 918          );
 919  
 920          // Create a new library.
 921          $this->framework->saveLibraryData($librarydata);
 922  
 923          $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
 924  
 925          // Make sure the library data was properly saved.
 926          $this->assertNotEmpty($library);
 927          $this->assertNotEmpty($librarydata['libraryId']);
 928          $this->assertEquals($librarydata['title'], $library->title);
 929          $this->assertEquals($librarydata['machineName'], $library->machinename);
 930          $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
 931          $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
 932          $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
 933          $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
 934          $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
 935          $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
 936      }
 937  
 938      /**
 939       * Test the behaviour of saveLibraryData() when saving (updating) data for an existing library.
 940       */
 941      public function test_saveLibraryData_existing_library() {
 942          global $DB;
 943  
 944          $this->resetAfterTest();
 945  
 946          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 947  
 948          // Create a library record.
 949          $library = $generator->create_library_record('TestLibrary', 'Test', 1, 0, 2);
 950  
 951          $librarydata = array(
 952              'libraryId' => $library->id,
 953              'title' => 'Test1',
 954              'machineName' => 'TestLibrary',
 955              'majorVersion' => '1',
 956              'minorVersion' => '2',
 957              'patchVersion' => '2',
 958              'runnable' => 1,
 959              'fullscreen' => 1,
 960              'preloadedJs' => array(
 961                  array(
 962                      'path' => 'js/name.min.js'
 963                  )
 964              ),
 965              'preloadedCss' => array(
 966                  array(
 967                      'path' => 'css/name.css'
 968                  )
 969              ),
 970              'dropLibraryCss' => array(
 971                  array(
 972                      'machineName' => 'Name2'
 973                  )
 974              )
 975          );
 976  
 977          // Update the library.
 978          $this->framework->saveLibraryData($librarydata, false);
 979  
 980          $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
 981  
 982          // Make sure the library data was properly updated.
 983          $this->assertNotEmpty($library);
 984          $this->assertNotEmpty($librarydata['libraryId']);
 985          $this->assertEquals($librarydata['title'], $library->title);
 986          $this->assertEquals($librarydata['machineName'], $library->machinename);
 987          $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
 988          $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
 989          $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
 990          $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
 991          $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
 992          $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
 993      }
 994  
 995      /**
 996       * Test the behaviour of insertContent().
 997       */
 998      public function test_insertContent() {
 999          global $DB;
1000  
1001          $this->resetAfterTest();
1002  
1003          $content = array(
1004              'params' => json_encode(['param1' => 'Test']),
1005              'library' => array(
1006                  'libraryId' => 1
1007              ),
1008              'disable' => 8
1009          );
1010  
1011          // Insert h5p content.
1012          $contentid = $this->framework->insertContent($content);
1013  
1014          // Get the entered content from the db.
1015          $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
1016  
1017          // Make sure the h5p content was properly inserted.
1018          $this->assertNotEmpty($dbcontent);
1019          $this->assertEquals($content['params'], $dbcontent->jsoncontent);
1020          $this->assertEquals($content['library']['libraryId'], $dbcontent->mainlibraryid);
1021          $this->assertEquals($content['disable'], $dbcontent->displayoptions);
1022      }
1023  
1024      /**
1025       * Test the behaviour of insertContent().
1026       */
1027      public function test_insertContent_latestlibrary() {
1028          global $DB;
1029  
1030          $this->resetAfterTest();
1031  
1032          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1033          // Create a library record.
1034          $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1035  
1036          $content = array(
1037              'params' => json_encode(['param1' => 'Test']),
1038              'library' => array(
1039                  'libraryId' => 0,
1040                  'machineName' => 'TestLibrary',
1041              ),
1042              'disable' => 8
1043          );
1044  
1045          // Insert h5p content.
1046          $contentid = $this->framework->insertContent($content);
1047  
1048          // Get the entered content from the db.
1049          $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
1050  
1051          // Make sure the h5p content was properly inserted.
1052          $this->assertNotEmpty($dbcontent);
1053          $this->assertEquals($content['params'], $dbcontent->jsoncontent);
1054          $this->assertEquals($content['disable'], $dbcontent->displayoptions);
1055          // As the libraryId was empty, the latest library has been used.
1056          $this->assertEquals($lib->id, $dbcontent->mainlibraryid);
1057      }
1058  
1059      /**
1060       * Test the behaviour of updateContent().
1061       */
1062      public function test_updateContent() {
1063          global $DB;
1064  
1065          $this->resetAfterTest();
1066  
1067          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1068  
1069          // Create a library record.
1070          $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1071  
1072          // Create an h5p content with 'TestLibrary' as it's main library.
1073          $contentid = $generator->create_h5p_record($lib->id);
1074  
1075          $content = array(
1076              'id' => $contentid,
1077              'params' => json_encode(['param2' => 'Test2']),
1078              'library' => array(
1079                  'libraryId' => $lib->id
1080              ),
1081              'disable' => 8
1082          );
1083  
1084          // Update the h5p content.
1085          $this->framework->updateContent($content);
1086  
1087          $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]);
1088  
1089          // Make sure the h5p content was properly updated.
1090          $this->assertNotEmpty($h5pcontent);
1091          $this->assertEquals($content['params'], $h5pcontent->jsoncontent);
1092          $this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid);
1093          $this->assertEquals($content['disable'], $h5pcontent->displayoptions);
1094      }
1095  
1096      /**
1097       * Test the behaviour of updateContent() with metadata.
1098       *
1099       * @covers ::updateContent
1100       */
1101      public function test_updateContent_withmetadata(): void {
1102          global $DB;
1103  
1104          $this->resetAfterTest();
1105  
1106          /** @var \core_h5p_generator $generator */
1107          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1108  
1109          // Create a library record.
1110          $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1111  
1112          // Create an h5p content with 'TestLibrary' as it's main library.
1113          $contentid = $generator->create_h5p_record($lib->id);
1114  
1115          $params = ['param2' => 'Test2'];
1116          $metadata = [
1117              'license' => 'CC BY',
1118              'licenseVersion' => '4.0',
1119              'yearFrom' => 2000,
1120              'yearTo' => 2023,
1121              'defaultLanguage' => 'ca',
1122          ];
1123          $content = [
1124              'id' => $contentid,
1125              'params' => json_encode($params),
1126              'library' => [
1127                  'libraryId' => $lib->id,
1128              ],
1129              'disable' => 8,
1130              'metadata' => $metadata,
1131          ];
1132  
1133          // Update the h5p content.
1134          $this->framework->updateContent($content);
1135  
1136          $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]);
1137  
1138          // Make sure the h5p content was properly updated.
1139          $this->assertNotEmpty($h5pcontent);
1140          $this->assertEquals(json_encode(array_merge($params, ['metadata' => $metadata])), $h5pcontent->jsoncontent);
1141          $this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid);
1142          $this->assertEquals($content['disable'], $h5pcontent->displayoptions);
1143      }
1144  
1145      /**
1146       * Test the behaviour of saveLibraryDependencies().
1147       */
1148      public function test_saveLibraryDependencies() {
1149          global $DB;
1150  
1151          $this->resetAfterTest();
1152  
1153          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1154  
1155          // Create a library 'Library'.
1156          $library = $generator->create_library_record('Library', 'Title');
1157          // Create a library 'DependencyLibrary1'.
1158          $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1159          // Create a library 'DependencyLibrary2'.
1160          $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1161  
1162          $dependencies = array(
1163              array(
1164                  'machineName' => $dependency1->machinename,
1165                  'majorVersion' => $dependency1->majorversion,
1166                  'minorVersion' => $dependency1->minorversion
1167              ),
1168              array(
1169                  'machineName' => $dependency2->machinename,
1170                  'majorVersion' => $dependency2->majorversion,
1171                  'minorVersion' => $dependency2->minorversion
1172              ),
1173          );
1174  
1175          // Set 'DependencyLibrary1' and 'DependencyLibrary2' as library dependencies of 'Library'.
1176          $this->framework->saveLibraryDependencies($library->id, $dependencies, 'preloaded');
1177  
1178          $libdependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library->id], 'id ASC');
1179  
1180          // Make sure the library dependencies for 'Library' are properly set.
1181          $this->assertEquals(2, count($libdependencies));
1182          $this->assertEquals($dependency1->id, reset($libdependencies)->requiredlibraryid);
1183          $this->assertEquals($dependency2->id, end($libdependencies)->requiredlibraryid);
1184      }
1185  
1186      /**
1187       * Test the behaviour of deleteContentData().
1188       */
1189      public function test_deleteContentData() {
1190          global $DB;
1191  
1192          $this->resetAfterTest();
1193  
1194          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1195  
1196          // Generate some h5p related data.
1197          $data = $generator->generate_h5p_data();
1198          $h5pid = $data->h5pcontent->h5pid;
1199  
1200          $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1201          // Make sure the particular h5p content exists in the DB.
1202          $this->assertNotEmpty($h5pcontent);
1203  
1204          // Get the h5p content libraries from the DB.
1205          $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1206  
1207          // Make sure the content libraries exists in the DB.
1208          $this->assertNotEmpty($h5pcontentlibraries);
1209          $this->assertCount(5, $h5pcontentlibraries);
1210  
1211          // Delete the h5p content and it's related data.
1212          $this->framework->deleteContentData($h5pid);
1213  
1214          $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1215          $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1216  
1217          // The particular h5p content should no longer exist in the db.
1218          $this->assertEmpty($h5pcontent);
1219          // The particular content libraries should no longer exist in the db.
1220          $this->assertEmpty($h5pcontentlibraries);
1221      }
1222  
1223      /**
1224       * Test the behaviour of deleteLibraryUsage().
1225       */
1226      public function test_deleteLibraryUsage() {
1227          global $DB;
1228  
1229          $this->resetAfterTest();
1230  
1231          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1232  
1233          // Generate some h5p related data.
1234          $data = $generator->generate_h5p_data();
1235          $h5pid = $data->h5pcontent->h5pid;
1236  
1237          // Get the h5p content libraries from the DB.
1238          $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1239  
1240          // The particular h5p content should have 5 content libraries.
1241          $this->assertNotEmpty($h5pcontentlibraries);
1242          $this->assertCount(5, $h5pcontentlibraries);
1243  
1244          // Delete the h5p content and it's related data.
1245          $this->framework->deleteLibraryUsage($h5pid);
1246  
1247          // Get the h5p content libraries from the DB.
1248          $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1249  
1250          // The particular h5p content libraries should no longer exist in the db.
1251          $this->assertEmpty($h5pcontentlibraries);
1252      }
1253  
1254      /**
1255       * Test the behaviour of test_saveLibraryUsage().
1256       */
1257      public function test_saveLibraryUsage() {
1258          global $DB;
1259  
1260          $this->resetAfterTest();
1261  
1262          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1263  
1264          // Create a library 'Library'.
1265          $library = $generator->create_library_record('Library', 'Title');
1266          // Create a library 'DependencyLibrary1'.
1267          $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1268          // Create a library 'DependencyLibrary2'.
1269          $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1270          // Create an h5p content with 'Library' as it's main library.
1271          $contentid = $generator->create_h5p_record($library->id);
1272  
1273          $dependencies = array(
1274              array(
1275                  'library' => array(
1276                      'libraryId' => $dependency1->id,
1277                      'machineName' => $dependency1->machinename,
1278                      'dropLibraryCss' => $dependency1->droplibrarycss
1279                  ),
1280                  'type' => 'preloaded',
1281                  'weight' => 1
1282              ),
1283              array(
1284                  'library' => array(
1285                      'libraryId' => $dependency2->id,
1286                      'machineName' => $dependency2->machinename,
1287                      'dropLibraryCss' => $dependency2->droplibrarycss
1288                  ),
1289                  'type' => 'preloaded',
1290                  'weight' => 2
1291              ),
1292          );
1293  
1294          // Save 'DependencyLibrary1' and 'DependencyLibrary2' as h5p content libraries.
1295          $this->framework->saveLibraryUsage($contentid, $dependencies);
1296  
1297          // Get the h5p content libraries from the DB.
1298          $libdependencies = $DB->get_records('h5p_contents_libraries', ['h5pid' => $contentid], 'id ASC');
1299  
1300          // Make sure that 'DependencyLibrary1' and 'DependencyLibrary2' are properly set as h5p content libraries.
1301          $this->assertEquals(2, count($libdependencies));
1302          $this->assertEquals($dependency1->id, reset($libdependencies)->libraryid);
1303          $this->assertEquals($dependency2->id, end($libdependencies)->libraryid);
1304      }
1305  
1306      /**
1307       * Test the behaviour of getLibraryUsage() without skipping a particular h5p content.
1308       */
1309      public function test_getLibraryUsage_no_skip_content() {
1310          $this->resetAfterTest();
1311  
1312          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1313  
1314          // Generate h5p related data.
1315          $generateddata = $generator->generate_h5p_data();
1316          // The Id of the library 'Library1'.
1317          $library1id = $generateddata->lib1->data->id;
1318          // The Id of the library 'Library2'.
1319          $library2id = $generateddata->lib2->data->id;
1320          // The Id of the library 'Library5'.
1321          $library5id = $generateddata->lib5->data->id;
1322  
1323          // Get the library usage for 'Library1' (do not skip content).
1324          $data = $this->framework->getLibraryUsage($library1id);
1325  
1326          $expected = array(
1327              'content' => 1,
1328              'libraries' => 1
1329          );
1330  
1331          // Make sure 'Library1' is used by 1 content and is a dependency to 1 library.
1332          $this->assertEquals($expected, $data);
1333  
1334          // Get the library usage for 'Library2' (do not skip content).
1335          $data = $this->framework->getLibraryUsage($library2id);
1336  
1337          $expected = array(
1338              'content' => 1,
1339              'libraries' => 2,
1340          );
1341  
1342          // Make sure 'Library2' is used by 1 content and is a dependency to 2 libraries.
1343          $this->assertEquals($expected, $data);
1344  
1345           // Get the library usage for 'Library5' (do not skip content).
1346          $data = $this->framework->getLibraryUsage($library5id);
1347  
1348          $expected = array(
1349              'content' => 0,
1350              'libraries' => 1,
1351          );
1352  
1353          // Make sure 'Library5' is not used by any content and is a dependency to 1 library.
1354          $this->assertEquals($expected, $data);
1355      }
1356  
1357      /**
1358       * Test the behaviour of getLibraryUsage() when skipping a particular content.
1359       */
1360      public function test_getLibraryUsage_skip_content() {
1361          $this->resetAfterTest();
1362  
1363          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1364  
1365          // Generate h5p related data.
1366          $generateddata = $generator->generate_h5p_data();
1367          // The Id of the library 'Library1'.
1368          $library1id = $generateddata->lib1->data->id;
1369  
1370          // Get the library usage for 'Library1' (skip content).
1371          $data = $this->framework->getLibraryUsage($library1id, true);
1372          $expected = array(
1373              'content' => -1,
1374              'libraries' => 1,
1375          );
1376  
1377          // Make sure 'Library1' is a dependency to 1 library.
1378          $this->assertEquals($expected, $data);
1379      }
1380  
1381      /**
1382       * Test the behaviour of loadLibrary() when requesting an existing library.
1383       */
1384      public function test_loadLibrary_existing_library() {
1385          $this->resetAfterTest();
1386  
1387          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1388  
1389          // Generate h5p related data.
1390          $generateddata = $generator->generate_h5p_data();
1391          // The library data of 'Library1'.
1392          $library1 = $generateddata->lib1->data;
1393          // The library data of 'Library5'.
1394          $library5 = $generateddata->lib5->data;
1395  
1396          // The preloaded dependencies.
1397          $preloadeddependencies = array();
1398  
1399          foreach ($generateddata->lib1->dependencies as $preloadeddependency) {
1400              $preloadeddependencies[] = array(
1401                  'machineName' => $preloadeddependency->machinename,
1402                  'majorVersion' => $preloadeddependency->majorversion,
1403                  'minorVersion' => $preloadeddependency->minorversion
1404              );
1405          }
1406  
1407          // Create a dynamic dependency.
1408          $generator->create_library_dependency_record($library1->id, $library5->id, 'dynamic');
1409  
1410          $dynamicdependencies[] = array(
1411              'machineName' => $library5->machinename,
1412              'majorVersion' => $library5->majorversion,
1413              'minorVersion' => $library5->minorversion
1414          );
1415  
1416          // Load 'Library1' data.
1417          $data = $this->framework->loadLibrary($library1->machinename, $library1->majorversion,
1418              $library1->minorversion);
1419  
1420          $expected = array(
1421              'libraryId' => $library1->id,
1422              'title' => $library1->title,
1423              'machineName' => $library1->machinename,
1424              'majorVersion' => $library1->majorversion,
1425              'minorVersion' => $library1->minorversion,
1426              'patchVersion' => $library1->patchversion,
1427              'runnable' => $library1->runnable,
1428              'fullscreen' => $library1->fullscreen,
1429              'embedTypes' => $library1->embedtypes,
1430              'preloadedJs' => $library1->preloadedjs,
1431              'preloadedCss' => $library1->preloadedcss,
1432              'dropLibraryCss' => $library1->droplibrarycss,
1433              'semantics' => $library1->semantics,
1434              'preloadedDependencies' => $preloadeddependencies,
1435              'dynamicDependencies' => $dynamicdependencies
1436          );
1437  
1438          // Make sure the 'Library1' data is properly loaded.
1439          $this->assertEquals($expected, $data);
1440      }
1441  
1442      /**
1443       * Test the behaviour of loadLibrary() when requesting a non-existent library.
1444       */
1445      public function test_loadLibrary_non_existent_library() {
1446          $this->resetAfterTest();
1447  
1448          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1449  
1450          // Generate h5p related data.
1451          $generator->generate_h5p_data();
1452  
1453          // Attempt to load a non-existent library.
1454          $data = $this->framework->loadLibrary('MissingLibrary', 1, 2);
1455  
1456          // Make sure nothing is loaded.
1457          $this->assertFalse($data);
1458      }
1459  
1460      /**
1461       * Test the behaviour of loadLibrarySemantics().
1462       *
1463       * @dataProvider loadLibrarySemantics_provider
1464       * @param array $libraryrecords Array containing data for the library creation
1465       * @param array $testlibrary Array containing the test library data
1466       * @param string $expected The expected semantics value
1467       **/
1468      public function test_loadLibrarySemantics(array $libraryrecords, array $testlibrary, string $expected): void {
1469          $this->resetAfterTest();
1470  
1471          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1472  
1473          foreach ($libraryrecords as $library) {
1474              call_user_func_array([$generator, 'create_library_record'], $library);
1475          }
1476  
1477          $this->assertEquals($expected, $this->framework->loadLibrarySemantics(
1478              $testlibrary['machinename'], $testlibrary['majorversion'], $testlibrary['minorversion']));
1479      }
1480  
1481      /**
1482       * Data provider for test_loadLibrarySemantics().
1483       *
1484       * @return array
1485       */
1486      public function loadLibrarySemantics_provider(): array {
1487  
1488          $semantics = json_encode(
1489              [
1490                  'type' => 'text',
1491                  'name' => 'text',
1492                  'label' => 'Plain text',
1493                  'description' => 'Please add some text'
1494              ]
1495          );
1496  
1497          return [
1498              'Library with semantics' => [
1499                  [
1500                      ['Library1', 'Lib1', 1, 1, 2, $semantics],
1501                  ],
1502                  [
1503                      'machinename' => 'Library1',
1504                      'majorversion' => 1,
1505                      'minorversion' => 1
1506                  ],
1507                  $semantics,
1508              ],
1509              'Library without semantics' => [
1510                  [
1511                      ['Library2', 'Lib2', 1, 2, 2, ''],
1512                  ],
1513                  [
1514                      'machinename' => 'Library2',
1515                      'majorversion' => 1,
1516                      'minorversion' => 2
1517                  ],
1518                  '',
1519              ]
1520          ];
1521      }
1522  
1523      /**
1524       * Test the behaviour of alterLibrarySemantics().
1525       */
1526      public function test_alterLibrarySemantics() {
1527          global $DB;
1528  
1529          $this->resetAfterTest();
1530  
1531          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1532  
1533          $semantics = json_encode(
1534              array(
1535                  'type' => 'text',
1536                  'name' => 'text',
1537                  'label' => 'Plain text',
1538                  'description' => 'Please add some text'
1539              )
1540          );
1541  
1542          // Create a library 'Library1' with semantics.
1543          $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2, $semantics);
1544  
1545          $updatedsemantics = array(
1546              'type' => 'text',
1547              'name' => 'updated text',
1548              'label' => 'Updated text',
1549              'description' => 'Please add some text'
1550          );
1551  
1552          // Alter the semantics of 'Library1'.
1553          $this->framework->alterLibrarySemantics($updatedsemantics, 'Library1', 1, 1);
1554  
1555          // Get the semantics of 'Library1' from the DB.
1556          $currentsemantics = $DB->get_field('h5p_libraries', 'semantics', array('id' => $library1->id));
1557  
1558          // The semantics for Library1 shouldn't be updated.
1559          $this->assertEquals($semantics, $currentsemantics);
1560      }
1561  
1562      /**
1563       * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1564       * dependencies of an existing library.
1565       */
1566      public function test_deleteLibraryDependencies_existing_library() {
1567          global $DB;
1568  
1569          $this->resetAfterTest();
1570  
1571          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1572  
1573          // Generate h5p related data.
1574          $data = $generator->generate_h5p_data();
1575          // The data of the library 'Library1'.
1576          $library1 = $data->lib1->data;
1577  
1578          // Get the dependencies of 'Library1'.
1579          $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1580          // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1581          $this->assertCount(3, $dependencies);
1582  
1583          // Delete the dependencies of 'Library1'.
1584          $this->framework->deleteLibraryDependencies($library1->id);
1585  
1586          $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1587          // The 'Library1' should have 0 dependencies.
1588          $this->assertCount(0, $dependencies);
1589      }
1590  
1591      /**
1592       * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1593       * dependencies of a non-existent library.
1594       */
1595      public function test_deleteLibraryDependencies_non_existent_library() {
1596          global $DB;
1597  
1598          $this->resetAfterTest();
1599  
1600          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1601  
1602          // Generate h5p related data.
1603          $data = $generator->generate_h5p_data();
1604          // The data of the library 'Library1'.
1605          $library1 = $data->lib1->data;
1606  
1607          // Get the dependencies of 'Library1'.
1608          $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1609          // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1610          $this->assertCount(3, $dependencies);
1611  
1612          // Delete the dependencies of a non-existent library.
1613          $this->framework->deleteLibraryDependencies(0);
1614  
1615          $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1616          // The 'Library1' should have 3 dependencies.
1617          $this->assertCount(3, $dependencies);
1618      }
1619  
1620      /**
1621       * Test the behaviour of deleteLibrary().
1622       */
1623      public function test_deleteLibrary() {
1624          global $DB;
1625  
1626          $this->resetAfterTest();
1627  
1628          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1629  
1630          // Generate h5p related data.
1631          $data = $generator->generate_h5p_data(true);
1632          // The data of the 'Library1' library.
1633          $library1 = $data->lib1->data;
1634  
1635          // Get the library dependencies of 'Library1'.
1636          $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1637  
1638          // The 'Library1' should have 3 library dependencies ('Library2', 'Library3', 'Library4').
1639          $this->assertCount(3, $dependencies);
1640  
1641          // Return the created 'Library1' files.
1642          $libraryfiles = $DB->get_records('files',
1643              array(
1644                  'component' => \core_h5p\file_storage::COMPONENT,
1645                  'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1646                  'itemid' => $library1->id
1647              )
1648          );
1649  
1650          // The library ('Library1') should have 7 related folders/files.
1651          $this->assertCount(7, $libraryfiles);
1652  
1653          // Delete the library.
1654          $this->framework->deleteLibrary($library1);
1655  
1656          $lib1 = $DB->get_record('h5p_libraries', ['machinename' => $library1->machinename]);
1657          $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1658          $libraryfiles = $DB->get_records('files',
1659              array(
1660                  'component' => \core_h5p\file_storage::COMPONENT,
1661                  'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1662                  'itemid' => $library1->id
1663              )
1664          );
1665  
1666          // The 'Library1' should not exist.
1667          $this->assertEmpty($lib1);
1668          // The library ('Library1')  should have 0 dependencies.
1669          $this->assertCount(0, $dependencies);
1670          // The library (library1) should have 0 related folders/files.
1671          $this->assertCount(0, $libraryfiles);
1672      }
1673  
1674      /**
1675       * Test the behaviour of loadContent().
1676       */
1677      public function test_loadContent() {
1678          global $DB;
1679  
1680          $this->resetAfterTest();
1681  
1682          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1683  
1684          // Generate h5p related data.
1685          $data = $generator->generate_h5p_data();
1686          // The Id of the created h5p content.
1687          $h5pid = $data->h5pcontent->h5pid;
1688          // Get the h5p content data from the DB.
1689          $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1690          // The data of content's main library ('MainLibrary').
1691          $mainlibrary = $data->mainlib->data;
1692  
1693          // Load the h5p content.
1694          $content = $this->framework->loadContent($h5pid);
1695  
1696          $expected = array(
1697              'id' => $h5p->id,
1698              'params' => $h5p->jsoncontent,
1699              'embedType' => 'iframe',
1700              'disable' => $h5p->displayoptions,
1701              'title' => $mainlibrary->title,
1702              'slug' => H5PCore::slugify($mainlibrary->title) . '-' . $h5p->id,
1703              'filtered' => $h5p->filtered,
1704              'libraryId' => $mainlibrary->id,
1705              'libraryName' => $mainlibrary->machinename,
1706              'libraryMajorVersion' => $mainlibrary->majorversion,
1707              'libraryMinorVersion' => $mainlibrary->minorversion,
1708              'libraryEmbedTypes' => $mainlibrary->embedtypes,
1709              'libraryFullscreen' => $mainlibrary->fullscreen,
1710              'metadata' => '',
1711              'pathnamehash' => $h5p->pathnamehash
1712          );
1713  
1714          $params = json_decode($h5p->jsoncontent);
1715          if (empty($params->metadata)) {
1716              $params->metadata = new \stdClass();
1717          }
1718          $expected['metadata'] = $params->metadata;
1719          $expected['params'] = json_encode($params->params ?? $params);
1720  
1721          // The returned content should match the expected array.
1722          $this->assertEquals($expected, $content);
1723      }
1724  
1725      /**
1726       * Test the behaviour of loadContentDependencies() when requesting content dependencies
1727       * without specifying the dependency type.
1728       */
1729      public function test_loadContentDependencies_no_type_defined() {
1730          $this->resetAfterTest();
1731  
1732          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1733  
1734          // Generate h5p related data.
1735          $data = $generator->generate_h5p_data();
1736          // The Id of the h5p content.
1737          $h5pid = $data->h5pcontent->h5pid;
1738          // The content dependencies.
1739          $dependencies = $data->h5pcontent->contentdependencies;
1740  
1741          // Add Library5 as a content dependency (dynamic dependency type).
1742          $library5 = $data->lib5->data;
1743          $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1744  
1745          // Get all content dependencies.
1746          $contentdependencies = $this->framework->loadContentDependencies($h5pid);
1747  
1748          $expected = array();
1749          foreach ($dependencies as $dependency) {
1750              $expected[$dependency->machinename] = array(
1751                  'libraryId' => $dependency->id,
1752                  'machineName' => $dependency->machinename,
1753                  'majorVersion' => $dependency->majorversion,
1754                  'minorVersion' => $dependency->minorversion,
1755                  'patchVersion' => $dependency->patchversion,
1756                  'preloadedCss' => $dependency->preloadedcss,
1757                  'preloadedJs' => $dependency->preloadedjs,
1758                  'dropCss' => '0',
1759                  'dependencyType' => 'preloaded'
1760              );
1761          }
1762  
1763          $expected = array_merge($expected,
1764              array(
1765                  'Library5' => array(
1766                      'libraryId' => $library5->id,
1767                      'machineName' => $library5->machinename,
1768                      'majorVersion' => $library5->majorversion,
1769                      'minorVersion' => $library5->minorversion,
1770                      'patchVersion' => $library5->patchversion,
1771                      'preloadedCss' => $library5->preloadedcss,
1772                      'preloadedJs' => $library5->preloadedjs,
1773                      'dropCss' => '0',
1774                      'dependencyType' => 'dynamic'
1775                  )
1776              )
1777          );
1778  
1779          // The loaded content dependencies should return 6 libraries.
1780          $this->assertCount(6, $contentdependencies);
1781          $this->assertEquals($expected, $contentdependencies);
1782      }
1783  
1784      /**
1785       * Test the behaviour of loadContentDependencies() when requesting content dependencies
1786       * with specifying the dependency type.
1787       */
1788      public function test_loadContentDependencies_type_defined() {
1789          $this->resetAfterTest();
1790  
1791          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1792  
1793          // Generate h5p related data.
1794          $data = $generator->generate_h5p_data();
1795          // The Id of the h5p content.
1796          $h5pid = $data->h5pcontent->h5pid;
1797          // The content dependencies.
1798          $dependencies = $data->h5pcontent->contentdependencies;
1799  
1800          // Add Library5 as a content dependency (dynamic dependency type).
1801          $library5 = $data->lib5->data;
1802          $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1803  
1804          // Load all content dependencies of dependency type 'preloaded'.
1805          $preloadeddependencies = $this->framework->loadContentDependencies($h5pid, 'preloaded');
1806  
1807          $expected = array();
1808          foreach ($dependencies as $dependency) {
1809              $expected[$dependency->machinename] = array(
1810                  'libraryId' => $dependency->id,
1811                  'machineName' => $dependency->machinename,
1812                  'majorVersion' => $dependency->majorversion,
1813                  'minorVersion' => $dependency->minorversion,
1814                  'patchVersion' => $dependency->patchversion,
1815                  'preloadedCss' => $dependency->preloadedcss,
1816                  'preloadedJs' => $dependency->preloadedjs,
1817                  'dropCss' => '0',
1818                  'dependencyType' => 'preloaded'
1819              );
1820          }
1821  
1822          // The loaded content dependencies should return 5 libraries.
1823          $this->assertCount(5, $preloadeddependencies);
1824          $this->assertEquals($expected, $preloadeddependencies);
1825  
1826          // Load all content dependencies of dependency type 'dynamic'.
1827          $dynamicdependencies = $this->framework->loadContentDependencies($h5pid, 'dynamic');
1828  
1829          $expected = array(
1830              'Library5' => array(
1831                  'libraryId' => $library5->id,
1832                  'machineName' => $library5->machinename,
1833                  'majorVersion' => $library5->majorversion,
1834                  'minorVersion' => $library5->minorversion,
1835                  'patchVersion' => $library5->patchversion,
1836                  'preloadedCss' => $library5->preloadedcss,
1837                  'preloadedJs' => $library5->preloadedjs,
1838                  'dropCss' => '0',
1839                  'dependencyType' => 'dynamic'
1840              )
1841          );
1842  
1843          // The loaded content dependencies should now return 1 library.
1844          $this->assertCount(1, $dynamicdependencies);
1845          $this->assertEquals($expected, $dynamicdependencies);
1846      }
1847  
1848      /**
1849       * Test the behaviour of getOption().
1850       */
1851      public function test_getOption(): void {
1852          $this->resetAfterTest();
1853  
1854          // Get value for display_option_download.
1855          $value = $this->framework->getOption(H5PCore::DISPLAY_OPTION_DOWNLOAD);
1856          $expected = H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1857          $this->assertEquals($expected, $value);
1858  
1859          // Get value for display_option_embed using default value (it should be ignored).
1860          $value = $this->framework->getOption(H5PCore::DISPLAY_OPTION_EMBED, H5PDisplayOptionBehaviour::NEVER_SHOW);
1861          $expected = H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1862          $this->assertEquals($expected, $value);
1863  
1864          // Get value for unexisting setting without default.
1865          $value = $this->framework->getOption('unexistingsetting');
1866          $expected = false;
1867          $this->assertEquals($expected, $value);
1868  
1869          // Get value for unexisting setting with default.
1870          $value = $this->framework->getOption('unexistingsetting', 'defaultvalue');
1871          $expected = 'defaultvalue';
1872          $this->assertEquals($expected, $value);
1873      }
1874  
1875      /**
1876       * Test the behaviour of setOption().
1877       */
1878      public function test_setOption(): void {
1879          $this->resetAfterTest();
1880  
1881          // Set value for 'newsetting' setting.
1882          $name = 'newsetting';
1883          $value = $this->framework->getOption($name);
1884          $this->assertEquals(false, $value);
1885          $newvalue = 'value1';
1886          $this->framework->setOption($name, $newvalue);
1887          $value = $this->framework->getOption($name);
1888          $this->assertEquals($newvalue, $value);
1889  
1890          // Set value for display_option_download and then get it again. Check it hasn't changed.
1891          $name = H5PCore::DISPLAY_OPTION_DOWNLOAD;
1892          $newvalue = H5PDisplayOptionBehaviour::NEVER_SHOW;
1893          $this->framework->setOption($name, $newvalue);
1894          $value = $this->framework->getOption($name);
1895          $expected = H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1896          $this->assertEquals($expected, $value);
1897      }
1898  
1899      /**
1900       * Test the behaviour of updateContentFields().
1901       */
1902      public function test_updateContentFields() {
1903          global $DB;
1904  
1905          $this->resetAfterTest();
1906  
1907          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1908  
1909          // Create 'Library1' library.
1910          $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1911          // Create 'Library2' library.
1912          $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1913  
1914          // Create an h5p content with 'Library1' as it's main library.
1915          $h5pid = $generator->create_h5p_record($library1->id, 'iframe');
1916  
1917          $updatedata = array(
1918              'jsoncontent' => json_encode(['value' => 'test']),
1919              'mainlibraryid' => $library2->id
1920          );
1921  
1922          // Update h5p content fields.
1923          $this->framework->updateContentFields($h5pid, $updatedata);
1924  
1925          // Get the h5p content from the DB.
1926          $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1927  
1928          $expected = json_encode(['value' => 'test']);
1929  
1930          // Make sure the h5p content fields are properly updated.
1931          $this->assertEquals($expected, $h5p->jsoncontent);
1932          $this->assertEquals($library2->id, $h5p->mainlibraryid);
1933      }
1934  
1935      /**
1936       * Test the behaviour of clearFilteredParameters().
1937       */
1938      public function test_clearFilteredParameters() {
1939          global $DB;
1940  
1941          $this->resetAfterTest();
1942  
1943          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1944  
1945          // Create 3 libraries.
1946          $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1947          $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1948          $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
1949  
1950          // Create h5p content with 'Library1' as a main library.
1951          $h5pcontentid1 = $generator->create_h5p_record($library1->id);
1952          // Create h5p content with 'Library1' as a main library.
1953          $h5pcontentid2 = $generator->create_h5p_record($library1->id);
1954          // Create h5p content with 'Library2' as a main library.
1955          $h5pcontentid3 = $generator->create_h5p_record($library2->id);
1956          // Create h5p content with 'Library3' as a main library.
1957          $h5pcontentid4 = $generator->create_h5p_record($library3->id);
1958  
1959          $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1960          $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1961          $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1962          $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1963  
1964          // The filtered parameters should be present in each h5p content.
1965          $this->assertNotEmpty($h5pcontent1->filtered);
1966          $this->assertNotEmpty($h5pcontent2->filtered);
1967          $this->assertNotEmpty($h5pcontent3->filtered);
1968          $this->assertNotEmpty($h5pcontent4->filtered);
1969  
1970          // Clear the filtered parameters for contents that have library1 and library3 as
1971          // their main library.
1972          $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
1973  
1974          $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1975          $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1976          $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1977          $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1978  
1979          // The filtered parameters should be still present only for the content that has
1980          // library 2 as a main library.
1981          $this->assertEmpty($h5pcontent1->filtered);
1982          $this->assertEmpty($h5pcontent2->filtered);
1983          $this->assertNotEmpty($h5pcontent3->filtered);
1984          $this->assertEmpty($h5pcontent4->filtered);
1985      }
1986  
1987      /**
1988       * Test the behaviour of getNumNotFiltered().
1989       */
1990      public function test_getNumNotFiltered() {
1991          global $DB;
1992  
1993          $this->resetAfterTest();
1994  
1995          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1996  
1997          // Create 3 libraries.
1998          $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1999          $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
2000          $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
2001  
2002          // Create h5p content with library1 as a main library.
2003          $h5pcontentid1 = $generator->create_h5p_record($library1->id);
2004          // Create h5p content with library1 as a main library.
2005          $h5pcontentid2 = $generator->create_h5p_record($library1->id);
2006          // Create h5p content with library2 as a main library.
2007          $h5pcontentid3 = $generator->create_h5p_record($library2->id);
2008          // Create h5p content with library3 as a main library.
2009          $h5pcontentid4 = $generator->create_h5p_record($library3->id);
2010  
2011          $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
2012          $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
2013          $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
2014          $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
2015  
2016          // The filtered parameters should be present in each h5p content.
2017          $this->assertNotEmpty($h5pcontent1->filtered);
2018          $this->assertNotEmpty($h5pcontent2->filtered);
2019          $this->assertNotEmpty($h5pcontent3->filtered);
2020          $this->assertNotEmpty($h5pcontent4->filtered);
2021  
2022          // Clear the filtered parameters for contents that have library1 and library3 as
2023          // their main library.
2024          $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
2025  
2026          $countnotfiltered = $this->framework->getNumNotFiltered();
2027  
2028          // 3 contents don't have their parameters filtered.
2029          $this->assertEquals(3, $countnotfiltered);
2030      }
2031  
2032      /**
2033       * Test the behaviour of getNumContent().
2034       */
2035      public function test_getNumContent() {
2036          $this->resetAfterTest();
2037  
2038          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2039  
2040          // Generate h5p related data.
2041          $data = $generator->generate_h5p_data();
2042  
2043          // The 'MainLibrary' library data.
2044          $mainlibrary = $data->mainlib->data;
2045  
2046          // The 'Library1' library data.
2047          $library1 = $data->lib1->data;
2048  
2049          // Create new h5p content with MainLibrary as a main library.
2050          $generator->create_h5p_record($mainlibrary->id);
2051  
2052          // Get the number of h5p contents that are using 'MainLibrary' as their main library.
2053          $countmainlib = $this->framework->getNumContent($mainlibrary->id);
2054  
2055          // Get the number of h5p contents that are using 'Library1' as their main library.
2056          $countlib1 = $this->framework->getNumContent($library1->id);
2057  
2058          // Make sure that 2 contents are using MainLibrary as their main library.
2059          $this->assertEquals(2, $countmainlib);
2060          // Make sure that 0 contents are using Library1 as their main library.
2061          $this->assertEquals(0, $countlib1);
2062      }
2063  
2064      /**
2065       * Test the behaviour of getNumContent() when certain contents are being skipped.
2066       */
2067      public function test_getNumContent_skip_content() {
2068          $this->resetAfterTest();
2069  
2070          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2071  
2072          // Generate h5p related data.
2073          $data = $generator->generate_h5p_data();
2074  
2075          // The 'MainLibrary' library data.
2076          $mainlibrary = $data->mainlib->data;
2077  
2078          // Create new h5p content with MainLibrary as a main library.
2079          $h5pcontentid = $generator->create_h5p_record($mainlibrary->id);
2080  
2081          // Get the number of h5p contents that are using 'MainLibrary' as their main library.
2082          // Skip the newly created content $h5pcontentid.
2083          $countmainlib = $this->framework->getNumContent($mainlibrary->id, [$h5pcontentid]);
2084  
2085          // Make sure that 1 content is returned instead of 2 ($h5pcontentid being skipped).
2086          $this->assertEquals(1, $countmainlib);
2087      }
2088  
2089      /**
2090       * Test the behaviour of isContentSlugAvailable().
2091       */
2092      public function test_isContentSlugAvailable() {
2093          $this->resetAfterTest();
2094  
2095          $slug = 'h5p-test-slug-1';
2096  
2097          // Currently this returns always true. The slug is generated as a unique value for
2098          // each h5p content and it is not stored in the h5p content table.
2099          $isslugavailable = $this->framework->isContentSlugAvailable($slug);
2100  
2101          $this->assertTrue($isslugavailable);
2102      }
2103  
2104      /**
2105       * Test that a record is stored for cached assets.
2106       */
2107      public function test_saveCachedAssets() {
2108          global $DB;
2109  
2110          $this->resetAfterTest();
2111  
2112          $libraries = array(
2113              array(
2114                  'machineName' => 'H5P.TestLib',
2115                  'libraryId' => 405,
2116              ),
2117              array(
2118                  'FontAwesome' => 'FontAwesome',
2119                  'libraryId' => 406,
2120              ),
2121              array(
2122                  'machineName' => 'H5P.SecondLib',
2123                  'libraryId' => 407,
2124              ),
2125          );
2126  
2127          $key = 'testhashkey';
2128  
2129          $this->framework->saveCachedAssets($key, $libraries);
2130  
2131          $records = $DB->get_records('h5p_libraries_cachedassets');
2132  
2133          $this->assertCount(3, $records);
2134      }
2135  
2136      /**
2137       * Test that the correct libraries are removed from the cached assets table
2138       */
2139      public function test_deleteCachedAssets() {
2140          global $DB;
2141  
2142          $this->resetAfterTest();
2143  
2144          $libraries = array(
2145              array(
2146                  'machineName' => 'H5P.TestLib',
2147                  'libraryId' => 405,
2148              ),
2149              array(
2150                  'FontAwesome' => 'FontAwesome',
2151                  'libraryId' => 406,
2152              ),
2153              array(
2154                  'machineName' => 'H5P.SecondLib',
2155                  'libraryId' => 407,
2156              ),
2157          );
2158  
2159          $key1 = 'testhashkey';
2160          $this->framework->saveCachedAssets($key1, $libraries);
2161  
2162          $libraries = array(
2163              array(
2164                  'machineName' => 'H5P.DiffLib',
2165                  'libraryId' => 408,
2166              ),
2167              array(
2168                  'FontAwesome' => 'FontAwesome',
2169                  'libraryId' => 406,
2170              ),
2171              array(
2172                  'machineName' => 'H5P.ThirdLib',
2173                  'libraryId' => 409,
2174              ),
2175          );
2176  
2177          $key2 = 'secondhashkey';
2178          $this->framework->saveCachedAssets($key2, $libraries);
2179  
2180          $libraries = array(
2181              array(
2182                  'machineName' => 'H5P.AnotherDiffLib',
2183                  'libraryId' => 410,
2184              ),
2185              array(
2186                  'FontAwesome' => 'NotRelated',
2187                  'libraryId' => 411,
2188              ),
2189              array(
2190                  'machineName' => 'H5P.ForthLib',
2191                  'libraryId' => 412,
2192              ),
2193          );
2194  
2195          $key3 = 'threeforthewin';
2196          $this->framework->saveCachedAssets($key3, $libraries);
2197  
2198          $records = $DB->get_records('h5p_libraries_cachedassets');
2199          $this->assertCount(9, $records);
2200  
2201          // Selecting one library id will result in all related library entries also being deleted.
2202          // Going to use the FontAwesome library id. The first two hashes should be returned.
2203          $hashes = $this->framework->deleteCachedAssets(406);
2204          $this->assertCount(2, $hashes);
2205          $index = array_search($key1, $hashes);
2206          $this->assertEquals($key1, $hashes[$index]);
2207          $index = array_search($key2, $hashes);
2208          $this->assertEquals($key2, $hashes[$index]);
2209          $index = array_search($key3, $hashes);
2210          $this->assertFalse($index);
2211  
2212          // Check that the records have been removed as well.
2213          $records = $DB->get_records('h5p_libraries_cachedassets');
2214          $this->assertCount(3, $records);
2215      }
2216  
2217      /**
2218       * Test the behaviour of getLibraryContentCount().
2219       */
2220      public function test_getLibraryContentCount() {
2221          $this->resetAfterTest();
2222  
2223          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2224  
2225          // Generate h5p related data.
2226          $data = $generator->generate_h5p_data();
2227  
2228          // The 'MainLibrary' library data.
2229          $mainlibrary = $data->mainlib->data;
2230  
2231          // The 'Library2' library data.
2232          $library2 = $data->lib2->data;
2233  
2234          // Create new h5p content with Library2 as it's main library.
2235          $generator->create_h5p_record($library2->id);
2236  
2237          // Create new h5p content with MainLibrary as it's main library.
2238          $generator->create_h5p_record($mainlibrary->id);
2239  
2240          $countlibrarycontent = $this->framework->getLibraryContentCount();
2241  
2242          $expected = array(
2243              "{$mainlibrary->machinename} {$mainlibrary->majorversion}.{$mainlibrary->minorversion}" => 2,
2244              "{$library2->machinename} {$library2->majorversion}.{$library2->minorversion}" => 1,
2245          );
2246  
2247          // MainLibrary and Library1 are currently main libraries to the existing h5p contents.
2248          // Should return the number of cases where MainLibrary and Library1 are main libraries to an h5p content.
2249          $this->assertEquals($expected, $countlibrarycontent);
2250      }
2251  
2252      /**
2253       * Test the behaviour of test_libraryHasUpgrade().
2254       *
2255       * @dataProvider libraryHasUpgrade_provider
2256       * @param array $libraryrecords Array containing data for the library creation
2257       * @param array $testlibrary Array containing the test library data
2258       * @param bool $expected The expectation whether the library is patched or not
2259       **/
2260      public function test_libraryHasUpgrade(array $libraryrecords, array $testlibrary, bool $expected): void {
2261          $this->resetAfterTest();
2262  
2263          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2264  
2265          foreach ($libraryrecords as $library) {
2266              call_user_func_array([$generator, 'create_library_record'], $library);
2267          }
2268  
2269          $this->assertEquals($expected, $this->framework->libraryHasUpgrade($testlibrary));
2270      }
2271  
2272      /**
2273       * Data provider for test_libraryHasUpgrade().
2274       *
2275       * @return array
2276       */
2277      public function libraryHasUpgrade_provider(): array {
2278          return [
2279              'Lower major version; Identical lower version' => [
2280                  [
2281                      ['Library', 'Lib', 2, 2],
2282                  ],
2283                  [
2284                      'machineName' => 'Library',
2285                      'majorVersion' => 1,
2286                      'minorVersion' => 2
2287                  ],
2288                  true,
2289              ],
2290              'Major version identical; Lower minor version' => [
2291                  [
2292                      ['Library', 'Lib', 2, 2],
2293                  ],
2294                  [
2295                      'machineName' => 'Library',
2296                      'majorVersion' => 2,
2297                      'minorVersion' => 1
2298                  ],
2299                  true,
2300              ],
2301              'Major version identical; Minor version identical' => [
2302                  [
2303                      ['Library', 'Lib', 2, 2],
2304                  ],
2305                  [
2306                      'machineName' => 'Library',
2307                      'majorVersion' => 2,
2308                      'minorVersion' => 2
2309                  ],
2310                  false,
2311              ],
2312              'Major version higher; Minor version identical' => [
2313                  [
2314                      ['Library', 'Lib', 2, 2],
2315                  ],
2316                  [
2317                      'machineName' => 'Library',
2318                      'majorVersion' => 3,
2319                      'minorVersion' => 2
2320                  ],
2321                  false,
2322              ],
2323              'Major version identical; Minor version newer' => [
2324                  [
2325                      ['Library', 'Lib', 2, 2],
2326                  ],
2327                  [
2328                      'machineName' => 'Library',
2329                      'majorVersion' => 2,
2330                      'minorVersion' => 4
2331                  ],
2332                  false,
2333              ]
2334          ];
2335      }
2336  
2337  
2338      /**
2339       * Test the behaviour of get_latest_library_version().
2340       */
2341      public function test_get_latest_library_version() {
2342          global $DB;
2343  
2344          $this->resetAfterTest();
2345  
2346          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2347          // Create a library record.
2348          $machinename = 'TestLibrary';
2349          $lib1 = $generator->create_library_record($machinename, 'Test', 1, 1, 2);
2350          $lib2 = $generator->create_library_record($machinename, 'Test', 1, 2, 1);
2351  
2352          $content = array(
2353              'params' => json_encode(['param1' => 'Test']),
2354              'library' => array(
2355                  'libraryId' => 0,
2356                  'machineName' => 'TestLibrary',
2357              ),
2358              'disable' => 8
2359          );
2360  
2361          // Get the latest id (at this point, should be lib2).
2362          $latestlib = $this->framework->get_latest_library_version($machinename);
2363          $this->assertEquals($lib2->id, $latestlib->id);
2364  
2365          // Get the latest id (at this point, should be lib3).
2366          $lib3 = $generator->create_library_record($machinename, 'Test', 2, 1, 0);
2367          $latestlib = $this->framework->get_latest_library_version($machinename);
2368          $this->assertEquals($lib3->id, $latestlib->id);
2369  
2370          // Get the latest id (at this point, should be still lib3).
2371          $lib4 = $generator->create_library_record($machinename, 'Test', 1, 1, 3);
2372          $latestlib = $this->framework->get_latest_library_version($machinename);
2373          $this->assertEquals($lib3->id, $latestlib->id);
2374  
2375          // Get the latest id (at this point, should be lib5).
2376          $lib5 = $generator->create_library_record($machinename, 'Test', 2, 1, 6);
2377          $latestlib = $this->framework->get_latest_library_version($machinename);
2378          $this->assertEquals($lib5->id, $latestlib->id);
2379      }
2380  }