Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 The Open University
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
  24   */
  25  
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->dirroot . '/mod/quiz/lib.php');
  31  
  32  /**
  33   * @copyright  2008 The Open University
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
  35   */
  36  class mod_quiz_lib_testcase extends advanced_testcase {
  37      public function test_quiz_has_grades() {
  38          $quiz = new stdClass();
  39          $quiz->grade = '100.0000';
  40          $quiz->sumgrades = '100.0000';
  41          $this->assertTrue(quiz_has_grades($quiz));
  42          $quiz->sumgrades = '0.0000';
  43          $this->assertFalse(quiz_has_grades($quiz));
  44          $quiz->grade = '0.0000';
  45          $this->assertFalse(quiz_has_grades($quiz));
  46          $quiz->sumgrades = '100.0000';
  47          $this->assertFalse(quiz_has_grades($quiz));
  48      }
  49  
  50      public function test_quiz_format_grade() {
  51          $quiz = new stdClass();
  52          $quiz->decimalpoints = 2;
  53          $this->assertEquals(quiz_format_grade($quiz, 0.12345678), format_float(0.12, 2));
  54          $this->assertEquals(quiz_format_grade($quiz, 0), format_float(0, 2));
  55          $this->assertEquals(quiz_format_grade($quiz, 1.000000000000), format_float(1, 2));
  56          $quiz->decimalpoints = 0;
  57          $this->assertEquals(quiz_format_grade($quiz, 0.12345678), '0');
  58      }
  59  
  60      public function test_quiz_get_grade_format() {
  61          $quiz = new stdClass();
  62          $quiz->decimalpoints = 2;
  63          $this->assertEquals(quiz_get_grade_format($quiz), 2);
  64          $this->assertEquals($quiz->questiondecimalpoints, -1);
  65          $quiz->questiondecimalpoints = 2;
  66          $this->assertEquals(quiz_get_grade_format($quiz), 2);
  67          $quiz->decimalpoints = 3;
  68          $quiz->questiondecimalpoints = -1;
  69          $this->assertEquals(quiz_get_grade_format($quiz), 3);
  70          $quiz->questiondecimalpoints = 4;
  71          $this->assertEquals(quiz_get_grade_format($quiz), 4);
  72      }
  73  
  74      public function test_quiz_format_question_grade() {
  75          $quiz = new stdClass();
  76          $quiz->decimalpoints = 2;
  77          $quiz->questiondecimalpoints = 2;
  78          $this->assertEquals(quiz_format_question_grade($quiz, 0.12345678), format_float(0.12, 2));
  79          $this->assertEquals(quiz_format_question_grade($quiz, 0), format_float(0, 2));
  80          $this->assertEquals(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 2));
  81          $quiz->decimalpoints = 3;
  82          $quiz->questiondecimalpoints = -1;
  83          $this->assertEquals(quiz_format_question_grade($quiz, 0.12345678), format_float(0.123, 3));
  84          $this->assertEquals(quiz_format_question_grade($quiz, 0), format_float(0, 3));
  85          $this->assertEquals(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 3));
  86          $quiz->questiondecimalpoints = 4;
  87          $this->assertEquals(quiz_format_question_grade($quiz, 0.12345678), format_float(0.1235, 4));
  88          $this->assertEquals(quiz_format_question_grade($quiz, 0), format_float(0, 4));
  89          $this->assertEquals(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 4));
  90      }
  91  
  92      /**
  93       * Test deleting a quiz instance.
  94       */
  95      public function test_quiz_delete_instance() {
  96          global $SITE, $DB;
  97          $this->resetAfterTest(true);
  98          $this->setAdminUser();
  99  
 100          // Setup a quiz with 1 standard and 1 random question.
 101          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 102          $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
 103  
 104          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 105          $cat = $questiongenerator->create_question_category();
 106          $standardq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
 107  
 108          quiz_add_quiz_question($standardq->id, $quiz);
 109          quiz_add_random_questions($quiz, 0, $cat->id, 1, false);
 110  
 111          // Get the random question.
 112          $randomq = $DB->get_record('question', array('qtype' => 'random'));
 113  
 114          quiz_delete_instance($quiz->id);
 115  
 116          // Check that the random question was deleted.
 117          $count = $DB->count_records('question', array('id' => $randomq->id));
 118          $this->assertEquals(0, $count);
 119          // Check that the standard question was not deleted.
 120          $count = $DB->count_records('question', array('id' => $standardq->id));
 121          $this->assertEquals(1, $count);
 122  
 123          // Check that all the slots were removed.
 124          $count = $DB->count_records('quiz_slots', array('quizid' => $quiz->id));
 125          $this->assertEquals(0, $count);
 126  
 127          // Check that the quiz was removed.
 128          $count = $DB->count_records('quiz', array('id' => $quiz->id));
 129          $this->assertEquals(0, $count);
 130      }
 131  
 132      /**
 133       * Test checking the completion state of a quiz.
 134       */
 135      public function test_quiz_get_completion_state() {
 136          global $CFG, $DB;
 137          $this->resetAfterTest(true);
 138  
 139          // Enable completion before creating modules, otherwise the completion data is not written in DB.
 140          $CFG->enablecompletion = true;
 141  
 142          // Create a course and student.
 143          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => true));
 144          $passstudent = $this->getDataGenerator()->create_user();
 145          $failstudent = $this->getDataGenerator()->create_user();
 146          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 147          $this->assertNotEmpty($studentrole);
 148  
 149          // Enrol students.
 150          $this->assertTrue($this->getDataGenerator()->enrol_user($passstudent->id, $course->id, $studentrole->id));
 151          $this->assertTrue($this->getDataGenerator()->enrol_user($failstudent->id, $course->id, $studentrole->id));
 152  
 153          // Make a scale and an outcome.
 154          $scale = $this->getDataGenerator()->create_scale();
 155          $data = array('courseid' => $course->id,
 156                        'fullname' => 'Team work',
 157                        'shortname' => 'Team work',
 158                        'scaleid' => $scale->id);
 159          $outcome = $this->getDataGenerator()->create_grade_outcome($data);
 160  
 161          // Make a quiz with the outcome on.
 162          $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
 163          $data = array('course' => $course->id,
 164                        'outcome_'.$outcome->id => 1,
 165                        'grade' => 100.0,
 166                        'questionsperpage' => 0,
 167                        'sumgrades' => 1,
 168                        'completion' => COMPLETION_TRACKING_AUTOMATIC,
 169                        'completionusegrade' => 1,
 170                        'completionpass' => 1);
 171          $quiz = $quizgenerator->create_instance($data);
 172          $cm = get_coursemodule_from_id('quiz', $quiz->cmid);
 173  
 174          // Create a couple of questions.
 175          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 176  
 177          $cat = $questiongenerator->create_question_category();
 178          $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
 179          quiz_add_quiz_question($question->id, $quiz);
 180  
 181          $quizobj = quiz::create($quiz->id, $passstudent->id);
 182  
 183          // Set grade to pass.
 184          $item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod',
 185                                          'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null));
 186          $item->gradepass = 80;
 187          $item->update();
 188  
 189          // Start the passing attempt.
 190          $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
 191          $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
 192  
 193          $timenow = time();
 194          $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $passstudent->id);
 195          quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
 196          quiz_attempt_save_started($quizobj, $quba, $attempt);
 197  
 198          // Process some responses from the student.
 199          $attemptobj = quiz_attempt::create($attempt->id);
 200          $tosubmit = array(1 => array('answer' => '3.14'));
 201          $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
 202  
 203          // Finish the attempt.
 204          $attemptobj = quiz_attempt::create($attempt->id);
 205          $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
 206          $attemptobj->process_finish($timenow, false);
 207  
 208          // Start the failing attempt.
 209          $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
 210          $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
 211  
 212          $timenow = time();
 213          $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $failstudent->id);
 214          quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
 215          quiz_attempt_save_started($quizobj, $quba, $attempt);
 216  
 217          // Process some responses from the student.
 218          $attemptobj = quiz_attempt::create($attempt->id);
 219          $tosubmit = array(1 => array('answer' => '0'));
 220          $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
 221  
 222          // Finish the attempt.
 223          $attemptobj = quiz_attempt::create($attempt->id);
 224          $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
 225          $attemptobj->process_finish($timenow, false);
 226  
 227          // Check the results.
 228          $this->assertTrue(quiz_get_completion_state($course, $cm, $passstudent->id, 'return'));
 229          $this->assertFalse(quiz_get_completion_state($course, $cm, $failstudent->id, 'return'));
 230      }
 231  
 232      public function test_quiz_get_user_attempts() {
 233          global $DB;
 234          $this->resetAfterTest();
 235  
 236          $dg = $this->getDataGenerator();
 237          $quizgen = $dg->get_plugin_generator('mod_quiz');
 238          $course = $dg->create_course();
 239          $u1 = $dg->create_user();
 240          $u2 = $dg->create_user();
 241          $u3 = $dg->create_user();
 242          $u4 = $dg->create_user();
 243          $role = $DB->get_record('role', ['shortname' => 'student']);
 244  
 245          $dg->enrol_user($u1->id, $course->id, $role->id);
 246          $dg->enrol_user($u2->id, $course->id, $role->id);
 247          $dg->enrol_user($u3->id, $course->id, $role->id);
 248          $dg->enrol_user($u4->id, $course->id, $role->id);
 249  
 250          $quiz1 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
 251          $quiz2 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
 252  
 253          // Questions.
 254          $questgen = $dg->get_plugin_generator('core_question');
 255          $quizcat = $questgen->create_question_category();
 256          $question = $questgen->create_question('numerical', null, ['category' => $quizcat->id]);
 257          quiz_add_quiz_question($question->id, $quiz1);
 258          quiz_add_quiz_question($question->id, $quiz2);
 259  
 260          $quizobj1a = quiz::create($quiz1->id, $u1->id);
 261          $quizobj1b = quiz::create($quiz1->id, $u2->id);
 262          $quizobj1c = quiz::create($quiz1->id, $u3->id);
 263          $quizobj1d = quiz::create($quiz1->id, $u4->id);
 264          $quizobj2a = quiz::create($quiz2->id, $u1->id);
 265  
 266          // Set attempts.
 267          $quba1a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1a->get_context());
 268          $quba1a->set_preferred_behaviour($quizobj1a->get_quiz()->preferredbehaviour);
 269          $quba1b = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1b->get_context());
 270          $quba1b->set_preferred_behaviour($quizobj1b->get_quiz()->preferredbehaviour);
 271          $quba1c = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1c->get_context());
 272          $quba1c->set_preferred_behaviour($quizobj1c->get_quiz()->preferredbehaviour);
 273          $quba1d = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1d->get_context());
 274          $quba1d->set_preferred_behaviour($quizobj1d->get_quiz()->preferredbehaviour);
 275          $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
 276          $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
 277  
 278          $timenow = time();
 279  
 280          // User 1 passes quiz 1.
 281          $attempt = quiz_create_attempt($quizobj1a, 1, false, $timenow, false, $u1->id);
 282          quiz_start_new_attempt($quizobj1a, $quba1a, $attempt, 1, $timenow);
 283          quiz_attempt_save_started($quizobj1a, $quba1a, $attempt);
 284          $attemptobj = quiz_attempt::create($attempt->id);
 285          $attemptobj->process_submitted_actions($timenow, false, [1 => ['answer' => '3.14']]);
 286          $attemptobj->process_finish($timenow, false);
 287  
 288          // User 2 goes overdue in quiz 1.
 289          $attempt = quiz_create_attempt($quizobj1b, 1, false, $timenow, false, $u2->id);
 290          quiz_start_new_attempt($quizobj1b, $quba1b, $attempt, 1, $timenow);
 291          quiz_attempt_save_started($quizobj1b, $quba1b, $attempt);
 292          $attemptobj = quiz_attempt::create($attempt->id);
 293          $attemptobj->process_going_overdue($timenow, true);
 294  
 295          // User 3 does not finish quiz 1.
 296          $attempt = quiz_create_attempt($quizobj1c, 1, false, $timenow, false, $u3->id);
 297          quiz_start_new_attempt($quizobj1c, $quba1c, $attempt, 1, $timenow);
 298          quiz_attempt_save_started($quizobj1c, $quba1c, $attempt);
 299  
 300          // User 4 abandons the quiz 1.
 301          $attempt = quiz_create_attempt($quizobj1d, 1, false, $timenow, false, $u4->id);
 302          quiz_start_new_attempt($quizobj1d, $quba1d, $attempt, 1, $timenow);
 303          quiz_attempt_save_started($quizobj1d, $quba1d, $attempt);
 304          $attemptobj = quiz_attempt::create($attempt->id);
 305          $attemptobj->process_abandon($timenow, true);
 306  
 307          // User 1 attempts the quiz three times (abandon, finish, in progress).
 308          $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
 309          $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
 310  
 311          $attempt = quiz_create_attempt($quizobj2a, 1, false, $timenow, false, $u1->id);
 312          quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 1, $timenow);
 313          quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
 314          $attemptobj = quiz_attempt::create($attempt->id);
 315          $attemptobj->process_abandon($timenow, true);
 316  
 317          $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
 318          $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
 319  
 320          $attempt = quiz_create_attempt($quizobj2a, 2, false, $timenow, false, $u1->id);
 321          quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 2, $timenow);
 322          quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
 323          $attemptobj = quiz_attempt::create($attempt->id);
 324          $attemptobj->process_finish($timenow, false);
 325  
 326          $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
 327          $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
 328  
 329          $attempt = quiz_create_attempt($quizobj2a, 3, false, $timenow, false, $u1->id);
 330          quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 3, $timenow);
 331          quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
 332  
 333          // Check for user 1.
 334          $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'all');
 335          $this->assertCount(1, $attempts);
 336          $attempt = array_shift($attempts);
 337          $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
 338          $this->assertEquals($u1->id, $attempt->userid);
 339          $this->assertEquals($quiz1->id, $attempt->quiz);
 340  
 341          $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'finished');
 342          $this->assertCount(1, $attempts);
 343          $attempt = array_shift($attempts);
 344          $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
 345          $this->assertEquals($u1->id, $attempt->userid);
 346          $this->assertEquals($quiz1->id, $attempt->quiz);
 347  
 348          $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'unfinished');
 349          $this->assertCount(0, $attempts);
 350  
 351          // Check for user 2.
 352          $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'all');
 353          $this->assertCount(1, $attempts);
 354          $attempt = array_shift($attempts);
 355          $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
 356          $this->assertEquals($u2->id, $attempt->userid);
 357          $this->assertEquals($quiz1->id, $attempt->quiz);
 358  
 359          $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'finished');
 360          $this->assertCount(0, $attempts);
 361  
 362          $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'unfinished');
 363          $this->assertCount(1, $attempts);
 364          $attempt = array_shift($attempts);
 365          $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
 366          $this->assertEquals($u2->id, $attempt->userid);
 367          $this->assertEquals($quiz1->id, $attempt->quiz);
 368  
 369          // Check for user 3.
 370          $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'all');
 371          $this->assertCount(1, $attempts);
 372          $attempt = array_shift($attempts);
 373          $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
 374          $this->assertEquals($u3->id, $attempt->userid);
 375          $this->assertEquals($quiz1->id, $attempt->quiz);
 376  
 377          $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'finished');
 378          $this->assertCount(0, $attempts);
 379  
 380          $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'unfinished');
 381          $this->assertCount(1, $attempts);
 382          $attempt = array_shift($attempts);
 383          $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
 384          $this->assertEquals($u3->id, $attempt->userid);
 385          $this->assertEquals($quiz1->id, $attempt->quiz);
 386  
 387          // Check for user 4.
 388          $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'all');
 389          $this->assertCount(1, $attempts);
 390          $attempt = array_shift($attempts);
 391          $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
 392          $this->assertEquals($u4->id, $attempt->userid);
 393          $this->assertEquals($quiz1->id, $attempt->quiz);
 394  
 395          $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'finished');
 396          $this->assertCount(1, $attempts);
 397          $attempt = array_shift($attempts);
 398          $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
 399          $this->assertEquals($u4->id, $attempt->userid);
 400          $this->assertEquals($quiz1->id, $attempt->quiz);
 401  
 402          $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'unfinished');
 403          $this->assertCount(0, $attempts);
 404  
 405          // Multiple attempts for user 1 in quiz 2.
 406          $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'all');
 407          $this->assertCount(3, $attempts);
 408          $attempt = array_shift($attempts);
 409          $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
 410          $this->assertEquals($u1->id, $attempt->userid);
 411          $this->assertEquals($quiz2->id, $attempt->quiz);
 412          $attempt = array_shift($attempts);
 413          $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
 414          $this->assertEquals($u1->id, $attempt->userid);
 415          $this->assertEquals($quiz2->id, $attempt->quiz);
 416          $attempt = array_shift($attempts);
 417          $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
 418          $this->assertEquals($u1->id, $attempt->userid);
 419          $this->assertEquals($quiz2->id, $attempt->quiz);
 420  
 421          $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'finished');
 422          $this->assertCount(2, $attempts);
 423          $attempt = array_shift($attempts);
 424          $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
 425          $attempt = array_shift($attempts);
 426          $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
 427  
 428          $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'unfinished');
 429          $this->assertCount(1, $attempts);
 430          $attempt = array_shift($attempts);
 431  
 432          // Multiple quiz attempts fetched at once.
 433          $attempts = quiz_get_user_attempts([$quiz1->id, $quiz2->id], $u1->id, 'all');
 434          $this->assertCount(4, $attempts);
 435          $attempt = array_shift($attempts);
 436          $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
 437          $this->assertEquals($u1->id, $attempt->userid);
 438          $this->assertEquals($quiz1->id, $attempt->quiz);
 439          $attempt = array_shift($attempts);
 440          $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
 441          $this->assertEquals($u1->id, $attempt->userid);
 442          $this->assertEquals($quiz2->id, $attempt->quiz);
 443          $attempt = array_shift($attempts);
 444          $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
 445          $this->assertEquals($u1->id, $attempt->userid);
 446          $this->assertEquals($quiz2->id, $attempt->quiz);
 447          $attempt = array_shift($attempts);
 448          $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
 449          $this->assertEquals($u1->id, $attempt->userid);
 450          $this->assertEquals($quiz2->id, $attempt->quiz);
 451      }
 452  
 453      /**
 454       * Test for quiz_get_group_override_priorities().
 455       */
 456      public function test_quiz_get_group_override_priorities() {
 457          global $DB;
 458          $this->resetAfterTest();
 459  
 460          $dg = $this->getDataGenerator();
 461          $quizgen = $dg->get_plugin_generator('mod_quiz');
 462          $course = $dg->create_course();
 463  
 464          $quiz = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
 465  
 466          $this->assertNull(quiz_get_group_override_priorities($quiz->id));
 467  
 468          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
 469          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
 470  
 471          $now = 100;
 472          $override1 = (object)[
 473              'quiz' => $quiz->id,
 474              'groupid' => $group1->id,
 475              'timeopen' => $now,
 476              'timeclose' => $now + 20
 477          ];
 478          $DB->insert_record('quiz_overrides', $override1);
 479  
 480          $override2 = (object)[
 481              'quiz' => $quiz->id,
 482              'groupid' => $group2->id,
 483              'timeopen' => $now - 10,
 484              'timeclose' => $now + 10
 485          ];
 486          $DB->insert_record('quiz_overrides', $override2);
 487  
 488          $priorities = quiz_get_group_override_priorities($quiz->id);
 489          $this->assertNotEmpty($priorities);
 490  
 491          $openpriorities = $priorities['open'];
 492          // Override 2's time open has higher priority since it is sooner than override 1's.
 493          $this->assertEquals(2, $openpriorities[$override1->timeopen]);
 494          $this->assertEquals(1, $openpriorities[$override2->timeopen]);
 495  
 496          $closepriorities = $priorities['close'];
 497          // Override 1's time close has higher priority since it is later than override 2's.
 498          $this->assertEquals(1, $closepriorities[$override1->timeclose]);
 499          $this->assertEquals(2, $closepriorities[$override2->timeclose]);
 500      }
 501  
 502      public function test_quiz_core_calendar_provide_event_action_open() {
 503          $this->resetAfterTest();
 504  
 505          $this->setAdminUser();
 506  
 507          // Create a course.
 508          $course = $this->getDataGenerator()->create_course();
 509          // Create a student and enrol into the course.
 510          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 511          // Create a quiz.
 512          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 513              'timeopen' => time() - DAYSECS, 'timeclose' => time() + DAYSECS));
 514  
 515          // Create a calendar event.
 516          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN);
 517          // Now, log in as student.
 518          $this->setUser($student);
 519          // Create an action factory.
 520          $factory = new \core_calendar\action_factory();
 521  
 522          // Decorate action event.
 523          $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory);
 524  
 525          // Confirm the event was decorated.
 526          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 527          $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name());
 528          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 529          $this->assertEquals(1, $actionevent->get_item_count());
 530          $this->assertTrue($actionevent->is_actionable());
 531      }
 532  
 533      public function test_quiz_core_calendar_provide_event_action_open_for_user() {
 534          $this->resetAfterTest();
 535  
 536          $this->setAdminUser();
 537  
 538          // Create a course.
 539          $course = $this->getDataGenerator()->create_course();
 540          // Create a student and enrol into the course.
 541          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 542          // Create a quiz.
 543          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 544              'timeopen' => time() - DAYSECS, 'timeclose' => time() + DAYSECS));
 545  
 546          // Create a calendar event.
 547          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN);
 548  
 549          // Create an action factory.
 550          $factory = new \core_calendar\action_factory();
 551  
 552          // Decorate action event for the student.
 553          $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id);
 554  
 555          // Confirm the event was decorated.
 556          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 557          $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name());
 558          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 559          $this->assertEquals(1, $actionevent->get_item_count());
 560          $this->assertTrue($actionevent->is_actionable());
 561      }
 562  
 563      public function test_quiz_core_calendar_provide_event_action_closed() {
 564          $this->resetAfterTest();
 565  
 566          $this->setAdminUser();
 567  
 568          // Create a course.
 569          $course = $this->getDataGenerator()->create_course();
 570  
 571          // Create a quiz.
 572          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 573              'timeclose' => time() - DAYSECS));
 574  
 575          // Create a calendar event.
 576          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE);
 577  
 578          // Create an action factory.
 579          $factory = new \core_calendar\action_factory();
 580  
 581          // Confirm the result was null.
 582          $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory));
 583      }
 584  
 585      public function test_quiz_core_calendar_provide_event_action_closed_for_user() {
 586          $this->resetAfterTest();
 587  
 588          $this->setAdminUser();
 589  
 590          // Create a course.
 591          $course = $this->getDataGenerator()->create_course();
 592  
 593          // Create a student.
 594          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 595  
 596          // Create a quiz.
 597          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 598              'timeclose' => time() - DAYSECS));
 599  
 600          // Create a calendar event.
 601          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE);
 602  
 603          // Create an action factory.
 604          $factory = new \core_calendar\action_factory();
 605  
 606          // Confirm the result was null.
 607          $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id));
 608      }
 609  
 610      public function test_quiz_core_calendar_provide_event_action_open_in_future() {
 611          $this->resetAfterTest();
 612  
 613          $this->setAdminUser();
 614  
 615          // Create a course.
 616          $course = $this->getDataGenerator()->create_course();
 617          // Create a student and enrol into the course.
 618          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 619          // Create a quiz.
 620          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 621              'timeopen' => time() + DAYSECS));
 622  
 623          // Create a calendar event.
 624          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE);
 625          // Now, log in as student.
 626          $this->setUser($student);
 627          // Create an action factory.
 628          $factory = new \core_calendar\action_factory();
 629  
 630          // Decorate action event.
 631          $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory);
 632  
 633          // Confirm the event was decorated.
 634          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 635          $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name());
 636          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 637          $this->assertEquals(1, $actionevent->get_item_count());
 638          $this->assertFalse($actionevent->is_actionable());
 639      }
 640  
 641      public function test_quiz_core_calendar_provide_event_action_open_in_future_for_user() {
 642          $this->resetAfterTest();
 643  
 644          $this->setAdminUser();
 645  
 646          // Create a course.
 647          $course = $this->getDataGenerator()->create_course();
 648          // Create a student and enrol into the course.
 649          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 650          // Create a quiz.
 651          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 652              'timeopen' => time() + DAYSECS));
 653  
 654          // Create a calendar event.
 655          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE);
 656  
 657          // Create an action factory.
 658          $factory = new \core_calendar\action_factory();
 659  
 660          // Decorate action event for the student.
 661          $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id);
 662  
 663          // Confirm the event was decorated.
 664          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 665          $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name());
 666          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 667          $this->assertEquals(1, $actionevent->get_item_count());
 668          $this->assertFalse($actionevent->is_actionable());
 669      }
 670  
 671      public function test_quiz_core_calendar_provide_event_action_no_capability() {
 672          global $DB;
 673  
 674          $this->resetAfterTest();
 675          $this->setAdminUser();
 676  
 677          // Create a course.
 678          $course = $this->getDataGenerator()->create_course();
 679  
 680          // Create a student.
 681          $student = $this->getDataGenerator()->create_user();
 682          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 683  
 684          // Enrol student.
 685          $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id));
 686  
 687          // Create a quiz.
 688          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
 689  
 690          // Remove the permission to attempt or review the quiz for the student role.
 691          $coursecontext = context_course::instance($course->id);
 692          assign_capability('mod/quiz:reviewmyattempts', CAP_PROHIBIT, $studentrole->id, $coursecontext);
 693          assign_capability('mod/quiz:attempt', CAP_PROHIBIT, $studentrole->id, $coursecontext);
 694  
 695          // Create a calendar event.
 696          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN);
 697  
 698          // Create an action factory.
 699          $factory = new \core_calendar\action_factory();
 700  
 701          // Set current user to the student.
 702          $this->setUser($student);
 703  
 704          // Confirm null is returned.
 705          $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory));
 706      }
 707  
 708      public function test_quiz_core_calendar_provide_event_action_no_capability_for_user() {
 709          global $DB;
 710  
 711          $this->resetAfterTest();
 712          $this->setAdminUser();
 713  
 714          // Create a course.
 715          $course = $this->getDataGenerator()->create_course();
 716  
 717          // Create a student.
 718          $student = $this->getDataGenerator()->create_user();
 719          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 720  
 721          // Enrol student.
 722          $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id));
 723  
 724          // Create a quiz.
 725          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id));
 726  
 727          // Remove the permission to attempt or review the quiz for the student role.
 728          $coursecontext = context_course::instance($course->id);
 729          assign_capability('mod/quiz:reviewmyattempts', CAP_PROHIBIT, $studentrole->id, $coursecontext);
 730          assign_capability('mod/quiz:attempt', CAP_PROHIBIT, $studentrole->id, $coursecontext);
 731  
 732          // Create a calendar event.
 733          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN);
 734  
 735          // Create an action factory.
 736          $factory = new \core_calendar\action_factory();
 737  
 738          // Confirm null is returned.
 739          $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id));
 740      }
 741  
 742      public function test_quiz_core_calendar_provide_event_action_already_finished() {
 743          global $DB;
 744  
 745          $this->resetAfterTest();
 746  
 747          $this->setAdminUser();
 748  
 749          // Create a course.
 750          $course = $this->getDataGenerator()->create_course();
 751  
 752          // Create a student.
 753          $student = $this->getDataGenerator()->create_user();
 754          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 755  
 756          // Enrol student.
 757          $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id));
 758  
 759          // Create a quiz.
 760          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 761              'sumgrades' => 1));
 762  
 763          // Add a question to the quiz.
 764          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 765          $cat = $questiongenerator->create_question_category();
 766          $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
 767          quiz_add_quiz_question($question->id, $quiz);
 768  
 769          // Get the quiz object.
 770          $quizobj = quiz::create($quiz->id, $student->id);
 771  
 772          // Create an attempt for the student in the quiz.
 773          $timenow = time();
 774          $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id);
 775          $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
 776          $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
 777          quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
 778          quiz_attempt_save_started($quizobj, $quba, $attempt);
 779  
 780          // Finish the attempt.
 781          $attemptobj = quiz_attempt::create($attempt->id);
 782          $attemptobj->process_finish($timenow, false);
 783  
 784          // Create a calendar event.
 785          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN);
 786  
 787          // Create an action factory.
 788          $factory = new \core_calendar\action_factory();
 789  
 790          // Set current user to the student.
 791          $this->setUser($student);
 792  
 793          // Confirm null is returned.
 794          $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory));
 795      }
 796  
 797      public function test_quiz_core_calendar_provide_event_action_already_finished_for_user() {
 798          global $DB;
 799  
 800          $this->resetAfterTest();
 801  
 802          $this->setAdminUser();
 803  
 804          // Create a course.
 805          $course = $this->getDataGenerator()->create_course();
 806  
 807          // Create a student.
 808          $student = $this->getDataGenerator()->create_user();
 809          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 810  
 811          // Enrol student.
 812          $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id));
 813  
 814          // Create a quiz.
 815          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id,
 816              'sumgrades' => 1));
 817  
 818          // Add a question to the quiz.
 819          $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
 820          $cat = $questiongenerator->create_question_category();
 821          $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
 822          quiz_add_quiz_question($question->id, $quiz);
 823  
 824          // Get the quiz object.
 825          $quizobj = quiz::create($quiz->id, $student->id);
 826  
 827          // Create an attempt for the student in the quiz.
 828          $timenow = time();
 829          $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id);
 830          $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
 831          $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
 832          quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
 833          quiz_attempt_save_started($quizobj, $quba, $attempt);
 834  
 835          // Finish the attempt.
 836          $attemptobj = quiz_attempt::create($attempt->id);
 837          $attemptobj->process_finish($timenow, false);
 838  
 839          // Create a calendar event.
 840          $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN);
 841  
 842          // Create an action factory.
 843          $factory = new \core_calendar\action_factory();
 844  
 845          // Confirm null is returned.
 846          $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id));
 847      }
 848  
 849      public function test_quiz_core_calendar_provide_event_action_already_completed() {
 850          $this->resetAfterTest();
 851          set_config('enablecompletion', 1);
 852          $this->setAdminUser();
 853  
 854          // Create the activity.
 855          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
 856          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id),
 857              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
 858  
 859          // Get some additional data.
 860          $cm = get_coursemodule_from_instance('quiz', $quiz->id);
 861  
 862          // Create a calendar event.
 863          $event = $this->create_action_event($course->id, $quiz->id,
 864              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 865  
 866          // Mark the activity as completed.
 867          $completion = new completion_info($course);
 868          $completion->set_module_viewed($cm);
 869  
 870          // Create an action factory.
 871          $factory = new \core_calendar\action_factory();
 872  
 873          // Decorate action event.
 874          $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory);
 875  
 876          // Ensure result was null.
 877          $this->assertNull($actionevent);
 878      }
 879  
 880      public function test_quiz_core_calendar_provide_event_action_already_completed_for_user() {
 881          $this->resetAfterTest();
 882          set_config('enablecompletion', 1);
 883          $this->setAdminUser();
 884  
 885          // Create the activity.
 886          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
 887          $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id),
 888              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
 889  
 890          // Enrol a student in the course.
 891          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 892  
 893          // Get some additional data.
 894          $cm = get_coursemodule_from_instance('quiz', $quiz->id);
 895  
 896          // Create a calendar event.
 897          $event = $this->create_action_event($course->id, $quiz->id,
 898              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 899  
 900          // Mark the activity as completed for the student.
 901          $completion = new completion_info($course);
 902          $completion->set_module_viewed($cm, $student->id);
 903  
 904          // Create an action factory.
 905          $factory = new \core_calendar\action_factory();
 906  
 907          // Decorate action event for the student.
 908          $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id);
 909  
 910          // Ensure result was null.
 911          $this->assertNull($actionevent);
 912      }
 913  
 914      /**
 915       * Creates an action event.
 916       *
 917       * @param int $courseid
 918       * @param int $instanceid The quiz id.
 919       * @param string $eventtype The event type. eg. QUIZ_EVENT_TYPE_OPEN.
 920       * @return bool|calendar_event
 921       */
 922      private function create_action_event($courseid, $instanceid, $eventtype) {
 923          $event = new stdClass();
 924          $event->name = 'Calendar event';
 925          $event->modulename  = 'quiz';
 926          $event->courseid = $courseid;
 927          $event->instance = $instanceid;
 928          $event->type = CALENDAR_EVENT_TYPE_ACTION;
 929          $event->eventtype = $eventtype;
 930          $event->timestart = time();
 931  
 932          return calendar_event::create($event);
 933      }
 934  
 935      /**
 936       * Test the callback responsible for returning the completion rule descriptions.
 937       * This function should work given either an instance of the module (cm_info), such as when checking the active rules,
 938       * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
 939       */
 940      public function test_mod_quiz_completion_get_active_rule_descriptions() {
 941          $this->resetAfterTest();
 942          $this->setAdminUser();
 943  
 944          // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
 945          $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
 946          $quiz1 = $this->getDataGenerator()->create_module('quiz', [
 947              'course' => $course->id,
 948              'completion' => 2,
 949              'completionusegrade' => 1,
 950              'completionattemptsexhausted' => 1,
 951              'completionpass' => 1
 952          ]);
 953          $quiz2 = $this->getDataGenerator()->create_module('quiz', [
 954              'course' => $course->id,
 955              'completion' => 2,
 956              'completionusegrade' => 0
 957          ]);
 958          $cm1 = cm_info::create(get_coursemodule_from_instance('quiz', $quiz1->id));
 959          $cm2 = cm_info::create(get_coursemodule_from_instance('quiz', $quiz2->id));
 960  
 961          // Data for the stdClass input type.
 962          // This type of input would occur when checking the default completion rules for an activity type, where we don't have
 963          // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
 964          $moddefaults = new stdClass();
 965          $moddefaults->customdata = ['customcompletionrules' => [
 966              'completionattemptsexhausted' => 1,
 967              'completionpass' => 1
 968          ]];
 969          $moddefaults->completion = 2;
 970  
 971          $activeruledescriptions = [
 972              get_string('completionattemptsexhausteddesc', 'quiz'),
 973              get_string('completionpassdesc', 'quiz'),
 974          ];
 975          $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
 976          $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions($cm2), []);
 977          $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
 978          $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions(new stdClass()), []);
 979      }
 980  
 981      /**
 982       * A user who does not have capabilities to add events to the calendar should be able to create a quiz.
 983       */
 984      public function test_creation_with_no_calendar_capabilities() {
 985          $this->resetAfterTest();
 986          $course = self::getDataGenerator()->create_course();
 987          $context = context_course::instance($course->id);
 988          $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher');
 989          $roleid = self::getDataGenerator()->create_role();
 990          self::getDataGenerator()->role_assign($roleid, $user->id, $context->id);
 991          assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
 992          $generator = self::getDataGenerator()->get_plugin_generator('mod_quiz');
 993          // Create an instance as a user without the calendar capabilities.
 994          $this->setUser($user);
 995          $time = time();
 996          $params = array(
 997              'course' => $course->id,
 998              'timeopen' => $time + 200,
 999              'timeclose' => $time + 2000,
1000          );
1001          $generator->create_instance($params);
1002      }
1003  }