MDL-36088 questions: Add new events
[moodle.git] / question / 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  * Events tests.
19  *
20  * @package core_question
21  * @copyright 2014 Mark Nelson <markn@moodle.com>
22  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
29 require_once($CFG->dirroot . '/question/editlib.php');
30 require_once($CFG->dirroot . '/question/category_class.php');
32 class core_question_events_testcase extends advanced_testcase {
34     /**
35      * Tests set up.
36      */
37     public function setUp() {
38         $this->resetAfterTest();
39     }
41     /**
42      * Test the question category created event.
43      */
44     public function test_question_category_created() {
45         $this->setAdminUser();
46         $course = $this->getDataGenerator()->create_course();
47         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
49         $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
51         $defaultcategoryobj = question_make_default_categories(array($contexts->lowest()));
52         $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
54         $qcobject = new question_category_object(
55             1,
56             new moodle_url('/mod/quiz/edit.php', array('cmid' => $quiz->cmid)),
57             $contexts->having_one_edit_tab_cap('categories'),
58             $defaultcategoryobj->id,
59             $defaultcategory,
60             null,
61             $contexts->having_cap('moodle/question:add'));
63         // Trigger and capture the event.
64         $sink = $this->redirectEvents();
65         $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
66         $events = $sink->get_events();
67         $event = reset($events);
69         // Check that the event data is valid.
70         $this->assertInstanceOf('\core\event\question_category_created', $event);
71         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
72         $expected = array($course->id, 'quiz', 'addcategory', 'view.php?id=' . $quiz->cmid , $categoryid, $quiz->cmid);
73         $this->assertEventLegacyLogData($expected, $event);
74         $this->assertEventContextNotUsed($event);
75     }
77     /**
78      * Test the question category deleted event.
79      */
80     public function test_question_category_deleted() {
81         $this->setAdminUser();
82         $course = $this->getDataGenerator()->create_course();
83         $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
85         $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
87         $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
88         $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
90         $qcobject = new question_category_object(
91                 1,
92                 new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
93                 $contexts->having_one_edit_tab_cap('categories'),
94                 $defaultcategoryobj->id,
95                 $defaultcategory,
96                 null,
97                 $contexts->having_cap('moodle/question:add'));
99         // Create the category.
100         $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
102         // Trigger and capture the event.
103         $sink = $this->redirectEvents();
104         $qcobject->delete_category($categoryid);
105         $events = $sink->get_events();
106         $event = reset($events);
108         // Check that the event data is valid.
109         $this->assertInstanceOf('\core\event\question_category_deleted', $event);
110         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
111         $this->assertEquals($categoryid, $event->objectid);
112         $this->assertDebuggingNotCalled();
113     }
115     /**
116      * Test the question category updated event.
117      */
118     public function test_question_category_updated() {
119         $this->setAdminUser();
120         $course = $this->getDataGenerator()->create_course();
121         $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
123         $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
125         $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
126         $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
128         $qcobject = new question_category_object(
129                 1,
130                 new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
131                 $contexts->having_one_edit_tab_cap('categories'),
132                 $defaultcategoryobj->id,
133                 $defaultcategory,
134                 null,
135                 $contexts->having_cap('moodle/question:add'));
137         // Create the category.
138         $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
140         // Trigger and capture the event.
141         $sink = $this->redirectEvents();
142         $qcobject->update_category($categoryid, $defaultcategory, 'updatedcategory', '', FORMAT_HTML, '', false);
143         $events = $sink->get_events();
144         $event = reset($events);
146         // Check that the event data is valid.
147         $this->assertInstanceOf('\core\event\question_category_updated', $event);
148         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
149         $this->assertEquals($categoryid, $event->objectid);
150         $this->assertDebuggingNotCalled();
151     }
153     /**
154      * Test the question category viewed event.
155      * There is no external API for viewing the category, so the unit test will simply
156      * create and trigger the event and ensure data is returned as expected.
157      */
158     public function test_question_category_viewed() {
160         $this->setAdminUser();
161         $course = $this->getDataGenerator()->create_course();
162         $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
164         $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
166         $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
167         $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
169         $qcobject = new question_category_object(
170                 1,
171                 new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
172                 $contexts->having_one_edit_tab_cap('categories'),
173                 $defaultcategoryobj->id,
174                 $defaultcategory,
175                 null,
176                 $contexts->having_cap('moodle/question:add'));
178         // Create the category.
179         $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
181         // Log the view of this category.
182         $category = new stdClass();
183         $category->id = $categoryid;
184         $context = context_module::instance($quiz->cmid);
185         $event = \core\event\question_category_viewed::create_from_question_category_instance($category, $context);
187         // Trigger and capture the event.
188         $sink = $this->redirectEvents();
189         $event->trigger();
190         $events = $sink->get_events();
191         $event = reset($events);
193         // Check that the event data is valid.
194         $this->assertInstanceOf('\core\event\question_category_viewed', $event);
195         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
196         $this->assertEquals($categoryid, $event->objectid);
197         $this->assertDebuggingNotCalled();
199     }
201     /**
202      * Test the questions imported event.
203      * There is no easy way to trigger this event using the API, so the unit test will simply
204      * create and trigger the event and ensure data is returned as expected.
205      */
206     public function test_questions_imported() {
208         $this->setAdminUser();
209         $course = $this->getDataGenerator()->create_course();
210         $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
212         $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
214         $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
215         $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
217         $qcobject = new question_category_object(
218                 1,
219                 new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
220                 $contexts->having_one_edit_tab_cap('categories'),
221                 $defaultcategoryobj->id,
222                 $defaultcategory,
223                 null,
224                 $contexts->having_cap('moodle/question:add'));
226         // Create the category.
227         $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
229         // Log the view of this category.
230         $params = [
231                 'context' => context_module::instance($quiz->cmid),
232                 'other' => ['categoryid' => $categoryid, 'format' => 'testformat'],
233         ];
235         $event = \core\event\questions_imported::create($params);
237         // Trigger and capture the event.
238         $sink = $this->redirectEvents();
239         $event->trigger();
240         $events = $sink->get_events();
241         $event = reset($events);
243         // Check that the event data is valid.
244         $this->assertInstanceOf('\core\event\questions_imported', $event);
245         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
246         $this->assertEquals($categoryid, $event->other['categoryid']);
247         $this->assertEquals('testformat', $event->other['format']);
248         $this->assertDebuggingNotCalled();
250     }
252     /**
253      * Test the questions exported event.
254      * There is no easy way to trigger this event using the API, so the unit test will simply
255      * create and trigger the event and ensure data is returned as expected.
256      */
257     public function test_questions_exported() {
259         $this->setAdminUser();
260         $course = $this->getDataGenerator()->create_course();
261         $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
263         $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
265         $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
266         $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
268         $qcobject = new question_category_object(
269                 1,
270                 new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
271                 $contexts->having_one_edit_tab_cap('categories'),
272                 $defaultcategoryobj->id,
273                 $defaultcategory,
274                 null,
275                 $contexts->having_cap('moodle/question:add'));
277         // Create the category.
278         $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
280         // Log the view of this category.
281         $params = [
282                 'context' => context_module::instance($quiz->cmid),
283                 'other' => ['categoryid' => $categoryid, 'format' => 'testformat'],
284         ];
286         $event = \core\event\questions_exported::create($params);
288         // Trigger and capture the event.
289         $sink = $this->redirectEvents();
290         $event->trigger();
291         $events = $sink->get_events();
292         $event = reset($events);
294         // Check that the event data is valid.
295         $this->assertInstanceOf('\core\event\questions_exported', $event);
296         $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context());
297         $this->assertEquals($categoryid, $event->other['categoryid']);
298         $this->assertEquals('testformat', $event->other['format']);
299         $this->assertDebuggingNotCalled();
301     }
303     /**
304      * Test the question created event.
305      */
306     public function test_question_created() {
308         $this->setAdminUser();
309         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
311         $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
313         // Trigger and capture the event.
314         $sink = $this->redirectEvents();
315         $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
316         $question = question_bank::load_question($questiondata->id);
318         $events = $sink->get_events();
319         $event = reset($events);
321         // Check that the event data is valid.
322         $this->assertInstanceOf('\core\event\question_created', $event);
323         $this->assertEquals($question->id, $event->objectid);
324         $this->assertEquals($cat->id, $event->other['categoryid']);
325         $this->assertDebuggingNotCalled();
327     }
329     /**
330      * Test the question deleted event.
331      */
332     public function test_question_deleted() {
334         $this->setAdminUser();
335         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
337         $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
339         $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
340         $question = question_bank::load_question($questiondata->id);
342         // Trigger and capture the event.
343         $sink = $this->redirectEvents();
344         question_delete_question($question->id);
345         $events = $sink->get_events();
346         $event = reset($events);
348         // Check that the event data is valid.
349         $this->assertInstanceOf('\core\event\question_deleted', $event);
350         $this->assertEquals($question->id, $event->objectid);
351         $this->assertEquals($cat->id, $event->other['categoryid']);
352         $this->assertDebuggingNotCalled();
354     }
356     /**
357      * Test the question updated event.
358      */
359     public function test_question_updated() {
361         global $CFG;
362         require_once($CFG->dirroot . '/question/type/description/questiontype.php');
363         require_once($CFG->dirroot . '/question/type/edit_question_form.php');
364         require_once($CFG->dirroot . '/question/type/description/edit_description_form.php');
366         $this->setAdminUser();
367         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
369         $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
371         $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
372         $question = question_bank::load_question($questiondata->id);
374         $qtype = new qtype_description();
375         $formdata = test_question_maker::get_question_form_data('description');
376         $formdata->category = "{$cat->id},{$cat->contextid}";
377         qtype_description_edit_form::mock_submit((array) $formdata);
379         $form = qtype_description_test_helper::get_question_editing_form($cat, $questiondata);
380         $fromform = $form->get_data();
382         // Trigger and capture the event.
383         $sink = $this->redirectEvents();
384         $qtype->save_question($questiondata, $fromform);
385         $events = $sink->get_events();
386         $event = reset($events);
388         // Check that the event data is valid.
389         $this->assertInstanceOf('\core\event\question_updated', $event);
390         $this->assertEquals($question->id, $event->objectid);
391         $this->assertEquals($cat->id, $event->other['categoryid']);
392         $this->assertDebuggingNotCalled();
394     }
396     /**
397      * Test the question moved event.
398      */
399     public function test_question_moved() {
401         $this->setAdminUser();
402         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
404         $cat1 = $generator->create_question_category([
405                 'name' => 'My category 1', 'sortorder' => 1]);
407         $cat2 = $generator->create_question_category([
408                 'name' => 'My category 2', 'sortorder' => 2]);
410         $questiondata = $generator->create_question('description', null, ['category' => $cat1->id]);
411         $question = question_bank::load_question($questiondata->id);
413         // Trigger and capture the event.
414         $sink = $this->redirectEvents();
415         question_move_questions_to_category([$question->id], $cat2->id);
416         $events = $sink->get_events();
417         $event = reset($events);
419         // Check that the event data is valid.
420         $this->assertInstanceOf('\core\event\question_moved', $event);
421         $this->assertEquals($question->id, $event->objectid);
422         $this->assertEquals($cat1->id, $event->other['oldcategoryid']);
423         $this->assertEquals($cat2->id, $event->other['newcategoryid']);
424         $this->assertDebuggingNotCalled();
426     }
428     /**
429      * Test the question viewed event.
430      * There is no external API for viewing the question, so the unit test will simply
431      * create and trigger the event and ensure data is returned as expected.
432      */
433     public function test_question_viewed() {
435         $this->setAdminUser();
436         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
438         $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
440         $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
441         $question = question_bank::load_question($questiondata->id);
443         $event = \core\event\question_viewed::create_from_question_instance($question, context::instance_by_id($cat->contextid));
445         // Trigger and capture the event.
446         $sink = $this->redirectEvents();
447         $event->trigger();
448         $events = $sink->get_events();
449         $event = reset($events);
451         // Check that the event data is valid.
452         $this->assertInstanceOf('\core\event\question_viewed', $event);
453         $this->assertEquals($question->id, $event->objectid);
454         $this->assertEquals($cat->id, $event->other['categoryid']);
455         $this->assertDebuggingNotCalled();
457     }