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