Search moodle.org's
Developer Documentation

See Release Notes

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

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

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Testing the H5P API.
  19   *
  20   * @package    core_h5p
  21   * @category   test
  22   * @copyright  2020 Sara Arjona <sara@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  declare(strict_types = 1);
  27  
  28  namespace core_h5p;
  29  
  30  defined('MOODLE_INTERNAL') || die();
  31  
  32  /**
  33   * Test class covering the H5P API.
  34   *
  35   * @package    core_h5p
  36   * @copyright  2020 Sara Arjona <sara@moodle.com>
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   * @coversDefaultClass \core_h5p\api
  39   */
  40  class api_test extends \advanced_testcase {
  41  
  42      /**
  43       * Test the behaviour of delete_library().
  44       *
  45       * @dataProvider  delete_library_provider
  46       * @param  string $libraryname          Machine name of the library to delete.
  47       * @param  int    $expectedh5p          Total of H5P contents expected after deleting the library.
  48       * @param  int    $expectedlibraries    Total of H5P libraries expected after deleting the library.
  49       * @param  int    $expectedcontents     Total of H5P content_libraries expected after deleting the library.
  50       * @param  int    $expecteddependencies Total of H5P library dependencies expected after deleting the library.
  51       */
  52      public function test_delete_library(string $libraryname, int $expectedh5p, int $expectedlibraries,
  53              int $expectedcontents, int $expecteddependencies): void {
  54          global $DB;
  55  
  56          $this->setRunTestInSeparateProcess(true);
  57          $this->resetAfterTest();
  58  
  59          // Generate h5p related data.
  60          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
  61          $generator->generate_h5p_data();
  62          $generator->create_library_record('H5P.TestingLibrary', 'TestingLibrary', 1, 0);
  63  
  64          // Check the current content in H5P tables is the expected.
  65          $counth5p = $DB->count_records('h5p');
  66          $counth5plibraries = $DB->count_records('h5p_libraries');
  67          $counth5pcontents = $DB->count_records('h5p_contents_libraries');
  68          $counth5pdependencies = $DB->count_records('h5p_library_dependencies');
  69  
  70          $this->assertSame(1, $counth5p);
  71          $this->assertSame(7, $counth5plibraries);
  72          $this->assertSame(5, $counth5pcontents);
  73          $this->assertSame(7, $counth5pdependencies);
  74  
  75          // Delete this library.
  76          $factory = new factory();
  77          $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname]);
  78          if ($library) {
  79              api::delete_library($factory, $library);
  80          }
  81  
  82          // Check the expected libraries and content have been removed.
  83          $counth5p = $DB->count_records('h5p');
  84          $counth5plibraries = $DB->count_records('h5p_libraries');
  85          $counth5pcontents = $DB->count_records('h5p_contents_libraries');
  86          $counth5pdependencies = $DB->count_records('h5p_library_dependencies');
  87  
  88          $this->assertSame($expectedh5p, $counth5p);
  89          $this->assertSame($expectedlibraries, $counth5plibraries);
  90          $this->assertSame($expectedcontents, $counth5pcontents);
  91          $this->assertSame($expecteddependencies, $counth5pdependencies);
  92      }
  93  
  94      /**
  95       * Data provider for test_delete_library().
  96       *
  97       * @return array
  98       */
  99      public function delete_library_provider(): array {
 100          return [
 101              'Delete MainLibrary' => [
 102                  'MainLibrary',
 103                  0,
 104                  6,
 105                  0,
 106                  4,
 107              ],
 108              'Delete Library1' => [
 109                  'Library1',
 110                  0,
 111                  5,
 112                  0,
 113                  1,
 114              ],
 115              'Delete Library2' => [
 116                  'Library2',
 117                  0,
 118                  4,
 119                  0,
 120                  1,
 121              ],
 122              'Delete Library3' => [
 123                  'Library3',
 124                  0,
 125                  4,
 126                  0,
 127                  0,
 128              ],
 129              'Delete Library4' => [
 130                  'Library4',
 131                  0,
 132                  4,
 133                  0,
 134                  1,
 135              ],
 136              'Delete Library5' => [
 137                  'Library5',
 138                  0,
 139                  3,
 140                  0,
 141                  0,
 142              ],
 143              'Delete a library without dependencies' => [
 144                  'H5P.TestingLibrary',
 145                  1,
 146                  6,
 147                  5,
 148                  7,
 149              ],
 150              'Delete unexisting library' => [
 151                  'LibraryX',
 152                  1,
 153                  7,
 154                  5,
 155                  7,
 156              ],
 157          ];
 158      }
 159  
 160      /**
 161       * Test the behaviour of get_dependent_libraries().
 162       *
 163       * @dataProvider  get_dependent_libraries_provider
 164       * @param  string $libraryname     Machine name of the library to delete.
 165       * @param  int    $expectedvalue   Total of H5P required libraries expected.
 166       */
 167      public function test_get_dependent_libraries(string $libraryname, int $expectedvalue): void {
 168          global $DB;
 169  
 170          $this->resetAfterTest();
 171  
 172          // Generate h5p related data.
 173          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 174          $generator->generate_h5p_data();
 175          $generator->create_library_record('H5P.TestingLibrary', 'TestingLibrary', 1, 0);
 176  
 177          // Get required libraries.
 178          $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname], 'id');
 179          if ($library) {
 180              $libraries = api::get_dependent_libraries((int)$library->id);
 181          } else {
 182              $libraries = [];
 183          }
 184  
 185          $this->assertCount($expectedvalue, $libraries);
 186      }
 187  
 188      /**
 189       * Data provider for test_get_dependent_libraries().
 190       *
 191       * @return array
 192       */
 193      public function get_dependent_libraries_provider(): array {
 194          return [
 195              'Main library of a content' => [
 196                  'MainLibrary',
 197                  0,
 198              ],
 199              'Library1' => [
 200                  'Library1',
 201                  1,
 202              ],
 203              'Library2' => [
 204                  'Library2',
 205                  2,
 206              ],
 207              'Library without dependencies' => [
 208                  'H5P.TestingLibrary',
 209                  0,
 210              ],
 211              'Unexisting library' => [
 212                  'LibraryX',
 213                  0,
 214              ],
 215          ];
 216      }
 217  
 218      /**
 219       * Test the behaviour of get_library().
 220       *
 221       * @dataProvider  get_library_provider
 222       * @param  string $libraryname     Machine name of the library to delete.
 223       * @param  bool   $emptyexpected   Wether the expected result is empty or not.
 224       */
 225      public function test_get_library(string $libraryname, bool $emptyexpected): void {
 226          global $DB;
 227  
 228          $this->resetAfterTest();
 229  
 230          // Generate h5p related data.
 231          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 232          $generator->generate_h5p_data();
 233          $generator->create_library_record('H5P.TestingLibrary', 'TestingLibrary', 1, 0);
 234  
 235          // Get the library identifier.
 236          $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname], 'id');
 237          if ($library) {
 238              $result = api::get_library((int)$library->id);
 239          } else {
 240              $result = null;
 241          }
 242  
 243          if ($emptyexpected) {
 244              $this->assertEmpty($result);
 245          } else {
 246              $this->assertEquals($library->id, $result->id);
 247              $this->assertEquals($libraryname, $result->machinename);
 248          }
 249  
 250      }
 251  
 252      /**
 253       * Data provider for test_get_library().
 254       *
 255       * @return array
 256       */
 257      public function get_library_provider(): array {
 258          return [
 259              'Main library of a content' => [
 260                  'MainLibrary',
 261                  false,
 262              ],
 263              'Library1' => [
 264                  'Library1',
 265                  false,
 266              ],
 267              'Library without dependencies' => [
 268                  'H5P.TestingLibrary',
 269                  false,
 270              ],
 271              'Unexisting library' => [
 272                  'LibraryX',
 273                  true,
 274              ],
 275          ];
 276      }
 277  
 278      /**
 279       * Test the behaviour of get_content_from_pluginfile_url().
 280       */
 281      public function test_get_content_from_pluginfile_url(): void {
 282          $this->setRunTestInSeparateProcess(true);
 283          $this->resetAfterTest();
 284          $factory = new factory();
 285  
 286          // Create the H5P data.
 287          $filename = 'find-the-words.h5p';
 288          $path = __DIR__ . '/fixtures/' . $filename;
 289          $fakefile = helper::create_fake_stored_file_from_path($path);
 290          $config = (object)[
 291              'frame' => 1,
 292              'export' => 1,
 293              'embed' => 0,
 294              'copyright' => 0,
 295          ];
 296  
 297          // Get URL for this H5P content file.
 298          $syscontext = \context_system::instance();
 299          $url = \moodle_url::make_pluginfile_url(
 300              $syscontext->id,
 301              \core_h5p\file_storage::COMPONENT,
 302              'unittest',
 303              $fakefile->get_itemid(),
 304              '/',
 305              $filename
 306          );
 307  
 308          // Scenario 1: Get the H5P for this URL and check there isn't any existing H5P (because it hasn't been saved).
 309          list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out());
 310          $this->assertEquals($fakefile->get_pathnamehash(), $newfile->get_pathnamehash());
 311          $this->assertEquals($fakefile->get_contenthash(), $newfile->get_contenthash());
 312          $this->assertFalse($h5p);
 313  
 314          // Scenario 2: Save the H5P and check now the H5P is exactly the same as the original one.
 315          $h5pid = helper::save_h5p($factory, $fakefile, $config);
 316          list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out());
 317  
 318          $this->assertEquals($h5pid, $h5p->id);
 319          $this->assertEquals($fakefile->get_pathnamehash(), $h5p->pathnamehash);
 320          $this->assertEquals($fakefile->get_contenthash(), $h5p->contenthash);
 321  
 322          // Scenario 3: Get the H5P for an unexisting H5P file.
 323          $url = \moodle_url::make_pluginfile_url(
 324              $syscontext->id,
 325              \core_h5p\file_storage::COMPONENT,
 326              'unittest',
 327              $fakefile->get_itemid(),
 328              '/',
 329              'unexisting.h5p'
 330          );
 331          list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out());
 332          $this->assertFalse($newfile);
 333          $this->assertFalse($h5p);
 334      }
 335  
 336      /**
 337       * Test the behaviour of create_content_from_pluginfile_url().
 338       */
 339      public function test_create_content_from_pluginfile_url(): void {
 340          global $DB;
 341  
 342          $this->setRunTestInSeparateProcess(true);
 343          $this->resetAfterTest();
 344          $factory = new factory();
 345  
 346          // Create the H5P data.
 347          $filename = 'find-the-words.h5p';
 348          $path = __DIR__ . '/fixtures/' . $filename;
 349          $fakefile = helper::create_fake_stored_file_from_path($path);
 350          $config = (object)[
 351              'frame' => 1,
 352              'export' => 1,
 353              'embed' => 0,
 354              'copyright' => 0,
 355          ];
 356  
 357          // Get URL for this H5P content file.
 358          $syscontext = \context_system::instance();
 359          $url = \moodle_url::make_pluginfile_url(
 360              $syscontext->id,
 361              \core_h5p\file_storage::COMPONENT,
 362              'unittest',
 363              $fakefile->get_itemid(),
 364              '/',
 365              $filename
 366          );
 367  
 368          // Scenario 1: Create the H5P from this URL and check the content is exactly the same as the fake file.
 369          $messages = new \stdClass();
 370          list($newfile, $h5pid) = api::create_content_from_pluginfile_url($url->out(), $config, $factory, $messages);
 371          $this->assertNotFalse($h5pid);
 372          $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
 373          $this->assertEquals($fakefile->get_pathnamehash(), $h5p->pathnamehash);
 374          $this->assertEquals($fakefile->get_contenthash(), $h5p->contenthash);
 375          $this->assertTrue(empty($messages->error));
 376          $this->assertTrue(empty($messages->info));
 377  
 378          // Scenario 2: Create the H5P for an unexisting H5P file.
 379          $url = \moodle_url::make_pluginfile_url(
 380              $syscontext->id,
 381              \core_h5p\file_storage::COMPONENT,
 382              'unittest',
 383              $fakefile->get_itemid(),
 384              '/',
 385              'unexisting.h5p'
 386          );
 387          list($newfile, $h5p) = api::create_content_from_pluginfile_url($url->out(), $config, $factory, $messages);
 388          $this->assertFalse($newfile);
 389          $this->assertFalse($h5p);
 390          $this->assertTrue(empty($messages->error));
 391          $this->assertTrue(empty($messages->info));
 392      }
 393  
 394      /**
 395       * Test the behaviour of delete_content_from_pluginfile_url().
 396       */
 397      public function test_delete_content_from_pluginfile_url(): void {
 398          global $DB;
 399  
 400          $this->setRunTestInSeparateProcess(true);
 401          $this->resetAfterTest();
 402          $factory = new factory();
 403  
 404          // Create the H5P data.
 405          $filename = 'find-the-words.h5p';
 406          $path = __DIR__ . '/fixtures/' . $filename;
 407          $fakefile = helper::create_fake_stored_file_from_path($path);
 408          $config = (object)[
 409              'frame' => 1,
 410              'export' => 1,
 411              'embed' => 0,
 412              'copyright' => 0,
 413          ];
 414  
 415          // Get URL for this H5P content file.
 416          $syscontext = \context_system::instance();
 417          $url = \moodle_url::make_pluginfile_url(
 418              $syscontext->id,
 419              \core_h5p\file_storage::COMPONENT,
 420              'unittest',
 421              $fakefile->get_itemid(),
 422              '/',
 423              $filename
 424          );
 425  
 426          // Scenario 1: Try to remove the H5P content for an undeployed file.
 427          list($newfile, $h5p) = api::get_content_from_pluginfile_url($url->out());
 428          $this->assertEquals(0, $DB->count_records('h5p'));
 429          api::delete_content_from_pluginfile_url($url->out(), $factory);
 430          $this->assertEquals(0, $DB->count_records('h5p'));
 431  
 432          // Scenario 2: Deploy an H5P from this URL, check it's created, remove it and check it has been removed as expected.
 433          $this->assertEquals(0, $DB->count_records('h5p'));
 434  
 435          $messages = new \stdClass();
 436          list($newfile, $h5pid) = api::create_content_from_pluginfile_url($url->out(), $config, $factory, $messages);
 437          $this->assertEquals(1, $DB->count_records('h5p'));
 438  
 439          api::delete_content_from_pluginfile_url($url->out(), $factory);
 440          $this->assertEquals(0, $DB->count_records('h5p'));
 441  
 442          // Scenario 3: Try to remove the H5P for an unexisting H5P URL.
 443          $url = \moodle_url::make_pluginfile_url(
 444              $syscontext->id,
 445              \core_h5p\file_storage::COMPONENT,
 446              'unittest',
 447              $fakefile->get_itemid(),
 448              '/',
 449              'unexisting.h5p'
 450          );
 451          $this->assertEquals(0, $DB->count_records('h5p'));
 452          api::delete_content_from_pluginfile_url($url->out(), $factory);
 453          $this->assertEquals(0, $DB->count_records('h5p'));
 454      }
 455  
 456      /**
 457       * Test the behaviour of get_export_info_from_context_id().
 458       */
 459      public function test_get_export_info_from_context_id(): void {
 460          global $DB;
 461  
 462          $this->setRunTestInSeparateProcess(true);
 463          $this->resetAfterTest();
 464          $factory = new factory();
 465  
 466          // Create the H5P data.
 467          $filename = 'find-the-words.h5p';
 468          $syscontext = \context_system::instance();
 469  
 470          // Test scenario 1: H5P exists and deployed.
 471          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 472          $fakeexportfile = $generator->create_export_file($filename,
 473              $syscontext->id,
 474              \core_h5p\file_storage::COMPONENT,
 475              \core_h5p\file_storage::EXPORT_FILEAREA);
 476  
 477          $exportfile = api::get_export_info_from_context_id($syscontext->id,
 478              $factory,
 479              \core_h5p\file_storage::COMPONENT,
 480              \core_h5p\file_storage::EXPORT_FILEAREA);
 481          $this->assertEquals($fakeexportfile['filename'], $exportfile['filename']);
 482          $this->assertEquals($fakeexportfile['filepath'], $exportfile['filepath']);
 483          $this->assertEquals($fakeexportfile['filesize'], $exportfile['filesize']);
 484          $this->assertEquals($fakeexportfile['timemodified'], $exportfile['timemodified']);
 485          $this->assertEquals($fakeexportfile['fileurl'], $exportfile['fileurl']);
 486  
 487          // Test scenario 2: H5P exist, deployed but the content has changed.
 488          // We need to change the contenthash to simulate the H5P file was changed.
 489          $h5pfile = $DB->get_record('h5p', []);
 490          $h5pfile->contenthash = sha1('testedit');
 491          $DB->update_record('h5p', $h5pfile);
 492          $exportfile = api::get_export_info_from_context_id($syscontext->id,
 493              $factory,
 494              \core_h5p\file_storage::COMPONENT,
 495              \core_h5p\file_storage::EXPORT_FILEAREA);
 496          $this->assertNull($exportfile);
 497  
 498          // Tests scenario 3: H5P is not deployed.
 499          // We need to delete the H5P record to simulate the H5P was not deployed.
 500          $DB->delete_records('h5p', ['id' => $h5pfile->id]);
 501          $exportfile = api::get_export_info_from_context_id($syscontext->id,
 502              $factory,
 503              \core_h5p\file_storage::COMPONENT,
 504              \core_h5p\file_storage::EXPORT_FILEAREA);
 505          $this->assertNull($exportfile);
 506      }
 507  
 508      /**
 509       * Test the behaviour of set_library_enabled().
 510       *
 511       * @covers ::set_library_enabled
 512       * @dataProvider set_library_enabled_provider
 513       *
 514       * @param string $libraryname Library name to enable/disable.
 515       * @param string $action Action to be done with the library. Supported values: enable, disable.
 516       * @param int $expected Expected value for the enabled library field. -1 will be passed if the library doesn't exist.
 517       */
 518      public function test_set_library_enabled(string $libraryname, string $action, int $expected): void {
 519          global $DB;
 520  
 521          $this->resetAfterTest();
 522  
 523          // Create libraries.
 524          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 525          $generator->generate_h5p_data();
 526  
 527          // Check by default the library is enabled.
 528          $library = $DB->get_record('h5p_libraries', ['machinename' => $libraryname]);
 529          if ($expected >= 0) {
 530              $this->assertEquals(1, $library->enabled);
 531              $libraryid = (int) $library->id;
 532          } else {
 533              // Unexisting library. Set libraryid to some unexisting id.
 534              $libraryid = -1;
 535              $this->expectException('dml_missing_record_exception');
 536          }
 537  
 538          \core_h5p\api::set_library_enabled($libraryid, ($action == 'enable'));
 539  
 540          // Check the value of the "enabled" field after calling enable/disable method.
 541          $libraries = $DB->get_records('h5p_libraries');
 542          foreach ($libraries as $libraryid => $library) {
 543              if ($library->machinename == $libraryname) {
 544                  $this->assertEquals($expected, $library->enabled);
 545              } else {
 546                  // Check that only $libraryname has been enabled/disabled.
 547                  $this->assertEquals(1, $library->enabled);
 548              }
 549          }
 550      }
 551  
 552      /**
 553       * Data provider for test_set_library_enabled().
 554       *
 555       * @return array
 556       */
 557      public function set_library_enabled_provider(): array {
 558          return [
 559              'Disable existing library' => [
 560                  'libraryname' => 'MainLibrary',
 561                  'action' => 'disable',
 562                  'expected' => 0,
 563              ],
 564              'Enable existing library' => [
 565                  'libraryname' => 'MainLibrary',
 566                  'action' => 'enable',
 567                  'expected' => 1,
 568              ],
 569              'Disable existing library (not main)' => [
 570                  'libraryname' => 'Library1',
 571                  'action' => 'disable',
 572                  'expected' => 0,
 573              ],
 574              'Enable existing library (not main)' => [
 575                  'libraryname' => 'Library1',
 576                  'action' => 'enable',
 577                  'expected' => 1,
 578              ],
 579              'Disable existing library (not runnable)' => [
 580                  'libraryname' => 'Library3',
 581                  'action' => 'disable',
 582                  'expected' => 1, // Not runnable libraries can't be disabled.
 583              ],
 584              'Enable existing library (not runnable)' => [
 585                  'libraryname' => 'Library3',
 586                  'action' => 'enable',
 587                  'expected' => 1,
 588              ],
 589              'Enable unexisting library' => [
 590                  'libraryname' => 'Unexisting library',
 591                  'action' => 'enable',
 592                  'expected' => -1,
 593              ],
 594              'Disable unexisting library' => [
 595                  'libraryname' => 'Unexisting library',
 596                  'action' => 'disable',
 597                  'expected' => -1,
 598              ],
 599          ];
 600      }
 601  
 602      /**
 603       * Test the behaviour of is_library_enabled().
 604       *
 605       * @covers ::is_library_enabled
 606       * @dataProvider is_library_enabled_provider
 607       *
 608       * @param string $libraryname Library name to check.
 609       * @param bool $expected Expected result after calling the method.
 610       * @param bool $exception Exception expected or not.
 611       * @param bool $useid Whether to use id for calling is_library_enabled method.
 612       * @param bool $uselibraryname Whether to use libraryname for calling is_library_enabled method.
 613       */
 614      public function test_is_library_enabled(string $libraryname, bool $expected, bool $exception = false,
 615          bool $useid = false, bool $uselibraryname = true): void {
 616          global $DB;
 617  
 618          $this->resetAfterTest();
 619  
 620          // Create the following libraries:
 621          // - H5P.Lib1: 1 version enabled, 1 version disabled.
 622          // - H5P.Lib2: 2 versions enabled.
 623          // - H5P.Lib3: 2 versions disabled.
 624          // - H5P.Lib4: 1 version disabled.
 625          // - H5P.Lib5: 1 version enabled.
 626          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 627          $libraries = [
 628              'H5P.Lib1.1' => $generator->create_library_record('H5P.Lib1', 'Lib1', 1, 1, 0, '', null, null, null, false),
 629              'H5P.Lib1.2' => $generator->create_library_record('H5P.Lib1', 'Lib1', 1, 2),
 630              'H5P.Lib2.1' => $generator->create_library_record('H5P.Lib2', 'Lib2', 2, 1),
 631              'H5P.Lib2.2' => $generator->create_library_record('H5P.Lib2', 'Lib2', 2, 2),
 632              'H5P.Lib3.1' => $generator->create_library_record('H5P.Lib3', 'Lib3', 3, 1, 0, '', null, null, null, false),
 633              'H5P.Lib3.2' => $generator->create_library_record('H5P.Lib3', 'Lib3', 3, 2, 0, '', null, null, null, false),
 634              'H5P.Lib4.1' => $generator->create_library_record('H5P.Lib4', 'Lib4', 4, 1, 0, '', null, null, null, false),
 635              'H5P.Lib5.1' => $generator->create_library_record('H5P.Lib5', 'Lib5', 5, 1),
 636          ];
 637  
 638          $countenabledlibraries = $DB->count_records('h5p_libraries', ['enabled' => 1]);
 639          $this->assertEquals(4, $countenabledlibraries);
 640  
 641          if ($useid) {
 642              $librarydata = ['id' => $libraries[$libraryname]->id];
 643          } else if ($uselibraryname) {
 644              $librarydata = ['machinename' => $libraryname];
 645          } else {
 646              $librarydata = ['invalid' => true];
 647          }
 648  
 649          if ($exception) {
 650              $this->expectException(\moodle_exception::class);
 651          }
 652  
 653          $result = api::is_library_enabled((object) $librarydata);
 654          $this->assertEquals($expected, $result);
 655      }
 656  
 657      /**
 658       * Data provider for test_is_library_enabled().
 659       *
 660       * @return array
 661       */
 662      public function is_library_enabled_provider(): array {
 663          return [
 664              'Library with 2 versions, one of them disabled' => [
 665                  'libraryname' => 'H5P.Lib1',
 666                  'expected' => false,
 667              ],
 668              'Library with 2 versions, all enabled' => [
 669                  'libraryname' => 'H5P.Lib2',
 670                  'expected' => true,
 671              ],
 672              'Library with 2 versions, all disabled' => [
 673                  'libraryname' => 'H5P.Lib3',
 674                  'expected' => false,
 675              ],
 676              'Library with only one version, disabled' => [
 677                  'libraryname' => 'H5P.Lib4',
 678                  'expected' => false,
 679              ],
 680              'Library with only one version, enabled' => [
 681                  'libraryname' => 'H5P.Lib5',
 682                  'expected' => true,
 683              ],
 684              'Library with 2 versions, one of them disabled (using id) - 1.1 (disabled)' => [
 685                  'libraryname' => 'H5P.Lib1.1',
 686                  'expected' => false,
 687                  'exception' => false,
 688                  'useid' => true,
 689              ],
 690              'Library with 2 versions, one of them disabled (using id) - 1.2 (enabled)' => [
 691                  'libraryname' => 'H5P.Lib1.2',
 692                  'expected' => true,
 693                  'exception' => false,
 694                  'useid' => true,
 695              ],
 696              'Library with 2 versions, all enabled (using id) - 2.1' => [
 697                  'libraryname' => 'H5P.Lib2.1',
 698                  'expected' => true,
 699                  'exception' => false,
 700                  'useid' => true,
 701              ],
 702              'Library with 2 versions, all enabled (using id) - 2.2' => [
 703                  'libraryname' => 'H5P.Lib2.2',
 704                  'expected' => true,
 705                  'exception' => false,
 706                  'useid' => true,
 707              ],
 708              'Library with 2 versions, all disabled (using id) - 3.1' => [
 709                  'libraryname' => 'H5P.Lib3.1',
 710                  'expected' => false,
 711                  'exception' => false,
 712                  'useid' => true,
 713              ],
 714              'Library with 2 versions, all disabled (using id) - 3.2' => [
 715                  'libraryname' => 'H5P.Lib3.2',
 716                  'expected' => false,
 717                  'exception' => false,
 718                  'useid' => true,
 719              ],
 720              'Library with only one version, disabled (using id)' => [
 721                  'libraryname' => 'H5P.Lib4.1',
 722                  'expected' => false,
 723                  'exception' => false,
 724                  'useid' => true,
 725              ],
 726              'Library with only one version, enabled (using id)' => [
 727                  'libraryname' => 'H5P.Lib5.1',
 728                  'expected' => true,
 729                  'exception' => false,
 730                  'useid' => true,
 731              ],
 732              'Unexisting library' => [
 733                  'libraryname' => 'H5P.Unexisting',
 734                  'expected' => true,
 735              ],
 736              'Missing required parameters' => [
 737                  'libraryname' => 'H5P.Unexisting',
 738                  'expected' => false,
 739                  'exception' => true,
 740                  'useid' => false,
 741                  'uselibraryname' => false,
 742              ],
 743          ];
 744      }
 745  
 746      /**
 747       * Test the behaviour of is_valid_package().
 748       * @runInSeparateProcess
 749       *
 750       * @covers ::is_valid_package
 751       * @dataProvider is_valid_package_provider
 752       *
 753       * @param string $filename The H5P content to validate.
 754       * @param bool $expected Expected result after calling the method.
 755       * @param bool $isadmin Whether the user calling the method will be admin or not.
 756       * @param bool $onlyupdatelibs Whether new libraries can be installed or only the existing ones can be updated.
 757       * @param bool $skipcontent Should the content be skipped (so only the libraries will be saved)?
 758       */
 759      public function test_is_valid_package(string $filename, bool $expected, bool $isadmin = false, bool $onlyupdatelibs = false,
 760              bool $skipcontent = false): void {
 761          global $USER;
 762  
 763          $this->resetAfterTest();
 764  
 765          if ($isadmin) {
 766              $this->setAdminUser();
 767              $user = $USER;
 768          } else {
 769              // Create a user.
 770              $user = $this->getDataGenerator()->create_user();
 771              $this->setUser($user);
 772          }
 773  
 774          // Prepare the file.
 775          $path = __DIR__ . $filename;
 776          $file = helper::create_fake_stored_file_from_path($path, (int)$user->id);
 777  
 778          // Check if the H5P content is valid or not.
 779          $result = api::is_valid_package($file, $onlyupdatelibs, $skipcontent);
 780          $this->assertEquals($expected, $result);
 781      }
 782  
 783      /**
 784       * Data provider for test_is_valid_package().
 785       *
 786       * @return array
 787       */
 788      public function is_valid_package_provider(): array {
 789          return [
 790              'Valid H5P file (as admin)' => [
 791                  'filename' => '/fixtures/greeting-card-887.h5p',
 792                  'expected' => true,
 793                  'isadmin' => true,
 794              ],
 795              'Valid H5P file (as user) without library update and checking content' => [
 796                  'filename' => '/fixtures/greeting-card-887.h5p',
 797                  'expected' => false, // Libraries are missing and user hasn't the right permissions to upload them.
 798                  'isadmin' => false,
 799                  'onlyupdatelibs' => false,
 800                  'skipcontent' => false,
 801              ],
 802              'Valid H5P file (as user) with library update and checking content' => [
 803                  'filename' => '/fixtures/greeting-card-887.h5p',
 804                  'expected' => false, // Libraries are missing and user hasn't the right permissions to upload them.
 805                  'isadmin' => false,
 806                  'onlyupdatelibs' => true,
 807                  'skipcontent' => false,
 808              ],
 809              'Valid H5P file (as user) without library update and skipping content' => [
 810                  'filename' => '/fixtures/greeting-card-887.h5p',
 811                  'expected' => true, // Content check is skipped so the package will be considered valid.
 812                  'isadmin' => false,
 813                  'onlyupdatelibs' => false,
 814                  'skipcontent' => true,
 815              ],
 816              'Valid H5P file (as user) with library update and skipping content' => [
 817                  'filename' => '/fixtures/greeting-card-887.h5p',
 818                  'expected' => true, // Content check is skipped so the package will be considered valid.
 819                  'isadmin' => false,
 820                  'onlyupdatelibs' => true,
 821                  'skipcontent' => true,
 822              ],
 823              'Invalid H5P file (as admin)' => [
 824                  'filename' => '/fixtures/h5ptest.zip',
 825                  'expected' => false,
 826                  'isadmin' => true,
 827              ],
 828              'Invalid H5P file (as user)' => [
 829                  'filename' => '/fixtures/h5ptest.zip',
 830                  'expected' => false,
 831                  'isadmin' => false,
 832              ],
 833              'Invalid H5P file (as user) skipping content' => [
 834                  'filename' => '/fixtures/h5ptest.zip',
 835                  'expected' => true, // Content check is skipped so the package will be considered valid.
 836                  'isadmin' => false,
 837                  'onlyupdatelibs' => false,
 838                  'skipcontent' => true,
 839              ],
 840          ];
 841      }
 842  }