MDL-63660 tool_dataprivacy: Increase expected export file size
[moodle.git] / mod / scorm / tests / events_test.php
blobbf44adf56bf00c51cb7d3b2232a7b7e98fb48051
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.
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/>.
17 /**
18 * This file contains tests for scorm events.
20 * @package mod_scorm
21 * @copyright 2013 onwards Ankit Agarwal
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 global $CFG;
26 require_once($CFG->dirroot . '/mod/scorm/locallib.php');
27 require_once($CFG->dirroot . '/mod/scorm/lib.php');
29 /**
30 * Test class for various events related to Scorm.
32 * @package mod_scorm
33 * @copyright 2013 onwards Ankit Agarwal
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class mod_scorm_event_testcase extends advanced_testcase {
38 /** @var stdClass store course object */
39 protected $eventcourse;
41 /** @var stdClass store user object */
42 protected $eventuser;
44 /** @var stdClass store scorm object */
45 protected $eventscorm;
47 /** @var stdClass store course module object */
48 protected $eventcm;
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);
60 /**
61 * Tests for attempt deleted event
63 * @expectedException coding_exception
65 public function test_attempt_deleted_event() {
67 global $USER;
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);
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);
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');
97 /**
98 * Tests for course module viewed event.
100 * There is no api involved so the best we can do is test legacy data by triggering event manually.
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
110 // Trigger and capture the event.
111 $sink = $this->redirectEvents();
112 $event->trigger();
113 $events = $sink->get_events();
114 $event = reset($events);
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);
124 * Tests for instance list viewed event.
126 * There is no api involved so the best we can do is test legacy data by triggering event manually.
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
135 // Trigger and capture the event.
136 $sink = $this->redirectEvents();
137 $event->trigger();
138 $events = $sink->get_events();
139 $event = reset($events);
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);
148 * Tests for interactions viewed.
150 * There is no api involved so the best we can do is test legacy data by triggering event manually and test validations.
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)
161 // Trigger and capture the event.
162 $sink = $this->redirectEvents();
163 $event->trigger();
164 $events = $sink->get_events();
165 $event = reset($events);
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);
175 * Tests for interactions viewed validations.
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)
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);
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)
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);
203 /** Tests for report viewed.
205 * There is no api involved so the best we can do is test legacy data and validations by triggering event manually.
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'
218 // Trigger and capture the event.
219 $sink = $this->redirectEvents();
220 $event->trigger();
221 $events = $sink->get_events();
222 $event = reset($events);
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);
231 /** Tests for sco launched event.
233 * There is no api involved so the best we can do is test legacy data and validations by triggering event manually.
235 * @expectedException coding_exception
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')
246 // Trigger and capture the event.
247 $sink = $this->redirectEvents();
248 $event->trigger();
249 $events = $sink->get_events();
250 $event = reset($events);
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);
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,
264 $this->fail('Event \\mod_scorm\\event\\sco_launched is not validating "loadedcontent" properly');
268 * Tests for tracks viewed event.
270 * There is no api involved so the best we can do is test validations by triggering event manually.
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)
281 // Trigger and capture the event.
282 $sink = $this->redirectEvents();
283 $event->trigger();
284 $events = $sink->get_events();
285 $event = reset($events);
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);
295 * Tests for tracks viewed event validations.
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)
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);
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)
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);
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)
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);
336 * Tests for userreport viewed event.
338 * There is no api involved so the best we can do is test validations and legacy log by triggering event manually.
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)
349 // Trigger and capture the event.
350 $sink = $this->redirectEvents();
351 $event->trigger();
352 $events = $sink->get_events();
353 $event = reset($events);
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);
363 * Tests for userreport viewed event validations.
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)
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);
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)
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);
392 * dataProvider for test_scoreraw_submitted_event().
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'),
416 * Tests for score submitted event.
418 * There is no api involved so the best we can do is test data by triggering event manually.
420 * @dataProvider get_scoreraw_submitted_event_provider
422 * @param string $cmielement a valid CMI raw score element
423 * @param string $cmivalue a valid CMI raw score value
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
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']);
444 // Check that no legacy log data is provided.
445 $this->assertEventLegacyLogData(null, $event);
446 $this->assertEventContextNotUsed($event);
450 * dataProvider for test_scoreraw_submitted_event_validations().
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."
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."
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)."
479 * Tests for score submitted event validations.
481 * @dataProvider get_scoreraw_submitted_event_validations
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
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)
496 if ($cmielement != null) {
497 $data['other']['cmielement'] = $cmielement;
499 if ($cmivalue != null) {
500 $data['other']['cmivalue'] = $cmivalue;
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());
511 * dataProvider for test_status_submitted_event().
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')
537 * Tests for status submitted event.
539 * There is no api involved so the best we can do is test data by triggering event manually.
541 * @dataProvider get_status_submitted_event_provider
543 * @param string $cmielement a valid CMI status element
544 * @param string $cmivalue a valid CMI status value
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
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']);
565 // Check that no legacy log data is provided.
566 $this->assertEventLegacyLogData(null, $event);
567 $this->assertEventContextNotUsed($event);
571 * dataProvider for test_status_submitted_event_validations().
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."
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."
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)."
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)."
607 * Tests for status submitted event validations.
609 * @dataProvider get_status_submitted_event_validations
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
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)
624 if ($cmielement != null) {
625 $data['other']['cmielement'] = $cmielement;
627 if ($cmivalue != null) {
628 $data['other']['cmivalue'] = $cmivalue;
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());