Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]

   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  namespace mod_quiz;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  
  21  use mod_quiz\question\bank\qbank_helper;
  22  
  23  global $CFG;
  24  require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  25  require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
  26  
  27  /**
  28   * Class mod_quiz_local_structure_slot_random_test
  29   * Class for tests related to the {@link \mod_quiz\local\structure\slot_random} class.
  30   *
  31   * @package    mod_quiz
  32   * @category   test
  33   * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   * @covers     \mod_quiz\local\structure\slot_random
  36   */
  37  class local_structure_slot_random_test extends \advanced_testcase {
  38  
  39      use \quiz_question_helper_test_trait;
  40  
  41      /**
  42       * Constructor test.
  43       */
  44      public function test_constructor() {
  45          global $SITE;
  46  
  47          $this->resetAfterTest();
  48          $this->setAdminUser();
  49  
  50          // Create a quiz.
  51          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
  52          $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]);
  53  
  54          // Create a question category in the system context.
  55          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
  56          $category = $questiongenerator->create_question_category();
  57  
  58          // Create a random question without adding it to a quiz.
  59          // We don't want to use quiz_add_random_questions because that itself, instantiates an object from the slot_random class.
  60          $form = new \stdClass();
  61          $form->category = $category->id . ',' . $category->contextid;
  62          $form->includesubcategories = true;
  63          $form->fromtags = [];
  64          $form->defaultmark = 1;
  65          $form->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN;
  66          $form->stamp = make_unique_id_code();
  67  
  68          // Set the filter conditions.
  69          $filtercondition = new \stdClass();
  70          $filtercondition->filters = \question_filter_test_helper::create_filters([$category->id], true);
  71  
  72          // Slot data.
  73          $randomslotdata = new \stdClass();
  74          $randomslotdata->quizid = $quiz->id;
  75          $randomslotdata->maxmark = 1;
  76          $randomslotdata->usingcontextid = \context_module::instance($quiz->cmid)->id;
  77          $randomslotdata->questionscontextid = $category->contextid;
  78  
  79          // Insert the random question to the quiz.
  80          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
  81          $randomslot->set_filter_condition(json_encode($filtercondition));
  82  
  83          $rc = new \ReflectionClass('\mod_quiz\local\structure\slot_random');
  84          $rcp = $rc->getProperty('filtercondition');
  85          $rcp->setAccessible(true);
  86          $record = json_decode($rcp->getValue($randomslot));
  87  
  88          $this->assertEquals($quiz->id, $randomslot->get_quiz()->id);
  89          $this->assertEquals($category->id, $record->filters->category->values[0]);
  90          $this->assertTrue($record->filters->category->filteroptions->includesubcategories);
  91  
  92          $rcp = $rc->getProperty('record');
  93          $rcp->setAccessible(true);
  94          $record = $rcp->getValue($randomslot);
  95          $this->assertEquals(1, $record->maxmark);
  96      }
  97  
  98      public function test_get_quiz_quiz() {
  99          global $SITE, $DB;
 100  
 101          $this->resetAfterTest();
 102          $this->setAdminUser();
 103  
 104          // Create a quiz.
 105          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 106          $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]);
 107  
 108          // Create a question category in the system context.
 109          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 110          $category = $questiongenerator->create_question_category();
 111  
 112          $this->add_random_questions($quiz->id, 0, $category->id, 1);
 113  
 114          // Set the filter conditions.
 115          $filtercondition = new \stdClass();
 116          $filtercondition->filters = \question_filter_test_helper::create_filters([$category->id], 1);
 117  
 118          // Slot data.
 119          $randomslotdata = new \stdClass();
 120          $randomslotdata->quizid = $quiz->id;
 121          $randomslotdata->maxmark = 1;
 122          $randomslotdata->usingcontextid = \context_module::instance($quiz->cmid)->id;
 123          $randomslotdata->questionscontextid = $category->contextid;
 124  
 125          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 126          $randomslot->set_filter_condition(json_encode($filtercondition));
 127  
 128          // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
 129          unset($quiz->cmid);
 130  
 131          $this->assertEquals($quiz, $randomslot->get_quiz());
 132      }
 133  
 134      public function test_set_quiz() {
 135          global $SITE, $DB;
 136  
 137          $this->resetAfterTest();
 138          $this->setAdminUser();
 139  
 140          // Create a quiz.
 141          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 142          $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]);
 143  
 144          // Create a question category in the system context.
 145          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 146          $category = $questiongenerator->create_question_category();
 147  
 148          $this->add_random_questions($quiz->id, 0, $category->id, 1);
 149  
 150          // Set the filter conditions.
 151          $filtercondition = new \stdClass();
 152          $filtercondition->filters = \question_filter_test_helper::create_filters([$category->id], 1);
 153  
 154          // Slot data.
 155          $randomslotdata = new \stdClass();
 156          $randomslotdata->quizid = $quiz->id;
 157          $randomslotdata->maxmark = 1;
 158          $randomslotdata->usingcontextid = \context_module::instance($quiz->cmid)->id;
 159          $randomslotdata->questionscontextid = $category->contextid;
 160  
 161          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 162          $randomslot->set_filter_condition(json_encode($filtercondition));
 163  
 164          // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
 165          unset($quiz->cmid);
 166  
 167          $randomslot->set_quiz($quiz);
 168  
 169          $rc = new \ReflectionClass('\mod_quiz\local\structure\slot_random');
 170          $rcp = $rc->getProperty('quiz');
 171          $rcp->setAccessible(true);
 172          $quizpropery = $rcp->getValue($randomslot);
 173  
 174          $this->assertEquals($quiz, $quizpropery);
 175      }
 176  
 177      private function setup_for_test_tags($tagnames) {
 178          global $SITE, $DB;
 179  
 180          // Create a quiz.
 181          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 182          $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]);
 183  
 184          // Create a question category in the system context.
 185          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 186          $category = $questiongenerator->create_question_category();
 187  
 188          $this->add_random_questions($quiz->id, 0, $category->id, 1);
 189  
 190          // Slot data.
 191          $randomslotdata = new \stdClass();
 192          $randomslotdata->quizid = $quiz->id;
 193          $randomslotdata->maxmark = 1;
 194          $randomslotdata->usingcontextid = \context_module::instance($quiz->cmid)->id;
 195          $randomslotdata->questionscontextid = $category->contextid;
 196  
 197          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 198  
 199          // Create tags.
 200          foreach ($tagnames as $tagname) {
 201              $tagrecord = [
 202                  'isstandard' => 1,
 203                  'flag' => 0,
 204                  'rawname' => $tagname,
 205                  'description' => $tagname . ' desc'
 206              ];
 207              $tags[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
 208          }
 209  
 210          return [$randomslot, $tags];
 211      }
 212  
 213      public function test_set_tags_filter() {
 214          $this->resetAfterTest();
 215          $this->setAdminUser();
 216  
 217          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar']);
 218  
 219          $qtagids = [$tags['foo']->id, $tags['bar']->id];
 220          $filtercondition = new \stdClass();
 221          $filtercondition->filters = \question_filter_test_helper::create_filters([], 0, $qtagids);
 222          $randomslot->set_filter_condition(json_encode($filtercondition));
 223  
 224          $rc = new \ReflectionClass('\mod_quiz\local\structure\slot_random');
 225          $rcp = $rc->getProperty('filtercondition');
 226          $rcp->setAccessible(true);
 227          $tagspropery = $rcp->getValue($randomslot);
 228  
 229          $this->assertEquals([$tags['foo']->id, $tags['bar']->id],
 230              (array)json_decode($tagspropery)->filters->qtagids->values);
 231      }
 232  
 233      public function test_insert() {
 234          global $SITE;
 235  
 236          $this->resetAfterTest();
 237          $this->setAdminUser();
 238  
 239          // Create a quiz.
 240          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 241          $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]);
 242          $quizcontext = \context_module::instance($quiz->cmid);
 243  
 244          // Create a question category in the system context.
 245          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 246          $category = $questiongenerator->create_question_category();
 247  
 248          // Create a random question without adding it to a quiz.
 249          $form = new \stdClass();
 250          $form->category = $category->id . ',' . $category->contextid;
 251          $form->includesubcategories = true;
 252          $form->fromtags = [];
 253          $form->defaultmark = 1;
 254          $form->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN;
 255          $form->stamp = make_unique_id_code();
 256  
 257          // Prepare 2 tags.
 258          $tagrecord = [
 259              'isstandard' => 1,
 260              'flag' => 0,
 261              'rawname' => 'foo',
 262              'description' => 'foo desc'
 263          ];
 264          $footag = $this->getDataGenerator()->create_tag($tagrecord);
 265          $tagrecord = [
 266              'isstandard' => 1,
 267              'flag' => 0,
 268              'rawname' => 'bar',
 269              'description' => 'bar desc'
 270          ];
 271          $bartag = $this->getDataGenerator()->create_tag($tagrecord);
 272  
 273  
 274          // Set the filter conditions.
 275          $filtercondition = new \stdClass();
 276          $filtercondition->filter = \question_filter_test_helper::create_filters([$category->id], true, [$footag->id, $bartag->id]);
 277  
 278          // Slot data.
 279          $randomslotdata = new \stdClass();
 280          $randomslotdata->quizid = $quiz->id;
 281          $randomslotdata->maxmark = 1;
 282          $randomslotdata->usingcontextid = $quizcontext->id;
 283          $randomslotdata->questionscontextid = $category->contextid;
 284  
 285          // Insert the random question to the quiz.
 286          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 287          $randomslot->set_filter_condition(json_encode($filtercondition));
 288          $randomslot->insert(1); // Put the question on the first page of the quiz.
 289  
 290          $slots = qbank_helper::get_question_structure($quiz->id, $quizcontext);
 291          $quizslot = reset($slots);
 292  
 293          $filter = $quizslot->filtercondition['filter'];
 294  
 295          $this->assertEquals($category->id, $filter['category']['values'][0]);
 296          $this->assertTrue($filter['category']['filteroptions']['includesubcategories']);
 297          $this->assertEquals(1, $quizslot->maxmark);
 298  
 299          $this->assertCount(2, $filter['qtagids']['values']);
 300          $this->assertEqualsCanonicalizing(
 301                  [
 302                      ['tagid' => $footag->id],
 303                      ['tagid' => $bartag->id]
 304                  ],
 305                  array_map(function($tagid) {
 306                      return ['tagid' => $tagid];
 307                  }, $filter['qtagids']['values']));
 308      }
 309  }