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 * Unit tests for (some of) mod/quiz/locallib.php. 19 * 20 * @package mod_quiz 21 * @category test 22 * @copyright 2008 Tim Hunt 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 namespace mod_quiz; 26 27 use quiz_attempt; 28 use mod_quiz_display_options; 29 30 defined('MOODLE_INTERNAL') || die(); 31 32 global $CFG; 33 require_once($CFG->dirroot . '/mod/quiz/locallib.php'); 34 35 36 /** 37 * Unit tests for (some of) mod/quiz/locallib.php. 38 * 39 * @copyright 2008 Tim Hunt 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 class locallib_test extends \advanced_testcase { 43 44 public function test_quiz_rescale_grade() { 45 $quiz = new \stdClass(); 46 $quiz->decimalpoints = 2; 47 $quiz->questiondecimalpoints = 3; 48 $quiz->grade = 10; 49 $quiz->sumgrades = 10; 50 $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, false), 0.12345678); 51 $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.12, 2)); 52 $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, 'question'), 53 format_float(0.123, 3)); 54 $quiz->sumgrades = 5; 55 $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, false), 0.24691356); 56 $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.25, 2)); 57 $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, 'question'), 58 format_float(0.247, 3)); 59 } 60 61 public function quiz_attempt_state_data_provider() { 62 return [ 63 [quiz_attempt::IN_PROGRESS, null, null, mod_quiz_display_options::DURING], 64 [quiz_attempt::FINISHED, -90, null, mod_quiz_display_options::IMMEDIATELY_AFTER], 65 [quiz_attempt::FINISHED, -7200, null, mod_quiz_display_options::LATER_WHILE_OPEN], 66 [quiz_attempt::FINISHED, -7200, 3600, mod_quiz_display_options::LATER_WHILE_OPEN], 67 [quiz_attempt::FINISHED, -30, 30, mod_quiz_display_options::IMMEDIATELY_AFTER], 68 [quiz_attempt::FINISHED, -90, -30, mod_quiz_display_options::AFTER_CLOSE], 69 [quiz_attempt::FINISHED, -7200, -3600, mod_quiz_display_options::AFTER_CLOSE], 70 [quiz_attempt::FINISHED, -90, -3600, mod_quiz_display_options::AFTER_CLOSE], 71 [quiz_attempt::ABANDONED, -10000000, null, mod_quiz_display_options::LATER_WHILE_OPEN], 72 [quiz_attempt::ABANDONED, -7200, 3600, mod_quiz_display_options::LATER_WHILE_OPEN], 73 [quiz_attempt::ABANDONED, -7200, -3600, mod_quiz_display_options::AFTER_CLOSE], 74 ]; 75 } 76 77 /** 78 * @dataProvider quiz_attempt_state_data_provider 79 * 80 * @param unknown $attemptstate as in the quiz_attempts.state DB column. 81 * @param unknown $relativetimefinish time relative to now when the attempt finished, or null for 0. 82 * @param unknown $relativetimeclose time relative to now when the quiz closes, or null for 0. 83 * @param unknown $expectedstate expected result. One of the mod_quiz_display_options constants/ 84 */ 85 public function test_quiz_attempt_state($attemptstate, 86 $relativetimefinish, $relativetimeclose, $expectedstate) { 87 88 $attempt = new \stdClass(); 89 $attempt->state = $attemptstate; 90 if ($relativetimefinish === null) { 91 $attempt->timefinish = 0; 92 } else { 93 $attempt->timefinish = time() + $relativetimefinish; 94 } 95 96 $quiz = new \stdClass(); 97 if ($relativetimeclose === null) { 98 $quiz->timeclose = 0; 99 } else { 100 $quiz->timeclose = time() + $relativetimeclose; 101 } 102 103 $this->assertEquals($expectedstate, quiz_attempt_state($quiz, $attempt)); 104 } 105 106 /** 107 * @covers ::quiz_question_tostring 108 */ 109 public function test_quiz_question_tostring() { 110 $question = new \stdClass(); 111 $question->qtype = 'multichoice'; 112 $question->name = 'The question name'; 113 $question->questiontext = '<p>What sort of <b>inequality</b> is x < y<img alt="?" src="..."></p>'; 114 $question->questiontextformat = FORMAT_HTML; 115 116 $summary = quiz_question_tostring($question); 117 $this->assertEquals('<span class="questionname">The question name</span> ' . 118 '<span class="questiontext">What sort of INEQUALITY is x < y[?]' . "\n" . '</span>', $summary); 119 } 120 121 /** 122 * @covers ::quiz_question_tostring 123 */ 124 public function test_quiz_question_tostring_does_not_filter() { 125 $question = new \stdClass(); 126 $question->qtype = 'multichoice'; 127 $question->name = 'The question name'; 128 $question->questiontext = '<p>No emoticons here :-)</p>'; 129 $question->questiontextformat = FORMAT_HTML; 130 131 $summary = quiz_question_tostring($question); 132 $this->assertEquals('<span class="questionname">The question name</span> ' . 133 '<span class="questiontext">No emoticons here :-)' . "\n</span>", $summary); 134 } 135 136 /** 137 * Test quiz_view 138 * @return void 139 */ 140 public function test_quiz_view() { 141 global $CFG; 142 143 $CFG->enablecompletion = 1; 144 $this->resetAfterTest(); 145 146 $this->setAdminUser(); 147 // Setup test data. 148 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 149 $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id), 150 array('completion' => 2, 'completionview' => 1)); 151 $context = \context_module::instance($quiz->cmid); 152 $cm = get_coursemodule_from_instance('quiz', $quiz->id); 153 154 // Trigger and capture the event. 155 $sink = $this->redirectEvents(); 156 157 quiz_view($quiz, $course, $cm, $context); 158 159 $events = $sink->get_events(); 160 // 2 additional events thanks to completion. 161 $this->assertCount(3, $events); 162 $event = array_shift($events); 163 164 // Checking that the event contains the expected values. 165 $this->assertInstanceOf('\mod_quiz\event\course_module_viewed', $event); 166 $this->assertEquals($context, $event->get_context()); 167 $moodleurl = new \moodle_url('/mod/quiz/view.php', array('id' => $cm->id)); 168 $this->assertEquals($moodleurl, $event->get_url()); 169 $this->assertEventContextNotUsed($event); 170 $this->assertNotEmpty($event->get_name()); 171 // Check completion status. 172 $completion = new \completion_info($course); 173 $completiondata = $completion->get_data($cm); 174 $this->assertEquals(1, $completiondata->completionstate); 175 } 176 177 /** 178 * Return false when there are not overrides for this quiz instance. 179 */ 180 public function test_quiz_is_overriden_calendar_event_no_override() { 181 global $CFG, $DB; 182 183 $this->resetAfterTest(); 184 $this->setAdminUser(); 185 186 $generator = $this->getDataGenerator(); 187 $user = $generator->create_user(); 188 $course = $generator->create_course(); 189 $quizgenerator = $generator->get_plugin_generator('mod_quiz'); 190 $quiz = $quizgenerator->create_instance(['course' => $course->id]); 191 192 $event = new \calendar_event((object)[ 193 'modulename' => 'quiz', 194 'instance' => $quiz->id, 195 'userid' => $user->id 196 ]); 197 198 $this->assertFalse(quiz_is_overriden_calendar_event($event)); 199 } 200 201 /** 202 * Return false if the given event isn't an quiz module event. 203 */ 204 public function test_quiz_is_overriden_calendar_event_no_module_event() { 205 global $CFG, $DB; 206 207 $this->resetAfterTest(); 208 $this->setAdminUser(); 209 210 $generator = $this->getDataGenerator(); 211 $user = $generator->create_user(); 212 $course = $generator->create_course(); 213 $quizgenerator = $generator->get_plugin_generator('mod_quiz'); 214 $quiz = $quizgenerator->create_instance(['course' => $course->id]); 215 216 $event = new \calendar_event((object)[ 217 'userid' => $user->id 218 ]); 219 220 $this->assertFalse(quiz_is_overriden_calendar_event($event)); 221 } 222 223 /** 224 * Return false if there is overrides for this use but they belong to another quiz 225 * instance. 226 */ 227 public function test_quiz_is_overriden_calendar_event_different_quiz_instance() { 228 global $CFG, $DB; 229 230 $this->resetAfterTest(); 231 $this->setAdminUser(); 232 233 $generator = $this->getDataGenerator(); 234 $user = $generator->create_user(); 235 $course = $generator->create_course(); 236 $quizgenerator = $generator->get_plugin_generator('mod_quiz'); 237 $quiz = $quizgenerator->create_instance(['course' => $course->id]); 238 $quiz2 = $quizgenerator->create_instance(['course' => $course->id]); 239 240 $event = new \calendar_event((object) [ 241 'modulename' => 'quiz', 242 'instance' => $quiz->id, 243 'userid' => $user->id 244 ]); 245 246 $record = (object) [ 247 'quiz' => $quiz2->id, 248 'userid' => $user->id 249 ]; 250 251 $DB->insert_record('quiz_overrides', $record); 252 253 $this->assertFalse(quiz_is_overriden_calendar_event($event)); 254 } 255 256 /** 257 * Return true if there is a user override for this event and quiz instance. 258 */ 259 public function test_quiz_is_overriden_calendar_event_user_override() { 260 global $CFG, $DB; 261 262 $this->resetAfterTest(); 263 $this->setAdminUser(); 264 265 $generator = $this->getDataGenerator(); 266 $user = $generator->create_user(); 267 $course = $generator->create_course(); 268 $quizgenerator = $generator->get_plugin_generator('mod_quiz'); 269 $quiz = $quizgenerator->create_instance(['course' => $course->id]); 270 271 $event = new \calendar_event((object) [ 272 'modulename' => 'quiz', 273 'instance' => $quiz->id, 274 'userid' => $user->id 275 ]); 276 277 $record = (object) [ 278 'quiz' => $quiz->id, 279 'userid' => $user->id 280 ]; 281 282 $DB->insert_record('quiz_overrides', $record); 283 284 $this->assertTrue(quiz_is_overriden_calendar_event($event)); 285 } 286 287 /** 288 * Return true if there is a group override for the event and quiz instance. 289 */ 290 public function test_quiz_is_overriden_calendar_event_group_override() { 291 global $CFG, $DB; 292 293 $this->resetAfterTest(); 294 $this->setAdminUser(); 295 296 $generator = $this->getDataGenerator(); 297 $user = $generator->create_user(); 298 $course = $generator->create_course(); 299 $quizgenerator = $generator->get_plugin_generator('mod_quiz'); 300 $quiz = $quizgenerator->create_instance(['course' => $course->id]); 301 $group = $this->getDataGenerator()->create_group(array('courseid' => $quiz->course)); 302 $groupid = $group->id; 303 $userid = $user->id; 304 305 $event = new \calendar_event((object) [ 306 'modulename' => 'quiz', 307 'instance' => $quiz->id, 308 'groupid' => $groupid 309 ]); 310 311 $record = (object) [ 312 'quiz' => $quiz->id, 313 'groupid' => $groupid 314 ]; 315 316 $DB->insert_record('quiz_overrides', $record); 317 318 $this->assertTrue(quiz_is_overriden_calendar_event($event)); 319 } 320 321 /** 322 * Test test_quiz_get_user_timeclose(). 323 */ 324 public function test_quiz_get_user_timeclose() { 325 global $DB; 326 327 $this->resetAfterTest(); 328 $this->setAdminUser(); 329 330 $basetimestamp = time(); // The timestamp we will base the enddates on. 331 332 // Create generator, course and quizzes. 333 $student1 = $this->getDataGenerator()->create_user(); 334 $student2 = $this->getDataGenerator()->create_user(); 335 $student3 = $this->getDataGenerator()->create_user(); 336 $teacher = $this->getDataGenerator()->create_user(); 337 $course = $this->getDataGenerator()->create_course(); 338 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 339 340 // Both quizzes close in two hours. 341 $quiz1 = $quizgenerator->create_instance(array('course' => $course->id, 'timeclose' => $basetimestamp + 7200)); 342 $quiz2 = $quizgenerator->create_instance(array('course' => $course->id, 'timeclose' => $basetimestamp + 7200)); 343 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 344 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 345 346 $student1id = $student1->id; 347 $student2id = $student2->id; 348 $student3id = $student3->id; 349 $teacherid = $teacher->id; 350 351 // Users enrolments. 352 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 353 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 354 $this->getDataGenerator()->enrol_user($student1id, $course->id, $studentrole->id, 'manual'); 355 $this->getDataGenerator()->enrol_user($student2id, $course->id, $studentrole->id, 'manual'); 356 $this->getDataGenerator()->enrol_user($student3id, $course->id, $studentrole->id, 'manual'); 357 $this->getDataGenerator()->enrol_user($teacherid, $course->id, $teacherrole->id, 'manual'); 358 359 // Create groups. 360 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 361 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 362 $group1id = $group1->id; 363 $group2id = $group2->id; 364 $this->getDataGenerator()->create_group_member(array('userid' => $student1id, 'groupid' => $group1id)); 365 $this->getDataGenerator()->create_group_member(array('userid' => $student2id, 'groupid' => $group2id)); 366 367 // Group 1 gets an group override for quiz 1 to close in three hours. 368 $record1 = (object) [ 369 'quiz' => $quiz1->id, 370 'groupid' => $group1id, 371 'timeclose' => $basetimestamp + 10800 // In three hours. 372 ]; 373 $DB->insert_record('quiz_overrides', $record1); 374 375 // Let's test quiz 1 closes in three hours for user student 1 since member of group 1. 376 // Quiz 2 closes in two hours. 377 $this->setUser($student1id); 378 $params = new \stdClass(); 379 380 $comparearray = array(); 381 $object = new \stdClass(); 382 $object->id = $quiz1->id; 383 $object->usertimeclose = $basetimestamp + 10800; // The overriden timeclose for quiz 1. 384 385 $comparearray[$quiz1->id] = $object; 386 387 $object = new \stdClass(); 388 $object->id = $quiz2->id; 389 $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 2. 390 391 $comparearray[$quiz2->id] = $object; 392 393 $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id)); 394 395 // Let's test quiz 1 closes in two hours (the original value) for user student 3 since member of no group. 396 $this->setUser($student3id); 397 $params = new \stdClass(); 398 399 $comparearray = array(); 400 $object = new \stdClass(); 401 $object->id = $quiz1->id; 402 $object->usertimeclose = $basetimestamp + 7200; // The original timeclose for quiz 1. 403 404 $comparearray[$quiz1->id] = $object; 405 406 $object = new \stdClass(); 407 $object->id = $quiz2->id; 408 $object->usertimeclose = $basetimestamp + 7200; // The original timeclose for quiz 2. 409 410 $comparearray[$quiz2->id] = $object; 411 412 $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id)); 413 414 // User 2 gets an user override for quiz 1 to close in four hours. 415 $record2 = (object) [ 416 'quiz' => $quiz1->id, 417 'userid' => $student2id, 418 'timeclose' => $basetimestamp + 14400 // In four hours. 419 ]; 420 $DB->insert_record('quiz_overrides', $record2); 421 422 // Let's test quiz 1 closes in four hours for user student 2 since personally overriden. 423 // Quiz 2 closes in two hours. 424 $this->setUser($student2id); 425 426 $comparearray = array(); 427 $object = new \stdClass(); 428 $object->id = $quiz1->id; 429 $object->usertimeclose = $basetimestamp + 14400; // The overriden timeclose for quiz 1. 430 431 $comparearray[$quiz1->id] = $object; 432 433 $object = new \stdClass(); 434 $object->id = $quiz2->id; 435 $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 2. 436 437 $comparearray[$quiz2->id] = $object; 438 439 $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id)); 440 441 // Let's test a teacher sees the original times. 442 // Quiz 1 and quiz 2 close in two hours. 443 $this->setUser($teacherid); 444 445 $comparearray = array(); 446 $object = new \stdClass(); 447 $object->id = $quiz1->id; 448 $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 1. 449 450 $comparearray[$quiz1->id] = $object; 451 452 $object = new \stdClass(); 453 $object->id = $quiz2->id; 454 $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 2. 455 456 $comparearray[$quiz2->id] = $object; 457 458 $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id)); 459 } 460 461 /** 462 * This function creates a quiz with some standard (non-random) and some random questions. 463 * The standard questions are created first and then random questions follow them. 464 * So in a quiz with 3 standard question and 2 random question, the first random question is at slot 4. 465 * 466 * @param int $qnum Number of standard questions that should be created in the quiz. 467 * @param int $randomqnum Number of random questions that should be created in the quiz. 468 * @param array $questiontags Tags to be used for random questions. 469 * This is an array in the following format: 470 * [ 471 * 0 => ['foo', 'bar'], 472 * 1 => ['baz', 'qux'] 473 * ] 474 * @param string[] $unusedtags Some additional tags to be created. 475 * @return array An array of 2 elements: $quiz and $tagobjects. 476 * $tagobjects is an associative array of all created tag objects with its key being tag names. 477 */ 478 private function setup_quiz_and_tags($qnum, $randomqnum, $questiontags = [], $unusedtags = []) { 479 global $SITE; 480 481 $tagobjects = []; 482 483 // Get all the tags that need to be created. 484 $alltags = []; 485 foreach ($questiontags as $questiontag) { 486 $alltags = array_merge($alltags, $questiontag); 487 } 488 $alltags = array_merge($alltags, $unusedtags); 489 $alltags = array_unique($alltags); 490 491 // Create tags. 492 foreach ($alltags as $tagname) { 493 $tagrecord = array( 494 'isstandard' => 1, 495 'flag' => 0, 496 'rawname' => $tagname, 497 'description' => $tagname . ' desc' 498 ); 499 $tagobjects[$tagname] = $this->getDataGenerator()->create_tag($tagrecord); 500 } 501 502 // Create a quiz. 503 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 504 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0)); 505 506 // Create a question category in the system context. 507 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 508 $cat = $questiongenerator->create_question_category(); 509 510 // Setup standard questions. 511 for ($i = 0; $i < $qnum; $i++) { 512 $question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id)); 513 quiz_add_quiz_question($question->id, $quiz); 514 } 515 // Setup random questions. 516 for ($i = 0; $i < $randomqnum; $i++) { 517 // Just create a standard question first, so there would be enough questions to pick a random question from. 518 $question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id)); 519 $tagids = []; 520 if (!empty($questiontags[$i])) { 521 foreach ($questiontags[$i] as $tagname) { 522 $tagids[] = $tagobjects[$tagname]->id; 523 } 524 } 525 quiz_add_random_questions($quiz, 0, $cat->id, 1, false, $tagids); 526 } 527 528 return array($quiz, $tagobjects); 529 } 530 531 public function test_quiz_override_summary() { 532 global $DB, $PAGE; 533 $this->resetAfterTest(); 534 $generator = $this->getDataGenerator(); 535 /** @var mod_quiz_generator $quizgenerator */ 536 $quizgenerator = $generator->get_plugin_generator('mod_quiz'); 537 /** @var mod_quiz_renderer $renderer */ 538 $renderer = $PAGE->get_renderer('mod_quiz'); 539 540 // Course with quiz and a group - plus some others, to verify they don't get counted. 541 $course = $generator->create_course(); 542 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'groupmode' => SEPARATEGROUPS]); 543 $cm = get_coursemodule_from_id('quiz', $quiz->cmid, $course->id); 544 $group = $generator->create_group(['courseid' => $course->id]); 545 $othergroup = $generator->create_group(['courseid' => $course->id]); 546 $otherquiz = $quizgenerator->create_instance(['course' => $course->id]); 547 548 // Initial test (as admin) with no data. 549 $this->setAdminUser(); 550 $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'allgroups'], 551 quiz_override_summary($quiz, $cm)); 552 $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'], 553 quiz_override_summary($quiz, $cm, $group->id)); 554 555 // Editing teacher. 556 $teacher = $generator->create_user(); 557 $generator->enrol_user($teacher->id, $course->id, 'editingteacher'); 558 559 // Non-editing teacher. 560 $tutor = $generator->create_user(); 561 $generator->enrol_user($tutor->id, $course->id, 'teacher'); 562 $generator->create_group_member(['userid' => $tutor->id, 'groupid' => $group->id]); 563 564 // Three students. 565 $student1 = $generator->create_user(); 566 $generator->enrol_user($student1->id, $course->id, 'student'); 567 $generator->create_group_member(['userid' => $student1->id, 'groupid' => $group->id]); 568 569 $student2 = $generator->create_user(); 570 $generator->enrol_user($student2->id, $course->id, 'student'); 571 $generator->create_group_member(['userid' => $student2->id, 'groupid' => $othergroup->id]); 572 573 $student3 = $generator->create_user(); 574 $generator->enrol_user($student3->id, $course->id, 'student'); 575 576 // Initial test now users exist, but before overrides. 577 // Test as teacher. 578 $this->setUser($teacher); 579 $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'allgroups'], 580 quiz_override_summary($quiz, $cm)); 581 $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'], 582 quiz_override_summary($quiz, $cm, $group->id)); 583 584 // Test as tutor. 585 $this->setUser($tutor); 586 $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'somegroups'], 587 quiz_override_summary($quiz, $cm)); 588 $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'], 589 quiz_override_summary($quiz, $cm, $group->id)); 590 $this->assertEquals('', $renderer->quiz_override_summary_links($quiz, $cm)); 591 592 // Quiz setting overrides for students 1 and 3. 593 $quizgenerator->create_override(['quiz' => $quiz->id, 'userid' => $student1->id, 'attempts' => 2]); 594 $quizgenerator->create_override(['quiz' => $quiz->id, 'userid' => $student3->id, 'attempts' => 2]); 595 $quizgenerator->create_override(['quiz' => $quiz->id, 'groupid' => $group->id, 'attempts' => 3]); 596 $quizgenerator->create_override(['quiz' => $quiz->id, 'groupid' => $othergroup->id, 'attempts' => 3]); 597 $quizgenerator->create_override(['quiz' => $otherquiz->id, 'userid' => $student2->id, 'attempts' => 2]); 598 599 // Test as teacher. 600 $this->setUser($teacher); 601 $this->assertEquals(['group' => 2, 'user' => 2, 'mode' => 'allgroups'], 602 quiz_override_summary($quiz, $cm)); 603 $this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)', 604 // Links checked by Behat, so strip them for these tests. 605 html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false)); 606 $this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'onegroup'], 607 quiz_override_summary($quiz, $cm, $group->id)); 608 $this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for this group', 609 html_to_text($renderer->quiz_override_summary_links($quiz, $cm, $group->id), 0, false)); 610 611 // Test as tutor. 612 $this->setUser($tutor); 613 $this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'somegroups'], 614 quiz_override_summary($quiz, $cm)); 615 $this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for your groups', 616 html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false)); 617 $this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'onegroup'], 618 quiz_override_summary($quiz, $cm, $group->id)); 619 $this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for this group', 620 html_to_text($renderer->quiz_override_summary_links($quiz, $cm, $group->id), 0, false)); 621 622 // Now set the quiz to be group mode: no groups, and re-test as tutor. 623 // In this case, the tutor should see all groups. 624 $DB->set_field('course_modules', 'groupmode', NOGROUPS, ['id' => $cm->id]); 625 $cm = get_coursemodule_from_id('quiz', $quiz->cmid, $course->id); 626 627 $this->assertEquals(['group' => 2, 'user' => 2, 'mode' => 'allgroups'], 628 quiz_override_summary($quiz, $cm)); 629 $this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)', 630 html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false)); 631 } 632 633 /** 634 * Test quiz_send_confirmation function. 635 */ 636 public function test_quiz_send_confirmation() { 637 global $CFG, $DB; 638 639 $this->resetAfterTest(); 640 $this->setAdminUser(); 641 $this->preventResetByRollback(); 642 643 $course = $this->getDataGenerator()->create_course(); 644 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 645 $quiz = $quizgenerator->create_instance(['course' => $course->id]); 646 $cm = get_coursemodule_from_instance('quiz', $quiz->id); 647 648 $recipient = $this->getDataGenerator()->create_user(['email' => 'student@example.com']); 649 650 // Allow recipent to receive email confirm submission. 651 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 652 assign_capability('mod/quiz:emailconfirmsubmission', CAP_ALLOW, $studentrole->id, 653 \context_course::instance($course->id), true); 654 $this->getDataGenerator()->enrol_user($recipient->id, $course->id, $studentrole->id, 'manual'); 655 656 $timenow = time(); 657 $data = new \stdClass(); 658 // Course info. 659 $data->courseid = $course->id; 660 $data->coursename = $course->fullname; 661 // Quiz info. 662 $data->quizname = $quiz->name; 663 $data->quizurl = $CFG->wwwroot . '/mod/quiz/view.php?id=' . $cm->id; 664 $data->quizid = $quiz->id; 665 $data->quizcmid = $quiz->cmid; 666 $data->attemptid = 1; 667 $data->submissiontime = userdate($timenow); 668 669 $sink = $this->redirectEmails(); 670 quiz_send_confirmation($recipient, $data, true); 671 $messages = $sink->get_messages(); 672 $message = reset($messages); 673 $this->assertStringContainsString("Thank you for submitting your answers" , 674 quoted_printable_decode($message->body)); 675 $sink->close(); 676 677 $sink = $this->redirectEmails(); 678 quiz_send_confirmation($recipient, $data, false); 679 $messages = $sink->get_messages(); 680 $message = reset($messages); 681 $this->assertStringContainsString("Your answers were submitted automatically" , 682 quoted_printable_decode($message->body)); 683 $sink->close(); 684 } 685 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body