See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [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 /** 18 * A test helper trait. 19 * 20 * @package quizaccess_seb 21 * @author Andrew Madden <andrewmadden@catalyst-au.net> 22 * @copyright 2019 Catalyst IT 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 use quizaccess_seb\access_manager; 27 use quizaccess_seb\settings_provider; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once($CFG->dirroot . "/mod/quiz/accessrule/seb/rule.php"); // Include plugin rule class. 33 require_once($CFG->dirroot . "/mod/quiz/mod_form.php"); // Include plugin rule class. 34 35 /** 36 * A test helper trait. It has some common helper methods. 37 * 38 * @copyright 2020 Catalyst IT 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 trait quizaccess_seb_test_helper_trait { 42 43 /** @var \stdClass $course Test course to contain quiz. */ 44 protected $course; 45 46 /** @var \stdClass $quiz A test quiz. */ 47 protected $quiz; 48 49 /** @var \stdClass $user A test logged-in user. */ 50 protected $user; 51 52 /** 53 * Assign a capability to $USER 54 * The function creates a student $USER if $USER->id is empty 55 * 56 * @param string $capability Capability name. 57 * @param int $contextid Context ID. 58 * @param int $roleid Role ID. 59 * @return int The role id - mainly returned for creation, so calling function can reuse it. 60 */ 61 protected function assign_user_capability($capability, $contextid, $roleid = null) { 62 global $USER; 63 64 // Create a new student $USER if $USER doesn't exist. 65 if (empty($USER->id)) { 66 $user = $this->getDataGenerator()->create_user(); 67 $this->setUser($user); 68 } 69 70 if (empty($roleid)) { 71 $roleid = \create_role('Dummy role', 'dummyrole', 'dummy role description'); 72 } 73 74 \assign_capability($capability, CAP_ALLOW, $roleid, $contextid); 75 76 \role_assign($roleid, $USER->id, $contextid); 77 78 \accesslib_clear_all_caches_for_unit_testing(); 79 80 return $roleid; 81 } 82 83 /** 84 * Strip the seb_ prefix from each setting key. 85 * 86 * @param \stdClass $settings Object containing settings. 87 * @return \stdClass The modified settings object. 88 */ 89 protected function strip_all_prefixes(\stdClass $settings) : \stdClass { 90 $newsettings = new \stdClass(); 91 foreach ($settings as $name => $setting) { 92 $newname = preg_replace("/^seb_/", "", $name); 93 $newsettings->$newname = $setting; // Add new key. 94 } 95 return $newsettings; 96 } 97 98 /** 99 * Creates a file in the user draft area. 100 * 101 * @param string $xml 102 * @return int The user draftarea id 103 */ 104 protected function create_test_draftarea_file(string $xml) : int { 105 global $USER; 106 107 $itemid = 0; 108 $usercontext = \context_user::instance($USER->id); 109 $filerecord = [ 110 'contextid' => \context_user::instance($USER->id)->id, 111 'component' => 'user', 112 'filearea' => 'draft', 113 'itemid' => $itemid, 114 'filepath' => '/', 115 'filename' => 'test.xml' 116 ]; 117 118 $fs = get_file_storage(); 119 $fs->create_file_from_string($filerecord, $xml); 120 121 $draftitemid = 0; 122 file_prepare_draft_area($draftitemid, $usercontext->id, 'user', 'draft', 0); 123 124 return $draftitemid; 125 } 126 127 /** 128 * Create a file in a modules filearea. 129 * 130 * @param string $xml XML content of the file. 131 * @param string $cmid Course module id. 132 * @return int Item ID of file. 133 */ 134 protected function create_module_test_file(string $xml, string $cmid) : int { 135 $itemid = 0; 136 $fs = get_file_storage(); 137 $filerecord = [ 138 'contextid' => \context_module::instance($cmid)->id, 139 'component' => 'quizaccess_seb', 140 'filearea' => 'filemanager_sebconfigfile', 141 'itemid' => $itemid, 142 'filepath' => '/', 143 'filename' => 'test.xml' 144 ]; 145 $fs->create_file_from_string($filerecord, $xml); 146 return $itemid; 147 } 148 149 /** 150 * Create a test quiz for the specified course. 151 * 152 * @param \stdClass $course 153 * @param int $requiresafeexambrowser How to use SEB for this quiz? 154 * @return array 155 */ 156 protected function create_test_quiz($course, $requiresafeexambrowser = settings_provider::USE_SEB_NO) { 157 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 158 159 $quiz = $quizgenerator->create_instance([ 160 'course' => $course->id, 161 'questionsperpage' => 0, 162 'grade' => 100.0, 163 'sumgrades' => 2, 164 'seb_requiresafeexambrowser' => $requiresafeexambrowser, 165 ]); 166 $quiz->seb_showsebdownloadlink = 1; 167 $quiz->coursemodule = $quiz->cmid; 168 169 // Create a couple of questions. 170 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 171 $cat = $questiongenerator->create_question_category(); 172 173 $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id)); 174 quiz_add_quiz_question($saq->id, $quiz); 175 $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id)); 176 quiz_add_quiz_question($numq->id, $quiz); 177 178 return $quiz; 179 } 180 181 /** 182 * Answer questions for a quiz + user. 183 * 184 * @param \stdClass $quiz Quiz to attempt. 185 * @param \stdClass $user A user to attempt the quiz. 186 * @return array 187 */ 188 protected function attempt_quiz($quiz, $user) { 189 $this->setUser($user); 190 191 $starttime = time(); 192 $quizobj = \quiz::create($quiz->id, $user->id); 193 194 $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); 195 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); 196 197 // Start the attempt. 198 $attempt = quiz_create_attempt($quizobj, 1, false, $starttime, false, $user->id); 199 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $starttime); 200 quiz_attempt_save_started($quizobj, $quba, $attempt); 201 202 // Answer the questions. 203 $attemptobj = \quiz_attempt::create($attempt->id); 204 205 $tosubmit = [ 206 1 => ['answer' => 'frog'], 207 2 => ['answer' => '3.14'], 208 ]; 209 210 $attemptobj->process_submitted_actions($starttime, false, $tosubmit); 211 212 // Finish the attempt. 213 $attemptobj = \quiz_attempt::create($attempt->id); 214 $attemptobj->process_finish($starttime, false); 215 216 $this->setUser(); 217 218 return [$quizobj, $quba, $attemptobj]; 219 } 220 221 /** 222 * Create test template. 223 * 224 * @param string|null $xml Template content. 225 * @return \quizaccess_seb\template Just created template. 226 */ 227 public function create_template(string $xml = null) { 228 $data = []; 229 230 if (!is_null($xml)) { 231 $data['content'] = $xml; 232 } 233 234 return $this->getDataGenerator()->get_plugin_generator('quizaccess_seb')->create_template($data); 235 } 236 237 /** 238 * Get access manager for testing. 239 * 240 * @return \quizaccess_seb\access_manager 241 */ 242 protected function get_access_manager() { 243 return new access_manager(new \quiz($this->quiz, 244 get_coursemodule_from_id('quiz', $this->quiz->cmid), $this->course)); 245 } 246 247 /** 248 * A helper method to make the rule form the currently created quiz and course. 249 * 250 * @return \quiz_access_rule_base|null 251 */ 252 protected function make_rule() { 253 return \quizaccess_seb::make( 254 new \quiz($this->quiz, get_coursemodule_from_id('quiz', $this->quiz->cmid), $this->course), 255 0, 256 true 257 ); 258 } 259 260 /** 261 * A helper method to set up quiz view page. 262 */ 263 protected function set_up_quiz_view_page() { 264 global $PAGE; 265 266 $page = new \moodle_page(); 267 $page->set_context(\context_module::instance($this->quiz->cmid)); 268 $page->set_course($this->course); 269 $page->set_pagelayout('standard'); 270 $page->set_pagetype("mod-quiz-view"); 271 $page->set_url('/mod/quiz/view.php?id=' . $this->quiz->cmid); 272 273 $PAGE = $page; 274 } 275 276 /** 277 * Get a test object containing mock test settings. 278 * 279 * @return \stdClass Settings. 280 */ 281 protected function get_test_settings(array $settings = []) : \stdClass { 282 return (object) array_merge([ 283 'quizid' => 1, 284 'cmid' => 1, 285 'requiresafeexambrowser' => '1', 286 'showsebtaskbar' => '1', 287 'showwificontrol' => '0', 288 'showreloadbutton' => '1', 289 'showtime' => '0', 290 'showkeyboardlayout' => '1', 291 'allowuserquitseb' => '1', 292 'quitpassword' => 'test', 293 'linkquitseb' => '', 294 'userconfirmquit' => '1', 295 'enableaudiocontrol' => '1', 296 'muteonstartup' => '0', 297 'allowspellchecking' => '0', 298 'allowreloadinexam' => '1', 299 'activateurlfiltering' => '1', 300 'filterembeddedcontent' => '0', 301 'expressionsallowed' => 'test.com', 302 'regexallowed' => '', 303 'expressionsblocked' => '', 304 'regexblocked' => '', 305 'showsebdownloadlink' => '1', 306 ], $settings); 307 } 308 309 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body