Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

   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_h5p\local\library\autoloader;
  20  
  21  /**
  22   * Test class covering the h5p data generator class.
  23   *
  24   * @package    core_h5p
  25   * @category   test
  26   * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
  27   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  28   * @runTestsInSeparateProcesses
  29   * @covers     \core_h5p_generator
  30  */
  31  class generator_test extends \advanced_testcase {
  32  
  33      /**
  34       * Tests set up.
  35       */
  36      protected function setUp(): void {
  37          parent::setUp();
  38  
  39          autoloader::register();
  40      }
  41  
  42      /**
  43       * Test the returned data of generate_h5p_data() when the method is called without requesting
  44       * creation of library files.
  45       */
  46      public function test_generate_h5p_data_no_files_created_return_data() {
  47          global $DB;
  48  
  49          $this->resetAfterTest();
  50  
  51          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
  52  
  53          $data = $generator->generate_h5p_data();
  54  
  55          $mainlib = $DB->get_record('h5p_libraries', ['machinename' => 'MainLibrary']);
  56          $lib1 = $DB->get_record('h5p_libraries', ['machinename' => 'Library1']);
  57          $lib2 = $DB->get_record('h5p_libraries', ['machinename' => 'Library2']);
  58          $lib3 = $DB->get_record('h5p_libraries', ['machinename' => 'Library3']);
  59          $lib4 = $DB->get_record('h5p_libraries', ['machinename' => 'Library4']);
  60          $lib5 = $DB->get_record('h5p_libraries', ['machinename' => 'Library5']);
  61  
  62          $h5p = $DB->get_record('h5p', ['mainlibraryid' => $mainlib->id]);
  63  
  64          $expected = (object) [
  65              'h5pcontent' => (object) array(
  66                   'h5pid' => $h5p->id,
  67                   'contentdependencies' => array($mainlib, $lib1, $lib2, $lib3, $lib4)
  68              ),
  69              'mainlib' => (object) array(
  70                  'data' => $mainlib,
  71                  'dependencies' => array($lib1, $lib2, $lib3)
  72              ),
  73              'lib1' => (object) array(
  74                  'data' => $lib1,
  75                  'dependencies' => array($lib2, $lib3, $lib4)
  76              ),
  77              'lib2' => (object) array(
  78                  'data' => $lib2,
  79                  'dependencies' => array()
  80              ),
  81              'lib3' => (object) array(
  82                  'data' => $lib3,
  83                  'dependencies' => array($lib5)
  84              ),
  85              'lib4' => (object) array(
  86                  'data' => $lib4,
  87                  'dependencies' => array()
  88              ),
  89              'lib5' => (object) array(
  90                  'data' => $lib5,
  91                  'dependencies' => array()
  92              ),
  93          ];
  94  
  95          $this->assertEquals($expected, $data);
  96      }
  97  
  98      /**
  99       * Test the returned data of generate_h5p_data() when the method requests
 100       * creation of library files.
 101       */
 102      public function test_generate_h5p_data_files_created_return_data() {
 103          global $DB;
 104  
 105          $this->resetAfterTest();
 106  
 107          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 108  
 109          $data = $generator->generate_h5p_data(true);
 110  
 111          $mainlib = $DB->get_record('h5p_libraries', ['machinename' => 'MainLibrary']);
 112          $lib1 = $DB->get_record('h5p_libraries', ['machinename' => 'Library1']);
 113          $lib2 = $DB->get_record('h5p_libraries', ['machinename' => 'Library2']);
 114          $lib3 = $DB->get_record('h5p_libraries', ['machinename' => 'Library3']);
 115          $lib4 = $DB->get_record('h5p_libraries', ['machinename' => 'Library4']);
 116          $lib5 = $DB->get_record('h5p_libraries', ['machinename' => 'Library5']);
 117  
 118          $h5p = $DB->get_record('h5p', ['mainlibraryid' => $mainlib->id]);
 119  
 120          $expected = (object) [
 121              'h5pcontent' => (object) array(
 122                   'h5pid' => $h5p->id,
 123                   'contentdependencies' => array($mainlib, $lib1, $lib2, $lib3, $lib4)
 124              ),
 125              'mainlib' => (object) array(
 126                  'data' => $mainlib,
 127                  'dependencies' => array($lib1, $lib2, $lib3)
 128              ),
 129              'lib1' => (object) array(
 130                  'data' => $lib1,
 131                  'dependencies' => array($lib2, $lib3, $lib4)
 132              ),
 133              'lib2' => (object) array(
 134                  'data' => $lib2,
 135                  'dependencies' => array()
 136              ),
 137              'lib3' => (object) array(
 138                  'data' => $lib3,
 139                  'dependencies' => array($lib5)
 140              ),
 141              'lib4' => (object) array(
 142                  'data' => $lib4,
 143                  'dependencies' => array()
 144              ),
 145              'lib5' => (object) array(
 146                  'data' => $lib5,
 147                  'dependencies' => array()
 148              ),
 149          ];
 150  
 151          $this->assertEquals($expected, $data);
 152      }
 153  
 154      /**
 155       * Test the behaviour of generate_h5p_data(). Test whether library files are created or not
 156       * on filesystem depending what the method defines.
 157       *
 158       * @dataProvider generate_h5p_data_files_creation_provider
 159       * @param bool $createlibraryfiles Whether to create library files on the filesystem
 160       * @param bool $expected The expectation whether the files have been created or not
 161       **/
 162      public function test_generate_h5p_data_files_creation(bool $createlibraryfiles, bool $expected) {
 163          global $DB;
 164  
 165          $this->resetAfterTest();
 166  
 167          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 168          $generator->generate_h5p_data($createlibraryfiles);
 169  
 170          $libraries[] = $DB->get_record('h5p_libraries', ['machinename' => 'MainLibrary']);
 171          $libraries[] = $DB->get_record('h5p_libraries', ['machinename' => 'Library1']);
 172          $libraries[] = $DB->get_record('h5p_libraries', ['machinename' => 'Library2']);
 173          $libraries[] = $DB->get_record('h5p_libraries', ['machinename' => 'Library3']);
 174          $libraries[] = $DB->get_record('h5p_libraries', ['machinename' => 'Library4']);
 175          $libraries[] = $DB->get_record('h5p_libraries', ['machinename' => 'Library5']);
 176  
 177          foreach($libraries as $lib) {
 178              // Return the created library files.
 179              $libraryfiles = $DB->get_records('files',
 180                  array(
 181                      'component' => \core_h5p\file_storage::COMPONENT,
 182                      'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
 183                      'itemid' => $lib->id
 184                  )
 185              );
 186  
 187              $haslibraryfiles = !empty($libraryfiles);
 188  
 189              $this->assertEquals($expected, $haslibraryfiles);
 190          }
 191      }
 192  
 193      /**
 194       * Data provider for test_generate_h5p_data_files_creation().
 195       *
 196       * @return array
 197       */
 198      public function generate_h5p_data_files_creation_provider(): array {
 199          return [
 200              'Do not create library related files on the filesystem' => [
 201                  false,
 202                  false
 203              ],
 204              'Create library related files on the filesystem' => [
 205                  true,
 206                  true
 207              ]
 208          ];
 209      }
 210  
 211      /**
 212       * Test the returned data of generate_h5p_data() when the method requests
 213       * creation of H5P file and xAPI states.
 214       *
 215       * @dataProvider generate_h5p_data_xapistates_provider
 216       * @param array|null $filerecord
 217       */
 218      public function test_generate_h5p_data_xapistates(?array $filerecord) {
 219          global $DB;
 220  
 221          $this->resetAfterTest();
 222  
 223          /** @var \core_h5p_generator $generator */
 224          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 225          $course = $this->getDataGenerator()->create_course();
 226          $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
 227          $this->setUser($user);
 228          $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
 229          $activitycontext = \context_module::instance($activity->cmid);
 230          if ($filerecord) {
 231              $filerecord['contextid'] = $activitycontext->id;
 232              $filerecord['component'] = 'mod_h5pactivity';
 233              $filerecord['filearea'] = 'package';
 234              $filerecord['itemid'] = 0;
 235              $filerecord['filepath'] = '/';
 236              $filerecord['filepath'] = '/';
 237              $filerecord['filename'] = 'dummy.h5p';
 238          }
 239  
 240          $data = $generator->generate_h5p_data(false, $filerecord);
 241  
 242          $mainlib = $DB->get_record('h5p_libraries', ['machinename' => 'MainLibrary']);
 243          $lib1 = $DB->get_record('h5p_libraries', ['machinename' => 'Library1']);
 244          $lib2 = $DB->get_record('h5p_libraries', ['machinename' => 'Library2']);
 245          $lib3 = $DB->get_record('h5p_libraries', ['machinename' => 'Library3']);
 246          $lib4 = $DB->get_record('h5p_libraries', ['machinename' => 'Library4']);
 247          $lib5 = $DB->get_record('h5p_libraries', ['machinename' => 'Library5']);
 248  
 249          $h5p = $DB->get_record('h5p', ['mainlibraryid' => $mainlib->id]);
 250  
 251          $expected = (object) [
 252              'h5pcontent' => (object) [
 253                   'h5pid' => $h5p->id,
 254                   'contentdependencies' => [$mainlib, $lib1, $lib2, $lib3, $lib4],
 255              ],
 256              'mainlib' => (object) [
 257                  'data' => $mainlib,
 258                  'dependencies' => [$lib1, $lib2, $lib3],
 259              ],
 260              'lib1' => (object) [
 261                  'data' => $lib1,
 262                  'dependencies' => [$lib2, $lib3, $lib4],
 263              ],
 264              'lib2' => (object) [
 265                  'data' => $lib2,
 266                  'dependencies' => [],
 267              ],
 268              'lib3' => (object) [
 269                  'data' => $lib3,
 270                  'dependencies' => [$lib5],
 271              ],
 272              'lib4' => (object) [
 273                  'data' => $lib4,
 274                  'dependencies' => [],
 275              ],
 276              'lib5' => (object) [
 277                  'data' => $lib5,
 278                  'dependencies' => [],
 279              ],
 280          ];
 281  
 282          $this->assertEquals($expected, $data);
 283          if ($filerecord) {
 284              // Confirm the H5P file has been created (when $filerecord is not empty).
 285              $fs = get_file_storage();
 286              $this->assertNotFalse($fs->get_file_by_hash($h5p->pathnamehash));
 287              // Confirm xAPI state has been created when $filerecord['addxapistate'] is given.
 288              if (array_key_exists('addxapistate', $filerecord) && $filerecord['addxapistate']) {
 289                  $this->assertEquals(1, $DB->count_records('xapi_states'));
 290              } else {
 291                  $this->assertEquals(0, $DB->count_records('xapi_states'));
 292              }
 293          } else {
 294              // Confirm the H5P file doesn't exist when $filerecord is null.
 295              $fs = get_file_storage();
 296              $this->assertFalse($fs->get_file_by_hash($h5p->pathnamehash));
 297              // Confirm xAPI state hasn't been created when $filerecord is null.
 298              $this->assertEquals(0, $DB->count_records('xapi_states'));
 299          }
 300      }
 301  
 302      /**
 303       * Data provider for test_generate_h5p_data_xapistates().
 304       *
 305       * @return array
 306       */
 307      public function generate_h5p_data_xapistates_provider(): array {
 308          return [
 309              'Do not create the file nor xAPI states' => [
 310                  'filerecord' => null,
 311              ],
 312              'Create the H5P file but not create any xAPI state' => [
 313                  'filerecord' => [
 314                      'addxapistate' => false,
 315                  ],
 316              ],
 317              'Create the H5P file and the xAPI state' => [
 318                  'filerecord' => [
 319                      'addxapistate' => true,
 320                  ],
 321              ],
 322          ];
 323      }
 324  
 325      /**
 326       * Test the behaviour of create_library_record(). Test whether the library data is properly
 327       * saved in the database.
 328       */
 329      public function test_create_library_record() {
 330          $this->resetAfterTest();
 331  
 332          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 333  
 334          $data = $generator->create_library_record(
 335              'Library', 'Lib', 1, 2, 3, 'Semantics example', '/regex11/', 'http://tutorial.org/', 'http://example.org/'
 336          );
 337          unset($data->id);
 338  
 339          $expected = (object) [
 340              'machinename' => 'Library',
 341              'title' => 'Lib',
 342              'majorversion' => '1',
 343              'minorversion' => '2',
 344              'patchversion' => '3',
 345              'runnable' => '1',
 346              'fullscreen' => '1',
 347              'embedtypes' => '',
 348              'preloadedjs' => 'js/example.js',
 349              'preloadedcss' => 'css/example.css',
 350              'droplibrarycss' => '',
 351              'semantics' => 'Semantics example',
 352              'addto' => '/regex11/',
 353              'tutorial' => 'http://tutorial.org/',
 354              'example' => 'http://example.org/',
 355              'coremajor' => null,
 356              'coreminor' => null,
 357              'metadatasettings' => null,
 358              'enabled' => 1,
 359          ];
 360  
 361          $this->assertEquals($expected, $data);
 362      }
 363  
 364      /**
 365       * Test the behaviour of create_h5p_record(). Test whather the h5p content data is
 366       * properly saved in the database.
 367       *
 368       * @dataProvider create_h5p_record_provider
 369       * @param array $h5pdata The h5p content data
 370       * @param \stdClass $expected The expected saved data
 371       **/
 372      public function test_create_h5p_record(array $h5pdata, \stdClass $expected) {
 373          global $DB;
 374  
 375          $this->resetAfterTest();
 376  
 377          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 378  
 379          $h5pid = call_user_func_array([$generator, 'create_h5p_record'], $h5pdata);
 380  
 381          $data = $DB->get_record('h5p', ['id' => $h5pid]);
 382          unset($data->id);
 383          unset($data->timecreated);
 384          unset($data->timemodified);
 385  
 386          $this->assertEquals($data, $expected);
 387      }
 388  
 389      /**
 390       * Data provider for test_create_h5p_record().
 391       *
 392       * @return array
 393       */
 394      public function create_h5p_record_provider(): array {
 395          $createdjsoncontent = json_encode(
 396              array(
 397                  'text' => '<p>Created dummy text<\/p>\n',
 398                  'questions' => '<p>Test created question<\/p>\n'
 399              )
 400          );
 401  
 402          $defaultjsoncontent = json_encode(
 403              array(
 404                  'text' => '<p>Dummy text<\/p>\n',
 405                  'questions' => '<p>Test question<\/p>\n'
 406              )
 407          );
 408  
 409          $createdfilteredcontent = json_encode(
 410              array(
 411                  'text' => 'Created dummy text',
 412                  'questions' => 'Test created question'
 413              )
 414          );
 415  
 416          $defaultfilteredcontent = json_encode(
 417              array(
 418                  'text' => 'Dummy text',
 419                  'questions' => 'Test question'
 420              )
 421          );
 422  
 423          return [
 424              'Create h5p content record with set json content and set filtered content' => [
 425                  [
 426                      1,
 427                      $createdjsoncontent,
 428                      $createdfilteredcontent
 429                  ],
 430                  (object) array(
 431                      'jsoncontent' => $createdjsoncontent,
 432                      'mainlibraryid' => '1',
 433                      'displayoptions' => '8',
 434                      'pathnamehash' => sha1('pathname'),
 435                      'contenthash' => sha1('content'),
 436                      'filtered' => $createdfilteredcontent,
 437                  )
 438              ],
 439              'Create h5p content record with set json content and default filtered content' => [
 440                  [
 441                      1,
 442                      $createdjsoncontent,
 443                      null
 444                  ],
 445                  (object) array(
 446                      'jsoncontent' => $createdjsoncontent,
 447                      'mainlibraryid' => '1',
 448                      'displayoptions' => '8',
 449                      'pathnamehash' => sha1('pathname'),
 450                      'contenthash' => sha1('content'),
 451                      'filtered' => $defaultfilteredcontent,
 452                  )
 453              ],
 454              'Create h5p content record with default json content and set filtered content' => [
 455                  [
 456                      1,
 457                      null,
 458                      $createdfilteredcontent
 459                  ],
 460                  (object) array(
 461                      'jsoncontent' => $defaultjsoncontent,
 462                      'mainlibraryid' => '1',
 463                      'displayoptions' => '8',
 464                      'pathnamehash' => sha1('pathname'),
 465                      'contenthash' => sha1('content'),
 466                      'filtered' => $createdfilteredcontent,
 467                  )
 468              ],
 469              'Create h5p content record with default json content and default filtered content' => [
 470                  [
 471                      1,
 472                      null,
 473                      null
 474                  ],
 475                  (object) array(
 476                      'jsoncontent' => $defaultjsoncontent,
 477                      'mainlibraryid' => '1',
 478                      'displayoptions' => '8',
 479                      'pathnamehash' => sha1('pathname'),
 480                      'contenthash' => sha1('content'),
 481                      'filtered' => $defaultfilteredcontent,
 482                  )
 483              ]
 484          ];
 485      }
 486  
 487      /**
 488       * Test the behaviour of create_contents_libraries_record(). Test whether the contents libraries
 489       * are properly saved in the database.
 490       *
 491       * @dataProvider create_contents_libraries_record_provider
 492       * @param array $contentslibrariestdata The h5p contents libraries data.
 493       * @param \stdClass $expected The expected saved data.
 494       **/
 495      public function test_create_contents_libraries_record(array $contentslibrariestdata, \stdClass $expected) {
 496          global $DB;
 497  
 498          $this->resetAfterTest();
 499  
 500          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 501  
 502          $contentlibid = call_user_func_array([$generator, 'create_contents_libraries_record'], $contentslibrariestdata);
 503  
 504          $data = $DB->get_record('h5p_contents_libraries', ['id' => $contentlibid]);
 505          unset($data->id);
 506  
 507          $this->assertEquals($data, $expected);
 508      }
 509  
 510      /**
 511       * Data provider for test_create_contents_libraries_record().
 512       *
 513       * @return array
 514       */
 515      public function create_contents_libraries_record_provider(): array {
 516          return [
 517              'Create h5p content library with set dependency type' => [
 518                  [
 519                      1,
 520                      1,
 521                      'dynamic'
 522                  ],
 523                  (object) array(
 524                      'h5pid' => '1',
 525                      'libraryid' => '1',
 526                      'dependencytype' => 'dynamic',
 527                      'dropcss' => '0',
 528                      'weight' => '1'
 529                  )
 530              ],
 531              'Create h5p content library with a default dependency type' => [
 532                  [
 533                      1,
 534                      1
 535                  ],
 536                  (object) array(
 537                      'h5pid' => '1',
 538                      'libraryid' => '1',
 539                      'dependencytype' => 'preloaded',
 540                      'dropcss' => '0',
 541                      'weight' => '1'
 542                  )
 543              ]
 544          ];
 545      }
 546  
 547      /**
 548       * Test the behaviour of create_library_dependency_record(). Test whether the contents libraries
 549       * are properly saved in the database.
 550       *
 551       * @dataProvider create_library_dependency_record_provider
 552       * @param array $librarydependencydata The library dependency data.
 553       * @param \stdClass $expected The expected saved data.
 554       **/
 555      public function test_create_library_dependency_record(array $librarydependencydata, \stdClass $expected) {
 556          global $DB;
 557  
 558          $this->resetAfterTest();
 559  
 560          $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
 561  
 562          $contentlibid = call_user_func_array([$generator, 'create_library_dependency_record'], $librarydependencydata);
 563  
 564          $data = $DB->get_record('h5p_library_dependencies', ['id' => $contentlibid]);
 565          unset($data->id);
 566  
 567          $this->assertEquals($data, $expected);
 568      }
 569  
 570      /**
 571       * Data provider for test_create_library_dependency_record().
 572       *
 573       * @return array
 574       */
 575      public function create_library_dependency_record_provider(): array {
 576          return [
 577              'Create h5p library dependency with set dependency type' => [
 578                  [
 579                      1,
 580                      1,
 581                      'dynamic'
 582                  ],
 583                  (object) array(
 584                      'libraryid' => '1',
 585                      'requiredlibraryid' => '1',
 586                      'dependencytype' => 'dynamic'
 587                  )
 588              ],
 589              'Create h5p library dependency with default dependency type' => [
 590                  [
 591                      1,
 592                      1
 593                  ],
 594                  (object) array(
 595                      'libraryid' => '1',
 596                      'requiredlibraryid' => '1',
 597                      'dependencytype' => 'preloaded'
 598                  )
 599              ]
 600          ];
 601      }
 602  
 603      /**
 604       * Test the behaviour of create_content_file(). Test whether a file belonging to a content is created.
 605       *
 606       * @dataProvider create_content_file_provider
 607       * @param array $filedata Data from the file to be created.
 608       * @param array $expecteddata Data expected.Data from the file to be created.
 609       */
 610      public function test_create_content_file($filedata, $expecteddata): void {
 611          $this->resetAfterTest();
 612  
 613          $generator = self::getDataGenerator()->get_plugin_generator('core_h5p');
 614  
 615          if ($expecteddata[1] === 'exception') {
 616              $this->expectException('coding_exception');
 617          }
 618          call_user_func_array([$generator, 'create_content_file'], $filedata);
 619  
 620          $systemcontext = \context_system::instance();
 621          $filearea = $filedata[1];
 622          $filepath = '/'. dirname($filedata[0]). '/';
 623          $filename = basename($filedata[0]);
 624          $itemid = $expecteddata[0];
 625  
 626          $fs = new \file_storage();
 627          $exists = $fs->file_exists($systemcontext->id, file_storage::COMPONENT, $filearea, $itemid, $filepath,
 628              $filename);
 629          if ($expecteddata[1] === true) {
 630              $this->assertTrue($exists);
 631          } else if ($expecteddata[1] === false) {
 632              $this->assertFalse($exists);
 633          }
 634      }
 635  
 636      /**
 637       * Data provider for test_create_content_file(). Data from different files to be created.
 638       *
 639       * @return array
 640       **/
 641      public function create_content_file_provider(): array {
 642          return [
 643              'Create file in content with id 4' => [
 644                  [
 645                      'images/img1.png',
 646                      'content',
 647                      4
 648                  ],
 649                  [
 650                      4,
 651                      true
 652                  ]
 653              ],
 654              'Create file in the editor' => [
 655                  [
 656                      'images/img1.png',
 657                      'editor'
 658                  ],
 659                  [
 660                      0,
 661                      true
 662                  ]
 663              ],
 664              'Create file in content without id' => [
 665                  [
 666                      'images/img1.png',
 667                      'content'
 668                  ],
 669                  [
 670                      0,
 671                      'exception'
 672                  ]
 673              ]
 674          ];
 675      }
 676  }