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 401 and 402] [Versions 401 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  use core_question\local\bank\question_version_status;
  20  use mod_quiz\external\submit_question_version;
  21  use mod_quiz\question\bank\qbank_helper;
  22  
  23  defined('MOODLE_INTERNAL') || die();
  24  
  25  require_once (__DIR__ . '/quiz_question_helper_test_trait.php');
  26  
  27  /**
  28   * Qbank helper test for quiz.
  29   *
  30   * @package    mod_quiz
  31   * @category   test
  32   * @copyright  2021 Catalyst IT Australia Pty Ltd
  33   * @author     Safat Shahin <safatshahin@catalyst-au.net>
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   * @coversDefaultClass \mod_quiz\question\bank\qbank_helper
  36   */
  37  class qbank_helper_test extends \advanced_testcase {
  38      use \quiz_question_helper_test_trait;
  39  
  40      /**
  41       * @var \stdClass test student user.
  42       */
  43      protected $student;
  44  
  45      /**
  46       * Called before every test.
  47       */
  48      public function setUp(): void {
  49          global $USER;
  50          parent::setUp();
  51          $this->setAdminUser();
  52          $this->course = $this->getDataGenerator()->create_course();
  53          $this->student = $this->getDataGenerator()->create_user();
  54          $this->user = $USER;
  55      }
  56  
  57      /**
  58       * Test reference records.
  59       *
  60       * @covers ::get_version_options
  61       */
  62      public function test_reference_records() {
  63          $this->resetAfterTest();
  64  
  65          $quiz = $this->create_test_quiz($this->course);
  66          // Test for questions from a different context.
  67          $context = \context_module::instance($quiz->cmid);
  68  
  69          // Create a couple of questions.
  70          /** @var \core_question_generator $questiongenerator */
  71          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
  72          $cat = $questiongenerator->create_question_category(['contextid' => $context->id]);
  73          $numq = $questiongenerator->create_question('essay', null,
  74              ['category' => $cat->id, 'name' => 'This is the first version']);
  75  
  76          // Create two version.
  77          $questiongenerator->update_question($numq, null, ['name' => 'This is the second version']);
  78          $questiongenerator->update_question($numq, null, ['name' => 'This is the third version']);
  79          quiz_add_quiz_question($numq->id, $quiz);
  80  
  81          // Create the quiz object.
  82          $quizobj = \quiz::create($quiz->id);
  83          $quizobj->preload_questions();
  84          $quizobj->load_questions();
  85          $questions = $quizobj->get_questions();
  86          $question = reset($questions);
  87          $structure = structure::create_for_quiz($quizobj);
  88          $slots = $structure->get_slots();
  89          $slot = reset($slots);
  90          $this->assertEquals(3, count(qbank_helper::get_version_options($question->id)));
  91          $this->assertEquals($question->id, qbank_helper::choose_question_for_redo(
  92                  $quiz->id, $context, $slot->id, new \qubaid_list([])));
  93  
  94          // Create another version.
  95          $questiongenerator->update_question($numq, null, ['name' => 'This is the latest version']);
  96  
  97          // Change to always latest.
  98          submit_question_version::execute($slot->id, 0);
  99          $quizobj->preload_questions();
 100          $quizobj->load_questions();
 101          $questions = $quizobj->get_questions();
 102          $question = reset($questions);
 103          $this->assertEquals($question->id, qbank_helper::choose_question_for_redo(
 104                  $quiz->id, $context, $slot->id, new \qubaid_list([])));
 105      }
 106  
 107      /**
 108       * Test question structure data.
 109       *
 110       * @covers ::get_question_structure
 111       * @covers ::get_always_latest_version_question_ids
 112       */
 113      public function test_get_question_structure() {
 114          $this->resetAfterTest();
 115  
 116          // Create a quiz.
 117          $quiz = $this->create_test_quiz($this->course);
 118          $quizcontext = \context_module::instance(get_coursemodule_from_instance("quiz", $quiz->id, $this->course->id)->id);
 119  
 120          // Create a question in the quiz question bank.
 121          /** @var \core_question_generator $questiongenerator */
 122          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 123          $cat = $questiongenerator->create_question_category(['contextid' => $quizcontext->id]);
 124          $q = $questiongenerator->create_question('essay', null,
 125              ['category' => $cat->id, 'name' => 'This is the first version']);
 126  
 127          // Edit it to create a second and third version.
 128          $questiongenerator->update_question($q, null, ['name' => 'This is the second version']);
 129          $finalq = $questiongenerator->update_question($q, null, ['name' => 'This is the third version']);
 130  
 131          // Add the question to the quiz.
 132          quiz_add_quiz_question($q->id, $quiz);
 133  
 134          // Load the quiz object and check.
 135          $quizobj = \quiz::create($quiz->id);
 136          $quizobj->preload_questions();
 137          $quizobj->load_questions();
 138          $questions = $quizobj->get_questions();
 139          $question = reset($questions);
 140          $this->assertEquals($finalq->id, $question->id);
 141  
 142          $structure = structure::create_for_quiz($quizobj);
 143          $slots = $structure->get_slots();
 144          $slot = reset($slots);
 145          $this->assertEquals($finalq->id, $slot->questionid);
 146      }
 147  
 148      /**
 149       * When a question only has draft versions, we should get those and not a dummy question.
 150       *
 151       * @return void
 152       * @covers ::get_question_structure
 153       */
 154      public function test_get_question_structure_with_drafts(): void {
 155          $this->resetAfterTest();
 156  
 157          // Create a quiz.
 158          $quiz = $this->create_test_quiz($this->course);
 159          $quizcontext = \context_module::instance(get_coursemodule_from_instance("quiz", $quiz->id, $this->course->id)->id);
 160  
 161          // Create some questions with drafts in the quiz question bank.
 162          /** @var \core_question_generator $questiongenerator */
 163          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 164          $cat = $questiongenerator->create_question_category(['contextid' => $quizcontext->id]);
 165          $q1 = $questiongenerator->create_question('essay', null,
 166                  ['category' => $cat->id, 'name' => 'This is q1 the first version']);
 167          $q2 = $questiongenerator->create_question('essay', null,
 168                  ['category' => $cat->id, 'name' => 'This is q2 the first version',
 169                          'status' => question_version_status::QUESTION_STATUS_DRAFT]);
 170          $q3 = $questiongenerator->create_question('essay', null,
 171                  ['category' => $cat->id, 'name' => 'This is q3 the first version',
 172                          'status' => question_version_status::QUESTION_STATUS_DRAFT]);
 173  
 174          // Create a new draft version of a question.
 175          $q1final = $questiongenerator->update_question(clone $q1, null,
 176                  ['name' => 'This is q1 the second version', 'status' => question_version_status::QUESTION_STATUS_DRAFT]);
 177          $q3final = $questiongenerator->update_question(clone $q3, null,
 178                  ['name' => 'This is q3 the second version', 'status' => question_version_status::QUESTION_STATUS_DRAFT]);
 179  
 180          // Add the questions to the quiz.
 181          quiz_add_quiz_question($q1->id, $quiz);
 182          quiz_add_quiz_question($q2->id, $quiz);
 183          quiz_add_quiz_question($q3->id, $quiz);
 184  
 185          // Load the quiz object and check.
 186          $quizobj = \quiz::create($quiz->id);
 187          $quizobj->preload_questions();
 188          $quizobj->load_questions();
 189          $questions = $quizobj->get_questions();
 190          $this->assertCount(3, $questions);
 191          // When a question has a Ready version, we should get that and not he draft.
 192          $this->assertTrue(array_key_exists($q1->id, $questions));
 193          $this->assertFalse(array_key_exists($q1final->id, $questions));
 194          $this->assertEquals(question_version_status::QUESTION_STATUS_READY, $questions[$q1->id]->status);
 195          $this->assertEquals('essay', $questions[$q1->id]->qtype);
 196          // When a question only has a draft, we should get that.
 197          $this->assertTrue(array_key_exists($q2->id, $questions));
 198          $this->assertEquals(question_version_status::QUESTION_STATUS_DRAFT, $questions[$q2->id]->status);
 199          $this->assertEquals('essay', $questions[$q2->id]->qtype);
 200          // When a question has several versions but all draft, we should get the latest draft.
 201          $this->assertFalse(array_key_exists($q3->id, $questions));
 202          $this->assertTrue(array_key_exists($q3final->id, $questions));
 203          $this->assertEquals(question_version_status::QUESTION_STATUS_DRAFT, $questions[$q3final->id]->status);
 204          $this->assertEquals('essay', $questions[$q3final->id]->qtype);
 205      }
 206  }