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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [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   * Unit tests for the {@link \mod_quiz\local\structure\slot_random} class.
  19   *
  20   * @package    mod_quiz
  21   * @category   test
  22   * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Class mod_quiz_local_structure_slot_random_test
  30   * Class for tests related to the {@link \mod_quiz\local\structure\slot_random} class.
  31   *
  32   * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class mod_quiz_local_structure_slot_random_test extends advanced_testcase {
  36      /**
  37       * Constructor test.
  38       */
  39      public function test_constructor() {
  40          global $SITE;
  41  
  42          $this->resetAfterTest();
  43          $this->setAdminUser();
  44  
  45          // Create a quiz.
  46          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
  47          $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
  48  
  49          // Create a question category in the system context.
  50          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
  51          $category = $questiongenerator->create_question_category();
  52  
  53          // Create a random question without adding it to a quiz.
  54          // We don't want to use quiz_add_random_questions because that itself, instantiates an object from the slot_random class.
  55          $form = new stdClass();
  56          $form->category = $category->id . ',' . $category->contextid;
  57          $form->includesubcategories = true;
  58          $form->fromtags = [];
  59          $form->defaultmark = 1;
  60          $form->hidden = 1;
  61          $form->stamp = make_unique_id_code();
  62          $question = new stdClass();
  63          $question->qtype = 'random';
  64          $question = question_bank::get_qtype('random')->save_question($question, $form);
  65  
  66          $randomslotdata = new stdClass();
  67          $randomslotdata->quizid = $quiz->id;
  68          $randomslotdata->questionid = $question->id;
  69          $randomslotdata->questioncategoryid = $category->id;
  70          $randomslotdata->includingsubcategories = 1;
  71          $randomslotdata->maxmark = 1;
  72  
  73          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
  74  
  75          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
  76          $rcp = $rc->getProperty('record');
  77          $rcp->setAccessible(true);
  78          $record = $rcp->getValue($randomslot);
  79  
  80          $this->assertEquals($quiz->id, $record->quizid);
  81          $this->assertEquals($question->id, $record->questionid);
  82          $this->assertEquals($category->id, $record->questioncategoryid);
  83          $this->assertEquals(1, $record->includingsubcategories);
  84          $this->assertEquals(1, $record->maxmark);
  85      }
  86  
  87      public function test_get_quiz_quiz() {
  88          global $SITE, $DB;
  89  
  90          $this->resetAfterTest();
  91          $this->setAdminUser();
  92  
  93          // Create a quiz.
  94          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
  95          $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
  96  
  97          // Create a question category in the system context.
  98          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
  99          $category = $questiongenerator->create_question_category();
 100  
 101          quiz_add_random_questions($quiz, 0, $category->id, 1, false);
 102  
 103          // Get the random question's id. It is at the first slot.
 104          $questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
 105  
 106          $randomslotdata = new stdClass();
 107          $randomslotdata->quizid = $quiz->id;
 108          $randomslotdata->questionid = $questionid;
 109          $randomslotdata->questioncategoryid = $category->id;
 110          $randomslotdata->includingsubcategories = 1;
 111          $randomslotdata->maxmark = 1;
 112  
 113          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 114  
 115          // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
 116          unset($quiz->cmid);
 117  
 118          $this->assertEquals($quiz, $randomslot->get_quiz());
 119      }
 120  
 121      public function test_set_quiz() {
 122          global $SITE, $DB;
 123  
 124          $this->resetAfterTest();
 125          $this->setAdminUser();
 126  
 127          // Create a quiz.
 128          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 129          $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
 130  
 131          // Create a question category in the system context.
 132          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 133          $category = $questiongenerator->create_question_category();
 134  
 135          quiz_add_random_questions($quiz, 0, $category->id, 1, false);
 136  
 137          // Get the random question's id. It is at the first slot.
 138          $questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
 139  
 140          $randomslotdata = new stdClass();
 141          $randomslotdata->quizid = $quiz->id;
 142          $randomslotdata->questionid = $questionid;
 143          $randomslotdata->questioncategoryid = $category->id;
 144          $randomslotdata->includingsubcategories = 1;
 145          $randomslotdata->maxmark = 1;
 146  
 147          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 148  
 149          // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
 150          unset($quiz->cmid);
 151  
 152          $randomslot->set_quiz($quiz);
 153  
 154          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 155          $rcp = $rc->getProperty('quiz');
 156          $rcp->setAccessible(true);
 157          $quizpropery = $rcp->getValue($randomslot);
 158  
 159          $this->assertEquals($quiz, $quizpropery);
 160      }
 161  
 162      private function setup_for_test_tags($tagnames) {
 163          global $SITE, $DB;
 164  
 165          // Create a quiz.
 166          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 167          $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
 168  
 169          // Create a question category in the system context.
 170          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 171          $category = $questiongenerator->create_question_category();
 172  
 173          quiz_add_random_questions($quiz, 0, $category->id, 1, false);
 174  
 175          // Get the random question's id. It is at the first slot.
 176          $questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
 177  
 178          $randomslotdata = new stdClass();
 179          $randomslotdata->quizid = $quiz->id;
 180          $randomslotdata->questionid = $questionid;
 181          $randomslotdata->questioncategoryid = $category->id;
 182          $randomslotdata->includingsubcategories = 1;
 183          $randomslotdata->maxmark = 1;
 184  
 185          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 186  
 187          // Create tags.
 188          foreach ($tagnames as $tagname) {
 189              $tagrecord = array(
 190                  'isstandard' => 1,
 191                  'flag' => 0,
 192                  'rawname' => $tagname,
 193                  'description' => $tagname . ' desc'
 194              );
 195              $tags[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
 196          }
 197  
 198          return array($randomslot, $tags);
 199      }
 200  
 201      public function test_set_tags() {
 202          $this->resetAfterTest();
 203          $this->setAdminUser();
 204  
 205          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar']);
 206          $randomslot->set_tags([$tags['foo'], $tags['bar']]);
 207  
 208          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 209          $rcp = $rc->getProperty('tags');
 210          $rcp->setAccessible(true);
 211          $tagspropery = $rcp->getValue($randomslot);
 212  
 213          $this->assertEquals([
 214              $tags['foo']->id => $tags['foo'],
 215              $tags['bar']->id => $tags['bar'],
 216          ], $tagspropery);
 217      }
 218  
 219      public function test_set_tags_twice() {
 220          $this->resetAfterTest();
 221          $this->setAdminUser();
 222  
 223          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
 224  
 225          // Set tags for the first time.
 226          $randomslot->set_tags([$tags['foo'], $tags['bar']]);
 227          // Now set the tags again.
 228          $randomslot->set_tags([$tags['baz']]);
 229  
 230          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 231          $rcp = $rc->getProperty('tags');
 232          $rcp->setAccessible(true);
 233          $tagspropery = $rcp->getValue($randomslot);
 234  
 235          $this->assertEquals([
 236              $tags['baz']->id => $tags['baz'],
 237          ], $tagspropery);
 238      }
 239  
 240      public function test_set_tags_duplicates() {
 241          $this->resetAfterTest();
 242          $this->setAdminUser();
 243  
 244          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
 245  
 246          $randomslot->set_tags([$tags['foo'], $tags['bar'], $tags['foo']]);
 247  
 248          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 249          $rcp = $rc->getProperty('tags');
 250          $rcp->setAccessible(true);
 251          $tagspropery = $rcp->getValue($randomslot);
 252  
 253          $this->assertEquals([
 254              $tags['foo']->id => $tags['foo'],
 255              $tags['bar']->id => $tags['bar'],
 256          ], $tagspropery);
 257      }
 258  
 259      public function test_set_tags_by_id() {
 260          $this->resetAfterTest();
 261          $this->setAdminUser();
 262  
 263          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
 264  
 265          $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
 266  
 267          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 268          $rcp = $rc->getProperty('tags');
 269          $rcp->setAccessible(true);
 270          $tagspropery = $rcp->getValue($randomslot);
 271  
 272          // The set_tags_by_id function only retrieves id and name fields of the tag object.
 273          $this->assertCount(2, $tagspropery);
 274          $this->assertArrayHasKey($tags['foo']->id, $tagspropery);
 275          $this->assertArrayHasKey($tags['bar']->id, $tagspropery);
 276          $this->assertEquals(
 277                  (object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
 278                  $tagspropery[$tags['foo']->id]->to_object()
 279          );
 280          $this->assertEquals(
 281                  (object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
 282                  $tagspropery[$tags['bar']->id]->to_object()
 283          );
 284      }
 285  
 286      public function test_set_tags_by_id_twice() {
 287          $this->resetAfterTest();
 288          $this->setAdminUser();
 289  
 290          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
 291  
 292          // Set tags for the first time.
 293          $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
 294          // Now set the tags again.
 295          $randomslot->set_tags_by_id([$tags['baz']->id]);
 296  
 297          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 298          $rcp = $rc->getProperty('tags');
 299          $rcp->setAccessible(true);
 300          $tagspropery = $rcp->getValue($randomslot);
 301  
 302          // The set_tags_by_id function only retrieves id and name fields of the tag object.
 303          $this->assertCount(1, $tagspropery);
 304          $this->assertArrayHasKey($tags['baz']->id, $tagspropery);
 305          $this->assertEquals(
 306                  (object)['id' => $tags['baz']->id, 'name' => $tags['baz']->name],
 307                  $tagspropery[$tags['baz']->id]->to_object()
 308          );
 309      }
 310  
 311      public function test_set_tags_by_id_duplicates() {
 312          $this->resetAfterTest();
 313          $this->setAdminUser();
 314  
 315          list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
 316  
 317          $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id], $tags['foo']->id);
 318  
 319          $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
 320          $rcp = $rc->getProperty('tags');
 321          $rcp->setAccessible(true);
 322          $tagspropery = $rcp->getValue($randomslot);
 323  
 324          // The set_tags_by_id function only retrieves id and name fields of the tag object.
 325          $this->assertCount(2, $tagspropery);
 326          $this->assertArrayHasKey($tags['foo']->id, $tagspropery);
 327          $this->assertArrayHasKey($tags['bar']->id, $tagspropery);
 328          $this->assertEquals(
 329                  (object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
 330                  $tagspropery[$tags['foo']->id]->to_object()
 331          );
 332          $this->assertEquals(
 333                  (object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
 334                  $tagspropery[$tags['bar']->id]->to_object()
 335          );
 336      }
 337  
 338      public function test_insert() {
 339          global $SITE, $DB;
 340  
 341          $this->resetAfterTest();
 342          $this->setAdminUser();
 343  
 344          // Create a quiz.
 345          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 346          $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
 347  
 348          // Create a question category in the system context.
 349          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 350          $category = $questiongenerator->create_question_category();
 351  
 352          // Create a random question without adding it to a quiz.
 353          $form = new stdClass();
 354          $form->category = $category->id . ',' . $category->contextid;
 355          $form->includesubcategories = true;
 356          $form->fromtags = [];
 357          $form->defaultmark = 1;
 358          $form->hidden = 1;
 359          $form->stamp = make_unique_id_code();
 360          $question = new stdClass();
 361          $question->qtype = 'random';
 362          $question = question_bank::get_qtype('random')->save_question($question, $form);
 363  
 364          // Prepare 2 tags.
 365          $tagrecord = array(
 366              'isstandard' => 1,
 367              'flag' => 0,
 368              'rawname' => 'foo',
 369              'description' => 'foo desc'
 370          );
 371          $footag = $this->getDataGenerator()->create_tag($tagrecord);
 372          $tagrecord = array(
 373              'isstandard' => 1,
 374              'flag' => 0,
 375              'rawname' => 'bar',
 376              'description' => 'bar desc'
 377          );
 378          $bartag = $this->getDataGenerator()->create_tag($tagrecord);
 379  
 380          $randomslotdata = new stdClass();
 381          $randomslotdata->quizid = $quiz->id;
 382          $randomslotdata->questionid = $question->id;
 383          $randomslotdata->questioncategoryid = $category->id;
 384          $randomslotdata->includingsubcategories = 1;
 385          $randomslotdata->maxmark = 1;
 386  
 387          // Insert the random question to the quiz.
 388          $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
 389          $randomslot->set_tags([$footag, $bartag]);
 390          $randomslot->insert(1); // Put the question on the first page of the quiz.
 391  
 392          // Get the random question's quiz_slot. It is at the first slot.
 393          $quizslot = $DB->get_record('quiz_slots', array('quizid' => $quiz->id, 'slot' => 1));
 394          // Get the random question's tags from quiz_slot_tags. It is at the first slot.
 395          $quizslottags = $DB->get_records('quiz_slot_tags', array('slotid' => $quizslot->id));
 396  
 397          $this->assertEquals($question->id, $quizslot->questionid);
 398          $this->assertEquals($category->id, $quizslot->questioncategoryid);
 399          $this->assertEquals(1, $quizslot->includingsubcategories);
 400          $this->assertEquals(1, $quizslot->maxmark);
 401  
 402          $this->assertCount(2, $quizslottags);
 403          $this->assertEqualsCanonicalizing(
 404                  [
 405                      ['tagid' => $footag->id, 'tagname' => $footag->name],
 406                      ['tagid' => $bartag->id, 'tagname' => $bartag->name]
 407                  ],
 408                  array_map(function($slottag) {
 409                      return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];
 410                  }, $quizslottags));
 411      }
 412  }