6c70949c2e78a3146162c065da2f211abaa14071
[moodle.git] / mod / quiz / tests / events_test.php
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/>.
17 /**
18  * Quiz events tests.
19  *
20  * @package    mod_quiz
21  * @category   phpunit
22  * @copyright  2013 Adrian Greeve
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
30 require_once($CFG->dirroot . '/mod/quiz/editlib.php');
32 /**
33  * Unit tests for quiz events.
34  *
35  * @package    mod_quiz
36  * @category   phpunit
37  * @copyright  2013 Adrian Greeve
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  */
40 class mod_quiz_events_testcase extends advanced_testcase {
42     protected function prepare_quiz_data() {
44         $this->resetAfterTest(true);
46         // Create a course
47         $course = $this->getDataGenerator()->create_course();
49         // Make a quiz.
50         $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
52         $quiz = $quizgenerator->create_instance(array('course'=>$course->id, 'questionsperpage' => 0,
53             'grade' => 100.0, 'sumgrades' => 2));
55         $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
57         // Create a couple of questions.
58         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
60         $cat = $questiongenerator->create_question_category();
61         $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
62         $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
64         // Add them to the quiz.
65         quiz_add_quiz_question($saq->id, $quiz);
66         quiz_add_quiz_question($numq->id, $quiz);
68         // Make a user to do the quiz.
69         $user1 = $this->getDataGenerator()->create_user();
70         $this->setUser($user1);
72         $quizobj = quiz::create($quiz->id, $user1->id);
74         // Start the attempt.
75         $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
76         $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
78         $timenow = time();
79         $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
80         quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
81         quiz_attempt_save_started($quizobj, $quba, $attempt);
83         return array($quizobj, $quba, $attempt);
84     }
86     public function test_attempt_submitted() {
88         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
89         $attemptobj = quiz_attempt::create($attempt->id);
91         // Catch the event.
92         $sink = $this->redirectEvents();
94         $timefinish = time();
95         $attemptobj->process_finish($timefinish, false);
96         $events = $sink->get_events();
97         $sink->close();
99         // Validate the event.
100         $this->assertCount(1, $events);
101         $event = $events[0];
102         $this->assertInstanceOf('\mod_quiz\event\attempt_submitted', $event);
103         $this->assertEquals('quiz_attempts', $event->objecttable);
104         $this->assertEquals($quizobj->get_context(), $event->get_context());
105         $this->assertEquals($attempt->userid, $event->relateduserid);
106         $this->assertEquals(null, $event->other['submitterid']); // Should be the user, but PHP Unit complains...
107         $this->assertEquals('quiz_attempt_submitted', $event->get_legacy_eventname());
108         $legacydata = new stdClass();
109         $legacydata->component = 'mod_quiz';
110         $legacydata->attemptid = (string) $attempt->id;
111         $legacydata->timestamp = $timefinish;
112         $legacydata->userid = $attempt->userid;
113         $legacydata->cmid = $quizobj->get_cmid();
114         $legacydata->courseid = $quizobj->get_courseid();
115         $legacydata->quizid = $quizobj->get_quizid();
116         // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
117         $legacydata->submitterid = null;
118         $legacydata->timefinish = $timefinish;
119         $this->assertEventLegacyData($legacydata, $event);
120         $this->assertEventContextNotUsed($event);
121     }
123     public function test_attempt_becameoverdue() {
125         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
126         $attemptobj = quiz_attempt::create($attempt->id);
128         // Catch the event.
129         $sink = $this->redirectEvents();
130         $timefinish = time();
131         $attemptobj->process_going_overdue($timefinish, false);
132         $events = $sink->get_events();
133         $sink->close();
135         $this->assertCount(1, $events);
136         $event = $events[0];
137         $this->assertInstanceOf('\mod_quiz\event\attempt_becameoverdue', $event);
138         $this->assertEquals('quiz_attempts', $event->objecttable);
139         $this->assertEquals($quizobj->get_context(), $event->get_context());
140         $this->assertEquals($attempt->userid, $event->relateduserid);
141         $this->assertNotEmpty($event->get_description());
142         // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
143         $this->assertEquals(null, $event->other['submitterid']);
144         $this->assertEquals('quiz_attempt_overdue', $event->get_legacy_eventname());
145         $legacydata = new stdClass();
146         $legacydata->component = 'mod_quiz';
147         $legacydata->attemptid = (string) $attempt->id;
148         $legacydata->timestamp = $timefinish;
149         $legacydata->userid = $attempt->userid;
150         $legacydata->cmid = $quizobj->get_cmid();
151         $legacydata->courseid = $quizobj->get_courseid();
152         $legacydata->quizid = $quizobj->get_quizid();
153         $legacydata->submitterid = null; // Should be the user, but PHP Unit complains...
154         $this->assertEventLegacyData($legacydata, $event);
155         $this->assertEventContextNotUsed($event);
156     }
158     public function test_attempt_abandoned() {
160         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
161         $attemptobj = quiz_attempt::create($attempt->id);
163         // Catch the event.
164         $sink = $this->redirectEvents();
165         $timefinish = time();
166         $attemptobj->process_abandon($timefinish, false);
167         $events = $sink->get_events();
168         $sink->close();
170         $this->assertCount(1, $events);
171         $event = $events[0];
172         $this->assertInstanceOf('\mod_quiz\event\attempt_abandoned', $event);
173         $this->assertEquals('quiz_attempts', $event->objecttable);
174         $this->assertEquals($quizobj->get_context(), $event->get_context());
175         $this->assertEquals($attempt->userid, $event->relateduserid);
176         // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
177         $this->assertEquals(null, $event->other['submitterid']);
178         $this->assertEquals('quiz_attempt_abandoned', $event->get_legacy_eventname());
179         $legacydata = new stdClass();
180         $legacydata->component = 'mod_quiz';
181         $legacydata->attemptid = (string) $attempt->id;
182         $legacydata->timestamp = $timefinish;
183         $legacydata->userid = $attempt->userid;
184         $legacydata->cmid = $quizobj->get_cmid();
185         $legacydata->courseid = $quizobj->get_courseid();
186         $legacydata->quizid = $quizobj->get_quizid();
187         $legacydata->submitterid = null; // Should be the user, but PHP Unit complains...
188         $this->assertEventLegacyData($legacydata, $event);
189         $this->assertEventContextNotUsed($event);
190     }
192     public function test_attempt_started() {
193         global $USER;
195         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
196         $attemptobj = quiz_attempt::create($attempt->id);
198         // Catch the event.
199         $sink = $this->redirectEvents();
200         quiz_fire_attempt_started_event($attempt, $quizobj);
201         $events = $sink->get_events();
202         $sink->close();
204         // Legacy event data.
205         $legacydata = new stdClass();
206         $legacydata->component = 'mod_quiz';
207         $legacydata->attemptid = $attempt->id;
208         $legacydata->timestart = $attempt->timestart;
209         $legacydata->timestamp = $attempt->timestart;
210         $legacydata->userid = $attempt->userid;
211         $legacydata->quizid = $quizobj->get_quizid();
212         $legacydata->cmid = $quizobj->get_cmid();
213         $legacydata->courseid = $quizobj->get_courseid();
215         // Validate the event.
216         $this->assertCount(1, $events);
217         $event = $events[0];
218         $this->assertInstanceOf('\mod_quiz\event\attempt_started', $event);
219         $this->assertEquals('quiz_attempts', $event->objecttable);
220         $this->assertEquals($attempt->id, $event->objectid);
221         $this->assertEquals($attempt->userid, $event->relateduserid);
222         $this->assertEquals($quizobj->get_context(), $event->get_context());
223         $this->assertEquals('quiz_attempt_started', $event->get_legacy_eventname());
224         $this->assertEventLegacyData($legacydata, $event);
225         $this->assertEventContextNotUsed($event);
227         // Create another attempt.
228         $attempt = quiz_create_attempt($quizobj, 1, false, time(), false, 2);
230         // Trigger and capture the event.
231         $sink = $this->redirectEvents();
232         quiz_attempt_save_started($quizobj, $quba, $attempt);
233         $events = $sink->get_events();
234         $event = reset($events);
236         // Check that the event data is valid.
237         $this->assertInstanceOf('\mod_quiz\event\attempt_started', $event);
238         $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
239         $expected = array($quizobj->get_courseid(), 'quiz', 'attempt', 'review.php?attempt=' . $attempt->id,
240             $quizobj->get_quizid(), $quizobj->get_cmid());
241         $this->assertEventLegacyLogData($expected, $event);
242     }
244     /**
245      * Test the edit page viewed event.
246      *
247      * There is no external API for updating a quiz, so the unit test will simply
248      * create and trigger the event and ensure the event data is returned as expected.
249      */
250     public function test_edit_page_viewed() {
251         $this->resetAfterTest();
253         $this->setAdminUser();
254         $course = $this->getDataGenerator()->create_course();
255         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
257         $params = array(
258             'courseid' => $course->id,
259             'context' => context_module::instance($quiz->cmid),
260             'other' => array(
261                 'quizid' => $quiz->id
262             )
263         );
264         $event = \mod_quiz\event\edit_page_viewed::create($params);
266         // Trigger and capture the event.
267         $sink = $this->redirectEvents();
268         $event->trigger();
269         $events = $sink->get_events();
270         $event = reset($events);
272         // Check that the event data is valid.
273         $this->assertInstanceOf('\mod_quiz\event\edit_page_viewed', $event);
274         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
275         $expected = array($course->id, 'quiz', 'editquestions', 'view.php?id=' . $quiz->cmid, $quiz->id, $quiz->cmid);
276         $this->assertEventLegacyLogData($expected, $event);
277         $this->assertEventContextNotUsed($event);
278     }
280     /**
281      * Test the attempt deleted event.
282      */
283     public function test_attempt_deleted() {
284         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
286         // Trigger and capture the event.
287         $sink = $this->redirectEvents();
288         quiz_delete_attempt($attempt, $quizobj->get_quiz());
289         $events = $sink->get_events();
290         $event = reset($events);
292         // Check that the event data is valid.
293         $this->assertInstanceOf('\mod_quiz\event\attempt_deleted', $event);
294         $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
295         $expected = array($quizobj->get_courseid(), 'quiz', 'delete attempt', 'report.php?id=' . $quizobj->get_cmid(),
296             $attempt->id, $quizobj->get_cmid());
297         $this->assertEventLegacyLogData($expected, $event);
298         $this->assertEventContextNotUsed($event);
299     }
301     /**
302      * Test the report viewed event.
303      *
304      * There is no external API for viewing reports, so the unit test will simply
305      * create and trigger the event and ensure the event data is returned as expected.
306      */
307     public function test_report_viewed() {
308         $this->resetAfterTest();
310         $this->setAdminUser();
311         $course = $this->getDataGenerator()->create_course();
312         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
314         $params = array(
315             'context' => $context = context_module::instance($quiz->cmid),
316             'other' => array(
317                 'quizid' => $quiz->id,
318                 'reportname' => 'overview'
319             )
320         );
321         $event = \mod_quiz\event\report_viewed::create($params);
323         // Trigger and capture the event.
324         $sink = $this->redirectEvents();
325         $event->trigger();
326         $events = $sink->get_events();
327         $event = reset($events);
329         // Check that the event data is valid.
330         $this->assertInstanceOf('\mod_quiz\event\report_viewed', $event);
331         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
332         $expected = array($course->id, 'quiz', 'report', 'report.php?id=' . $quiz->cmid . '&mode=overview',
333             $quiz->id, $quiz->cmid);
334         $this->assertEventLegacyLogData($expected, $event);
335         $this->assertEventContextNotUsed($event);
336     }
338     /**
339      * Test the attempt reviewed event.
340      *
341      * There is no external API for reviewing attempts, so the unit test will simply
342      * create and trigger the event and ensure the event data is returned as expected.
343      */
344     public function test_attempt_reviewed() {
345         $this->resetAfterTest();
347         $this->setAdminUser();
348         $course = $this->getDataGenerator()->create_course();
349         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
351         $params = array(
352             'objectid' => 1,
353             'relateduserid' => 2,
354             'courseid' => $course->id,
355             'context' => context_module::instance($quiz->cmid),
356             'other' => array(
357                 'quizid' => $quiz->id
358             )
359         );
360         $event = \mod_quiz\event\attempt_reviewed::create($params);
362         // Trigger and capture the event.
363         $sink = $this->redirectEvents();
364         $event->trigger();
365         $events = $sink->get_events();
366         $event = reset($events);
368         // Check that the event data is valid.
369         $this->assertInstanceOf('\mod_quiz\event\attempt_reviewed', $event);
370         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
371         $expected = array($course->id, 'quiz', 'review', 'review.php?attempt=1', $quiz->id, $quiz->cmid);
372         $this->assertEventLegacyLogData($expected, $event);
373         $this->assertEventContextNotUsed($event);
374     }
376     /**
377      * Test the attempt summary viewed event.
378      *
379      * There is no external API for viewing the attempt summary, so the unit test will simply
380      * create and trigger the event and ensure the event data is returned as expected.
381      */
382     public function test_attempt_summary_viewed() {
383         $this->resetAfterTest();
385         $this->setAdminUser();
386         $course = $this->getDataGenerator()->create_course();
387         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
389         $params = array(
390             'objectid' => 1,
391             'relateduserid' => 2,
392             'courseid' => $course->id,
393             'context' => context_module::instance($quiz->cmid),
394             'other' => array(
395                 'quizid' => $quiz->id
396             )
397         );
398         $event = \mod_quiz\event\attempt_summary_viewed::create($params);
400         // Trigger and capture the event.
401         $sink = $this->redirectEvents();
402         $event->trigger();
403         $events = $sink->get_events();
404         $event = reset($events);
406         // Check that the event data is valid.
407         $this->assertInstanceOf('\mod_quiz\event\attempt_summary_viewed', $event);
408         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
409         $expected = array($course->id, 'quiz', 'view summary', 'summary.php?attempt=1', $quiz->id, $quiz->cmid);
410         $this->assertEventLegacyLogData($expected, $event);
411         $this->assertEventContextNotUsed($event);
412     }
414     /**
415      * Test the user override created event.
416      *
417      * There is no external API for creating a user override, so the unit test will simply
418      * create and trigger the event and ensure the event data is returned as expected.
419      */
420     public function test_user_override_created() {
421         $this->resetAfterTest();
423         $this->setAdminUser();
424         $course = $this->getDataGenerator()->create_course();
425         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
427         $params = array(
428             'objectid' => 1,
429             'relateduserid' => 2,
430             'context' => context_module::instance($quiz->cmid),
431             'other' => array(
432                 'quizid' => $quiz->id
433             )
434         );
435         $event = \mod_quiz\event\user_override_created::create($params);
437         // Trigger and capture the event.
438         $sink = $this->redirectEvents();
439         $event->trigger();
440         $events = $sink->get_events();
441         $event = reset($events);
443         // Check that the event data is valid.
444         $this->assertInstanceOf('\mod_quiz\event\user_override_created', $event);
445         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
446         $this->assertEventContextNotUsed($event);
447     }
449     /**
450      * Test the group override created event.
451      *
452      * There is no external API for creating a group override, so the unit test will simply
453      * create and trigger the event and ensure the event data is returned as expected.
454      */
455     public function test_group_override_created() {
456         $this->resetAfterTest();
458         $this->setAdminUser();
459         $course = $this->getDataGenerator()->create_course();
460         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
462         $params = array(
463             'objectid' => 1,
464             'context' => context_module::instance($quiz->cmid),
465             'other' => array(
466                 'quizid' => $quiz->id,
467                 'groupid' => 2
468             )
469         );
470         $event = \mod_quiz\event\group_override_created::create($params);
472         // Trigger and capture the event.
473         $sink = $this->redirectEvents();
474         $event->trigger();
475         $events = $sink->get_events();
476         $event = reset($events);
478         // Check that the event data is valid.
479         $this->assertInstanceOf('\mod_quiz\event\group_override_created', $event);
480         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
481         $this->assertEventContextNotUsed($event);
482     }
484     /**
485      * Test the user override updated event.
486      *
487      * There is no external API for updating a user override, so the unit test will simply
488      * create and trigger the event and ensure the event data is returned as expected.
489      */
490     public function test_user_override_updated() {
491         $this->resetAfterTest();
493         $this->setAdminUser();
494         $course = $this->getDataGenerator()->create_course();
495         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
497         $params = array(
498             'objectid' => 1,
499             'relateduserid' => 2,
500             'context' => context_module::instance($quiz->cmid),
501             'other' => array(
502                 'quizid' => $quiz->id
503             )
504         );
505         $event = \mod_quiz\event\user_override_updated::create($params);
507         // Trigger and capture the event.
508         $sink = $this->redirectEvents();
509         $event->trigger();
510         $events = $sink->get_events();
511         $event = reset($events);
513         // Check that the event data is valid.
514         $this->assertInstanceOf('\mod_quiz\event\user_override_updated', $event);
515         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
516         $expected = array($course->id, 'quiz', 'edit override', 'overrideedit.php?id=1', $quiz->id, $quiz->cmid);
517         $this->assertEventLegacyLogData($expected, $event);
518         $this->assertEventContextNotUsed($event);
519     }
521     /**
522      * Test the group override updated event.
523      *
524      * There is no external API for updating a group override, so the unit test will simply
525      * create and trigger the event and ensure the event data is returned as expected.
526      */
527     public function test_group_override_updated() {
528         $this->resetAfterTest();
530         $this->setAdminUser();
531         $course = $this->getDataGenerator()->create_course();
532         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
534         $params = array(
535             'objectid' => 1,
536             'context' => context_module::instance($quiz->cmid),
537             'other' => array(
538                 'quizid' => $quiz->id,
539                 'groupid' => 2
540             )
541         );
542         $event = \mod_quiz\event\group_override_updated::create($params);
544         // Trigger and capture the event.
545         $sink = $this->redirectEvents();
546         $event->trigger();
547         $events = $sink->get_events();
548         $event = reset($events);
550         // Check that the event data is valid.
551         $this->assertInstanceOf('\mod_quiz\event\group_override_updated', $event);
552         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
553         $expected = array($course->id, 'quiz', 'edit override', 'overrideedit.php?id=1', $quiz->id, $quiz->cmid);
554         $this->assertEventLegacyLogData($expected, $event);
555         $this->assertEventContextNotUsed($event);
556     }
558     /**
559      * Test the user override deleted event.
560      */
561     public function test_user_override_deleted() {
562         global $DB;
564         $this->resetAfterTest();
566         $this->setAdminUser();
567         $course = $this->getDataGenerator()->create_course();
568         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
570         // Create an override.
571         $override = new stdClass();
572         $override->quiz = $quiz->id;
573         $override->userid = 2;
574         $override->id = $DB->insert_record('quiz_overrides', $override);
576         // Trigger and capture the event.
577         $sink = $this->redirectEvents();
578         quiz_delete_override($quiz, $override->id);
579         $events = $sink->get_events();
580         $event = reset($events);
582         // Check that the event data is valid.
583         $this->assertInstanceOf('\mod_quiz\event\user_override_deleted', $event);
584         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
585         $expected = array($course->id, 'quiz', 'delete override', 'overrides.php?cmid=' . $quiz->cmid, $quiz->id, $quiz->cmid);
586         $this->assertEventLegacyLogData($expected, $event);
587         $this->assertEventContextNotUsed($event);
588     }
590     /**
591      * Test the group override deleted event.
592      */
593     public function test_group_override_deleted() {
594         global $DB;
596         $this->resetAfterTest();
598         $this->setAdminUser();
599         $course = $this->getDataGenerator()->create_course();
600         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
602         // Create an override.
603         $override = new stdClass();
604         $override->quiz = $quiz->id;
605         $override->groupid = 2;
606         $override->id = $DB->insert_record('quiz_overrides', $override);
608         // Trigger and capture the event.
609         $sink = $this->redirectEvents();
610         quiz_delete_override($quiz, $override->id);
611         $events = $sink->get_events();
612         $event = reset($events);
614         // Check that the event data is valid.
615         $this->assertInstanceOf('\mod_quiz\event\group_override_deleted', $event);
616         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
617         $expected = array($course->id, 'quiz', 'delete override', 'overrides.php?cmid=' . $quiz->cmid, $quiz->id, $quiz->cmid);
618         $this->assertEventLegacyLogData($expected, $event);
619         $this->assertEventContextNotUsed($event);
620     }
622     /**
623      * Test the attempt viewed event.
624      *
625      * There is no external API for continuing an attempt, so the unit test will simply
626      * create and trigger the event and ensure the event data is returned as expected.
627      */
628     public function test_attempt_viewed() {
629         $this->resetAfterTest();
631         $this->setAdminUser();
632         $course = $this->getDataGenerator()->create_course();
633         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
635         $params = array(
636             'objectid' => 1,
637             'relateduserid' => 2,
638             'courseid' => $course->id,
639             'context' => context_module::instance($quiz->cmid),
640             'other' => array(
641                 'quizid' => $quiz->id
642             )
643         );
644         $event = \mod_quiz\event\attempt_viewed::create($params);
646         // Trigger and capture the event.
647         $sink = $this->redirectEvents();
648         $event->trigger();
649         $events = $sink->get_events();
650         $event = reset($events);
652         // Check that the event data is valid.
653         $this->assertInstanceOf('\mod_quiz\event\attempt_viewed', $event);
654         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
655         $expected = array($course->id, 'quiz', 'continue attempt', 'review.php?attempt=1', $quiz->id, $quiz->cmid);
656         $this->assertEventLegacyLogData($expected, $event);
657         $this->assertEventContextNotUsed($event);
658     }
660     /**
661      * Test the attempt previewed event.
662      */
663     public function test_attempt_preview_started() {
664         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
666         // We want to preview this attempt.
667         $attempt = quiz_create_attempt($quizobj, 1, false, time(), false, 2);
668         $attempt->preview = 1;
670         // Trigger and capture the event.
671         $sink = $this->redirectEvents();
672         quiz_attempt_save_started($quizobj, $quba, $attempt);
673         $events = $sink->get_events();
674         $event = reset($events);
676         // Check that the event data is valid.
677         $this->assertInstanceOf('\mod_quiz\event\attempt_preview_started', $event);
678         $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
679         $expected = array($quizobj->get_courseid(), 'quiz', 'preview', 'view.php?id=' . $quizobj->get_cmid(),
680             $quizobj->get_quizid(), $quizobj->get_cmid());
681         $this->assertEventLegacyLogData($expected, $event);
682         $this->assertEventContextNotUsed($event);
683     }
685     /**
686      * Test the question manually graded event.
687      *
688      * There is no external API for manually grading a question, so the unit test will simply
689      * create and trigger the event and ensure the event data is returned as expected.
690      */
691     public function test_question_manually_graded() {
692         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
694         $params = array(
695             'objectid' => 1,
696             'courseid' => $quizobj->get_courseid(),
697             'context' => context_module::instance($quizobj->get_cmid()),
698             'other' => array(
699                 'quizid' => $quizobj->get_quizid(),
700                 'attemptid' => 2,
701                 'slot' => 3
702             )
703         );
704         $event = \mod_quiz\event\question_manually_graded::create($params);
706         // Trigger and capture the event.
707         $sink = $this->redirectEvents();
708         $event->trigger();
709         $events = $sink->get_events();
710         $event = reset($events);
712         // Check that the event data is valid.
713         $this->assertInstanceOf('\mod_quiz\event\question_manually_graded', $event);
714         $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
715         $expected = array($quizobj->get_courseid(), 'quiz', 'manualgrade', 'comment.php?attempt=2&slot=3',
716             $quizobj->get_quizid(), $quizobj->get_cmid());
717         $this->assertEventLegacyLogData($expected, $event);
718         $this->assertEventContextNotUsed($event);
719     }