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]

   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   * This file contains tests for scorm events.
  19   *
  20   * @package    mod_scorm
  21   * @copyright  2013 onwards Ankit Agarwal
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  global $CFG;
  26  require_once($CFG->dirroot . '/mod/scorm/locallib.php');
  27  require_once($CFG->dirroot . '/mod/scorm/lib.php');
  28  
  29  /**
  30   * Test class for various events related to Scorm.
  31   *
  32   * @package    mod_scorm
  33   * @copyright  2013 onwards Ankit Agarwal
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class mod_scorm_event_testcase extends advanced_testcase {
  37  
  38      /** @var stdClass store course object */
  39      protected $eventcourse;
  40  
  41      /** @var stdClass store user object */
  42      protected $eventuser;
  43  
  44      /** @var stdClass store scorm object */
  45      protected $eventscorm;
  46  
  47      /** @var stdClass store course module object */
  48      protected $eventcm;
  49  
  50      protected function setUp() {
  51          $this->setAdminUser();
  52          $this->eventcourse = $this->getDataGenerator()->create_course();
  53          $this->eventuser = $this->getDataGenerator()->create_user();
  54          $record = new stdClass();
  55          $record->course = $this->eventcourse->id;
  56          $this->eventscorm = $this->getDataGenerator()->create_module('scorm', $record);
  57          $this->eventcm = get_coursemodule_from_instance('scorm', $this->eventscorm->id);
  58      }
  59  
  60      /**
  61       * Tests for attempt deleted event
  62       *
  63       * @expectedException coding_exception
  64       */
  65      public function test_attempt_deleted_event() {
  66  
  67          global $USER;
  68  
  69          $this->resetAfterTest();
  70          scorm_insert_track(2, $this->eventscorm->id, 1, 4, 'cmi.core.score.raw', 10);
  71          $sink = $this->redirectEvents();
  72          scorm_delete_attempt(2, $this->eventscorm, 4);
  73          $events = $sink->get_events();
  74          $sink->close();
  75          $event = reset($events);
  76  
  77          // Verify data.
  78          $this->assertCount(3, $events);
  79          $this->assertInstanceOf('\mod_scorm\event\attempt_deleted', $event);
  80          $this->assertEquals($USER->id, $event->userid);
  81          $this->assertEquals(context_module::instance($this->eventcm->id), $event->get_context());
  82          $this->assertEquals(4, $event->other['attemptid']);
  83          $this->assertEquals(2, $event->relateduserid);
  84          $expected = array($this->eventcourse->id, 'scorm', 'delete attempts', 'report.php?id=' . $this->eventcm->id,
  85                  4, $this->eventcm->id);
  86          $this->assertEventLegacyLogData($expected, $events[0]);
  87          $this->assertEventContextNotUsed($event);
  88  
  89          // Test event validations.
  90          \mod_scorm\event\attempt_deleted::create(array(
  91              'contextid' => 5,
  92              'relateduserid' => 2
  93          ));
  94          $this->fail('event \\mod_scorm\\event\\attempt_deleted is not validating events properly');
  95      }
  96  
  97      /**
  98       * Tests for course module viewed event.
  99       *
 100       * There is no api involved so the best we can do is test legacy data by triggering event manually.
 101       */
 102      public function test_course_module_viewed_event() {
 103          $this->resetAfterTest();
 104          $event = \mod_scorm\event\course_module_viewed::create(array(
 105              'objectid' => $this->eventscorm->id,
 106              'context' => context_module::instance($this->eventcm->id),
 107              'courseid' => $this->eventcourse->id
 108          ));
 109  
 110          // Trigger and capture the event.
 111          $sink = $this->redirectEvents();
 112          $event->trigger();
 113          $events = $sink->get_events();
 114          $event = reset($events);
 115  
 116          // Check that the legacy log data is valid.
 117          $expected = array($this->eventcourse->id, 'scorm', 'pre-view', 'view.php?id=' . $this->eventcm->id,
 118                  $this->eventscorm->id, $this->eventcm->id);
 119          $this->assertEventLegacyLogData($expected, $event);
 120          $this->assertEventContextNotUsed($event);
 121      }
 122  
 123      /**
 124       * Tests for instance list viewed event.
 125       *
 126       * There is no api involved so the best we can do is test legacy data by triggering event manually.
 127       */
 128      public function test_course_module_instance_list_viewed_event() {
 129          $this->resetAfterTest();
 130          $event = \mod_scorm\event\course_module_instance_list_viewed::create(array(
 131              'context' => context_course::instance($this->eventcourse->id),
 132              'courseid' => $this->eventcourse->id
 133          ));
 134  
 135          // Trigger and capture the event.
 136          $sink = $this->redirectEvents();
 137          $event->trigger();
 138          $events = $sink->get_events();
 139          $event = reset($events);
 140  
 141          // Check that the legacy log data is valid.
 142          $expected = array($this->eventcourse->id, 'scorm', 'view all', 'index.php?id=' . $this->eventcourse->id, '');
 143          $this->assertEventLegacyLogData($expected, $event);
 144          $this->assertEventContextNotUsed($event);
 145      }
 146  
 147      /**
 148       * Tests for interactions viewed.
 149       *
 150       * There is no api involved so the best we can do is test legacy data by triggering event manually and test validations.
 151       */
 152      public function test_interactions_viewed_event() {
 153          $this->resetAfterTest();
 154          $event = \mod_scorm\event\interactions_viewed::create(array(
 155              'relateduserid' => 5,
 156              'context' => context_module::instance($this->eventcm->id),
 157              'courseid' => $this->eventcourse->id,
 158              'other' => array('attemptid' => 2, 'instanceid' => $this->eventscorm->id)
 159          ));
 160  
 161          // Trigger and capture the event.
 162          $sink = $this->redirectEvents();
 163          $event->trigger();
 164          $events = $sink->get_events();
 165          $event = reset($events);
 166  
 167          // Check that the legacy log data is valid.
 168          $expected = array($this->eventcourse->id, 'scorm', 'userreportinteractions', 'report/userreportinteractions.php?id=' .
 169                  $this->eventcm->id . '&user=5&attempt=' . 2, $this->eventscorm->id, $this->eventcm->id);
 170          $this->assertEventLegacyLogData($expected, $event);
 171          $this->assertEventContextNotUsed($event);
 172      }
 173  
 174      /**
 175       * Tests for interactions viewed validations.
 176       */
 177      public function test_interactions_viewed_event_validations() {
 178          $this->resetAfterTest();
 179          try {
 180              \mod_scorm\event\interactions_viewed::create(array(
 181                  'context' => context_module::instance($this->eventcm->id),
 182                  'courseid' => $this->eventcourse->id,
 183                  'other' => array('attemptid' => 2)
 184              ));
 185              $this->fail("Event validation should not allow \\mod_scorm\\event\\interactions_viewed to be triggered without
 186                      other['instanceid']");
 187          } catch (Exception $e) {
 188              $this->assertInstanceOf('coding_exception', $e);
 189          }
 190          try {
 191              \mod_scorm\event\interactions_viewed::create(array(
 192                  'context' => context_module::instance($this->eventcm->id),
 193                  'courseid' => $this->eventcourse->id,
 194                  'other' => array('instanceid' => 2)
 195              ));
 196              $this->fail("Event validation should not allow \\mod_scorm\\event\\interactions_viewed to be triggered without
 197                      other['attemptid']");
 198          } catch (Exception $e) {
 199              $this->assertInstanceOf('coding_exception', $e);
 200          }
 201      }
 202  
 203      /** Tests for report viewed.
 204       *
 205       * There is no api involved so the best we can do is test legacy data and validations by triggering event manually.
 206       */
 207      public function test_report_viewed_event() {
 208          $this->resetAfterTest();
 209          $event = \mod_scorm\event\report_viewed::create(array(
 210               'context' => context_module::instance($this->eventcm->id),
 211               'courseid' => $this->eventcourse->id,
 212               'other' => array(
 213                   'scormid' => $this->eventscorm->id,
 214                   'mode' => 'basic'
 215               )
 216          ));
 217  
 218          // Trigger and capture the event.
 219          $sink = $this->redirectEvents();
 220          $event->trigger();
 221          $events = $sink->get_events();
 222          $event = reset($events);
 223  
 224          // Check that the legacy log data is valid.
 225          $expected = array($this->eventcourse->id, 'scorm', 'report', 'report.php?id=' . $this->eventcm->id . '&mode=basic',
 226                  $this->eventscorm->id, $this->eventcm->id);
 227          $this->assertEventLegacyLogData($expected, $event);
 228          $this->assertEventContextNotUsed($event);
 229      }
 230  
 231      /** Tests for sco launched event.
 232       *
 233       * There is no api involved so the best we can do is test legacy data and validations by triggering event manually.
 234       *
 235       * @expectedException coding_exception
 236       */
 237      public function test_sco_launched_event() {
 238          $this->resetAfterTest();
 239          $event = \mod_scorm\event\sco_launched::create(array(
 240               'objectid' => 2,
 241               'context' => context_module::instance($this->eventcm->id),
 242               'courseid' => $this->eventcourse->id,
 243               'other' => array('loadedcontent' => 'url_to_content_that_was_laoded.php')
 244          ));
 245  
 246          // Trigger and capture the event.
 247          $sink = $this->redirectEvents();
 248          $event->trigger();
 249          $events = $sink->get_events();
 250          $event = reset($events);
 251  
 252          // Check that the legacy log data is valid.
 253          $expected = array($this->eventcourse->id, 'scorm', 'launch', 'view.php?id=' . $this->eventcm->id,
 254                            'url_to_content_that_was_laoded.php', $this->eventcm->id);
 255          $this->assertEventLegacyLogData($expected, $event);
 256          $this->assertEventContextNotUsed($event);
 257  
 258          // Test validations.
 259          \mod_scorm\event\sco_launched::create(array(
 260               'objectid' => $this->eventscorm->id,
 261               'context' => context_module::instance($this->eventcm->id),
 262               'courseid' => $this->eventcourse->id,
 263          ));
 264          $this->fail('Event \\mod_scorm\\event\\sco_launched is not validating "loadedcontent" properly');
 265      }
 266  
 267      /**
 268       * Tests for tracks viewed event.
 269       *
 270       * There is no api involved so the best we can do is test validations by triggering event manually.
 271       */
 272      public function test_tracks_viewed_event() {
 273          $this->resetAfterTest();
 274          $event = \mod_scorm\event\tracks_viewed::create(array(
 275              'relateduserid' => 5,
 276              'context' => context_module::instance($this->eventcm->id),
 277              'courseid' => $this->eventcourse->id,
 278              'other' => array('attemptid' => 2, 'instanceid' => $this->eventscorm->id, 'scoid' => 3)
 279          ));
 280  
 281          // Trigger and capture the event.
 282          $sink = $this->redirectEvents();
 283          $event->trigger();
 284          $events = $sink->get_events();
 285          $event = reset($events);
 286  
 287          // Check that the legacy log data is valid.
 288          $expected = array($this->eventcourse->id, 'scorm', 'userreporttracks', 'report/userreporttracks.php?id=' .
 289                  $this->eventcm->id . '&user=5&attempt=' . 2 . '&scoid=3', $this->eventscorm->id, $this->eventcm->id);
 290          $this->assertEventLegacyLogData($expected, $event);
 291          $this->assertEventContextNotUsed($event);
 292      }
 293  
 294      /**
 295       * Tests for tracks viewed event validations.
 296       */
 297      public function test_tracks_viewed_event_validations() {
 298          $this->resetAfterTest();
 299          try {
 300              \mod_scorm\event\tracks_viewed::create(array(
 301                  'context' => context_module::instance($this->eventcm->id),
 302                  'courseid' => $this->eventcourse->id,
 303                  'other' => array('attemptid' => 2, 'scoid' => 2)
 304              ));
 305              $this->fail("Event validation should not allow \\mod_scorm\\event\\tracks_viewed to be triggered without
 306                      other['instanceid']");
 307          } catch (Exception $e) {
 308              $this->assertInstanceOf('coding_exception', $e);
 309          }
 310          try {
 311              \mod_scorm\event\tracks_viewed::create(array(
 312                  'context' => context_module::instance($this->eventcm->id),
 313                  'courseid' => $this->eventcourse->id,
 314                  'other' => array('instanceid' => 2, 'scoid' => 2)
 315              ));
 316              $this->fail("Event validation should not allow \\mod_scorm\\event\\tracks_viewed to be triggered without
 317                      other['attemptid']");
 318          } catch (Exception $e) {
 319              $this->assertInstanceOf('coding_exception', $e);
 320          }
 321  
 322          try {
 323              \mod_scorm\event\tracks_viewed::create(array(
 324                  'context' => context_module::instance($this->eventcm->id),
 325                  'courseid' => $this->eventcourse->id,
 326                  'other' => array('attemptid' => 2, 'instanceid' => 2)
 327              ));
 328              $this->fail("Event validation should not allow \\mod_scorm\\event\\tracks_viewed to be triggered without
 329                      other['scoid']");
 330          } catch (Exception $e) {
 331              $this->assertInstanceOf('coding_exception', $e);
 332          }
 333      }
 334  
 335      /**
 336       * Tests for userreport viewed event.
 337       *
 338       * There is no api involved so the best we can do is test validations and legacy log by triggering event manually.
 339       */
 340      public function test_user_report_viewed_event() {
 341          $this->resetAfterTest();
 342          $event = \mod_scorm\event\user_report_viewed::create(array(
 343              'relateduserid' => 5,
 344              'context' => context_module::instance($this->eventcm->id),
 345              'courseid' => $this->eventcourse->id,
 346              'other' => array('attemptid' => 2, 'instanceid' => $this->eventscorm->id)
 347          ));
 348  
 349          // Trigger and capture the event.
 350          $sink = $this->redirectEvents();
 351          $event->trigger();
 352          $events = $sink->get_events();
 353          $event = reset($events);
 354  
 355          // Check that the legacy log data is valid.
 356          $expected = array($this->eventcourse->id, 'scorm', 'userreport', 'report/userreport.php?id=' .
 357                  $this->eventcm->id . '&user=5&attempt=' . 2, $this->eventscorm->id, $this->eventcm->id);
 358          $this->assertEventLegacyLogData($expected, $event);
 359          $this->assertEventContextNotUsed($event);
 360      }
 361  
 362      /**
 363       * Tests for userreport viewed event validations.
 364       */
 365      public function test_user_report_viewed_event_validations() {
 366          $this->resetAfterTest();
 367          try {
 368              \mod_scorm\event\user_report_viewed::create(array(
 369                  'context' => context_module::instance($this->eventcm->id),
 370                  'courseid' => $this->eventcourse->id,
 371                  'other' => array('attemptid' => 2)
 372              ));
 373              $this->fail("Event validation should not allow \\mod_scorm\\event\\user_report_viewed to be triggered without
 374                      other['instanceid']");
 375          } catch (Exception $e) {
 376              $this->assertInstanceOf('coding_exception', $e);
 377          }
 378          try {
 379              \mod_scorm\event\user_report_viewed::create(array(
 380                  'context' => context_module::instance($this->eventcm->id),
 381                  'courseid' => $this->eventcourse->id,
 382                  'other' => array('instanceid' => 2)
 383              ));
 384              $this->fail("Event validation should not allow \\mod_scorm\\event\\user_report_viewed to be triggered without
 385                      other['attemptid']");
 386          } catch (Exception $e) {
 387              $this->assertInstanceOf('coding_exception', $e);
 388          }
 389      }
 390  
 391      /**
 392       * dataProvider for test_scoreraw_submitted_event().
 393       */
 394      public function get_scoreraw_submitted_event_provider() {
 395          return array(
 396              // SCORM 1.2.
 397              // - cmi.core.score.raw.
 398              'cmi.core.score.raw => 100' => array('cmi.core.score.raw', '100'),
 399              'cmi.core.score.raw => 90' => array('cmi.core.score.raw', '90'),
 400              'cmi.core.score.raw => 50' => array('cmi.core.score.raw', '50'),
 401              'cmi.core.score.raw => 10' => array('cmi.core.score.raw', '10'),
 402              // Check an edge case (PHP empty() vs isset()): score value equals to '0'.
 403              'cmi.core.score.raw => 0' => array('cmi.core.score.raw', '0'),
 404              // SCORM 1.3 AKA 2004.
 405              // - cmi.score.raw.
 406              'cmi.score.raw => 100' => array('cmi.score.raw', '100'),
 407              'cmi.score.raw => 90' => array('cmi.score.raw', '90'),
 408              'cmi.score.raw => 50' => array('cmi.score.raw', '50'),
 409              'cmi.score.raw => 10' => array('cmi.score.raw', '10'),
 410              // Check an edge case (PHP empty() vs isset()): score value equals to '0'.
 411              'cmi.score.raw => 0' => array('cmi.score.raw', '0'),
 412          );
 413      }
 414  
 415      /**
 416       * Tests for score submitted event.
 417       *
 418       * There is no api involved so the best we can do is test data by triggering event manually.
 419       *
 420       * @dataProvider get_scoreraw_submitted_event_provider
 421       *
 422       * @param string $cmielement a valid CMI raw score element
 423       * @param string $cmivalue a valid CMI raw score value
 424       */
 425      public function test_scoreraw_submitted_event($cmielement, $cmivalue) {
 426          $this->resetAfterTest();
 427          $event = \mod_scorm\event\scoreraw_submitted::create(array(
 428              'other' => array('attemptid' => '2', 'cmielement' => $cmielement, 'cmivalue' => $cmivalue),
 429              'objectid' => $this->eventscorm->id,
 430              'context' => context_module::instance($this->eventcm->id),
 431              'relateduserid' => $this->eventuser->id
 432          ));
 433  
 434          // Trigger and capture the event.
 435          $sink = $this->redirectEvents();
 436          $event->trigger();
 437          $events = $sink->get_events();
 438          $sink->close();
 439          $event = reset($events);
 440          $this->assertEquals(2, $event->other['attemptid']);
 441          $this->assertEquals($cmielement, $event->other['cmielement']);
 442          $this->assertEquals($cmivalue, $event->other['cmivalue']);
 443  
 444          // Check that no legacy log data is provided.
 445          $this->assertEventLegacyLogData(null, $event);
 446          $this->assertEventContextNotUsed($event);
 447      }
 448  
 449      /**
 450       * dataProvider for test_scoreraw_submitted_event_validations().
 451       */
 452      public function get_scoreraw_submitted_event_validations() {
 453          return array(
 454              'scoreraw_submitted => missing cmielement' => array(
 455                  null, '50',
 456                  "Event validation should not allow \\mod_scorm\\event\\scoreraw_submitted " .
 457                      "to be triggered without other['cmielement']",
 458                  'Coding error detected, it must be fixed by a programmer: ' .
 459                      "The 'cmielement' must be set in other."
 460              ),
 461              'scoreraw_submitted => missing cmivalue' => array(
 462                  'cmi.core.score.raw', null,
 463                  "Event validation should not allow \\mod_scorm\\event\\scoreraw_submitted " .
 464                      "to be triggered without other['cmivalue']",
 465                  'Coding error detected, it must be fixed by a programmer: ' .
 466                      "The 'cmivalue' must be set in other."
 467              ),
 468              'scoreraw_submitted => wrong CMI element' => array(
 469                  'cmi.core.lesson_status', '50',
 470                  "Event validation should not allow \\mod_scorm\\event\\scoreraw_submitted " .
 471                      'to be triggered with a CMI element not representing a raw score',
 472                  'Coding error detected, it must be fixed by a programmer: ' .
 473                      "The 'cmielement' must represents a valid CMI raw score (cmi.core.lesson_status)."
 474              ),
 475          );
 476      }
 477  
 478      /**
 479       * Tests for score submitted event validations.
 480       *
 481       * @dataProvider get_scoreraw_submitted_event_validations
 482       *
 483       * @param string $cmielement a valid CMI raw score element
 484       * @param string $cmivalue a valid CMI raw score value
 485       * @param string $failmessage the message used to fail the test in case of missing to violate a validation rule
 486       * @param string $excmessage the exception message when violating the validations rules
 487       */
 488      public function test_scoreraw_submitted_event_validations($cmielement, $cmivalue, $failmessage, $excmessage) {
 489          $this->resetAfterTest();
 490          try {
 491              $data = array(
 492                  'context' => context_module::instance($this->eventcm->id),
 493                  'courseid' => $this->eventcourse->id,
 494                  'other' => array('attemptid' => 2)
 495              );
 496              if ($cmielement != null) {
 497                  $data['other']['cmielement'] = $cmielement;
 498              }
 499              if ($cmivalue != null) {
 500                  $data['other']['cmivalue'] = $cmivalue;
 501              }
 502              \mod_scorm\event\scoreraw_submitted::create($data);
 503              $this->fail($failmessage);
 504          } catch (Exception $e) {
 505              $this->assertInstanceOf('coding_exception', $e);
 506              $this->assertEquals($excmessage, $e->getMessage());
 507          }
 508      }
 509  
 510      /**
 511       * dataProvider for test_status_submitted_event().
 512       */
 513      public function get_status_submitted_event_provider() {
 514          return array(
 515              // SCORM 1.2.
 516              // 1. Status: cmi.core.lesson_status.
 517              'cmi.core.lesson_status => passed' => array('cmi.core.lesson_status', 'passed'),
 518              'cmi.core.lesson_status => completed' => array('cmi.core.lesson_status', 'completed'),
 519              'cmi.core.lesson_status => failed' => array('cmi.core.lesson_status', 'failed'),
 520              'cmi.core.lesson_status => incomplete' => array('cmi.core.lesson_status', 'incomplete'),
 521              'cmi.core.lesson_status => browsed' => array('cmi.core.lesson_status', 'browsed'),
 522              'cmi.core.lesson_status => not attempted' => array('cmi.core.lesson_status', 'not attempted'),
 523              // SCORM 1.3 AKA 2004.
 524              // 1. Completion status: cmi.completion_status.
 525              'cmi.completion_status => completed' => array('cmi.completion_status', 'completed'),
 526              'cmi.completion_status => incomplete' => array('cmi.completion_status', 'incomplete'),
 527              'cmi.completion_status => not attempted' => array('cmi.completion_status', 'not attempted'),
 528              'cmi.completion_status => unknown' => array('cmi.completion_status', 'unknown'),
 529              // 2. Success status: cmi.success_status.
 530              'cmi.success_status => passed' => array('cmi.success_status', 'passed'),
 531              'cmi.success_status => failed' => array('cmi.success_status', 'failed'),
 532              'cmi.success_status => unknown' => array('cmi.success_status', 'unknown')
 533          );
 534      }
 535  
 536      /**
 537       * Tests for status submitted event.
 538       *
 539       * There is no api involved so the best we can do is test data by triggering event manually.
 540       *
 541       * @dataProvider get_status_submitted_event_provider
 542       *
 543       * @param string $cmielement a valid CMI status element
 544       * @param string $cmivalue a valid CMI status value
 545       */
 546      public function test_status_submitted_event($cmielement, $cmivalue) {
 547          $this->resetAfterTest();
 548          $event = \mod_scorm\event\status_submitted::create(array(
 549              'other' => array('attemptid' => '2', 'cmielement' => $cmielement, 'cmivalue' => $cmivalue),
 550              'objectid' => $this->eventscorm->id,
 551              'context' => context_module::instance($this->eventcm->id),
 552              'relateduserid' => $this->eventuser->id
 553          ));
 554  
 555          // Trigger and capture the event.
 556          $sink = $this->redirectEvents();
 557          $event->trigger();
 558          $events = $sink->get_events();
 559          $sink->close();
 560          $event = reset($events);
 561          $this->assertEquals(2, $event->other['attemptid']);
 562          $this->assertEquals($cmielement, $event->other['cmielement']);
 563          $this->assertEquals($cmivalue, $event->other['cmivalue']);
 564  
 565          // Check that no legacy log data is provided.
 566          $this->assertEventLegacyLogData(null, $event);
 567          $this->assertEventContextNotUsed($event);
 568      }
 569  
 570      /**
 571       * dataProvider for test_status_submitted_event_validations().
 572       */
 573      public function get_status_submitted_event_validations() {
 574          return array(
 575              'status_submitted => missing cmielement' => array(
 576                  null, 'passed',
 577                  "Event validation should not allow \\mod_scorm\\event\\status_submitted " .
 578                      "to be triggered without other['cmielement']",
 579                  'Coding error detected, it must be fixed by a programmer: ' .
 580                      "The 'cmielement' must be set in other."
 581              ),
 582              'status_submitted => missing cmivalue' => array(
 583                  'cmi.core.lesson_status', null,
 584                  "Event validation should not allow \\mod_scorm\\event\\status_submitted " .
 585                      "to be triggered without other['cmivalue']",
 586                  'Coding error detected, it must be fixed by a programmer: ' .
 587                      "The 'cmivalue' must be set in other."
 588              ),
 589              'status_submitted => wrong CMI element' => array(
 590                  'cmi.core.score.raw', 'passed',
 591                  "Event validation should not allow \\mod_scorm\\event\\status_submitted " .
 592                      'to be triggered with a CMI element not representing a valid CMI status element',
 593                  'Coding error detected, it must be fixed by a programmer: ' .
 594                      "The 'cmielement' must represents a valid CMI status element (cmi.core.score.raw)."
 595              ),
 596              'status_submitted => wrong CMI value' => array(
 597                  'cmi.core.lesson_status', 'blahblahblah',
 598                  "Event validation should not allow \\mod_scorm\\event\\status_submitted " .
 599                      'to be triggered with a CMI element not representing a valid CMI status',
 600                  'Coding error detected, it must be fixed by a programmer: ' .
 601                      "The 'cmivalue' must represents a valid CMI status value (blahblahblah)."
 602              ),
 603          );
 604      }
 605  
 606      /**
 607       * Tests for status submitted event validations.
 608       *
 609       * @dataProvider get_status_submitted_event_validations
 610       *
 611       * @param string $cmielement a valid CMI status element
 612       * @param string $cmivalue a valid CMI status value
 613       * @param string $failmessage the message used to fail the test in case of missing to violate a validation rule
 614       * @param string $excmessage the exception message when violating the validations rules
 615       */
 616      public function test_status_submitted_event_validations($cmielement, $cmivalue, $failmessage, $excmessage) {
 617          $this->resetAfterTest();
 618          try {
 619              $data = array(
 620                  'context' => context_module::instance($this->eventcm->id),
 621                  'courseid' => $this->eventcourse->id,
 622                  'other' => array('attemptid' => 2)
 623              );
 624              if ($cmielement != null) {
 625                  $data['other']['cmielement'] = $cmielement;
 626              }
 627              if ($cmivalue != null) {
 628                  $data['other']['cmivalue'] = $cmivalue;
 629              }
 630              \mod_scorm\event\status_submitted::create($data);
 631              $this->fail($failmessage);
 632          } catch (Exception $e) {
 633              $this->assertInstanceOf('coding_exception', $e);
 634              $this->assertEquals($excmessage, $e->getMessage());
 635          }
 636      }
 637  }