Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

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

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