Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 38 and 311] [Versions 39 and 311]

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