MDL-40063 mod_quiz: replaced 'view summary' add_to_log call with an event
[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         // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
142         $this->assertEquals(null, $event->other['submitterid']);
143         $this->assertEquals('quiz_attempt_overdue', $event->get_legacy_eventname());
144         $legacydata = new stdClass();
145         $legacydata->component = 'mod_quiz';
146         $legacydata->attemptid = (string) $attempt->id;
147         $legacydata->timestamp = $timefinish;
148         $legacydata->userid = $attempt->userid;
149         $legacydata->cmid = $quizobj->get_cmid();
150         $legacydata->courseid = $quizobj->get_courseid();
151         $legacydata->quizid = $quizobj->get_quizid();
152         $legacydata->submitterid = null; // Should be the user, but PHP Unit complains...
153         $this->assertEventLegacyData($legacydata, $event);
154         $this->assertEventContextNotUsed($event);
155     }
157     public function test_attempt_abandoned() {
159         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
160         $attemptobj = quiz_attempt::create($attempt->id);
162         // Catch the event.
163         $sink = $this->redirectEvents();
164         $timefinish = time();
165         $attemptobj->process_abandon($timefinish, false);
166         $events = $sink->get_events();
167         $sink->close();
169         $this->assertCount(1, $events);
170         $event = $events[0];
171         $this->assertInstanceOf('\mod_quiz\event\attempt_abandoned', $event);
172         $this->assertEquals('quiz_attempts', $event->objecttable);
173         $this->assertEquals($quizobj->get_context(), $event->get_context());
174         $this->assertEquals($attempt->userid, $event->relateduserid);
175         // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
176         $this->assertEquals(null, $event->other['submitterid']);
177         $this->assertEquals('quiz_attempt_abandoned', $event->get_legacy_eventname());
178         $legacydata = new stdClass();
179         $legacydata->component = 'mod_quiz';
180         $legacydata->attemptid = (string) $attempt->id;
181         $legacydata->timestamp = $timefinish;
182         $legacydata->userid = $attempt->userid;
183         $legacydata->cmid = $quizobj->get_cmid();
184         $legacydata->courseid = $quizobj->get_courseid();
185         $legacydata->quizid = $quizobj->get_quizid();
186         $legacydata->submitterid = null; // Should be the user, but PHP Unit complains...
187         $this->assertEventLegacyData($legacydata, $event);
188         $this->assertEventContextNotUsed($event);
189     }
191     public function test_attempt_started() {
192         global $USER;
194         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
195         $attemptobj = quiz_attempt::create($attempt->id);
197         // Catch the event.
198         $sink = $this->redirectEvents();
199         quiz_fire_attempt_started_event($attempt, $quizobj);
200         $events = $sink->get_events();
201         $sink->close();
203         // Legacy event data.
204         $legacydata = new stdClass();
205         $legacydata->component = 'mod_quiz';
206         $legacydata->attemptid = $attempt->id;
207         $legacydata->timestart = $attempt->timestart;
208         $legacydata->timestamp = $attempt->timestart;
209         $legacydata->userid = $attempt->userid;
210         $legacydata->quizid = $quizobj->get_quizid();
211         $legacydata->cmid = $quizobj->get_cmid();
212         $legacydata->courseid = $quizobj->get_courseid();
214         // Validate the event.
215         $this->assertCount(1, $events);
216         $event = $events[0];
217         $this->assertInstanceOf('\mod_quiz\event\attempt_started', $event);
218         $this->assertEquals('quiz_attempts', $event->objecttable);
219         $this->assertEquals($attempt->id, $event->objectid);
220         $this->assertEquals($attempt->userid, $event->relateduserid);
221         $this->assertEquals($quizobj->get_context(), $event->get_context());
222         $this->assertEquals('quiz_attempt_started', $event->get_legacy_eventname());
223         $this->assertEventLegacyData($legacydata, $event);
224         $this->assertEventContextNotUsed($event);
225     }
227     /**
228      * Test the edit page viewed event.
229      *
230      * There is no external API for updating a quiz, so the unit test will simply
231      * create and trigger the event and ensure the event data is returned as expected.
232      */
233     public function test_edit_page_viewed() {
234         $this->resetAfterTest();
236         $this->setAdminUser();
237         $course = $this->getDataGenerator()->create_course();
238         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
240         $params = array(
241             'courseid' => $course->id,
242             'context' => context_module::instance($quiz->cmid),
243             'other' => array(
244                 'quizid' => $quiz->id
245             )
246         );
247         $event = \mod_quiz\event\edit_page_viewed::create($params);
249         // Trigger and capture the event.
250         $sink = $this->redirectEvents();
251         $event->trigger();
252         $events = $sink->get_events();
253         $event = reset($events);
255         // Check that the event data is valid.
256         $this->assertInstanceOf('\mod_quiz\event\edit_page_viewed', $event);
257         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
258         $expected = array($course->id, 'quiz', 'editquestions', 'view.php?id=' . $quiz->cmid, $quiz->id, $quiz->cmid);
259         $this->assertEventLegacyLogData($expected, $event);
260         $this->assertEventContextNotUsed($event);
261     }
263     /**
264      * Test the attempt deleted event.
265      */
266     public function test_attempt_deleted() {
267         list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
269         // Trigger and capture the event.
270         $sink = $this->redirectEvents();
271         quiz_delete_attempt($attempt, $quizobj->get_quiz());
272         $events = $sink->get_events();
273         $event = reset($events);
275         // Check that the event data is valid.
276         $this->assertInstanceOf('\mod_quiz\event\attempt_deleted', $event);
277         $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
278         $expected = array($quizobj->get_courseid(), 'quiz', 'delete attempt', 'report.php?id=' . $quizobj->get_cmid(),
279             $attempt->id, $quizobj->get_cmid());
280         $this->assertEventLegacyLogData($expected, $event);
281         $this->assertEventContextNotUsed($event);
282     }
284     /**
285      * Test the report viewed event.
286      *
287      * There is no external API for viewing reports, so the unit test will simply
288      * create and trigger the event and ensure the event data is returned as expected.
289      */
290     public function test_report_viewed() {
291         $this->resetAfterTest();
293         $this->setAdminUser();
294         $course = $this->getDataGenerator()->create_course();
295         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
297         $params = array(
298             'context' => $context = context_module::instance($quiz->cmid),
299             'other' => array(
300                 'quizid' => $quiz->id,
301                 'reportname' => 'overview'
302             )
303         );
304         $event = \mod_quiz\event\report_viewed::create($params);
306         // Trigger and capture the event.
307         $sink = $this->redirectEvents();
308         $event->trigger();
309         $events = $sink->get_events();
310         $event = reset($events);
312         // Check that the event data is valid.
313         $this->assertInstanceOf('\mod_quiz\event\report_viewed', $event);
314         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
315         $expected = array($course->id, 'quiz', 'report', 'report.php?id=' . $quiz->cmid . '&mode=overview',
316             $quiz->id, $quiz->cmid);
317         $this->assertEventLegacyLogData($expected, $event);
318         $this->assertEventContextNotUsed($event);
319     }
321     /**
322      * Test the attempt reviewed event.
323      *
324      * There is no external API for reviewing attempts, so the unit test will simply
325      * create and trigger the event and ensure the event data is returned as expected.
326      */
327     public function test_attempt_reviewed() {
328         $this->resetAfterTest();
330         $this->setAdminUser();
331         $course = $this->getDataGenerator()->create_course();
332         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
334         $params = array(
335             'objectid' => 1,
336             'relateduserid' => 2,
337             'courseid' => $course->id,
338             'context' => context_module::instance($quiz->cmid),
339             'other' => array(
340                 'quizid' => $quiz->id
341             )
342         );
343         $event = \mod_quiz\event\attempt_reviewed::create($params);
345         // Trigger and capture the event.
346         $sink = $this->redirectEvents();
347         $event->trigger();
348         $events = $sink->get_events();
349         $event = reset($events);
351         // Check that the event data is valid.
352         $this->assertInstanceOf('\mod_quiz\event\attempt_reviewed', $event);
353         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
354         $expected = array($course->id, 'quiz', 'review', 'review.php?attempt=1', $quiz->id, $quiz->cmid);
355         $this->assertEventLegacyLogData($expected, $event);
356         $this->assertEventContextNotUsed($event);
357     }
359     /**
360      * Test the attempt summary viewed event.
361      *
362      * There is no external API for viewing the attempt summary, so the unit test will simply
363      * create and trigger the event and ensure the event data is returned as expected.
364      */
365     public function test_attempt_summary_viewed() {
366         $this->resetAfterTest();
368         $this->setAdminUser();
369         $course = $this->getDataGenerator()->create_course();
370         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
372         $params = array(
373             'objectid' => 1,
374             'relateduserid' => 2,
375             'courseid' => $course->id,
376             'context' => context_module::instance($quiz->cmid),
377             'other' => array(
378                 'quizid' => $quiz->id
379             )
380         );
381         $event = \mod_quiz\event\attempt_summary_viewed::create($params);
383         // Trigger and capture the event.
384         $sink = $this->redirectEvents();
385         $event->trigger();
386         $events = $sink->get_events();
387         $event = reset($events);
389         // Check that the event data is valid.
390         $this->assertInstanceOf('\mod_quiz\event\attempt_summary_viewed', $event);
391         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
392         $expected = array($course->id, 'quiz', 'view summary', 'summary.php?attempt=1', $quiz->id, $quiz->cmid);
393         $this->assertEventLegacyLogData($expected, $event);
394         $this->assertEventContextNotUsed($event);
395     }