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()); }
/** * Put the specified questions on the specified pages of a given quiz. * * Give the question name in the first column, and that page number in the * second column. You may optionally give the desired maximum mark for each * question in a third column. * * @param string $quizname the name of the quiz to add questions to. * @param TableNode $data information about the questions to add. * * @Given /^quiz "([^"]*)" contains the following questions:$/ */ public function quiz_contains_the_following_questions($quizname, TableNode $data) { global $DB; $quiz = $DB->get_record('quiz', array('name' => $quizname), '*', MUST_EXIST); // The action depends on the field type. foreach ($data->getRows() as $questiondata) { if (count($questiondata) < 2 || count($questiondata) > 3) { throw new ExpectationException('When adding questions to a quiz, you should give 2 or three 3 things: ' . ' the question name, the page number, and optionally a the maxiumum mark. ' . count($questiondata) . ' values passed.', $this->getSession()); } list($questionname, $rawpage) = $questiondata; if (!isset($questiondata[2]) || $questiondata[2] === '') { $maxmark = null; } else { $maxmark = clean_param($questiondata[2], PARAM_FLOAT); if (!is_numeric($questiondata[2]) || $maxmark < 0) { throw new ExpectationException('When adding questions to a quiz, the max mark must be a positive number.', $this->getSession()); } } $page = clean_param($rawpage, PARAM_INT); if ($page <= 0 || (string) $page !== $rawpage) { throw new ExpectationException('When adding questions to a quiz, the page number must be a positive integer.', $this->getSession()); } $questionid = $DB->get_field('question', 'id', array('name' => $questionname), MUST_EXIST); quiz_add_quiz_question($questionid, $quiz, $page, $maxmark); } quiz_update_sumgrades($quiz); }
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); }
/** * Utility method to add a quiz to a course. * @param $course * @return testable_assign */ private function add_quiz_to_course($course) { // Add a quiz to the course. $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 using test data in mod_quiz. $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); return $quiz; }
/** * Setup a course, a quiz, a question category and a question for testing. * * @param string $type The type of question category to create. * @return array The created data objects */ public function setup_quiz_and_questions($type = 'module') { // Create course category. $category = $this->getDataGenerator()->create_category(); // Create course. $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); $options = array('course' => $course->id, 'duedate' => time()); // Generate an assignment with due date (will generate a course event). $quiz = $this->getDataGenerator()->create_module('quiz', $options); $qgen = $this->getDataGenerator()->get_plugin_generator('core_question'); if ('course' == $type) { $context = context_course::instance($course->id); } else { if ('category' == $type) { $context = context_coursecat::instance($category->id); } else { $context = context_module::instance($quiz->cmid); } } $qcat = $qgen->create_question_category(array('contextid' => $context->id)); $questions = array($qgen->create_question('shortanswer', null, array('category' => $qcat->id)), $qgen->create_question('shortanswer', null, array('category' => $qcat->id))); quiz_add_quiz_question($questions[0]->id, $quiz); return array($category, $course, $quiz, $qcat, $questions); }
// on whether to include questions in subcategories $form->questiontextformat = 0; $form->image = ''; $form->defaultgrade = 1; $form->hidden = 1; for ($i = 0; $i < $randomcount; $i++) { $form->category = "{$category->id},{$category->contextid}"; $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed) $question = new stdClass(); $question->qtype = RANDOM; $question = $QTYPES[RANDOM]->save_question($question, $form, $course); if (!isset($question->id)) { error('Could not insert new random question!'); } quiz_add_quiz_question($question->id, $quiz); } } $significantchangemade = true; } if (optional_param('repaginate', false, PARAM_BOOL) and confirm_sesskey()) { /// Re-paginate the quiz $questionsperpage = optional_param('questionsperpage', $quiz->questionsperpage, PARAM_INT); if ($questionsperpage != $quiz->questionsperpage) { $quiz->questionsperpage = $questionsperpage; if (!set_field('quiz', 'questionsperpage', $quiz->questionsperpage, 'id', $quiz->id)) { error('Could not save number of questions per page'); } } $quiz->questions = quiz_repaginate($quiz->questions, $quiz->questionsperpage); if (!set_field('quiz', 'questions', $quiz->questions, 'id', $quiz->id)) {
$questions[$courseid][] = $question->generate_test("question{$qtype}-{$i}", $courseid); verbose("Generated a question of type {$qtype} for course id {$courseid}."); } } // Assign questions to quizzes, if such exist if (!empty($quizzes) && !empty($questions) && !empty($settings['questions-per-quiz'])) { // Cannot assign more questions per quiz than are available, so determine which is the largest $questions_per_quiz = max(count($questions), $settings['questions-per-quiz']); foreach ($quizzes as $quiz) { $questions_added = array(); for ($i = 0; $i < $questions_per_quiz; $i++) { // Add a random question to the quiz do { $random = rand(0, count($questions[$quiz->course])); } while (in_array($random, $questions_added) || !array_key_exists($random, $questions[$quiz->course])); if (!quiz_add_quiz_question($questions[$quiz->course][$random]->id, $quiz)) { // Could not add question to quiz!! report error echo "WARNING: Could not add question id {$random} to quiz id {$quiz->id}{$settings['eolchar']}"; } else { verbose("Adding question id {$random} to quiz id {$quiz->id}."); $questions_added[] = $random; } } } } } /** * ROLE ASSIGNMENTS */ if (count($courses) > 0) { verbose("Inserting student->course role assignments...");
$form->questiontextformat = 0; $form->image = ''; $form->defaultgrade = 1; $form->hidden = 1; for ($i = 0; $i < $randomcount; $i++) { $form->category = $category->id . ',' . $category->contextid; $form->stamp = make_unique_id_code(); // Set the unique //code (not to be changed) $question = new stdClass(); $question->qtype = RANDOM; $question = $QTYPES[RANDOM]->save_question($question, $form, $course); if (!isset($question->id)) { print_error('cannotinsertrandomquestion', 'quiz'); } quiz_add_quiz_question($question->id, $quiz, $addonpage); } } quiz_update_sumgrades($quiz); quiz_delete_previews($quiz); redirect($thispageurl->out()); } if (optional_param('addnewpagesafterselected', null) && !empty($selectedquestionids) && confirm_sesskey()) { foreach ($selectedquestionids as $questionid) { $quiz->questions = quiz_add_page_break_after($quiz->questions, $questionid); } quiz_save_new_layout($quiz); redirect($thispageurl->out()); } $addpage = optional_param('addpage', false, PARAM_INT); if ($addpage !== false && confirm_sesskey()) {
/** * This adds a particular question to the supplied quiz. Based on /mod/quiz/edit.php * * @param int $questionid * @param stdClass $quiz * @return void */ public function add_question_to_quiz($questionid, $quiz) { quiz_require_question_use($questionid); quiz_add_quiz_question($questionid, $quiz, 0); quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); }
public function test_question_remove_stale_questions_from_category() { global $DB; $this->resetAfterTest(true); $dg = $this->getDataGenerator(); $course = $dg->create_course(); $quiz = $dg->create_module('quiz', ['course' => $course->id]); $qgen = $dg->get_plugin_generator('core_question'); $context = context_system::instance(); $qcat1 = $qgen->create_question_category(['contextid' => $context->id]); $q1a = $qgen->create_question('shortanswer', null, ['category' => $qcat1->id]); // Will be hidden. $q1b = $qgen->create_question('random', null, ['category' => $qcat1->id]); // Will not be used. $DB->set_field('question', 'hidden', 1, ['id' => $q1a->id]); $qcat2 = $qgen->create_question_category(['contextid' => $context->id]); $q2a = $qgen->create_question('shortanswer', null, ['category' => $qcat2->id]); // Will be hidden. $q2b = $qgen->create_question('shortanswer', null, ['category' => $qcat2->id]); // Will be hidden but used. $q2c = $qgen->create_question('random', null, ['category' => $qcat2->id]); // Will not be used. $q2d = $qgen->create_question('random', null, ['category' => $qcat2->id]); // Will be used. $DB->set_field('question', 'hidden', 1, ['id' => $q2a->id]); $DB->set_field('question', 'hidden', 1, ['id' => $q2b->id]); quiz_add_quiz_question($q2b->id, $quiz); quiz_add_quiz_question($q2d->id, $quiz); $this->assertEquals(2, $DB->count_records('question', ['category' => $qcat1->id])); $this->assertEquals(4, $DB->count_records('question', ['category' => $qcat2->id])); // Non-existing category, nothing will happen. question_remove_stale_questions_from_category(0); $this->assertEquals(2, $DB->count_records('question', ['category' => $qcat1->id])); $this->assertEquals(4, $DB->count_records('question', ['category' => $qcat2->id])); // First category, should be empty afterwards. question_remove_stale_questions_from_category($qcat1->id); $this->assertEquals(0, $DB->count_records('question', ['category' => $qcat1->id])); $this->assertEquals(4, $DB->count_records('question', ['category' => $qcat2->id])); $this->assertFalse($DB->record_exists('question', ['id' => $q1a->id])); $this->assertFalse($DB->record_exists('question', ['id' => $q1b->id])); // Second category, used questions should be left untouched. question_remove_stale_questions_from_category($qcat2->id); $this->assertEquals(0, $DB->count_records('question', ['category' => $qcat1->id])); $this->assertEquals(2, $DB->count_records('question', ['category' => $qcat2->id])); $this->assertFalse($DB->record_exists('question', ['id' => $q2a->id])); $this->assertTrue($DB->record_exists('question', ['id' => $q2b->id])); $this->assertFalse($DB->record_exists('question', ['id' => $q2c->id])); $this->assertTrue($DB->record_exists('question', ['id' => $q2d->id])); }
/** * Test deleting a quiz instance. */ public function test_quiz_delete_instance() { global $SITE, $DB; $this->resetAfterTest(true); $this->setAdminUser(); // Setup a quiz with 1 standard and 1 random question. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0)); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $standardq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id)); quiz_add_quiz_question($standardq->id, $quiz); quiz_add_random_questions($quiz, 0, $cat->id, 1, false); // Get the random question. $randomq = $DB->get_record('question', array('qtype' => 'random')); quiz_delete_instance($quiz->id); // Check that the random question was deleted. $count = $DB->count_records('question', array('id' => $randomq->id)); $this->assertEquals(0, $count); // Check that the standard question was not deleted. $count = $DB->count_records('question', array('id' => $standardq->id)); $this->assertEquals(1, $count); // Check that all the slots were removed. $count = $DB->count_records('quiz_slots', array('quizid' => $quiz->id)); $this->assertEquals(0, $count); // Check that the quiz was removed. $count = $DB->count_records('quiz', array('id' => $quiz->id)); $this->assertEquals(0, $count); }
/** * Create a quiz, add five questions to the quiz * which are all on one page and return the quiz object. */ private function get_quiz_object() { global $SITE; $this->resetAfterTest(true); // Make a quiz. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $quiz = $quizgenerator->create_instance(array( 'course' => $SITE->id, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => 2)); // Create five questions. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $shortanswer = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id)); $numerical = $questiongenerator->create_question('numerical', null, array('category' => $cat->id)); $essay = $questiongenerator->create_question('essay', null, array('category' => $cat->id)); $truefalse = $questiongenerator->create_question('truefalse', null, array('category' => $cat->id)); $match = $questiongenerator->create_question('match', null, array('category' => $cat->id)); // Add them to the quiz. quiz_add_quiz_question($shortanswer->id, $quiz); quiz_add_quiz_question($numerical->id, $quiz); quiz_add_quiz_question($essay->id, $quiz); quiz_add_quiz_question($truefalse->id, $quiz); quiz_add_quiz_question($match->id, $quiz); // Return the quiz object. return \mod_quiz\structure::create_for($quiz); }
public function generate_questions($courses, $modules) { global $DB, $CFG; if (!is_null($this->get('questions_per_course')) && count($courses) > 0 && is_array($courses)) { require_once $CFG->libdir . '/questionlib.php'; require_once $CFG->dirroot . '/mod/quiz/editlib.php'; $questions = array(); $questionsmenu = question_type_menu(); $questiontypes = array(); foreach ($questionsmenu as $qtype => $qname) { $questiontypes[] = $qtype; } // Add the questions foreach ($courses as $courseid) { $questions[$courseid] = array(); for ($i = 0; $i < $this->get('questions_per_course'); $i++) { $qtype = $questiontypes[array_rand($questiontypes)]; // Only the following types are supported right now. Hang around for more! $supported_types = array('match', 'essay', 'multianswer', 'multichoice', 'shortanswer', 'numerical', 'truefalse', 'calculated'); $qtype = $supported_types[array_rand($supported_types)]; if ($qtype == 'calculated') { continue; } $classname = "question_{$qtype}_qtype"; if ($qtype == 'multianswer') { $classname = "embedded_cloze_qtype"; } $question = new $classname(); $question->qtype = $qtype; $questions[$courseid][] = $question->generate_test("question{$qtype}-{$i}", $courseid); $this->verbose("Generated a question of type {$qtype} for course id {$courseid}."); } } // Assign questions to quizzes, if such exist if (!empty($modules['quiz']) && !empty($questions) && !is_null($this->get('questions_per_quiz'))) { $quizzes = $modules['quiz']; // Cannot assign more questions per quiz than are available, so determine which is the largest $questions_per_quiz = max(count($questions), $this->get('questions_per_quiz')); foreach ($quizzes as $quiz) { $questions_added = array(); for ($i = 0; $i < $questions_per_quiz; $i++) { // Add a random question to the quiz do { if (empty($quiz->course)) { print_object($quizzes); die; } $random = rand(0, count($questions[$quiz->course])); } while (in_array($random, $questions_added) || !array_key_exists($random, $questions[$quiz->course])); if (!quiz_add_quiz_question($questions[$quiz->course][$random]->id, $quiz)) { // Could not add question to quiz!! report error if (!$this->get('quiet')) { echo "WARNING: Could not add question id {$random} to quiz id {$quiz->id}{$this->eolchar}"; } } else { $this->verbose("Adding question id {$random} to quiz id {$quiz->id}."); $questions_added[] = $random; } } } } return $questions; } return null; }
quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); $thispageurl->param('lastchanged', $addquestion); redirect($afteractionurl); } if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) { $structure->check_can_be_edited(); $addonpage = optional_param('addonpage', 0, PARAM_INT); // Add selected questions to the current quiz. $rawdata = (array) data_submitted(); foreach ($rawdata as $key => $value) { // Parse input for question ids. if (preg_match('!^q([0-9]+)$!', $key, $matches)) { $key = $matches[1]; quiz_require_question_use($key); quiz_add_quiz_question($key, $quiz, $addonpage); } } quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); redirect($afteractionurl); } if (optional_param('addrandom', false, PARAM_BOOL) && confirm_sesskey()) { // Add random questions to the quiz. $structure->check_can_be_edited(); $recurse = optional_param('recurse', 0, PARAM_BOOL); $addonpage = optional_param('addonpage', 0, PARAM_INT); $categoryid = required_param('categoryid', PARAM_INT); $randomcount = required_param('randomcount', PARAM_INT); quiz_add_random_questions($quiz, $addonpage, $categoryid, $randomcount, $recurse); quiz_delete_previews($quiz);
function addRandomQuizQuestions($cmid, $cat_id) { global $QTYPES; $result = true; $recurse = 1; list($quiz, $cm) = get_module_from_cmid($cmid); if ($rs = get_records('question_categories', 'parent', $cat_id, 'sortorder')) { $course = get_record('course', 'id', $quiz->course); foreach ($rs as $cat) { $categoryid = $cat->id; $randomcount = 1; // load category if (!($category = get_record('question_categories', 'id', $categoryid))) { error('Category ID is incorrect'); } $catcontext = get_context_instance_by_id($category->contextid); require_capability('moodle/question:useall', $catcontext); $category->name = addslashes($category->name); // Find existing random questions in this category that are not used by any quiz. if ($existingquestions = get_records_sql("SELECT * FROM " . $CFG->prefix . "question q\n WHERE qtype = '" . RANDOM . "'\n AND category = {$category->id}\n AND " . sql_compare_text('questiontext') . " = '{$recurse}'\n AND NOT EXISTS (SELECT * FROM " . $CFG->prefix . "quiz_question_instances WHERE question = q.id)\n ORDER BY id")) { // Take as many of these as needed. while ($existingquestion = array_shift($existingquestions) and $randomcount > 0) { if (!quiz_add_quiz_question($existingquestion->id, $quiz)) { $result = false; } $randomcount--; } } // If more are needed, create them. if ($randomcount > 0) { //echo "NOT EXISTING:".$cat->id."<br/>"; $form->questiontext = $recurse; // we use the questiontext field to store the info // on whether to include questions in subcategories $form->questiontextformat = 0; $form->image = ''; $form->defaultgrade = 1; $form->hidden = 1; for ($i = 0; $i < $randomcount; $i++) { $form->category = "{$category->id},{$category->contextid}"; $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed) $question = new stdClass(); $question->qtype = RANDOM; $question = $QTYPES[RANDOM]->save_question($question, $form, $course); if (!isset($question->id)) { error('Could not insert new random question!'); $result = false; } //quiz_add_quiz_question($question->id, $quiz); if (!quiz_add_quiz_question($question->id, $quiz)) { $result = false; } } } $significantchangemade = true; } } return $result; /* $result = true; $recurse = 1; list($quiz, $cm) = get_module_from_cmid($cmid); if ($rs = get_recordset('question_categories','parent',$cat_id)) { $course = get_record('course','id',$quiz->course); foreach ($rs as $category) { echo $category->name."<br/>"; /// Add random questions to the quiz // - Source from: /mod/quiz/edit.php $randomcount = 1; // load category //$catcontext = get_context_instance_by_id($category->contextid); //require_capability('moodle/question:useall', $catcontext); $category->name = $category->name; // Find existing random questions in this category that are // not used by any quiz. if ($existingquestions = get_records_sql( "SELECT q.id,q.qtype FROM {question} q WHERE qtype = '" . RANDOM . "' AND category = ? AND " . $DB->sql_compare_text('questiontext') . " = ? AND NOT EXISTS (SELECT * FROM {quiz_question_instances} WHERE question = q.id) ORDER BY id", array($category->id, $recurse))) { // Take as many of these as needed. while (($existingquestion = array_shift($existingquestions)) && $randomcount > 0) { //quiz_add_quiz_question($existingquestion->id, $quiz); if(!quiz_add_quiz_question($existingquestion->id, $quiz)){ $result = false; } $randomcount--; } } // If more are needed, create them. if ($randomcount > 0) { $form->questiontext = $recurse; // we use the questiontext field // to store the info on whether to include // questions in subcategories $form->questiontextformat = 0; $form->image = ''; $form->defaultgrade = 1; $form->hidden = 1; for ($i = 0; $i < $randomcount; $i++) { $form->category = $category->id . ',' . $category->contextid; $form->stamp = make_unique_id_code(); // Set the unique //code (not to be changed) $question = new stdClass; $question->qtype = RANDOM; $question = $QTYPES[RANDOM]->save_question($question, $form, $course); if(!isset($question->id)) { //print_error('cannotinsertrandomquestion', 'quiz'); $result = false; } //quiz_add_quiz_question($question->id, $quiz); if(!quiz_add_quiz_question($question->id, $quiz)){ $result = false; } } } quiz_update_sumgrades($quiz); quiz_delete_previews($quiz); } //$rs->close(); /// Don't forget to close the recordset! } return $result; */ }
/** * 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); }
/** * Populate quiz with eight questions. * @param stdClass $quiz the quiz to add to. */ public function add_eight_questions_to_the_quiz($quiz) { // We add 8 numerical questions with this layout: // Slot 1 2 3 4 5 6 7 8 // Page 1 2 2 2 2 2 3 4. // Create slots. $pagenumber = 1; $pagenumberdefaults = array(2, 7, 8); // Create a couple of questions. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); for ($i = 0; $i < 8; $i++) { $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id)); if (in_array($i + 1, $pagenumberdefaults)) { $pagenumber++; } // Add them to the quiz. quiz_add_quiz_question($numq->id, $quiz, $pagenumber); } }
// we use the questiontext field to store the info // on whether to include questions in subcategories $form->questiontextformat = 0; $form->image = ''; $form->defaultgrade = 1; $form->hidden = 1; for ($i = 0; $i < $randomcreate; $i++) { $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed) $question = new stdClass(); $question->qtype = RANDOM; $question = $QTYPES[RANDOM]->save_question($question, $form, $course); if (!isset($question->id)) { error('Could not insert new random question!'); } quiz_add_quiz_question($question->id, $modform); } } } if (isset($_REQUEST['repaginate']) and confirm_sesskey()) { /// Re-paginate the quiz if (isset($_REQUEST['questionsperpage'])) { $modform->questionsperpage = required_param('questionsperpage', PARAM_INT); if (!set_field('quiz', 'questionsperpage', $modform->questionsperpage, 'id', $modform->id)) { error('Could not save number of questions per page'); } } $modform->questions = quiz_repaginate($modform->questions, $modform->questionsperpage); if (!set_field('quiz', 'questions', $modform->questions, 'id', $modform->id)) { error('Could not save layout'); }
/** * Put the specified questions on the specified pages of a given quiz. * * The first row should be column names: * | question | page | maxmark | * The first two of those are required. The others are optional. * * question needs to uniquely match a question name. * page is a page number. Must start at 1, and on each following * row should be the same as the previous, or one more. * maxmark What the question is marked out of. Defaults to question.defaultmark. * * Then there should be a number of rows of data, one for each question you want to add. * * For backwards-compatibility reasons, specifying the column names is optional * (but strongly encouraged). If not specified, the columns are asseumed to be * | question | page | maxmark |. * * @param string $quizname the name of the quiz to add questions to. * @param TableNode $data information about the questions to add. * * @Given /^quiz "([^"]*)" contains the following questions:$/ */ public function quiz_contains_the_following_questions($quizname, TableNode $data) { global $CFG, $DB; require_once __DIR__ . '/../../editlib.php'; $quiz = $DB->get_record('quiz', array('name' => $quizname), '*', MUST_EXIST); // Deal with backwards-compatibility, optional first row. $firstrow = $data->getRow(0); if (!in_array('question', $firstrow) && !in_array('page', $firstrow)) { if (count($firstrow) == 2) { $headings = array('question', 'page'); } else { if (count($firstrow) == 3) { $headings = array('question', 'page', 'maxmark'); } else { throw new ExpectationException('When adding questions to a quiz, you should give 2 or three 3 things: ' . ' the question name, the page number, and optionally the maxiumum mark. ' . count($firstrow) . ' values passed.', $this->getSession()); } } $rows = $data->getRows(); array_unshift($rows, $headings); $data->setRows($rows); } // Add the questions. $lastpage = 0; foreach ($data->getHash() as $questiondata) { if (!array_key_exists('question', $questiondata)) { throw new ExpectationException('When adding questions to a quiz, ' . 'the question name column is required.', $this->getSession()); } if (!array_key_exists('page', $questiondata)) { throw new ExpectationException('When adding questions to a quiz, ' . 'the page number column is required.', $this->getSession()); } // Question id. $questionid = $DB->get_field('question', 'id', array('name' => $questiondata['question']), MUST_EXIST); // Page number. $page = clean_param($questiondata['page'], PARAM_INT); if ($page <= 0 || (string) $page !== $questiondata['page']) { throw new ExpectationException('The page number for question "' . $questiondata['question'] . '" must be a positive integer.', $this->getSession()); } if ($page < $lastpage || $page > $lastpage + 1) { throw new ExpectationException('When adding questions to a quiz, ' . 'the page number for each question must either be the same, ' . 'or one more, then the page number for the previous question.', $this->getSession()); } $lastpage = $page; // Max mark. if (!array_key_exists('maxmark', $questiondata) || $questiondata['maxmark'] === '') { $maxmark = null; } else { $maxmark = clean_param($questiondata['maxmark'], PARAM_FLOAT); if (!is_numeric($questiondata['maxmark']) || $maxmark < 0) { throw new ExpectationException('The max mark for question "' . $questiondata['question'] . '" must be a positive number.', $this->getSession()); } } // Add the question. quiz_add_quiz_question($questionid, $quiz, $page, $maxmark); } quiz_update_sumgrades($quiz); }
public function test_add_question_at_end_does_not_update_headings() { $quizobj = $this->create_test_quiz(array(array('TF1', 1, 'truefalse'), 'Heading 2', array('TF2', 2, 'truefalse'))); $structure = \mod_quiz\structure::create_for_quiz($quizobj); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $q = $questiongenerator->create_question('truefalse', null, array('name' => 'TF3', 'category' => $cat->id)); quiz_add_quiz_question($q->id, $quizobj->get_quiz(), 0); $structure = \mod_quiz\structure::create_for_quiz($quizobj); $this->assert_quiz_layout(array(array('TF1', 1, 'truefalse'), 'Heading 2', array('TF2', 2, 'truefalse'), array('TF3', 2, 'truefalse')), $structure); }
/** * 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); }
function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, $includesubcategories) { global $DB; $category = $DB->get_record('question_categories', array('id' => $categoryid)); if (!$category) { print_error('invalidcategoryid', 'error'); } $catcontext = get_context_instance_by_id($category->contextid); require_capability('moodle/question:useall', $catcontext); // Find existing random questions in this category that are // not used by any quiz. if ($existingquestions = $DB->get_records_sql( "SELECT q.id, q.qtype FROM {question} q WHERE qtype = 'random' AND category = ? AND " . $DB->sql_compare_text('questiontext') . " = ? AND NOT EXISTS ( SELECT * FROM {quiz_question_instances} WHERE question = q.id) ORDER BY id", array($category->id, $includesubcategories))) { // Take as many of these as needed. while (($existingquestion = array_shift($existingquestions)) && $number > 0) { quiz_add_quiz_question($existingquestion->id, $quiz, $addonpage); $number -= 1; } } if ($number <= 0) { return; } // More random questions are needed, create them. for ($i = 0; $i < $number; $i += 1) { $form = new stdClass(); $form->questiontext = array('text' => $includesubcategories, 'format' => 0); $form->category = $category->id . ',' . $category->contextid; $form->defaultmark = 1; $form->hidden = 1; $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed). $question = new stdClass(); $question->qtype = 'random'; $question = question_bank::get_qtype('random')->save_question($question, $form); if (!isset($question->id)) { print_error('cannotinsertrandomquestion', 'quiz'); } quiz_add_quiz_question($question->id, $quiz, $addonpage); } }
/** * Test get_quiz_required_qtypes */ public function test_get_quiz_required_qtypes() { global $DB; // Create a new quiz. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $data = array('course' => $this->course->id); $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); $this->setUser($this->student); $result = mod_quiz_external::get_quiz_required_qtypes($quiz->id); $result = external_api::clean_returnvalue(mod_quiz_external::get_quiz_required_qtypes_returns(), $result); $expected = array('questiontypes' => ['essay', 'numerical', 'random', 'shortanswer', 'truefalse'], 'warnings' => []); $this->assertEquals($expected, $result); }
/** * @desc Takes in an array of questins and adds them to a quiz * @param array $questions An array of the question data to add. * @param integer $quizid The ID of the quiz. * @return bool. */ function insert_set_definition_questions($questions, $quizid) { global $COURSE; //partial quiz object $quizinfo = new stdClass(); $quizinfo->grades = array(); $quizinfo->questionsperpage = 1; $quizinfo->questions = ""; $quizinfo->instance = $quizid; $quizinfo->id = $quizid; //loop to find questions $count = 0; foreach ($questions as $question) { //get question name $filepath = $question['file']; $name = $this->filepath_to_name($filepath); $parts = explode('/', $filepath); $partcount = count($parts); if ($partcount >= 2) { $categoryname = $parts[$partcount - 2]; //try first with course constraint $result = get_field('question_categories', 'id', 'name', $categoryname, 'course', $COURSE->id); if ($result == false) { $result = get_field('question_categories', 'id', 'name', $categoryname); if ($result == false) { echo "The category '{$categoryname}' was not found for question '{$name}'. - You will have to manually add this question.<br>"; continue; } else { $categoryid = $result; } } else { $categoryid = $result; } $result = get_field('question', 'id', 'category', $categoryid, 'name', $name); } $result = get_field('question', 'id', 'name', $name); if ($result != false) { echo "Added Question '{$name}' to quiz.<br>"; quiz_add_quiz_question($result, $quizinfo); $count++; } else { echo "A question was not found: '{$name}' - You will have to manually add it.<br>"; } } return $count; }
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); }
/** * 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')); }
function RWSAAQRand() { global $CFG; global $DB; global $RWSUID; RWSCMAuth(); RWSCRAuth(); RWSCMUSvc(); RWSCMMaint(); $r_pm = RWSGSOpt("quizid", PARAM_ALPHANUM); if ($r_pm === false || strlen($r_pm) == 0) { RWSSErr("2067"); } $r_qzmi = intval($r_pm); $r_cmod = RWSCMUQuiz($r_qzmi); $r_cid = $r_cmod->course; RWSCMUCourse($r_cid, true); $r_mr = $DB->get_record("modules", array("id" => $r_cmod->module)); if ($r_mr === false) { RWSSErr("2043"); } $r_qiz = $DB->get_record($r_mr->name, array("id" => $r_cmod->instance)); if ($r_qiz === false) { RWSSErr("2044"); } $r_pm = RWSGSOpt("qcatid", PARAM_ALPHANUM); if ($r_pm === false || strlen($r_pm) == 0) { RWSSErr("2064"); } $r_qci = intval($r_pm); $r_qca = $DB->get_record("question_categories", array("id" => $r_qci)); if ($r_qca === false) { RWSSErr("2065"); } if (respondusws_floatcompare($CFG->version, 2013111800, 2) >= 0) { $r_ctx = context::instance_by_id($r_qca->contextid); } else { $r_ctx = get_context_instance_by_id($r_qca->contextid); } $r_qcci = RWSGCFCat($r_ctx); if ($r_qcci != $r_cid) { if (is_siteadmin($RWSUID)) { if ($r_qcci != SITEID) { RWSSErr("2109"); } } else { RWSSErr("2084"); } } $r_pm = RWSGSOpt("qcount", PARAM_ALPHANUM); if ($r_pm === false || strlen($r_pm) == 0) { RWSSErr("2085"); } $r_qct = intval($r_pm); if ($r_qct <= 0) { RWSSErr("2085"); } $r_pm = RWSGSOpt("qgrade", PARAM_NOTAGS); if ($r_pm === false || strlen($r_pm) == 0) { RWSSErr("2086"); } $r_qg = round(floatval($r_pm)); if ($r_qg <= 0) { RWSSErr("2086"); } $r_mr = $DB->get_record("modules", array("id" => $r_cmod->module)); if ($r_mr === false) { RWSSErr("2043"); } $r_qiz = $DB->get_record($r_mr->name, array("id" => $r_cmod->instance)); if ($r_qiz === false) { RWSSErr("2044"); } if (!isset($r_qiz->instance)) { $r_qiz->instance = $r_qiz->id; } $r_aerr = 0; for ($r_i = 0; $r_i < $r_qct; $r_i++) { $r_qst = new stdClass(); $r_qst->qtype = RWSRND; $r_qst->parent = 0; $r_qst->hidden = 0; $r_qst->length = 1; $r_qst->questiontext = 1; if (respondusws_floatcompare($CFG->version, 2011070100, 2) >= 0) { $r_rqt = question_bank::get_qtype("random"); $r_qst->name = $r_rqt->question_name($r_qca, !empty($r_qst->questiontext)); } else { $r_qst->name = random_qtype::question_name($r_qca, !empty($r_qst->questiontext)); } $r_qst->questiontextformat = FORMAT_HTML; $r_qst->penalty = 0; if (respondusws_floatcompare($CFG->version, 2011070100, 2) >= 0) { $r_qst->defaultmark = $r_qg; } else { $r_qst->defaultgrade = $r_qg; } $r_qst->generalfeedback = ""; $r_qst->generalfeedbackformat = FORMAT_HTML; $r_qst->category = $r_qca->id; $r_qst->stamp = make_unique_id_code(); $r_qst->createdby = $RWSUID; $r_qst->modifiedby = $RWSUID; $r_qst->timecreated = time(); $r_qst->timemodified = time(); $r_qst->id = $DB->insert_record("question", $r_qst); $DB->set_field("question", "parent", $r_qst->id, array("id" => $r_qst->id)); $r_h = question_hash($r_qst); $DB->set_field("question", "version", $r_h, array("id" => $r_qst->id)); if (respondusws_floatcompare($CFG->version, 2011070100, 2) >= 0) { quiz_add_quiz_question($r_qst->id, $r_qiz); } else { $r_ok = quiz_add_quiz_question($r_qst->id, $r_qiz); if (!$r_ok) { $DB->delete_records("question", array("id" => $r_qst->id)); $r_aerr++; } } } if ($r_aerr > 0) { RWSSErr("2087,{$r_aerr}"); } if ($r_aerr < $r_qct) { quiz_delete_previews($r_qiz); } if (respondusws_floatcompare($CFG->version, 2014051200, 2) >= 0) { quiz_update_sumgrades($r_qiz); } else { $r_qiz->grades = quiz_get_all_question_grades($r_qiz); $r_sumg = array_sum($r_qiz->grades); $DB->set_field("quiz", "sumgrades", $r_sumg, array("id" => $r_qiz->id)); } RWSSStat("1006"); }
public function create_quiz($quizsettings, $qs) { global $SITE, $DB; $this->setAdminUser(); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $slots = array(); $qidsbycat = array(); $sumofgrades = 0; for ($rowno = 0; $rowno < $qs->getRowCount(); $rowno++) { $q = $this->explode_dot_separated_keys_to_make_subindexs($qs->getRow($rowno)); $catname = array('name' => $q['cat']); if (!($cat = $DB->get_record('question_categories', array('name' => $q['cat'])))) { $cat = $questiongenerator->create_question_category($catname); } $q['catid'] = $cat->id; foreach (array('which' => null, 'overrides' => array()) as $key => $default) { if (empty($q[$key])) { $q[$key] = $default; } } if ($q['type'] !== 'random') { // Don't actually create random questions here. $overrides = array('category' => $cat->id, 'defaultmark' => $q['mark']) + $q['overrides']; $question = $questiongenerator->create_question($q['type'], $q['which'], $overrides); $q['id'] = $question->id; if (!isset($qidsbycat[$q['cat']])) { $qidsbycat[$q['cat']] = array(); } if (!empty($q['which'])) { $name = $q['type'] . '_' . $q['which']; } else { $name = $q['type']; } $qidsbycat[$q['catid']][$name] = $q['id']; } if (!empty($q['slot'])) { $slots[$q['slot']] = $q; $sumofgrades += $q['mark']; } } ksort($slots); // Make a quiz. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); // Settings from param override defaults. $aggregratedsettings = $quizsettings + array('course' => $SITE->id, 'questionsperpage' => 0, 'grade' => 100.0, 'sumgrades' => $sumofgrades); $this->quiz = $quizgenerator->create_instance($aggregratedsettings); $this->randqids = array(); foreach ($slots as $slotno => $slotquestion) { if ($slotquestion['type'] !== 'random') { quiz_add_quiz_question($slotquestion['id'], $this->quiz, 0, $slotquestion['mark']); } else { quiz_add_random_questions($this->quiz, 0, $slotquestion['catid'], 1, 0); $this->randqids[$slotno] = $qidsbycat[$slotquestion['catid']]; } } }
$addonpage = optional_param('addonpage', 0, PARAM_INT); quiz_add_quiz_question($addquestion, $quiz, $addonpage); quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); $thispageurl->param('lastchanged', $addquestion); redirect($afteractionurl); } if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) { // Add selected questions to the current quiz. $rawdata = (array) data_submitted(); foreach ($rawdata as $key => $value) { // Parse input for question ids. if (preg_match('!^q([0-9]+)$!', $key, $matches)) { $key = $matches[1]; quiz_require_question_use($key); quiz_add_quiz_question($key, $quiz); } } quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); redirect($afteractionurl); } if (optional_param('addrandom', false, PARAM_BOOL) && confirm_sesskey()) { // Add random questions to the quiz. $recurse = optional_param('recurse', 0, PARAM_BOOL); $addonpage = optional_param('addonpage', 0, PARAM_INT); $categoryid = required_param('categoryid', PARAM_INT); $randomcount = required_param('randomcount', PARAM_INT); quiz_add_random_questions($quiz, $addonpage, $categoryid, $randomcount, $recurse); quiz_delete_previews($quiz); quiz_update_sumgrades($quiz);
/** * Test start_attempt */ public function test_start_attempt() { global $DB; // Create a new quiz with attempts. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $data = array('course' => $this->course->id, 'sumgrades' => 1); $quiz = $quizgenerator->create_instance($data); $context = context_module::instance($quiz->cmid); try { mod_quiz_external::start_attempt($quiz->id); $this->fail('Exception expected due to missing questions.'); } catch (moodle_quiz_exception $e) { $this->assertEquals('noquestionsfound', $e->errorcode); } // Create a question. $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, $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); // Try to open attempt in closed quiz. $quiz->timeopen = time() - WEEKSECS; $quiz->timeclose = time() - DAYSECS; $DB->update_record('quiz', $quiz); $result = mod_quiz_external::start_attempt($quiz->id); $result = external_api::clean_returnvalue(mod_quiz_external::start_attempt_returns(), $result); $this->assertEquals([], $result['attempt']); $this->assertCount(1, $result['warnings']); // Now with a password. $quiz->timeopen = 0; $quiz->timeclose = 0; $quiz->password = '******'; $DB->update_record('quiz', $quiz); try { mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'bad'))); $this->fail('Exception expected due to invalid passwod.'); } catch (moodle_exception $e) { $this->assertEquals(get_string('passworderror', 'quizaccess_password'), $e->errorcode); } // Now, try everything correct. $result = mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'abc'))); $result = external_api::clean_returnvalue(mod_quiz_external::start_attempt_returns(), $result); $this->assertEquals(1, $result['attempt']['attempt']); $this->assertEquals($this->student->id, $result['attempt']['userid']); $this->assertEquals($quiz->id, $result['attempt']['quiz']); $this->assertCount(0, $result['warnings']); $attemptid = $result['attempt']['id']; // We are good, try to start a new attempt now. try { mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'abc'))); $this->fail('Exception expected due to attempt not finished.'); } catch (moodle_quiz_exception $e) { $this->assertEquals('attemptstillinprogress', $e->errorcode); } // Finish the started attempt. // Process some responses from the student. $timenow = time(); $attemptobj = quiz_attempt::create($attemptid); $tosubmit = array(1 => array('answer' => '3.14')); $attemptobj->process_submitted_actions($timenow, false, $tosubmit); // Finish the attempt. $attemptobj = quiz_attempt::create($attemptid); $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question()); $attemptobj->process_finish($timenow, false); // We should be able to start a new attempt. $result = mod_quiz_external::start_attempt($quiz->id, array(array("name" => "quizpassword", "value" => 'abc'))); $result = external_api::clean_returnvalue(mod_quiz_external::start_attempt_returns(), $result); $this->assertEquals(2, $result['attempt']['attempt']); $this->assertEquals($this->student->id, $result['attempt']['userid']); $this->assertEquals($quiz->id, $result['attempt']['quiz']); $this->assertCount(0, $result['warnings']); // Test user with no capabilities. // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles. assign_capability('mod/quiz:attempt', CAP_PROHIBIT, $this->studentrole->id, $context->id); // Empty all the caches that may be affected by this change. accesslib_clear_all_caches_for_unit_testing(); course_modinfo::clear_instance_cache(); try { mod_quiz_external::start_attempt($quiz->id); $this->fail('Exception expected due to missing capability.'); } catch (required_capability_exception $e) { $this->assertEquals('nopermissions', $e->errorcode); } }