Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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

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