Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

   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  defined('MOODLE_INTERNAL') || die();
  26  
  27  global $CFG;
  28  
  29  require_once($CFG->dirroot . '/question/editlib.php');
  30  require_once($CFG->dirroot . '/question/category_class.php');
  31  
  32  class core_question_events_testcase extends advanced_testcase {
  33  
  34      /**
  35       * Tests set up.
  36       */
  37      public function setUp(): void {
  38          $this->resetAfterTest();
  39      }
  40  
  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));
  48  
  49          $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
  50  
  51          $defaultcategoryobj = question_make_default_categories(array($contexts->lowest()));
  52          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
  53  
  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'));
  62  
  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);
  68  
  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      }
  76  
  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]);
  84  
  85          $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
  86  
  87          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
  88          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
  89  
  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'));
  98  
  99          // Create the category.
 100          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
 101  
 102          // Trigger and capture the event.
 103          $sink = $this->redirectEvents();
 104          $qcobject->delete_category($categoryid);
 105          $events = $sink->get_events();
 106          $event = reset($events);
 107  
 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      }
 114  
 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]);
 122  
 123          $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
 124  
 125          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
 126          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
 127  
 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'));
 136  
 137          // Create the category.
 138          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
 139  
 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);
 145  
 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      }
 152  
 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() {
 159  
 160          $this->setAdminUser();
 161          $course = $this->getDataGenerator()->create_course();
 162          $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
 163  
 164          $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
 165  
 166          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
 167          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
 168  
 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'));
 177  
 178          // Create the category.
 179          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
 180  
 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);
 186  
 187          // Trigger and capture the event.
 188          $sink = $this->redirectEvents();
 189          $event->trigger();
 190          $events = $sink->get_events();
 191          $event = reset($events);
 192  
 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();
 198  
 199      }
 200  
 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() {
 207  
 208          $this->setAdminUser();
 209          $course = $this->getDataGenerator()->create_course();
 210          $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
 211  
 212          $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
 213  
 214          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
 215          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
 216  
 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'));
 225  
 226          // Create the category.
 227          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
 228  
 229          // Log the view of this category.
 230          $params = [
 231                  'context' => context_module::instance($quiz->cmid),
 232                  'other' => ['categoryid' => $categoryid, 'format' => 'testformat'],
 233          ];
 234  
 235          $event = \core\event\questions_imported::create($params);
 236  
 237          // Trigger and capture the event.
 238          $sink = $this->redirectEvents();
 239          $event->trigger();
 240          $events = $sink->get_events();
 241          $event = reset($events);
 242  
 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();
 249  
 250      }
 251  
 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() {
 258  
 259          $this->setAdminUser();
 260          $course = $this->getDataGenerator()->create_course();
 261          $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
 262  
 263          $contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
 264  
 265          $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]);
 266          $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
 267  
 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'));
 276  
 277          // Create the category.
 278          $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true);
 279  
 280          // Log the view of this category.
 281          $params = [
 282                  'context' => context_module::instance($quiz->cmid),
 283                  'other' => ['categoryid' => $categoryid, 'format' => 'testformat'],
 284          ];
 285  
 286          $event = \core\event\questions_exported::create($params);
 287  
 288          // Trigger and capture the event.
 289          $sink = $this->redirectEvents();
 290          $event->trigger();
 291          $events = $sink->get_events();
 292          $event = reset($events);
 293  
 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();
 300  
 301      }
 302  
 303      /**
 304       * Test the question created event.
 305       */
 306      public function test_question_created() {
 307  
 308          $this->setAdminUser();
 309          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 310  
 311          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 312  
 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);
 317  
 318          $events = $sink->get_events();
 319          $event = reset($events);
 320  
 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();
 326  
 327      }
 328  
 329      /**
 330       * Test the question deleted event.
 331       */
 332      public function test_question_deleted() {
 333  
 334          $this->setAdminUser();
 335          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 336  
 337          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 338  
 339          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 340          $question = question_bank::load_question($questiondata->id);
 341  
 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);
 347  
 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();
 353  
 354      }
 355  
 356      /**
 357       * Test the question updated event.
 358       */
 359      public function test_question_updated() {
 360  
 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');
 365  
 366          $this->setAdminUser();
 367          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 368  
 369          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 370  
 371          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 372          $question = question_bank::load_question($questiondata->id);
 373  
 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);
 378  
 379          $form = qtype_description_test_helper::get_question_editing_form($cat, $questiondata);
 380          $fromform = $form->get_data();
 381  
 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);
 387  
 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();
 393  
 394      }
 395  
 396      /**
 397       * Test the question moved event.
 398       */
 399      public function test_question_moved() {
 400  
 401          $this->setAdminUser();
 402          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 403  
 404          $cat1 = $generator->create_question_category([
 405                  'name' => 'My category 1', 'sortorder' => 1]);
 406  
 407          $cat2 = $generator->create_question_category([
 408                  'name' => 'My category 2', 'sortorder' => 2]);
 409  
 410          $questiondata = $generator->create_question('description', null, ['category' => $cat1->id]);
 411          $question = question_bank::load_question($questiondata->id);
 412  
 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);
 418  
 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();
 425  
 426      }
 427  
 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() {
 434  
 435          $this->setAdminUser();
 436          $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
 437  
 438          $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]);
 439  
 440          $questiondata = $generator->create_question('description', null, ['category' => $cat->id]);
 441          $question = question_bank::load_question($questiondata->id);
 442  
 443          $event = \core\event\question_viewed::create_from_question_instance($question, context::instance_by_id($cat->contextid));
 444  
 445          // Trigger and capture the event.
 446          $sink = $this->redirectEvents();
 447          $event->trigger();
 448          $events = $sink->get_events();
 449          $event = reset($events);
 450  
 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();
 456  
 457      }
 458  }