Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 311 and 401]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * 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   */
  24  
  25  namespace core_question\event;
  26  
  27  use qbank_managecategories\question_category_object;
  28  use qtype_description;
  29  use qtype_description_edit_form;
  30  use qtype_description_test_helper;
  31  use test_question_maker;
  32  
  33  defined('MOODLE_INTERNAL') || die();
  34  
  35  global $CFG;
  36  
  37  require_once($CFG->dirroot . '/question/editlib.php');
  38  
  39  class events_test extends \advanced_testcase {
  40  
  41      /**
  42       * Tests set up.
  43       */
  44      public function setUp(): void {
  45          $this->resetAfterTest();
  46      }
  47  
  48      /**
  49       * Test the questions imported event.
  50       * There is no easy way to trigger this event using the API, so the unit test will simply
  51       * create and trigger the event and ensure data is returned as expected.
  52       */
  53      public function test_questions_imported() {
  54  
  55          $this->setAdminUser();
  56          $course = $this->getDataGenerator()->create_course();
  57          $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
  58  
  59          $contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
  60  
  61          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
  62          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
  63  
  64          $qcobject = new question_category_object(
  65                  1,
  66                  new \moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
  67                  $contexts->having_one_edit_tab_cap('categories'),
  68                  $defaultcategoryobj->id,
  69                  $defaultcategory,
  70                  null,
  71                  $contexts->having_cap('moodle/question:add'));
  72  
  73          // Create the category.
  74          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
  75  
  76          // Log the view of this category.
  77          $params = [
  78                  'context' => \context_module::instance($quiz->cmid),
  79                  'other' => ['categoryid' => $categoryid, 'format' => 'testformat'],
  80          ];
  81  
  82          $event = \core\event\questions_imported::create($params);
  83  
  84          // Trigger and capture the event.
  85          $sink = $this->redirectEvents();
  86          $event->trigger();
  87          $events = $sink->get_events();
  88          $event = reset($events);
  89  
  90          // Check that the event data is valid.
  91          $this->assertInstanceOf('\core\event\questions_imported', $event);
  92          $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
  93          $this->assertEquals($categoryid, $event->other['categoryid']);
  94          $this->assertEquals('testformat', $event->other['format']);
  95          $this->assertDebuggingNotCalled();
  96  
  97      }
  98  
  99      /**
 100       * Test the questions exported event.
 101       * There is no easy way to trigger this event using the API, so the unit test will simply
 102       * create and trigger the event and ensure data is returned as expected.
 103       */
 104      public function test_questions_exported() {
 105  
 106          $this->setAdminUser();
 107          $course = $this->getDataGenerator()->create_course();
 108          $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
 109  
 110          $contexts = new \core_question\local\bank\question_edit_contexts(\context_module::instance($quiz->cmid));
 111  
 112          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
 113          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
 114  
 115          $qcobject = new question_category_object(
 116                  1,
 117                  new \moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]),
 118                  $contexts->having_one_edit_tab_cap('categories'),
 119                  $defaultcategoryobj->id,
 120                  $defaultcategory,
 121                  null,
 122                  $contexts->having_cap('moodle/question:add'));
 123  
 124          // Create the category.
 125          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
 126  
 127          // Log the view of this category.
 128          $params = [
 129                  'context' => \context_module::instance($quiz->cmid),
 130                  'other' => ['categoryid' => $categoryid, 'format' => 'testformat'],
 131          ];
 132  
 133          $event = \core\event\questions_exported::create($params);
 134  
 135          // Trigger and capture the event.
 136          $sink = $this->redirectEvents();
 137          $event->trigger();
 138          $events = $sink->get_events();
 139          $event = reset($events);
 140  
 141          // Check that the event data is valid.
 142          $this->assertInstanceOf('\core\event\questions_exported', $event);
 143          $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
 144          $this->assertEquals($categoryid, $event->other['categoryid']);
 145          $this->assertEquals('testformat', $event->other['format']);
 146          $this->assertDebuggingNotCalled();
 147  
 148      }
 149  
 150      /**
 151       * Test the question created event.
 152       */
 153      public function test_question_created() {
 154  
 155          $this->setAdminUser();
 156          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 157  
 158          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 159  
 160          // Trigger and capture the event.
 161          $sink = $this->redirectEvents();
 162          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 163          $question = \question_bank::load_question($questiondata->id);
 164  
 165          $events = $sink->get_events();
 166          $event = reset($events);
 167  
 168          // Check that the event data is valid.
 169          $this->assertInstanceOf('\core\event\question_created', $event);
 170          $this->assertEquals($question->id, $event->objectid);
 171          $this->assertEquals($cat->id, $event->other['categoryid']);
 172          $this->assertDebuggingNotCalled();
 173  
 174      }
 175  
 176      /**
 177       * Test the question deleted event.
 178       */
 179      public function test_question_deleted() {
 180  
 181          $this->setAdminUser();
 182          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 183  
 184          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 185  
 186          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 187          $question = \question_bank::load_question($questiondata->id);
 188  
 189          // Trigger and capture the event.
 190          $sink = $this->redirectEvents();
 191          question_delete_question($question->id);
 192          $events = $sink->get_events();
 193          $event = reset($events);
 194  
 195          // Check that the event data is valid.
 196          $this->assertInstanceOf('\core\event\question_deleted', $event);
 197          $this->assertEquals($question->id, $event->objectid);
 198          $this->assertEquals($cat->id, $event->other['categoryid']);
 199          $this->assertDebuggingNotCalled();
 200  
 201      }
 202  
 203      /**
 204       * Test the question updated event.
 205       */
 206      public function test_question_updated() {
 207  
 208          global $CFG;
 209          require_once($CFG->dirroot . '/question/type/description/questiontype.php');
 210          require_once($CFG->dirroot . '/question/type/edit_question_form.php');
 211          require_once($CFG->dirroot . '/question/type/description/edit_description_form.php');
 212  
 213          $this->setAdminUser();
 214          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 215  
 216          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 217  
 218          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 219          $question = \question_bank::load_question($questiondata->id);
 220  
 221          $qtype = new qtype_description();
 222          $formdata = test_question_maker::get_question_form_data('description');
 223          $formdata->category = "{$cat->id},{$cat->contextid}";
 224          qtype_description_edit_form::mock_submit((array) $formdata);
 225  
 226          $form = qtype_description_test_helper::get_question_editing_form($cat, $questiondata);
 227          $fromform = $form->get_data();
 228  
 229          // Trigger and capture the event.
 230          $sink = $this->redirectEvents();
 231          $question = $qtype->save_question($questiondata, $fromform);
 232          $events = $sink->get_events();
 233          $event = reset($events);
 234  
 235          // Check that the event data is valid.
 236          // Every save is a new question after Moodle 4.0.
 237          $this->assertInstanceOf('\core\event\question_created', $event);
 238          $this->assertEquals($question->id, $event->objectid);
 239          $this->assertEquals($cat->id, $event->other['categoryid']);
 240          $this->assertDebuggingNotCalled();
 241  
 242      }
 243  
 244      /**
 245       * Test the question moved event.
 246       */
 247      public function test_question_moved() {
 248  
 249          $this->setAdminUser();
 250          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 251  
 252          $cat1 = $generator->create_question_category([
 253                  'name' => 'My category 1', 'sortorder' => 1]);
 254  
 255          $cat2 = $generator->create_question_category([
 256                  'name' => 'My category 2', 'sortorder' => 2]);
 257  
 258          $questiondata = $generator->create_question('description', null, ['category' => $cat1->id]);
 259          $question = \question_bank::load_question($questiondata->id);
 260  
 261          // Trigger and capture the event.
 262          $sink = $this->redirectEvents();
 263          question_move_questions_to_category([$question->id], $cat2->id);
 264          $events = $sink->get_events();
 265          $event = reset($events);
 266  
 267          // Check that the event data is valid.
 268          $this->assertInstanceOf('\core\event\question_moved', $event);
 269          $this->assertEquals($question->id, $event->objectid);
 270          $this->assertEquals($cat1->id, $event->other['oldcategoryid']);
 271          $this->assertEquals($cat2->id, $event->other['newcategoryid']);
 272          $this->assertDebuggingNotCalled();
 273  
 274      }
 275  
 276      /**
 277       * Test the question viewed event.
 278       * There is no external API for viewing the question, so the unit test will simply
 279       * create and trigger the event and ensure data is returned as expected.
 280       */
 281      public function test_question_viewed() {
 282  
 283          $this->setAdminUser();
 284          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 285  
 286          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 287  
 288          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 289          $question = \question_bank::load_question($questiondata->id);
 290  
 291          $event = \core\event\question_viewed::create_from_question_instance($question, \context::instance_by_id($cat->contextid));
 292  
 293          // Trigger and capture the event.
 294          $sink = $this->redirectEvents();
 295          $event->trigger();
 296          $events = $sink->get_events();
 297          $event = reset($events);
 298  
 299          // Check that the event data is valid.
 300          $this->assertInstanceOf('\core\event\question_viewed', $event);
 301          $this->assertEquals($question->id, $event->objectid);
 302          $this->assertEquals($cat->id, $event->other['categoryid']);
 303          $this->assertDebuggingNotCalled();
 304  
 305      }
 306  }