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 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  use mod_quiz\quiz_attempt;
  17  use mod_quiz\quiz_settings;
  18  
  19  /**
  20   * Helper trait for quiz question unit tests.
  21   *
  22   * This trait helps to execute different tests for quiz, for example if it needs to create a quiz, add question
  23   * to the question, add random quetion to the quiz, do a backup or restore.
  24   *
  25   * @package    mod_quiz
  26   * @category   test
  27   * @copyright  2021 Catalyst IT Australia Pty Ltd
  28   * @author     Safat Shahin <safatshahin@catalyst-au.net>
  29   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   */
  31  trait quiz_question_helper_test_trait {
  32  
  33      /** @var \stdClass $course Test course to contain quiz. */
  34      protected $course;
  35  
  36      /** @var \stdClass $quiz A test quiz. */
  37      protected $quiz;
  38  
  39      /** @var \stdClass $user A test logged-in user. */
  40      protected $user;
  41  
  42      /**
  43       * Create a test quiz for the specified course.
  44       *
  45       * @param \stdClass $course
  46       * @return  \stdClass
  47       */
  48      protected function create_test_quiz(\stdClass $course): \stdClass {
  49  
  50          /** @var mod_quiz_generator $quizgenerator */
  51          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
  52  
  53          return $quizgenerator->create_instance([
  54              'course' => $course->id,
  55              'questionsperpage' => 0,
  56              'grade' => 100.0,
  57              'sumgrades' => 2,
  58          ]);
  59      }
  60  
  61      /**
  62       * Helper method to add regular questions in quiz.
  63       *
  64       * @param component_generator_base $questiongenerator
  65       * @param \stdClass $quiz
  66       * @param array $override
  67       */
  68      protected function add_two_regular_questions($questiongenerator, \stdClass $quiz, $override = null): void {
  69          // Create a couple of questions.
  70          $cat = $questiongenerator->create_question_category($override);
  71  
  72          $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
  73          // Create another version.
  74          $questiongenerator->update_question($saq);
  75          quiz_add_quiz_question($saq->id, $quiz);
  76          $numq = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
  77          // Create two version.
  78          $questiongenerator->update_question($numq);
  79          $questiongenerator->update_question($numq);
  80          quiz_add_quiz_question($numq->id, $quiz);
  81      }
  82  
  83      /**
  84       * Helper method to add random question to quiz.
  85       *
  86       * @param component_generator_base $questiongenerator
  87       * @param \stdClass $quiz
  88       * @param array $override
  89       */
  90      protected function add_one_random_question($questiongenerator, \stdClass $quiz, $override = []): void {
  91          // Create a random question.
  92          $cat = $questiongenerator->create_question_category($override);
  93          $questiongenerator->create_question('truefalse', null, ['category' => $cat->id]);
  94          $questiongenerator->create_question('essay', null, ['category' => $cat->id]);
  95          $this->add_random_questions($quiz->id, 0, $cat->id, 1);
  96      }
  97  
  98      /**
  99       * Attempt questions for a quiz and user.
 100       *
 101       * @param \stdClass $quiz Quiz to attempt.
 102       * @param \stdClass $user A user to attempt the quiz.
 103       * @param int $attemptnumber
 104       * @return array
 105       */
 106      protected function attempt_quiz(\stdClass $quiz, \stdClass $user, $attemptnumber = 1): array {
 107          $this->setUser($user);
 108  
 109          $starttime = time();
 110          $quizobj = quiz_settings::create($quiz->id, $user->id);
 111  
 112          $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
 113          $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
 114  
 115          // Start the attempt.
 116          $attempt = quiz_create_attempt($quizobj, $attemptnumber, null, $starttime, false, $user->id);
 117          quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $starttime);
 118          quiz_attempt_save_started($quizobj, $quba, $attempt);
 119  
 120          // Finish the attempt.
 121          $attemptobj = quiz_attempt::create($attempt->id);
 122          $attemptobj->process_finish($starttime, false);
 123  
 124          $this->setUser();
 125          return [$quizobj, $quba, $attemptobj];
 126      }
 127  
 128      /**
 129       * A helper method to backup test quiz.
 130       *
 131       * @param \stdClass $quiz Quiz to attempt.
 132       * @param \stdClass $user A user to attempt the quiz.
 133       * @return string A backup ID ready to be restored.
 134       */
 135      protected function backup_quiz(\stdClass $quiz, \stdClass $user): string {
 136          global $CFG;
 137  
 138          // Get the necessary files to perform backup and restore.
 139          require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
 140          require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
 141  
 142          $backupid = 'test-question-backup-restore';
 143  
 144          $bc = new backup_controller(backup::TYPE_1ACTIVITY, $quiz->cmid, backup::FORMAT_MOODLE,
 145              backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user->id);
 146          $bc->execute_plan();
 147  
 148          $results = $bc->get_results();
 149          $file = $results['backup_destination'];
 150          $fp = get_file_packer('application/vnd.moodle.backup');
 151          $filepath = $CFG->dataroot . '/temp/backup/' . $backupid;
 152          $file->extract_to_pathname($fp, $filepath);
 153          $bc->destroy();
 154  
 155          return $backupid;
 156      }
 157  
 158      /**
 159       * A helper method to restore provided backup.
 160       *
 161       * @param string $backupid Backup ID to restore.
 162       * @param stdClass $course
 163       * @param stdClass $user
 164       */
 165      protected function restore_quiz(string $backupid, stdClass $course, stdClass $user): void {
 166          $rc = new restore_controller($backupid, $course->id,
 167              backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user->id, backup::TARGET_CURRENT_ADDING);
 168          $this->assertTrue($rc->execute_precheck());
 169          $rc->execute_plan();
 170          $rc->destroy();
 171      }
 172  
 173      /**
 174       * A helper method to emulate duplication of the quiz.
 175       *
 176       * @param stdClass $course
 177       * @param stdClass $quiz
 178       * @return \cm_info|null
 179       */
 180      protected function duplicate_quiz($course, $quiz): ?\cm_info {
 181          return duplicate_module($course, get_fast_modinfo($course)->get_cm($quiz->cmid));
 182      }
 183  
 184      /**
 185       * Add random questions to a quiz, with a filter condition based on a category ID.
 186       *
 187       * @param int $quizid The quiz to add the questions to.
 188       * @param int $page The page number to add the questions to.
 189       * @param int $categoryid The category ID to use for the filter condition.
 190       * @param int $number The number of questions to add.
 191       * @return void
 192       */
 193      protected function add_random_questions(int $quizid, int $page, int $categoryid, int $number): void {
 194          $settings = quiz_settings::create($quizid);
 195          $structure = \mod_quiz\structure::create_for_quiz($settings);
 196          $filtercondition = [
 197              'filter' => [
 198                  'category' => [
 199                      'jointype' => \qbank_managecategories\category_condition::JOINTYPE_DEFAULT,
 200                      'values' => [$categoryid],
 201                      'filteroptions' => ['includesubcategories' => false],
 202                  ],
 203              ],
 204          ];
 205          $structure->add_random_questions($page, $number, $filtercondition);
 206      }
 207  }