public function test_quiz_report_overview_report_forcesubmit_specific_attempt()
 {
     global $DB;
     $this->resetAfterTest();
     $generator = $this->getDataGenerator();
     $quizgenerator = $generator->get_plugin_generator('mod_quiz');
     $questiongenerator = $generator->get_plugin_generator('core_question');
     // Make a user to do the quiz.
     $user1 = $generator->create_user();
     $user2 = $generator->create_user();
     $user3 = $generator->create_user();
     // Create our course.
     $course = $generator->create_course(array('visible' => true));
     // Create the quiz.
     $quiz = $quizgenerator->create_instance(array('course' => $course->id, 'visible' => true, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 2));
     // Create two questions.
     $cat = $questiongenerator->create_question_category();
     $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     // Add the questions to the quiz.
     quiz_add_quiz_question($saq->id, $quiz);
     quiz_add_quiz_question($numq->id, $quiz);
     // Get a quiz object with user access overrides.
     $quizobj = quiz::create($quiz->id, $user1->id);
     $quizobj2 = quiz::create($quiz->id, $user2->id);
     $quizobj3 = quiz::create($quiz->id, $user3->id);
     // Start the attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $quba2 = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2->get_context());
     $quba2->set_preferred_behaviour($quizobj2->get_quiz()->preferredbehaviour);
     $quba3 = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj3->get_context());
     $quba3->set_preferred_behaviour($quizobj3->get_quiz()->preferredbehaviour);
     // Create a quiz attempt.
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $user1->id);
     $attempt2 = quiz_create_attempt($quizobj2, 1, false, $timenow, false, $user2->id);
     $attempt3 = quiz_create_attempt($quizobj3, 1, false, $timenow, false, $user3->id);
     // Start the attempt.
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     quiz_start_new_attempt($quizobj2, $quba2, $attempt2, 1, $timenow);
     quiz_attempt_save_started($quizobj2, $quba2, $attempt2);
     quiz_start_new_attempt($quizobj3, $quba3, $attempt3, 1, $timenow);
     quiz_attempt_save_started($quizobj3, $quba3, $attempt3);
     // Answer first question and set it overdue.
     $tosubmit = array(1 => array('answer' => 'frog'));
     $tosubmit2 = array(1 => array('answer' => 'tiger'));
     $tosubmit3 = array(1 => array('answer' => 'tiger'));
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_submitted_actions($timenow, true, $tosubmit);
     $attemptobj2 = quiz_attempt::create($attempt2->id);
     $attemptobj2->process_submitted_actions($timenow, true, $tosubmit2);
     $attemptobj3 = quiz_attempt::create($attempt3->id);
     $attemptobj3->process_submitted_actions($timenow, true, $tosubmit3);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     $attemptobj->process_abandon($timenow, false);
     // Re-load quiz attempt2 data.
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj2 = quiz_attempt::create($attempt2->id);
     $attemptobj3 = quiz_attempt::create($attempt3->id);
     // Check that the state of the attempt is as expected.
     $this->assertEquals(1, $attemptobj->get_attempt_number());
     $this->assertEquals(quiz_attempt::ABANDONED, $attemptobj->get_state());
     $this->assertEquals($user1->id, $attemptobj->get_userid());
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     // Check that the state of the attempt2 is as expected.
     $this->assertEquals(1, $attemptobj2->get_attempt_number());
     $this->assertEquals(quiz_attempt::OVERDUE, $attemptobj2->get_state());
     $this->assertEquals($user2->id, $attemptobj2->get_userid());
     $this->assertTrue($attemptobj2->has_response_to_at_least_one_graded_question());
     // Check that the state of the attempt3 is as expected.
     $this->assertEquals(1, $attemptobj3->get_attempt_number());
     $this->assertEquals(quiz_attempt::OVERDUE, $attemptobj3->get_state());
     $this->assertEquals($user3->id, $attemptobj3->get_userid());
     $this->assertTrue($attemptobj3->has_response_to_at_least_one_graded_question());
     // Force submit the attempts.
     $overviewreport = new quiz_overview_report_testable();
     $overviewreport->forcesubmit_attempts($quiz, false, array(), array($attempt->id, $attempt3->id));
     // Check that it is now finished.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertEquals(quiz_attempt::FINISHED, $attemptobj->get_state());
     $attemptobj2 = quiz_attempt::create($attempt2->id);
     $this->assertEquals(quiz_attempt::OVERDUE, $attemptobj2->get_state());
     $attemptobj3 = quiz_attempt::create($attempt3->id);
     $this->assertEquals(quiz_attempt::FINISHED, $attemptobj3->get_state());
 }
Ejemplo n.º 2
0
 protected function prepare_quiz_data()
 {
     $this->resetAfterTest(true);
     // Create a course
     $course = $this->getDataGenerator()->create_course();
     // Make a quiz.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $quiz = $quizgenerator->create_instance(array('course' => $course->id, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 2));
     $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
     // Create a couple of questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     // Add them to the quiz.
     quiz_add_quiz_question($saq->id, $quiz);
     quiz_add_quiz_question($numq->id, $quiz);
     // Make a user to do the quiz.
     $user1 = $this->getDataGenerator()->create_user();
     $this->setUser($user1);
     $quizobj = quiz::create($quiz->id, $user1->id);
     // Start the attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     return array($quizobj, $quba, $attempt);
 }
Ejemplo n.º 3
0
 /**
  * Test update question flag
  */
 public function test_core_question_update_flag()
 {
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     // Create a question category.
     $cat = $questiongenerator->create_question_category();
     $quba = question_engine::make_questions_usage_by_activity('core_question_update_flag', context_system::instance());
     $quba->set_preferred_behaviour('deferredfeedback');
     $questiondata = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     $question = question_bank::load_question($questiondata->id);
     $slot = $quba->add_question($question);
     $qa = $quba->get_question_attempt($slot);
     self::setUser($this->student);
     $quba->start_all_questions();
     question_engine::save_questions_usage_by_activity($quba);
     $qubaid = $quba->get_id();
     $questionid = $question->id;
     $qaid = $qa->get_database_id();
     $checksum = md5($qubaid . "_" . $this->student->secret . "_" . $questionid . "_" . $qaid . "_" . $slot);
     $flag = core_question_external::update_flag($qubaid, $questionid, $qaid, $slot, $checksum, true);
     $this->assertTrue($flag['status']);
     // Test invalid checksum.
     try {
         // Using random_string to force failing.
         $checksum = md5($qubaid . "_" . random_string(11) . "_" . $questionid . "_" . $qaid . "_" . $slot);
         core_question_external::update_flag($qubaid, $questionid, $qaid, $slot, $checksum, true);
         $this->fail('Exception expected due to invalid checksum.');
     } catch (moodle_exception $e) {
         $this->assertEquals('errorsavingflags', $e->errorcode);
     }
 }
Ejemplo n.º 4
0
 /**
  * We create two usages, each with two questions, a short-answer marked
  * out of 5, and and essay marked out of 10. We just start these attempts.
  *
  * Then we change the max mark for the short-answer question in one of the
  * usages to 20, using a qubaid_list, and verify.
  *
  * Then we change the max mark for the essay question in the other
  * usage to 2, using a qubaid_join, and verify.
  */
 public function test_set_max_mark_in_attempts()
 {
     // Set up some things the tests will need.
     $this->resetAfterTest();
     $dm = new question_engine_data_mapper();
     // Create the questions.
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category();
     $sa = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $essay = $generator->create_question('essay', null, array('category' => $cat->id));
     // Create the first usage.
     $q = question_bank::load_question($sa->id);
     $this->start_attempt_at_question($q, 'interactive', 5);
     $q = question_bank::load_question($essay->id);
     $this->start_attempt_at_question($q, 'interactive', 10);
     $this->finish();
     $this->save_quba();
     $usage1id = $this->quba->get_id();
     // Create the second usage.
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', context_system::instance());
     $q = question_bank::load_question($sa->id);
     $this->start_attempt_at_question($q, 'interactive', 5);
     $this->process_submission(array('answer' => 'fish'));
     $q = question_bank::load_question($essay->id);
     $this->start_attempt_at_question($q, 'interactive', 10);
     $this->finish();
     $this->save_quba();
     $usage2id = $this->quba->get_id();
     // Test set_max_mark_in_attempts with a qubaid_list.
     $usagestoupdate = new qubaid_list(array($usage1id));
     $dm->set_max_mark_in_attempts($usagestoupdate, 1, 20.0);
     $quba1 = question_engine::load_questions_usage_by_activity($usage1id);
     $quba2 = question_engine::load_questions_usage_by_activity($usage2id);
     $this->assertEquals(20, $quba1->get_question_max_mark(1));
     $this->assertEquals(10, $quba1->get_question_max_mark(2));
     $this->assertEquals(5, $quba2->get_question_max_mark(1));
     $this->assertEquals(10, $quba2->get_question_max_mark(2));
     // Test set_max_mark_in_attempts with a qubaid_join.
     $usagestoupdate = new qubaid_join('{question_usages} qu', 'qu.id', 'qu.id = :usageid', array('usageid' => $usage2id));
     $dm->set_max_mark_in_attempts($usagestoupdate, 2, 2.0);
     $quba1 = question_engine::load_questions_usage_by_activity($usage1id);
     $quba2 = question_engine::load_questions_usage_by_activity($usage2id);
     $this->assertEquals(20, $quba1->get_question_max_mark(1));
     $this->assertEquals(10, $quba1->get_question_max_mark(2));
     $this->assertEquals(5, $quba2->get_question_max_mark(1));
     $this->assertEquals(2, $quba2->get_question_max_mark(2));
     // Test the nothing to do case.
     $usagestoupdate = new qubaid_join('{question_usages} qu', 'qu.id', 'qu.id = :usageid', array('usageid' => -1));
     $dm->set_max_mark_in_attempts($usagestoupdate, 2, 2.0);
     $quba1 = question_engine::load_questions_usage_by_activity($usage1id);
     $quba2 = question_engine::load_questions_usage_by_activity($usage2id);
     $this->assertEquals(20, $quba1->get_question_max_mark(1));
     $this->assertEquals(10, $quba1->get_question_max_mark(2));
     $this->assertEquals(5, $quba2->get_question_max_mark(1));
     $this->assertEquals(2, $quba2->get_question_max_mark(2));
 }
 protected function setUp()
 {
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', context_system::instance());
     $this->quba->set_preferred_behaviour('deferredfeedback');
     $slot = $this->quba->add_question(test_question_maker::make_question('description'));
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $slot = $this->quba->add_question(test_question_maker::make_question('description'));
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $this->iterator = $this->quba->get_attempt_iterator();
 }
 public function setUp()
 {
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', get_context_instance(CONTEXT_SYSTEM));
     $this->quba->set_preferred_behaviour('deferredfeedback');
     $slot = $this->quba->add_question(test_question_maker::make_a_description_question());
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $slot = $this->quba->add_question(test_question_maker::make_a_description_question());
     $this->qas[$slot] = $this->quba->get_question_attempt($slot);
     $this->iterator = $this->quba->get_attempt_iterator();
 }
 /**
  * Test the various methods that load data for reporting.
  *
  * Since these methods need an expensive set-up, and then only do read-only
  * operations on the data, we use a single method to do the set-up, which
  * calls diffents methods to test each query.
  */
 public function test_reporting_queries()
 {
     // We create two usages, each with two questions, a short-answer marked
     // out of 5, and and essay marked out of 10.
     //
     // In the first usage, the student answers the short-answer
     // question correctly, and enters something in the essay.
     //
     // In the second useage, the student answers the short-answer question
     // wrongly, and leaves the essay blank.
     $this->resetAfterTest();
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category();
     $this->sa = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $this->essay = $generator->create_question('essay', null, array('category' => $cat->id));
     $this->usageids = array();
     // Create the first usage.
     $q = question_bank::load_question($this->sa->id);
     $this->start_attempt_at_question($q, 'interactive', 5);
     $this->allslots[] = $this->slot;
     $this->process_submission(array('answer' => 'cat'));
     $this->process_submission(array('answer' => 'frog', '-submit' => 1));
     $q = question_bank::load_question($this->essay->id);
     $this->start_attempt_at_question($q, 'interactive', 10);
     $this->allslots[] = $this->slot;
     $this->process_submission(array('answer' => '<p>The cat sat on the mat.</p>', 'answerformat' => FORMAT_HTML));
     $this->finish();
     $this->save_quba();
     $this->usageids[] = $this->quba->get_id();
     // Create the second usage.
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', context_system::instance());
     $q = question_bank::load_question($this->sa->id);
     $this->start_attempt_at_question($q, 'interactive', 5);
     $this->process_submission(array('answer' => 'fish'));
     $q = question_bank::load_question($this->essay->id);
     $this->start_attempt_at_question($q, 'interactive', 10);
     $this->finish();
     $this->save_quba();
     $this->usageids[] = $this->quba->get_id();
     // Set up some things the tests will need.
     $this->dm = new question_engine_data_mapper();
     $this->bothusages = new qubaid_list($this->usageids);
     // Now test the various queries.
     $this->dotest_load_questions_usages_latest_steps();
     $this->dotest_load_questions_usages_question_state_summary();
     $this->dotest_load_questions_usages_where_question_in_state();
     $this->dotest_load_average_marks();
     $this->dotest_sum_usage_marks_subquery();
     $this->dotest_question_attempt_latest_state_view();
 }
Ejemplo n.º 8
0
 public function test_get_questions_from_categories_with_usage_counts()
 {
     $this->resetAfterTest();
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category();
     $questiondata1 = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $questiondata2 = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $questiondata3 = $generator->create_question('shortanswer', null, array('category' => $cat->id));
     $quba = question_engine::make_questions_usage_by_activity('test', context_system::instance());
     $quba->set_preferred_behaviour('deferredfeedback');
     $question1 = question_bank::load_question($questiondata1->id);
     $question3 = question_bank::load_question($questiondata3->id);
     $quba->add_question($question1);
     $quba->add_question($question1);
     $quba->add_question($question3);
     $quba->start_all_questions();
     question_engine::save_questions_usage_by_activity($quba);
     $this->assertEquals(array($questiondata2->id => 0, $questiondata3->id => 1, $questiondata1->id => 2), question_bank::get_finder()->get_questions_from_categories_with_usage_counts(array($cat->id), new qubaid_list(array($quba->get_id()))));
 }
 /**
  * Construct the class.  if a dbattempt object is passed in set it, otherwise initialize empty class
  *
  * @param questionmanager $questionmanager
  * @param \stdClass
  * @param \context_module $context
  */
 public function __construct($questionmanager, $dbattempt = null, $context = null)
 {
     $this->questionmanager = $questionmanager;
     $this->context = $context;
     // if empty create new attempt
     if (empty($dbattempt)) {
         $this->attempt = new \stdClass();
         // create a new quba since we're creating a new attempt
         $this->quba = \question_engine::make_questions_usage_by_activity('mod_activequiz', $this->questionmanager->getRTQ()->getContext());
         $this->quba->set_preferred_behaviour('immediatefeedback');
         $attemptlayout = $this->questionmanager->add_questions_to_quba($this->quba);
         // add the attempt layout to this instance
         $this->attempt->qubalayout = implode(',', $attemptlayout);
     } else {
         // else load it up in this class instance
         $this->attempt = $dbattempt;
         $this->quba = \question_engine::load_questions_usage_by_activity($this->attempt->questionengid);
     }
 }
Ejemplo n.º 10
0
 public function get_clone($qinstances)
 {
     // The new quba doesn't have to be cloned, so we can use the parent class.
     $newquba = question_engine::make_questions_usage_by_activity($this->owningcomponent, $this->context);
     $newquba->set_preferred_behaviour('immediatefeedback');
     foreach ($this->get_slots() as $slot) {
         $slotquestion = $this->get_question($slot);
         $attempt = $this->get_question_attempt($slot);
         // We have to check for the type because we might have old migrated templates
         // that could contain description questions.
         if ($slotquestion->get_type_name() == 'multichoice' || $slotquestion->get_type_name() == 'multichoiceset') {
             $order = $slotquestion->get_order($attempt);
             // Order of the answers.
             $order = implode(',', $order);
             $newslot = $newquba->add_question($slotquestion, $qinstances[$slotquestion->id]->maxmark);
             $qa = $newquba->get_question_attempt($newslot);
             $qa->start('immediatefeedback', 1, array('_order' => $order));
         }
     }
     question_engine::save_questions_usage_by_activity($newquba);
     return $newquba;
 }
 public function test_load_with_unnecessary_autosaved_data()
 {
     // The point here is that the somehow (probably due to two things
     // happening concurrently, we have autosaved data in the database that
     // has already been superceded by real data, so it should be ignored.
     // There is also a second lot of redundant data to delete.
     $records = new question_test_recordset(array(array('questionattemptid', 'contextid', 'questionusageid', 'slot', 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'maxfraction', 'flagged', 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', 'attemptstepid', 'sequencenumber', 'state', 'fraction', 'timecreated', 'userid', 'name', 'value'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 5, -2, 'complete', null, 1256233715, 1, 'answer', '0'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 4, -1, 'complete', null, 1256233715, 1, 'answer', '0'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'), array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0, 0.0, 1.0, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0')));
     $question = test_question_maker::make_question('truefalse', 'true');
     $question->id = -1;
     question_bank::start_unit_test();
     question_bank::load_test_question_data($question);
     $observer = new testable_question_engine_unit_of_work(question_engine::make_questions_usage_by_activity('unit_test', context_system::instance()));
     $qa = question_attempt::load_from_records($records, 1, $observer, 'deferredfeedback');
     question_bank::end_unit_test();
     $this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
     $this->assertEquals(3, $qa->get_num_steps());
     $this->assertFalse($qa->has_autosaved_step());
     $step = $qa->get_step(0);
     $this->assertEquals(question_state::$todo, $step->get_state());
     $this->assertNull($step->get_fraction());
     $this->assertEquals(1256233700, $step->get_timecreated());
     $this->assertEquals(1, $step->get_user_id());
     $this->assertEquals(array(), $step->get_all_data());
     $step = $qa->get_step(1);
     $this->assertEquals(question_state::$complete, $step->get_state());
     $this->assertNull($step->get_fraction());
     $this->assertEquals(1256233705, $step->get_timecreated());
     $this->assertEquals(1, $step->get_user_id());
     $this->assertEquals(array('answer' => '1'), $step->get_all_data());
     $step = $qa->get_step(2);
     $this->assertEquals(question_state::$complete, $step->get_state());
     $this->assertNull($step->get_fraction());
     $this->assertEquals(1256233710, $step->get_timecreated());
     $this->assertEquals(1, $step->get_user_id());
     $this->assertEquals(array('answer' => '0'), $step->get_all_data());
     $this->assertEquals(2, count($observer->get_steps_deleted()));
 }
Ejemplo n.º 12
0
 /**
  * Whether it is possible for another question to depend on this one finishing.
  * Note that the answer is not exact, because of random questions, and sometimes
  * questions cannot be depended upon because of quiz options.
  * @param int $slotnumber the index of the slot in question.
  * @return bool can this question finish naturally during the attempt?
  */
 public function can_finish_during_the_attempt($slotnumber)
 {
     if ($this->quizobj->get_quiz()->shufflequestions || $this->quizobj->get_navigation_method() == QUIZ_NAVMETHOD_SEQ) {
         return false;
     }
     if ($this->get_question_type_for_slot($slotnumber) == 'random') {
         return true;
     }
     if (isset($this->slotsinorder[$slotnumber]->canfinish)) {
         return $this->slotsinorder[$slotnumber]->canfinish;
     }
     $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $this->quizobj->get_context());
     $tempslot = $quba->add_question(\question_bank::load_question($this->slotsinorder[$slotnumber]->questionid));
     $quba->set_preferred_behaviour($this->quizobj->get_quiz()->preferredbehaviour);
     $quba->start_all_questions();
     $this->slotsinorder[$slotnumber]->canfinish = $quba->can_question_finish_during_attempt($tempslot);
     return $this->slotsinorder[$slotnumber]->canfinish;
 }
Ejemplo n.º 13
0
 /**
  * Test get_attempt_access_information
  */
 public function test_get_attempt_access_information()
 {
     global $DB;
     // Create a new quiz with attempts.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $data = array('course' => $this->course->id, 'sumgrades' => 2);
     $quiz = $quizgenerator->create_instance($data);
     // Create some questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     // Add new question types in the category (for the random one).
     $question = $questiongenerator->create_question('truefalse', null, array('category' => $cat->id));
     $question = $questiongenerator->create_question('essay', null, array('category' => $cat->id));
     $question = $questiongenerator->create_question('random', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $quizobj = quiz::create($quiz->id, $this->student->id);
     // Set grade to pass.
     $item = grade_item::fetch(array('courseid' => $this->course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null));
     $item->gradepass = 80;
     $item->update();
     $this->setUser($this->student);
     // Default restrictions (none).
     $result = mod_quiz_external::get_attempt_access_information($quiz->id);
     $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
     $expected = array('isfinished' => false, 'preventnewattemptreasons' => [], 'warnings' => []);
     $this->assertEquals($expected, $result);
     // Limited attempts.
     $quiz->attempts = 1;
     $DB->update_record('quiz', $quiz);
     // Now, do one attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $this->student->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     // Process some responses from the student.
     $attemptobj = quiz_attempt::create($attempt->id);
     $tosubmit = array(1 => array('answer' => '3.14'));
     $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     $attemptobj->process_finish($timenow, false);
     // Can we start a new attempt? We shall not!
     $result = mod_quiz_external::get_attempt_access_information($quiz->id, $attempt->id);
     $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
     // Now new attemps allowed.
     $this->assertCount(1, $result['preventnewattemptreasons']);
     $this->assertFalse($result['ispreflightcheckrequired']);
     $this->assertEquals(get_string('nomoreattempts', 'quiz'), $result['preventnewattemptreasons'][0]);
 }
Ejemplo n.º 14
0
 protected function setUp()
 {
     parent::setUp();
     $this->resetAfterTest(true);
     $this->displayoptions = new question_display_options();
     $this->quba = question_engine::make_questions_usage_by_activity('unit_test', context_system::instance());
 }
 /**
  * Creates a single printable copy of the given quiz.
  *
  * @return  The ID of the created printable question usage.
  *
  */
 protected function create_printable_copy($shuffle_mode = quiz_papercopy_shuffle_modes::MODE_SHUFFLE_IGNORE_PAGES, $fix_descriptions = false, $fix_first = false, $fix_last = false)
 {
     //get a reference to the current user
     global $USER;
     //create a new usage object, which will allow us to create a psuedoquiz in the same context as the online quiz
     $usage = question_engine::make_questions_usage_by_activity('mod_quiz', $this->context);
     //and set the grading mode to "deferred feedback", the standard for paper quizzes
     //this makes sense, since our paradigm is duriven by the idea that feedback is only offered once a paper quiz has been uploaded/graded
     $usage->set_preferred_behaviour('deferredfeedback');
     //get an array of questions in the current quiz
     $quiz_questions = $this->quizobj->get_questions();
     //randomize the question order, as requested
     $quiz_questions = self::shuffle_questions($quiz_questions, $this->quiz->questions, $shuffle_mode, $fix_descriptions, $fix_first, $fix_last);
     //for each question in our online quiz
     foreach ($quiz_questions as $slot => $qdata) {
         $question = question_bank::make_question($qdata);
         //add the new question instance to our new printable copy, keeping the maximum grade from the quiz
         //TODO: respect maximum marks
         $usage->add_question($question);
     }
     //initialize each of the questions
     $usage->start_all_questions();
     //save the usage to the database
     question_engine::save_questions_usage_by_activity($usage);
     //return the ID of the newly created questions usage
     return $usage->get_id();
 }
Ejemplo n.º 16
0
/**
 * Prepare and start a new attempt deleting the previous preview attempts.
 *
 * @param  quiz $quizobj quiz object
 * @param  int $attemptnumber the attempt number
 * @param  object $lastattempt last attempt object
 * @param bool $offlineattempt whether is an offline attempt or not
 * @return object the new attempt
 * @since  Moodle 3.1
 */
function quiz_prepare_and_start_new_attempt(quiz $quizobj, $attemptnumber, $lastattempt, $offlineattempt = false)
{
    global $DB, $USER;
    // Delete any previous preview attempts belonging to this user.
    quiz_delete_previews($quizobj->get_quiz(), $USER->id);
    $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
    $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
    // Create the new attempt and initialize the question sessions
    $timenow = time();
    // Update time now, in case the server is running really slowly.
    $attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow, $quizobj->is_preview_user());
    if (!($quizobj->get_quiz()->attemptonlast && $lastattempt)) {
        $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow);
    } else {
        $attempt = quiz_start_attempt_built_on_last($quba, $attempt, $lastattempt);
    }
    $transaction = $DB->start_delegated_transaction();
    // Init the timemodifiedoffline for offline attempts.
    if ($offlineattempt) {
        $attempt->timemodifiedoffline = $attempt->timemodified;
    }
    $attempt = quiz_attempt_save_started($quizobj, $quba, $attempt);
    $transaction->allow_commit();
    return $attempt;
}
Ejemplo n.º 17
0
        $quba = question_engine::load_questions_usage_by_activity($previewid);
    } catch (Exception $e) {
        print_error('submissionoutofsequencefriendlymessage', 'question',
                question_preview_url($question->id, $options->behaviour,
                $options->maxmark, $options), null, $e);
    }
    $slot = $quba->get_first_question_number();
    $usedquestion = $quba->get_question($slot);
    if ($usedquestion->id != $question->id) {
        print_error('questionidmismatch', 'question');
    }
    $question = $usedquestion;
    $options->variant = $quba->get_variant($slot);

} else {
    $quba = question_engine::make_questions_usage_by_activity('core_question_preview',
            get_context_instance_by_id($category->contextid));
    $quba->set_preferred_behaviour($options->behaviour);
    $slot = $quba->add_question($question, $options->maxmark);

    if ($options->variant) {
        $options->variant = min($maxvariant, max(1, $options->variant));
    } else {
        $options->variant = rand(1, $maxvariant);
    }

    $quba->start_question($slot, $options->variant);

    $transaction = $DB->start_delegated_transaction();
    question_engine::save_questions_usage_by_activity($quba);
    $transaction->allow_commit();
Ejemplo n.º 18
0
function emarking_add_user_attempt($cm, $user)
{
    global $DB;
    // Get the quiz object
    $quizobj = quiz::create($cm->instance, $user->id);
    // TODO get to know what usage by activity means
    $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
    $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
    // Create the new attempt and initialize the question sessions
    $attemptnumber = 1;
    $lastattempt = null;
    $timenow = time();
    // Update time now, in case the server is running really slowly.
    $attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow, false, $user->id);
    $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow);
    $transaction = $DB->start_delegated_transaction();
    $attempt = quiz_attempt_save_started($quizobj, $quba, $attempt);
    $DB->commit_delegated_transaction($transaction);
}
Ejemplo n.º 19
0
    public function test_deferred_feedback_plain_attempt_on_last() {
        global $CFG, $USER;

        $this->resetAfterTest(true);
        $this->setAdminUser();
        $usercontextid = context_user::instance($USER->id)->id;

        // Create an essay question in the DB.
        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
        $cat = $generator->create_question_category();
        $question = $generator->create_question('essay', 'plain', array('category' => $cat->id));

        // Start attempt at the question.
        $q = question_bank::load_question($question->id);
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);

        $this->check_current_state(question_state::$todo);
        $this->check_current_mark(null);
        $this->check_step_count(1);

        // Process a response and check the expected result.

        $this->process_submission(array(
            'answer' => 'Once upon a time there was a frog called Freddy. He lived happily ever after.',
            'answerformat' => FORMAT_PLAIN,
        ));

        $this->check_current_state(question_state::$complete);
        $this->check_current_mark(null);
        $this->check_step_count(2);
        $this->save_quba();

        // Now submit all and finish.
        $this->finish();
        $this->check_current_state(question_state::$needsgrading);
        $this->check_current_mark(null);
        $this->check_step_count(3);
        $this->save_quba();

        // Now start a new attempt based on the old one.
        $this->load_quba();
        $oldqa = $this->get_question_attempt();

        $q = question_bank::load_question($question->id);
        $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
                context_system::instance());
        $this->quba->set_preferred_behaviour('deferredfeedback');
        $this->slot = $this->quba->add_question($q, 1);
        $this->quba->start_question_based_on($this->slot, $oldqa);

        $this->check_current_state(question_state::$complete);
        $this->check_current_mark(null);
        $this->check_step_count(1);
        $this->save_quba();

        // Check the display.
        $this->load_quba();
        $this->render();
        // Test taht no HTML comment has been added to the response.
        $this->assertRegExp('/Once upon a time there was a frog called Freddy. He lived happily ever after.(?!&lt;!--)/', $this->currentoutput);
        // Test for the hash of an empty file area.
        $this->assertNotContains('d41d8cd98f00b204e9800998ecf8427e', $this->currentoutput);
    }
Ejemplo n.º 20
0
            if (empty($quizobj->get_quiz()->showblocks)) {
                $PAGE->blocks->show_only_fake_blocks();
            }
            echo $output->start_attempt_page($quizobj, $mform);
            die;
        }
    }
    // Pre-flight check passed.
    $accessmanager->notify_preflight_check_passed($currentattemptid);
}
if ($currentattemptid) {
    redirect($quizobj->attempt_url($currentattemptid, $page));
}
// Delete any previous preview attempts belonging to this user.
quiz_delete_previews($quizobj->get_quiz(), $USER->id);
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
// Create the new attempt and initialize the question sessions
$timenow = time();
// Update time now, in case the server is running really slowly.
$attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow, $quizobj->is_preview_user());
if (!($quizobj->get_quiz()->attemptonlast && $lastattempt)) {
    // Starting a normal, new, quiz attempt.
    // Fully load all the questions in this quiz.
    $quizobj->preload_questions();
    $quizobj->load_questions();
    // Add them all to the $quba.
    $idstoslots = array();
    $questionsinuse = array_keys($quizobj->get_questions());
    foreach ($quizobj->get_questions() as $i => $questiondata) {
        if ($questiondata->qtype != 'random') {
Ejemplo n.º 21
0
    public function test_access_out_of_sequence_throws_exception() {
        // Start a deferred feedback attempt with CBM and add the question to it.
        $tf = test_question_maker::make_question('truefalse', 'true');
        $quba = question_engine::make_questions_usage_by_activity('unit_test',
                context_system::instance());
        $quba->set_preferred_behaviour('deferredcbm');
        $slot = $quba->add_question($tf);
        $quba->start_all_questions();

        // Prepare data to be submitted
        $prefix = $quba->get_field_prefix($slot);
        $answername = $prefix . 'answer';
        $certaintyname = $prefix . '-certainty';
        $postdata = array(
            $answername => 1,
            $certaintyname => 3,
            $prefix . ':sequencecheck' => 1,
            'irrelevant' => 'should be ignored',
        );

        // Exercise SUT - no exception yet.
        $quba->process_all_actions($slot, $postdata);

        $postdata = array(
            $answername => 1,
            $certaintyname => 3,
            $prefix . ':sequencecheck' => 3,
            'irrelevant' => 'should be ignored',
        );

        // Exercise SUT - now it should fail.
        $this->setExpectedException('question_out_of_sequence_exception');
        $quba->process_all_actions($slot, $postdata);
    }
Ejemplo n.º 22
0
 /**
  * Utility method to submit an attempt on a quiz.
  * @param $quiz
  * @param $user
  * @param $answers
  * @return testable_assign
  */
 private function submit_quiz_attempt($quiz, $user, $answers)
 {
     // Create a quiz attempt for the user.
     $quizobj = quiz::create($quiz->id, $user->id);
     // Set up and start an attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $user->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_submitted_actions($timenow, false, $answers);
     $timefinish = time();
     // Finish the attempt.
     $attemptobj->process_finish($timefinish, false);
     return $timefinish;
 }
 /**
  * Starts an attempt and returns the object representing it.
  *
  * @param int $quizid
  * @param int $userid
  * @throws moodle_exception
  * @return \stdClass
  */
 public function start_quiz_attempt($quizid, $userid)
 {
     global $DB;
     $quizobj = quiz::create($quizid, $userid);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj->get_quiz(), 1, false, $timenow, false);
     // Taken from /mod/quiz/startattempt.php.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     // Starting a normal, new, quiz attempt.
     // Fully load all the questions in this quiz.
     $quizobj->preload_questions();
     $quizobj->load_questions();
     // Add them all to the $quba.
     $idstoslots = array();
     $questionsinuse = array_keys($quizobj->get_questions());
     foreach ($quizobj->get_questions() as $i => $questiondata) {
         if ($questiondata->qtype != 'random') {
             if (!$quizobj->get_quiz()->shuffleanswers) {
                 $questiondata->options->shuffleanswers = false;
             }
             $question = question_bank::make_question($questiondata);
         } else {
             $question = question_bank::get_qtype('random')->choose_other_question($questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers);
             if (is_null($question)) {
                 throw new moodle_exception('notenoughrandomquestions', 'quiz', $quizobj->view_url(), $questiondata);
             }
         }
         $idstoslots[$i] = $quba->add_question($question, $questiondata->maxmark);
         $questionsinuse[] = $question->id;
     }
     // Start all the questions.
     if ($attempt->preview) {
         $variantoffset = rand(1, 100);
     } else {
         $variantoffset = 1;
     }
     $quba->start_all_questions(new question_variant_pseudorandom_no_repeats_strategy($variantoffset), $timenow);
     // Update attempt layout.
     $newlayout = array();
     foreach (explode(',', $attempt->layout) as $qid) {
         if ($qid != 0) {
             $newlayout[] = $idstoslots[$qid];
         } else {
             $newlayout[] = 0;
         }
     }
     $attempt->layout = implode(',', $newlayout);
     question_engine::save_questions_usage_by_activity($quba);
     $attempt->uniqueid = $quba->get_id();
     $attempt->id = $DB->insert_record('quiz_attempts', $attempt);
     return $attempt;
 }
Ejemplo n.º 24
0
        // This may not seem like the right error message to display, but
        // actually from the user point of view, it makes sense.
        print_error('submissionoutofsequencefriendlymessage', 'question', question_preview_url($question->id, $options->behaviour, $options->maxmark, $options, $options->variant, $context), null, $e);
    }
    if ($quba->get_owning_context()->instanceid != $USER->id) {
        print_error('notyourpreview', 'question');
    }
    $slot = $quba->get_first_question_number();
    $usedquestion = $quba->get_question($slot);
    if ($usedquestion->id != $question->id) {
        print_error('questionidmismatch', 'question');
    }
    $question = $usedquestion;
    $options->variant = $quba->get_variant($slot);
} else {
    $quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_user::instance($USER->id));
    $quba->set_preferred_behaviour($options->behaviour);
    $slot = $quba->add_question($question, $options->maxmark);
    if ($options->variant) {
        $options->variant = min($maxvariant, max(1, $options->variant));
    } else {
        $options->variant = rand(1, $maxvariant);
    }
    $quba->start_question($slot, $options->variant);
    $transaction = $DB->start_delegated_transaction();
    question_engine::save_questions_usage_by_activity($quba);
    $transaction->allow_commit();
}
$options->behaviour = $quba->get_preferred_behaviour();
$options->maxmark = $quba->get_question_max_mark($slot);
// Create the settings form, and initialise the fields.
Ejemplo n.º 25
0
 /**
  * Test checking the completion state of a quiz.
  */
 public function test_quiz_get_completion_state()
 {
     global $CFG, $DB;
     $this->resetAfterTest(true);
     // Enable completion before creating modules, otherwise the completion data is not written in DB.
     $CFG->enablecompletion = true;
     // Create a course and student.
     $course = $this->getDataGenerator()->create_course(array('enablecompletion' => true));
     $passstudent = $this->getDataGenerator()->create_user();
     $failstudent = $this->getDataGenerator()->create_user();
     $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     $this->assertNotEmpty($studentrole);
     // Enrol students.
     $this->assertTrue($this->getDataGenerator()->enrol_user($passstudent->id, $course->id, $studentrole->id));
     $this->assertTrue($this->getDataGenerator()->enrol_user($failstudent->id, $course->id, $studentrole->id));
     // Make a scale and an outcome.
     $scale = $this->getDataGenerator()->create_scale();
     $data = array('courseid' => $course->id, 'fullname' => 'Team work', 'shortname' => 'Team work', 'scaleid' => $scale->id);
     $outcome = $this->getDataGenerator()->create_grade_outcome($data);
     // Make a quiz with the outcome on.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $data = array('course' => $course->id, 'outcome_' . $outcome->id => 1, 'grade' => 100.0, 'questionsperpage' => 0, 'sumgrades' => 1, 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionpass' => 1);
     $quiz = $quizgenerator->create_instance($data);
     $cm = get_coursemodule_from_id('quiz', $quiz->cmid);
     // Create a couple of questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     quiz_add_quiz_question($question->id, $quiz);
     $quizobj = quiz::create($quiz->id, $passstudent->id);
     // Set grade to pass.
     $item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod', 'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null));
     $item->gradepass = 80;
     $item->update();
     // Start the passing attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $passstudent->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     // Process some responses from the student.
     $attemptobj = quiz_attempt::create($attempt->id);
     $tosubmit = array(1 => array('answer' => '3.14'));
     $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     $attemptobj->process_finish($timenow, false);
     // Start the failing attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $failstudent->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     // Process some responses from the student.
     $attemptobj = quiz_attempt::create($attempt->id);
     $tosubmit = array(1 => array('answer' => '0'));
     $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
     $attemptobj->process_finish($timenow, false);
     // Check the results.
     $this->assertTrue(quiz_get_completion_state($course, $cm, $passstudent->id, 'return'));
     $this->assertFalse(quiz_get_completion_state($course, $cm, $failstudent->id, 'return'));
 }
Ejemplo n.º 26
0
    try {
        $quba = question_engine::load_questions_usage_by_activity($previewid);
    } catch (Exception $e) {
        // This may not seem like the right error message to display, but
        // actually from the user point of view, it makes sense.
        print_error('submissionoutofsequencefriendlymessage', 'question', question_preview_url($question->id, $options->behaviour, $options->maxmark, $options, $options->variant, $context), null, $e);
    }
    $slot = $quba->get_first_question_number();
    $usedquestion = $quba->get_question($slot);
    if ($usedquestion->id != $question->id) {
        print_error('questionidmismatch', 'question');
    }
    $question = $usedquestion;
    $options->variant = $quba->get_variant($slot);
} else {
    $quba = question_engine::make_questions_usage_by_activity('core_question_preview', $context);
    $quba->set_preferred_behaviour($options->behaviour);
    $slot = $quba->add_question($question, $options->maxmark);
    if ($options->variant) {
        $options->variant = min($maxvariant, max(1, $options->variant));
    } else {
        $options->variant = rand(1, $maxvariant);
    }
    $quba->start_question($slot, $options->variant);
    $transaction = $DB->start_delegated_transaction();
    question_engine::save_questions_usage_by_activity($quba);
    $transaction->allow_commit();
    $SESSION->question_previews[$quba->get_id()] = true;
}
$options->behaviour = $quba->get_preferred_behaviour();
$options->maxmark = $quba->get_question_max_mark($slot);
Ejemplo n.º 27
0
 public function test_quiz_get_user_attempts()
 {
     global $DB;
     $this->resetAfterTest();
     $dg = $this->getDataGenerator();
     $quizgen = $dg->get_plugin_generator('mod_quiz');
     $course = $dg->create_course();
     $u1 = $dg->create_user();
     $u2 = $dg->create_user();
     $u3 = $dg->create_user();
     $u4 = $dg->create_user();
     $role = $DB->get_record('role', ['shortname' => 'student']);
     $dg->enrol_user($u1->id, $course->id, $role->id);
     $dg->enrol_user($u2->id, $course->id, $role->id);
     $dg->enrol_user($u3->id, $course->id, $role->id);
     $dg->enrol_user($u4->id, $course->id, $role->id);
     $quiz1 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
     $quiz2 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]);
     // Questions.
     $questgen = $dg->get_plugin_generator('core_question');
     $quizcat = $questgen->create_question_category();
     $question = $questgen->create_question('numerical', null, ['category' => $quizcat->id]);
     quiz_add_quiz_question($question->id, $quiz1);
     quiz_add_quiz_question($question->id, $quiz2);
     $quizobj1a = quiz::create($quiz1->id, $u1->id);
     $quizobj1b = quiz::create($quiz1->id, $u2->id);
     $quizobj1c = quiz::create($quiz1->id, $u3->id);
     $quizobj1d = quiz::create($quiz1->id, $u4->id);
     $quizobj2a = quiz::create($quiz2->id, $u1->id);
     // Set attempts.
     $quba1a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1a->get_context());
     $quba1a->set_preferred_behaviour($quizobj1a->get_quiz()->preferredbehaviour);
     $quba1b = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1b->get_context());
     $quba1b->set_preferred_behaviour($quizobj1b->get_quiz()->preferredbehaviour);
     $quba1c = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1c->get_context());
     $quba1c->set_preferred_behaviour($quizobj1c->get_quiz()->preferredbehaviour);
     $quba1d = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1d->get_context());
     $quba1d->set_preferred_behaviour($quizobj1d->get_quiz()->preferredbehaviour);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $timenow = time();
     // User 1 passes quiz 1.
     $attempt = quiz_create_attempt($quizobj1a, 1, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj1a, $quba1a, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1a, $quba1a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_submitted_actions($timenow, false, [1 => ['answer' => '3.14']]);
     $attemptobj->process_finish($timenow, false);
     // User 2 goes overdue in quiz 1.
     $attempt = quiz_create_attempt($quizobj1b, 1, false, $timenow, false, $u2->id);
     quiz_start_new_attempt($quizobj1b, $quba1b, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1b, $quba1b, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_going_overdue($timenow, true);
     // User 3 does not finish quiz 1.
     $attempt = quiz_create_attempt($quizobj1c, 1, false, $timenow, false, $u3->id);
     quiz_start_new_attempt($quizobj1c, $quba1c, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1c, $quba1c, $attempt);
     // User 4 abandons the quiz 1.
     $attempt = quiz_create_attempt($quizobj1d, 1, false, $timenow, false, $u4->id);
     quiz_start_new_attempt($quizobj1d, $quba1d, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj1d, $quba1d, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_abandon($timenow, true);
     // User 1 attempts the quiz three times (abandon, finish, in progress).
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 1, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_abandon($timenow, true);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 2, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 2, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_finish($timenow, false);
     $quba2a = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context());
     $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour);
     $attempt = quiz_create_attempt($quizobj2a, 3, false, $timenow, false, $u1->id);
     quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 3, $timenow);
     quiz_attempt_save_started($quizobj2a, $quba2a, $attempt);
     // Check for user 1.
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'finished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'unfinished');
     $this->assertCount(0, $attempts);
     // Check for user 2.
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
     $this->assertEquals($u2->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'finished');
     $this->assertCount(0, $attempts);
     $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state);
     $this->assertEquals($u2->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     // Check for user 3.
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u3->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'finished');
     $this->assertCount(0, $attempts);
     $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u3->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     // Check for user 4.
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'all');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u4->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'finished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u4->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'unfinished');
     $this->assertCount(0, $attempts);
     // Multiple attempts for user 1 in quiz 2.
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'all');
     $this->assertCount(3, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'finished');
     $this->assertCount(2, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'unfinished');
     $this->assertCount(1, $attempts);
     $attempt = array_shift($attempts);
     // Multiple quiz attempts fetched at once.
     $attempts = quiz_get_user_attempts([$quiz1->id, $quiz2->id], $u1->id, 'all');
     $this->assertCount(4, $attempts);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz1->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::FINISHED, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
     $attempt = array_shift($attempts);
     $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state);
     $this->assertEquals($u1->id, $attempt->userid);
     $this->assertEquals($quiz2->id, $attempt->quiz);
 }
Ejemplo n.º 28
0
 /**
  * This function is a copy of code taken from attempt_walkthrough_test.php
  * that creates a sample quiz and has a student complete the quiz.
  *
  * If the test suddenly stops working, grab the new code from that file, then
  * adjust to required inputs/outputs.
  *
  * @param object $course The course object to create the quiz in
  * @param object $student The student object that takes the quiz
  * @return array {attempt ID (int), quiz ID (int)}
  *
  */
 private function create_quiz_attempt($course, $student)
 {
     // Make a quiz.
     $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
     $quiz = $quizgenerator->create_instance(array('course' => $course->id, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 2));
     // Create a couple of questions.
     $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $questiongenerator->create_question_category();
     $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
     $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
     // Add them to the quiz.
     quiz_add_quiz_question($saq->id, $quiz);
     quiz_add_quiz_question($numq->id, $quiz);
     $quizobj = quiz::create($quiz->id, $student->id);
     // Start the attempt.
     $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
     $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
     $timenow = time();
     $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id);
     quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
     quiz_attempt_save_started($quizobj, $quba, $attempt);
     // Process some responses from the student.
     $attemptobj = quiz_attempt::create($attempt->id);
     $prefix1 = $quba->get_field_prefix(1);
     $prefix2 = $quba->get_field_prefix(2);
     $tosubmit = array(1 => array('answer' => 'frog'), 2 => array('answer' => '3.14'));
     $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
     // Finish the attempt.
     $attemptobj = quiz_attempt::create($attempt->id);
     $attemptobj->process_finish($timenow, false);
     // Re-load quiz attempt data.
     $attemptobj = quiz_attempt::create($attempt->id);
     return array($attempt->id, $quiz->id);
 }
Ejemplo n.º 29
0
 while ($failedattempts < $maxfailedattempts && $numberdeployed < $deploy) {
     // Genrate a new seed.
     $seed = mt_rand();
     $variantdeployed = false;
     // Reload the question to ensure any new deployed version is included.
     $question = question_bank::load_question($questionid);
     $question->seed = (int) $seed;
     $quba = question_engine::make_questions_usage_by_activity('qtype_stack', $context);
     $quba->set_preferred_behaviour('adaptive');
     $slot = $quba->add_question($question, $question->defaultmark);
     $quba->start_question($slot);
     foreach ($question->deployedseeds as $key => $deployedseed) {
         $qn = question_bank::load_question($questionid);
         $qn->seed = (int) $deployedseed;
         $cn = $qn->get_context();
         $qunote = question_engine::make_questions_usage_by_activity('qtype_stack', $cn);
         $qunote->set_preferred_behaviour('adaptive');
         $slotnote = $qunote->add_question($qn, $qn->defaultmark);
         $qunote->start_question($slotnote);
         // Check if the question note has already been deployed.
         if ($qn->get_question_summary() == $question->get_question_summary()) {
             $variantdeployed = true;
             $failedattempts++;
         }
     }
     if (!$variantdeployed) {
         // Load the list of test cases.
         $testscases = question_bank::get_qtype('stack')->load_question_tests($question->id);
         // Exectue the tests.
         $testresults = array();
         $allpassed = true;
Ejemplo n.º 30
0
    /**
     * Create a quiz with a single question with variants and walk through quiz attempts.
     *
     * @dataProvider get_correct_response_for_variants
     */
    public function test_quiz_with_question_with_variants_attempt_walkthrough($variantno, $correctresponse, $done = false) {
        global $SITE;

        $this->resetAfterTest($done);

        $this->setAdminUser();

        if ($this->quizwithvariants === null) {
            // Make a quiz.
            $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');

            $this->quizwithvariants = $quizgenerator->create_instance(array('course'=>$SITE->id,
                                                                            'questionsperpage' => 0,
                                                                            'grade' => 100.0,
                                                                            'sumgrades' => 1));

            $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');

            $cat = $questiongenerator->create_question_category();
            $calc = $questiongenerator->create_question('calculatedsimple', 'sumwithvariants', array('category' => $cat->id));
            quiz_add_quiz_question($calc->id, $this->quizwithvariants, 0);
        }


        // Make a new user to do the quiz.
        $user1 = $this->getDataGenerator()->create_user();
        $this->setUser($user1);
        $quizobj = quiz::create($this->quizwithvariants->id, $user1->id);

        // Start the attempt.
        $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
        $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);

        $timenow = time();
        $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);

        // Select variant.
        quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow, array(), array(1 => $variantno));
        $this->assertEquals('1,0', $attempt->layout);
        quiz_attempt_save_started($quizobj, $quba, $attempt);

        // Process some responses from the student.
        $attemptobj = quiz_attempt::create($attempt->id);
        $tosubmit = array(1 => array('answer' => $correctresponse));
        $attemptobj->process_submitted_actions($timenow, false, $tosubmit);

        // Finish the attempt.
        $attemptobj = quiz_attempt::create($attempt->id);
        $attemptobj->process_finish($timenow, false);

        // Re-load quiz attempt data.
        $attemptobj = quiz_attempt::create($attempt->id);

        // Check that results are stored as expected.
        $this->assertEquals(1, $attemptobj->get_attempt_number());
        $this->assertEquals(1, $attemptobj->get_sum_marks());
        $this->assertEquals(true, $attemptobj->is_finished());
        $this->assertEquals($timenow, $attemptobj->get_submitted_date());
        $this->assertEquals($user1->id, $attemptobj->get_userid());

        // Check quiz grades.
        $grades = quiz_get_user_grades($this->quizwithvariants, $user1->id);
        $grade = array_shift($grades);
        $this->assertEquals(100.0, $grade->rawgrade);

        // Check grade book.
        $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $this->quizwithvariants->id, $user1->id);
        $gradebookitem = array_shift($gradebookgrades->items);
        $gradebookgrade = array_shift($gradebookitem->grades);
        $this->assertEquals(100, $gradebookgrade->grade);
    }