See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 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 namespace mod_quiz; 18 19 use core_question\local\bank\question_version_status; 20 use question_engine; 21 use quiz; 22 use quiz_attempt; 23 24 defined('MOODLE_INTERNAL') || die(); 25 26 global $CFG; 27 require_once($CFG->dirroot . '/mod/quiz/locallib.php'); 28 29 /** 30 * Tests for the quiz_attempt class. 31 * 32 * @package mod_quiz 33 * @category test 34 * @copyright 2014 Tim Hunt 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class attempt_test extends \advanced_testcase { 38 39 /** 40 * Create quiz and attempt data with layout. 41 * 42 * @param string $layout layout to set. Like quiz attempt.layout. E.g. '1,2,0,3,4,0,'. 43 * @param string $navmethod quiz navigation method (defaults to free) 44 * @return quiz_attempt the new quiz_attempt object 45 */ 46 protected function create_quiz_and_attempt_with_layout($layout, $navmethod = QUIZ_NAVMETHOD_FREE) { 47 $this->resetAfterTest(true); 48 49 // Make a user to do the quiz. 50 $user = $this->getDataGenerator()->create_user(); 51 $course = $this->getDataGenerator()->create_course(); 52 // Make a quiz. 53 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 54 $quiz = $quizgenerator->create_instance(['course' => $course->id, 55 'grade' => 100.0, 'sumgrades' => 2, 'layout' => $layout, 'navmethod' => $navmethod]); 56 57 $quizobj = quiz::create($quiz->id, $user->id); 58 59 60 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); 61 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); 62 63 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 64 $cat = $questiongenerator->create_question_category(); 65 66 $page = 1; 67 foreach (explode(',', $layout) as $slot) { 68 if ($slot == 0) { 69 $page += 1; 70 continue; 71 } 72 73 $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); 74 quiz_add_quiz_question($question->id, $quiz, $page); 75 } 76 77 $timenow = time(); 78 $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $user->id); 79 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow); 80 quiz_attempt_save_started($quizobj, $quba, $attempt); 81 82 return quiz_attempt::create($attempt->id); 83 } 84 85 public function test_attempt_url() { 86 $attempt = $this->create_quiz_and_attempt_with_layout('1,2,0,3,4,0,5,6,0'); 87 88 $attemptid = $attempt->get_attempt()->id; 89 $cmid = $attempt->get_cmid(); 90 $url = '/mod/quiz/attempt.php'; 91 $params = ['attempt' => $attemptid, 'cmid' => $cmid, 'page' => 2]; 92 93 $this->assertEquals(new \moodle_url($url, $params), $attempt->attempt_url(null, 2)); 94 95 $params['page'] = 1; 96 $this->assertEquals(new \moodle_url($url, $params), $attempt->attempt_url(3)); 97 98 $questionattempt = $attempt->get_question_attempt(4); 99 $expecteanchor = $questionattempt->get_outer_question_div_unique_id(); 100 $this->assertEquals(new \moodle_url($url, $params, $expecteanchor), $attempt->attempt_url(4)); 101 102 $questionattempt = $attempt->get_question_attempt(3); 103 $expecteanchor = '#' . $questionattempt->get_outer_question_div_unique_id(); 104 $this->assertEquals(new \moodle_url('#'), $attempt->attempt_url(null, 2, 2)); 105 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->attempt_url(3, -1, 1)); 106 107 $questionattempt = $attempt->get_question_attempt(4); 108 $expecteanchor = $questionattempt->get_outer_question_div_unique_id(); 109 $this->assertEquals(new \moodle_url(null, null, $expecteanchor, null), $attempt->attempt_url(4, -1, 1)); 110 111 // Summary page. 112 $url = '/mod/quiz/summary.php'; 113 unset($params['page']); 114 $this->assertEquals(new \moodle_url($url, $params), $attempt->summary_url()); 115 116 // Review page. 117 $url = '/mod/quiz/review.php'; 118 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url()); 119 120 $params['page'] = 1; 121 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(3, -1, false)); 122 $this->assertEquals(new \moodle_url($url, $params, $expecteanchor), $attempt->review_url(4, -1, false)); 123 124 unset($params['page']); 125 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2, true)); 126 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(1, -1, true)); 127 128 $params['page'] = 2; 129 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2, false)); 130 unset($params['page']); 131 132 $params['showall'] = 0; 133 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 0, false)); 134 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(1, -1, false)); 135 136 $params['page'] = 1; 137 unset($params['showall']); 138 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(3, -1, false)); 139 140 $params['page'] = 2; 141 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2)); 142 $this->assertEquals(new \moodle_url('#'), $attempt->review_url(null, -1, null, 0)); 143 144 $questionattempt = $attempt->get_question_attempt(3); 145 $expecteanchor = '#' . $questionattempt->get_outer_question_div_unique_id(); 146 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->review_url(3, -1, null, 0)); 147 148 $questionattempt = $attempt->get_question_attempt(4); 149 $expecteanchor = '#' . $questionattempt->get_outer_question_div_unique_id(); 150 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->review_url(4, -1, null, 0)); 151 $this->assertEquals(new \moodle_url('#'), $attempt->review_url(null, 2, true, 0)); 152 153 $questionattempt = $attempt->get_question_attempt(1); 154 $expecteanchor = '#' . $questionattempt->get_outer_question_div_unique_id(); 155 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->review_url(1, -1, true, 0)); 156 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->review_url(1, -1, false, 0)); 157 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2, false, 0)); 158 $this->assertEquals(new \moodle_url('#'), $attempt->review_url(null, 0, false, 0)); 159 160 $params['page'] = 1; 161 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(3, -1, false, 0)); 162 163 // Setup another attempt. 164 $attempt = $this->create_quiz_and_attempt_with_layout( 165 '1,2,3,4,5,6,7,8,9,10,0,11,12,13,14,15,16,17,18,19,20,0,' . 166 '21,22,23,24,25,26,27,28,29,30,0,31,32,33,34,35,36,37,38,39,40,0,' . 167 '41,42,43,44,45,46,47,48,49,50,0,51,52,53,54,55,56,57,58,59,60,0'); 168 169 $attemptid = $attempt->get_attempt()->id; 170 $cmid = $attempt->get_cmid(); 171 $params = ['attempt' => $attemptid, 'cmid' => $cmid]; 172 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url()); 173 174 $params['page'] = 2; 175 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2)); 176 177 $params['page'] = 1; 178 unset($params['showall']); 179 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(11, -1, false)); 180 181 $questionattempt = $attempt->get_question_attempt(12); 182 $expecteanchor = $questionattempt->get_outer_question_div_unique_id(); 183 $this->assertEquals(new \moodle_url($url, $params, $expecteanchor), $attempt->review_url(12, -1, false)); 184 185 $params['showall'] = 1; 186 unset($params['page']); 187 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2, true)); 188 189 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(1, -1, true)); 190 $params['page'] = 2; 191 unset($params['showall']); 192 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2, false)); 193 unset($params['page']); 194 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 0, false)); 195 $params['page'] = 1; 196 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(11, -1, false)); 197 $this->assertEquals(new \moodle_url($url, $params, $expecteanchor), $attempt->review_url(12, -1, false)); 198 $params['page'] = 2; 199 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2)); 200 $this->assertEquals(new \moodle_url('#'), $attempt->review_url(null, -1, null, 0)); 201 202 $questionattempt = $attempt->get_question_attempt(3); 203 $expecteanchor = $questionattempt->get_outer_question_div_unique_id(); 204 $this->assertEquals(new \moodle_url(null, null, $expecteanchor), $attempt->review_url(3, -1, null, 0)); 205 206 $questionattempt = $attempt->get_question_attempt(4); 207 $expecteanchor = $questionattempt->get_outer_question_div_unique_id(); 208 $this->assertEquals(new \moodle_url(null, null, $expecteanchor), $attempt->review_url(4, -1, null, 0)); 209 210 $questionattempt = $attempt->get_question_attempt(1); 211 $expecteanchor = '#' . $questionattempt->get_outer_question_div_unique_id(); 212 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->review_url(1, -1, true, 0)); 213 $this->assertEquals(new \moodle_url('#'), $attempt->review_url(null, 2, true, 0)); 214 215 $params['page'] = 2; 216 $questionattempt = $attempt->get_question_attempt(1); 217 $expecteanchor = '#' . $questionattempt->get_outer_question_div_unique_id(); 218 $this->assertEquals(new \moodle_url($expecteanchor), $attempt->review_url(1, -1, false, 0)); 219 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(null, 2, false, 0)); 220 $this->assertEquals(new \moodle_url('#'), $attempt->review_url(null, 0, false, 0)); 221 222 $params['page'] = 1; 223 $this->assertEquals(new \moodle_url($url, $params), $attempt->review_url(11, -1, false, 0)); 224 } 225 226 /** 227 * Tests attempt page titles when all questions are on a single page. 228 */ 229 public function test_attempt_titles_single() { 230 $attempt = $this->create_quiz_and_attempt_with_layout('1,2,0'); 231 232 // Attempt page. 233 $this->assertEquals('Quiz 1', $attempt->attempt_page_title(0)); 234 235 // Summary page. 236 $this->assertEquals('Quiz 1: Attempt summary', $attempt->summary_page_title()); 237 238 // Review page. 239 $this->assertEquals('Quiz 1: Attempt review', $attempt->review_page_title(0)); 240 } 241 242 /** 243 * Tests attempt page titles when questions are on multiple pages, but are reviewed on a single page. 244 */ 245 public function test_attempt_titles_multiple_single() { 246 $attempt = $this->create_quiz_and_attempt_with_layout('1,2,0,3,4,0,5,6,0'); 247 248 // Attempt page. 249 $this->assertEquals('Quiz 1 (page 1 of 3)', $attempt->attempt_page_title(0)); 250 $this->assertEquals('Quiz 1 (page 2 of 3)', $attempt->attempt_page_title(1)); 251 $this->assertEquals('Quiz 1 (page 3 of 3)', $attempt->attempt_page_title(2)); 252 253 // Summary page. 254 $this->assertEquals('Quiz 1: Attempt summary', $attempt->summary_page_title()); 255 256 // Review page. 257 $this->assertEquals('Quiz 1: Attempt review', $attempt->review_page_title(0, true)); 258 } 259 260 /** 261 * Tests attempt page titles when questions are on multiple pages, and they are reviewed on multiple pages as well. 262 */ 263 public function test_attempt_titles_multiple_multiple() { 264 $attempt = $this->create_quiz_and_attempt_with_layout( 265 '1,2,3,4,5,6,7,8,9,10,0,11,12,13,14,15,16,17,18,19,20,0,' . 266 '21,22,23,24,25,26,27,28,29,30,0,31,32,33,34,35,36,37,38,39,40,0,' . 267 '41,42,43,44,45,46,47,48,49,50,0,51,52,53,54,55,56,57,58,59,60,0'); 268 269 // Attempt page. 270 $this->assertEquals('Quiz 1 (page 1 of 6)', $attempt->attempt_page_title(0)); 271 $this->assertEquals('Quiz 1 (page 2 of 6)', $attempt->attempt_page_title(1)); 272 $this->assertEquals('Quiz 1 (page 6 of 6)', $attempt->attempt_page_title(5)); 273 274 // Summary page. 275 $this->assertEquals('Quiz 1: Attempt summary', $attempt->summary_page_title()); 276 277 // Review page. 278 $this->assertEquals('Quiz 1: Attempt review (page 1 of 6)', $attempt->review_page_title(0)); 279 $this->assertEquals('Quiz 1: Attempt review (page 2 of 6)', $attempt->review_page_title(1)); 280 $this->assertEquals('Quiz 1: Attempt review (page 6 of 6)', $attempt->review_page_title(5)); 281 282 // When all questions are shown. 283 $this->assertEquals('Quiz 1: Attempt review', $attempt->review_page_title(0, true)); 284 $this->assertEquals('Quiz 1: Attempt review', $attempt->review_page_title(1, true)); 285 } 286 287 public function test_is_participant() { 288 global $USER; 289 $this->resetAfterTest(); 290 $this->setAdminUser(); 291 $course = $this->getDataGenerator()->create_course(); 292 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 293 $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student', [], 'manual', 0, 0, ENROL_USER_SUSPENDED); 294 $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id)); 295 $quizobj = quiz::create($quiz->id); 296 297 // Login as student. 298 $this->setUser($student); 299 // Convert to a lesson object. 300 $this->assertEquals(true, $quizobj->is_participant($student->id), 301 'Student is enrolled, active and can participate'); 302 303 // Login as student2. 304 $this->setUser($student2); 305 $this->assertEquals(false, $quizobj->is_participant($student2->id), 306 'Student is enrolled, suspended and can NOT participate'); 307 308 // Login as an admin. 309 $this->setAdminUser(); 310 $this->assertEquals(false, $quizobj->is_participant($USER->id), 311 'Admin is not enrolled and can NOT participate'); 312 313 $this->getDataGenerator()->enrol_user(2, $course->id); 314 $this->assertEquals(true, $quizobj->is_participant($USER->id), 315 'Admin is enrolled and can participate'); 316 317 $this->getDataGenerator()->enrol_user(2, $course->id, [], 'manual', 0, 0, ENROL_USER_SUSPENDED); 318 $this->assertEquals(true, $quizobj->is_participant($USER->id), 319 'Admin is enrolled, suspended and can participate'); 320 } 321 322 /** 323 * Test quiz_prepare_and_start_new_attempt function 324 */ 325 public function test_quiz_prepare_and_start_new_attempt() { 326 global $USER; 327 $this->resetAfterTest(); 328 329 // Create course. 330 $course = $this->getDataGenerator()->create_course(); 331 // Create students. 332 $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 333 $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 334 // Create quiz. 335 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 336 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'grade' => 100.0, 'sumgrades' => 2, 'layout' => '1,0']); 337 // Create question and add it to quiz. 338 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 339 $cat = $questiongenerator->create_question_category(); 340 $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); 341 quiz_add_quiz_question($question->id, $quiz, 1); 342 343 $quizobj = quiz::create($quiz->id); 344 345 // Login as student1. 346 $this->setUser($student1); 347 // Create attempt for student1. 348 $attempt = quiz_prepare_and_start_new_attempt($quizobj, 1, null, false, [], []); 349 $this->assertEquals($student1->id, $attempt->userid); 350 $this->assertEquals(0, $attempt->preview); 351 352 // Login as student2. 353 $this->setUser($student2); 354 // Create attempt for student2. 355 $attempt = quiz_prepare_and_start_new_attempt($quizobj, 1, null, false, [], []); 356 $this->assertEquals($student2->id, $attempt->userid); 357 $this->assertEquals(0, $attempt->preview); 358 359 // Login as admin. 360 $this->setAdminUser(); 361 // Create attempt for student1. 362 $attempt = quiz_prepare_and_start_new_attempt($quizobj, 2, null, false, [], [], $student1->id); 363 $this->assertEquals($student1->id, $attempt->userid); 364 $this->assertEquals(0, $attempt->preview); 365 $student1attempt = $attempt; // Save for extra verification below. 366 // Create attempt for student2. 367 $attempt = quiz_prepare_and_start_new_attempt($quizobj, 2, null, false, [], [], $student2->id); 368 $this->assertEquals($student2->id, $attempt->userid); 369 $this->assertEquals(0, $attempt->preview); 370 // Create attempt for user id that the same with current $USER->id. 371 $attempt = quiz_prepare_and_start_new_attempt($quizobj, 2, null, false, [], [], $USER->id); 372 $this->assertEquals($USER->id, $attempt->userid); 373 $this->assertEquals(1, $attempt->preview); 374 375 // Check that the userid stored in the first step is the user the attempt is for, 376 // not the user who triggered the creation. 377 $quba = question_engine::load_questions_usage_by_activity($student1attempt->uniqueid); 378 $step = $quba->get_question_attempt(1)->get_step(0); 379 $this->assertEquals($student1->id, $step->get_user_id()); 380 } 381 382 /** 383 * Test check_page_access function 384 * @covers \quiz_attempt::check_page_access 385 */ 386 public function test_check_page_access() { 387 $timenow = time(); 388 389 // Free navigation. 390 $attempt = $this->create_quiz_and_attempt_with_layout('1,0,2,0,3,0,4,0,5,0', QUIZ_NAVMETHOD_FREE); 391 392 // Check access. 393 $this->assertTrue($attempt->check_page_access(4)); 394 $this->assertTrue($attempt->check_page_access(3)); 395 $this->assertTrue($attempt->check_page_access(2)); 396 $this->assertTrue($attempt->check_page_access(1)); 397 $this->assertTrue($attempt->check_page_access(0)); 398 $this->assertTrue($attempt->check_page_access(2)); 399 400 // Access page 2. 401 $attempt->set_currentpage(2); 402 $attempt = quiz_attempt::create($attempt->get_attempt()->id); 403 404 // Check access. 405 $this->assertTrue($attempt->check_page_access(0)); 406 $this->assertTrue($attempt->check_page_access(1)); 407 $this->assertTrue($attempt->check_page_access(2)); 408 $this->assertTrue($attempt->check_page_access(3)); 409 $this->assertTrue($attempt->check_page_access(4)); 410 411 // Sequential navigation. 412 $attempt = $this->create_quiz_and_attempt_with_layout('1,0,2,0,3,0,4,0,5,0', QUIZ_NAVMETHOD_SEQ); 413 414 // Check access. 415 $this->assertTrue($attempt->check_page_access(0)); 416 $this->assertTrue($attempt->check_page_access(1)); 417 $this->assertFalse($attempt->check_page_access(2)); 418 $this->assertFalse($attempt->check_page_access(3)); 419 $this->assertFalse($attempt->check_page_access(4)); 420 421 // Access page 1. 422 $attempt->set_currentpage(1); 423 $attempt = quiz_attempt::create($attempt->get_attempt()->id); 424 $this->assertTrue($attempt->check_page_access(1)); 425 426 // Access page 2. 427 $attempt->set_currentpage(2); 428 $attempt = quiz_attempt::create($attempt->get_attempt()->id); 429 $this->assertTrue($attempt->check_page_access(2)); 430 431 $this->assertTrue($attempt->check_page_access(3)); 432 $this->assertFalse($attempt->check_page_access(4)); 433 $this->assertFalse($attempt->check_page_access(1)); 434 } 435 436 /** 437 * Starting a new attempt with a question in draft status should throw an exception. 438 * 439 * @covers ::quiz_start_new_attempt() 440 * @return void 441 */ 442 public function test_start_new_attempt_with_draft(): void { 443 $this->resetAfterTest(); 444 445 // Create course. 446 $course = $this->getDataGenerator()->create_course(); 447 // Create students. 448 $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 449 $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 450 // Create quiz. 451 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 452 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'grade' => 100.0, 'sumgrades' => 2, 'layout' => '1,0']); 453 // Create question and add it to quiz. 454 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 455 $cat = $questiongenerator->create_question_category(); 456 $question = $questiongenerator->create_question('shortanswer', null, 457 ['category' => $cat->id, 'status' => question_version_status::QUESTION_STATUS_DRAFT]); 458 quiz_add_quiz_question($question->id, $quiz, 1); 459 460 $quizobj = quiz::create($quiz->id); 461 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); 462 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); 463 $attempt = quiz_create_attempt($quizobj, 1, false, time(), false, $student1->id); 464 465 $this->expectExceptionObject(new \moodle_exception('questiondraftonly', 'mod_quiz', '', $question->name)); 466 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, time()); 467 } 468 469 /** 470 * Starting a new attempt built on last with a question in draft status should throw an exception. 471 * 472 * @covers ::quiz_start_attempt_built_on_last() 473 * @return void 474 */ 475 public function test_quiz_start_attempt_built_on_last_with_draft(): void { 476 global $DB; 477 $this->resetAfterTest(); 478 479 // Create course. 480 $course = $this->getDataGenerator()->create_course(); 481 // Create students. 482 $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 483 $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 484 // Create quiz. 485 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 486 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'grade' => 100.0, 'sumgrades' => 2, 'layout' => '1,0']); 487 // Create question and add it to quiz. 488 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 489 $cat = $questiongenerator->create_question_category(); 490 $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); 491 quiz_add_quiz_question($question->id, $quiz, 1); 492 493 $quizobj = quiz::create($quiz->id); 494 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); 495 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); 496 $attempt = quiz_create_attempt($quizobj, 1, false, time(), false, $student1->id); 497 $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, 1, time()); 498 $attempt = quiz_attempt_save_started($quizobj, $quba, $attempt); 499 500 $DB->set_field('question_versions', 'status', question_version_status::QUESTION_STATUS_DRAFT, 501 ['questionid' => $question->id]); 502 $quizobj = quiz::create($quiz->id); 503 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); 504 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); 505 $newattempt = quiz_create_attempt($quizobj, 2, $attempt, time(), false, $student1->id); 506 507 $this->expectExceptionObject(new \moodle_exception('questiondraftonly', 'mod_quiz', '', $question->name)); 508 quiz_start_attempt_built_on_last($quba, $newattempt, $attempt); 509 } 510 511 /** 512 * Starting a new attempt and check the summary previous attempts table. 513 * 514 * @covers ::view_table() 515 */ 516 public function test_view_table(): void { 517 global $PAGE; 518 $this->resetAfterTest(); 519 520 $timenow = time(); 521 // Create attempt object. 522 $attempt = $this->create_quiz_and_attempt_with_layout('1,1,0'); 523 // Finish attempt. 524 $attempt->process_finish($timenow, false); 525 526 $quiz = $attempt->get_quiz(); 527 $context = $attempt->get_quizobj()->get_context(); 528 529 // Prepare view object. 530 $viewobj = new \mod_quiz_view_object(); 531 $viewobj->attemptcolumn = true; 532 $viewobj->markcolumn = true; 533 $viewobj->gradecolumn = true; 534 $viewobj->canreviewmine = true; 535 $viewobj->mygrade = 0.00; 536 $viewobj->feedbackcolumn = false; 537 $viewobj->attempts = $attempt; 538 $viewobj->attemptobjs[] = new quiz_attempt($attempt->get_attempt(), 539 $quiz, $attempt->get_cm(), $attempt->get_course(), false); 540 $viewobj->accessmanager = new \quiz_access_manager($attempt->get_quizobj(), $timenow, 541 has_capability('mod/quiz:ignoretimelimits', $context, null, false)); 542 543 // Render summary previous attempts table. 544 $renderer = $PAGE->get_renderer('mod_quiz'); 545 $table = $renderer->view_table($quiz, $context, $viewobj); 546 $captionpattern = '/<caption\b[^>]*>' . get_string('summaryofattempts', 'quiz') . '<\/caption>/'; 547 548 // Check caption existed. 549 $this->assertMatchesRegularExpression($captionpattern, $table); 550 // Check column attempt. 551 $this->assertMatchesRegularExpression('/<td\b[^>]*>' . $attempt->get_attempt_number() . '<\/td>/', $table); 552 // Check column state. 553 $this->assertMatchesRegularExpression('/<td\b[^>]*>' . ucfirst($attempt->get_state()) . '.+?<\/td>/', $table); 554 // Check column marks. 555 $this->assertMatchesRegularExpression('/<td\b[^>]* c2.+?' . 556 quiz_format_grade($quiz, $attempt->get_sum_marks()) .'<\/td>/', $table); 557 // Check column grades. 558 $this->assertMatchesRegularExpression('/<td\b[^>]* c2.+?0\.00<\/td>/', $table); 559 // Check column review. 560 $this->assertMatchesRegularExpression('/<td\b[^>]*>.+?Review<\/a><\/td>/', $table); 561 } 562 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body