/** * Returns the qtype information to attach to question element. */ protected function define_question_plugin_structure() { $qtypeobj = question_bank::get_qtype($this->pluginname); // Define the virtual plugin element with the condition to fulfill. $plugin = $this->get_plugin_element(null, '../../qtype', $qtypeobj->name()); // Create one standard named plugin element (the visible container). $pluginwrapper = new backup_nested_element($this->get_recommended_name()); // Connect the visible container ASAP. $plugin->add_child($pluginwrapper); // This qtype uses standard question_answers, add them here // to the tree before any other information that will use them. $this->add_question_question_answers($pluginwrapper); $answers = $pluginwrapper->get_child('answers'); $answer = $answers->get_child('answer'); // Extra question fields. $extraquestionfields = $qtypeobj->extra_question_fields(); if (!empty($extraquestionfields)) { $tablename = array_shift($extraquestionfields); $child = new backup_nested_element($qtypeobj->name(), array('id'), $extraquestionfields); $pluginwrapper->add_child($child); $child->set_source_table($tablename, array($qtypeobj->questionid_column_name() => backup::VAR_PARENTID)); } // Extra answer fields. $extraanswerfields = $qtypeobj->extra_answer_fields(); if (!empty($extraanswerfields)) { $tablename = array_shift($extraanswerfields); $child = new backup_nested_element('extraanswerdata', array('id'), $extraanswerfields); $answer->add_child($child); $child->set_source_table($tablename, array('answerid' => backup::VAR_PARENTID)); } // Don't need to annotate ids nor files. return $plugin; }
protected function definition_inner($mform) { global $DB, $question; $loaded_initialy = optional_param('reloaded_initialy', 1, PARAM_INT); $qtype = question_bank::get_qtype('javaunittest'); $definitionoptions = $this->_customdata['definitionoptions']; $attachmentoptions = $this->_customdata['attachmentoptions']; // -------------------------- feedback options $mform->addElement('select', 'feedbacklevel', get_string('feedbacklevel', 'qtype_javaunittest'), $qtype->feedback_levels()); $mform->setDefault('feedbacklevel', FEEDBACK_ONLY_TIMES); // -------------------------- size of the response field $mform->addElement('select', 'responsefieldlines', get_string('responsefieldlines', 'qtype_javaunittest'), $qtype->response_sizes()); $mform->setDefault('responsefieldlines', 15); // -------------------------- "Given Code" Text-Area $mform->addElement('textarea', 'givencode', get_string('givencode', 'qtype_javaunittest'), array('cols' => 80, 'rows' => 20)); $mform->setType('givencode', PARAM_RAW); $mform->addHelpButton('givencode', 'givencode', 'qtype_javaunittest'); // -------------------------- "Test class" Text-Area $mform->addElement('textarea', 'testclassname', get_string('testclassname', 'qtype_javaunittest'), array('cols' => 80, 'rows' => 1)); $mform->setType('testclassname', PARAM_ALPHANUMEXT); $mform->addRule('testclassname', null, 'required'); $mform->addHelpButton('testclassname', 'testclassname', 'qtype_javaunittest'); $mform->addElement('textarea', 'junitcode', get_string('uploadtestclass', 'qtype_javaunittest'), array('cols' => 80, 'rows' => 20)); $mform->setType('junitcode', PARAM_RAW); $mform->addRule('junitcode', null, 'required'); $mform->addHelpButton('junitcode', 'uploadtestclass', 'qtype_javaunittest'); }
/** * Function to read all questions for category into big array * * @param int $category category number * @param bool $noparent if true only questions with NO parent will be selected * @param bool $recurse include subdirectories * @param bool $export set true if this is called by questionbank export */ function get_questions_category($category, $noparent = false, $recurse = true, $export = true) { global $DB; // Build sql bit for $noparent $npsql = ''; if ($noparent) { $npsql = " and parent='0' "; } // Get list of categories if ($recurse) { $categorylist = question_categorylist($category->id); } else { $categorylist = array($category->id); } // Get the list of questions for the category list($usql, $params) = $DB->get_in_or_equal($categorylist); $questions = $DB->get_records_select('question', "category {$usql} {$npsql}", $params, 'qtype, name'); // Iterate through questions, getting stuff we need $qresults = array(); foreach ($questions as $key => $question) { $question->export_process = $export; $qtype = question_bank::get_qtype($question->qtype, false); if ($export && $qtype->name() == 'missingtype') { // Unrecognised question type. Skip this question when exporting. continue; } $qtype->get_question_options($question); $qresults[] = $question; } return $qresults; }
protected function definition_inner($mform) { global $PAGE, $CFG; $PAGE->requires->js('/question/type/jme/jme_script.js'); $PAGE->requires->css('/question/type/jme/styles.css'); $mform->addElement('hidden', 'usecase', 1); $mform->setType('usecase', PARAM_INT); $optionscript = 'onClick = "setJSMEoptions()"'; $label = get_string('jmeoptions', 'qtype_jme'); $editoroptions[] = $mform->createElement('text', 'jmeoptions', '', array('size' => 50)); $editoroptions[] = $mform->createElement('button', 'setoptions', get_string('setoptions', 'qtype_jme'), $optionscript); $mform->addElement('group', 'editoroptions', $label, $editoroptions, null, false); $mform->setDefault('jmeoptions', $CFG->qtype_jme_options); $mform->setType('jmeoptions', PARAM_RAW); $mform->addHelpButton('editoroptions', 'jmeoptions', 'qtype_jme'); $mform->addElement('text', 'width', get_string('width', 'qtype_jme'), array('size' => 6)); $mform->setDefault('width', QTYPE_JME_APPLET_WIDTH); $mform->setType('width', PARAM_INT); $mform->addElement('text', 'height', get_string('height', 'qtype_jme'), array('size' => 6)); $mform->setDefault('height', QTYPE_JME_APPLET_HEIGHT); $mform->setType('height', PARAM_INT); $mform->addElement('static', 'answersinstruct', get_string('correctanswers', 'qtype_jme'), get_string('filloutoneanswer', 'qtype_jme')); $mform->addElement('html', html_writer::tag('div', get_string('enablejavascript', 'qtype_jme'), array('class' => 'jme_applet', 'code' => 'JME.class', 'id' => 'jme1', 'name' => 'JME1', 'archive' => 'JME.jar', 'width' => '360', 'height' => '315', 'style' => 'margin: 1.5em auto'))); $mform->closeHeaderBefore('answersinstruct'); $this->add_per_answer_fields($mform, get_string('answerno', 'qtype_jme', '{no}'), question_bank::fraction_options()); $this->add_interactive_settings(); // Include JSME loader script as an html tag. $jsmescript = $CFG->wwwroot . '/question/type/jme/jsme/jsme.nocache.js'; $mform->addElement('html', html_writer::tag('script', '', array('src' => $jsmescript))); }
public function validation($data, $files) { global $DB; $errors = parent::validation($data, $files); if (isset($data->categorymoveto)) { list($category) = explode(',', $data['categorymoveto']); } else { list($category) = explode(',', $data['category']); } $saquestions = question_bank::get_qtype('randomsamatch')->get_sa_candidates($category); $numberavailable = count($saquestions); if ($saquestions === false) { $a = new stdClass(); $a->catname = $DB->get_field('question_categories', 'name', array('id' => $category)); $errors['choose'] = get_string('nosaincategory', 'qtype_randomsamatch', $a); } else { if ($numberavailable < $data['choose']) { $a = new stdClass(); $a->catname = $DB->get_field('question_categories', 'name', array('id' => $category)); $a->nosaquestions = $numberavailable; $errors['choose'] = get_string('notenoughsaincategory', 'qtype_randomsamatch', $a); } } return $errors; }
protected function definition_inner($mform) { $qtype = question_bank::get_qtype('poodllrecording'); $mform->addElement('select', 'responseformat', get_string('responseformat', 'qtype_poodllrecording'), $qtype->response_formats()); $mform->setDefault('responseformat', 'editor'); $mform->addElement('editor', 'graderinfo', get_string('graderinfo', 'qtype_poodllrecording'), array('rows' => 10), $this->editoroptions); }
/** * 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); } }
protected function definition_inner($mform) { $this->add_per_answer_fields($mform, get_string('answerno', 'qtype_numerical', '{no}'), question_bank::fraction_options()); $this->add_unit_options($mform); $this->add_unit_fields($mform); $this->add_interactive_settings(); }
protected function definition_inner($mform) { $qtype = question_bank::get_qtype('essay'); $mform->addElement('editor', 'graderinfo', get_string('graderinfo', 'qtype_essay'), array('rows' => 10), $this->editoroptions); $mform->addElement('header', 'responseheader', get_string('responseheader', 'qtype_essay')); $mform->addElement('select', 'responseformat', get_string('responseformat', 'qtype_essay'), $qtype->response_formats()); $mform->setDefault('responseformat', 'editor'); $mform->addElement('select', 'responsefieldlines', get_string('responsefieldlines', 'qtype_essay'), $qtype->response_sizes()); $mform->setDefault('responsefieldlines', 15); $mform->addElement('select', 'attachments', get_string('allowattachments', 'qtype_essay'), $qtype->attachment_options()); $mform->setDefault('attachments', 0); $mform->addElement('select', 'responselimitpolicy', get_string('responselimitpolicy', 'qtype_essay'), $qtype->response_limit_policies()); $mform->addHelpButton('responselimitpolicy', 'responselimitpolicy', 'qtype_essay'); $mform->addElement('text', 'wordlimit', get_string('wordlimit', 'qtype_essay'), array('size' => 3)); $mform->disabledIf('wordlimit', 'responselimitpolicy', 'eq', 0); $mform->setType('wordlimit', PARAM_INT); $mform->addElement('text', 'charlimit', get_string('charlimit', 'qtype_essay'), array('size' => 3)); $mform->disabledIf('charlimit', 'responselimitpolicy', 'eq', 0); $mform->setType('charlimit', PARAM_INT); }
public static function make_question($type, $answers = array("cat", "mat")) { question_bank::load_question_definition_classes($type); $question = new qtype_gapfill_question(); test_question_maker::initialise_a_question($question); $question->qtype = question_bank::get_qtype('gapfill'); $question->name = 'Gapfill Test Question'; $question->questiontext = "The [cat] sat on the [mat]"; $question->textfragments = array('The ', ' sat on the '); $question->displayanswers = '1'; $question->casesensitive = '1'; $question->generalfeedback = 'congratulations on your knowledge of pets and floor covering'; $question->places[1] = $answers[0]; $question->places[2] = $answers[1]; $answer1 = new question_answer(43, $answers[0], 4, 1, 1); $answer2 = new question_answer(44, $answers[1], 4, 1, 1); $question->answers = array($answer1, $answer2); $question->options = new stdClass(); $question->options->showanswers = false; $question->options->delimitchars = "[]"; $question->options->casesensitive = false; $question->options->correctfeedback = ""; $question->options->correctfeedbackformat = ""; $question->options->partiallycorrectfeedback = ""; $question->options->partiallycorrectfeedbackformat = ""; $question->options->incorrectfeedback = ""; $question->options->incorrectfeedbackformat = ""; $question->options->shuffledanswers = "mat,cat"; $question->options->wronganswers = "bat,dog"; $question->shuffledanswers = "mat,cat,bat,dog"; $answers = new stdClass(); $question->options->answers = array($answer1, $answer2); $question->hints = array(new question_hint(1, 'This is the first hint.', FORMAT_HTML), new question_hint(2, 'This is the second hint.', FORMAT_HTML)); return $question; }
public function test_grading_rounding_three_right() { question_bank::load_question_definition_classes('multichoice'); $mc = new qtype_multichoice_multi_question(); test_question_maker::initialise_a_question($mc); $mc->name = 'Odd numbers'; $mc->questiontext = 'Which are the odd numbers?'; $mc->generalfeedback = '1, 3 and 5 are the odd numbers.'; $mc->qtype = question_bank::get_qtype('multichoice'); $mc->shuffleanswers = 0; $mc->answernumbering = 'abc'; test_question_maker::set_standard_combined_feedback_fields($mc); $mc->answers = array( 11 => new question_answer(11, '1', 0.3333333, '', FORMAT_HTML), 12 => new question_answer(12, '2', -1, '', FORMAT_HTML), 13 => new question_answer(13, '3', 0.3333333, '', FORMAT_HTML), 14 => new question_answer(14, '4', -1, '', FORMAT_HTML), 15 => new question_answer(15, '5', 0.3333333, '', FORMAT_HTML), 16 => new question_answer(16, '6', -1, '', FORMAT_HTML), ); $mc->start_attempt(new question_attempt_step(), 1); list($grade, $state) = $mc->grade_response( array('choice0' => 1, 'choice2' => 1, 'choice4' => 1)); $this->assertEquals(1, $grade, '', 0.000001); $this->assertEquals(question_state::$gradedright, $state); }
public function test_import_match() { $xml = $this->make_test_xml(); $importer = new qformat_blackboard_six(); $questions = $importer->readquestions($xml); $q = $questions[5]; // If qtype_ddmatch is installed, the formatter produces ddmatch // qtypes, not match ones. $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch'); $expectedq = new stdClass(); $expectedq->qtype = $ddmatchisinstalled ? 'ddmatch' : 'match'; $expectedq->name = 'Classify the animals.'; $expectedq->questiontext = '<i>Classify the animals.</i>'; $expectedq->questiontextformat = FORMAT_HTML; $expectedq->correctfeedback = array('text' => '', 'format' => FORMAT_HTML); $expectedq->partiallycorrectfeedback = array('text' => '', 'format' => FORMAT_HTML); $expectedq->incorrectfeedback = array('text' => '', 'format' => FORMAT_HTML); $expectedq->generalfeedback = ''; $expectedq->generalfeedbackformat = FORMAT_HTML; $expectedq->defaultmark = 1; $expectedq->length = 1; $expectedq->penalty = 0.3333333; $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers'); $expectedq->subquestions = array(array('text' => 'cat', 'format' => FORMAT_HTML), array('text' => '', 'format' => FORMAT_HTML), array('text' => 'frog', 'format' => FORMAT_HTML), array('text' => 'newt', 'format' => FORMAT_HTML)); if ($ddmatchisinstalled) { $expectedq->subanswers = array(array('text' => 'mammal', 'format' => FORMAT_HTML), array('text' => 'insect', 'format' => FORMAT_HTML), array('text' => 'amphibian', 'format' => FORMAT_HTML), array('text' => 'amphibian', 'format' => FORMAT_HTML)); } else { $expectedq->subanswers = array('mammal', 'insect', 'amphibian', 'amphibian'); } $this->assert(new question_check_specified_fields_expectation($expectedq), $q); }
/** * Add question-type specific form fields. * * @param MoodleQuickForm $mform the form being built. */ public function __construct($submiturl, $question, $regenerate) { global $SESSION, $CFG, $DB; $this->regenerate = $regenerate; $this->question = $question; $this->qtypeobj = question_bank::get_qtype($this->question->qtype); // Validate the question category. if (!($category = $DB->get_record('question_categories', array('id' => $question->category)))) { print_error('categorydoesnotexist', 'question', $returnurl); } $this->category = $category; $this->categorycontext = context::instance_by_id($category->contextid); // Get the dataset defintions for this question. if (empty($question->id)) { $this->datasetdefs = $this->qtypeobj->get_dataset_definitions($question->id, $SESSION->calculated->definitionform->dataset); } else { if (empty($question->options)) { $this->get_question_options($question); } $this->datasetdefs = $this->qtypeobj->get_dataset_definitions($question->id, array()); } foreach ($this->datasetdefs as $datasetdef) { // Get maxnumber. if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) { $this->maxnumber = $datasetdef->itemcount; } } foreach ($this->datasetdefs as $defid => $datasetdef) { if (isset($datasetdef->id)) { $this->datasetdefs[$defid]->items = $this->qtypeobj->get_database_dataset_items($datasetdef->id); } } parent::__construct($submiturl); }
public function readquestions($lines) { question_bank::get_qtype('multianswer'); // Ensure the multianswer code is loaded. // For this class the method has been simplified as // there can never be more than one question for a // multianswer import. $questions = array(); $questiontext = array(); $questiontext['text'] = implode('', $lines); $questiontext['format'] = FORMAT_MOODLE; $questiontext['itemid'] = ''; $question = qtype_multianswer_extract_question($questiontext); $question->questiontext = $question->questiontext['text']; $question->questiontextformat = 0; $question->qtype = 'multianswer'; $question->generalfeedback = ''; $question->generalfeedbackformat = FORMAT_MOODLE; $question->length = 1; $question->penalty = 0.3333333; if (!empty($question)) { $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question')); $questions[] = $question; } return $questions; }
protected function definition_inner($mform) { $qtype = question_bank::get_qtype('essay'); $mform->addElement('header', 'responseoptions', get_string('responseoptions', 'qtype_essay')); $mform->setExpanded('responseoptions'); $mform->addElement('select', 'responseformat', get_string('responseformat', 'qtype_essay'), $qtype->response_formats()); $mform->setDefault('responseformat', 'editor'); $mform->addElement('select', 'responserequired', get_string('responserequired', 'qtype_essay'), $qtype->response_required_options()); $mform->setDefault('responserequired', 1); $mform->disabledIf('responserequired', 'responseformat', 'eq', 'noinline'); $mform->addElement('select', 'responsefieldlines', get_string('responsefieldlines', 'qtype_essay'), $qtype->response_sizes()); $mform->setDefault('responsefieldlines', 15); $mform->disabledIf('responsefieldlines', 'responseformat', 'eq', 'noinline'); $mform->addElement('select', 'attachments', get_string('allowattachments', 'qtype_essay'), $qtype->attachment_options()); $mform->setDefault('attachments', 0); $mform->addElement('select', 'attachmentsrequired', get_string('attachmentsrequired', 'qtype_essay'), $qtype->attachments_required_options()); $mform->setDefault('attachmentsrequired', 0); $mform->addHelpButton('attachmentsrequired', 'attachmentsrequired', 'qtype_essay'); $mform->disabledIf('attachmentsrequired', 'attachments', 'eq', 0); $mform->addElement('header', 'responsetemplateheader', get_string('responsetemplateheader', 'qtype_essay')); $mform->addElement('editor', 'responsetemplate', get_string('responsetemplate', 'qtype_essay'), array('rows' => 10), array_merge($this->editoroptions, array('maxfiles' => 0))); $mform->addHelpButton('responsetemplate', 'responsetemplate', 'qtype_essay'); $mform->addElement('header', 'graderinfoheader', get_string('graderinfoheader', 'qtype_essay')); $mform->setExpanded('graderinfoheader'); $mform->addElement('editor', 'graderinfo', get_string('graderinfo', 'qtype_essay'), array('rows' => 10), $this->editoroptions); }
/** * Add question-type specific form fields. * * @param object $mform the form being built. */ protected function definition_inner($mform) { $menu = array( get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'), ); $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu); $mform->setDefault('single', 1); $mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0, 1)); $mform->addHelpButton('shuffleanswers', 'shuffleanswers', 'qtype_multichoice'); $mform->setDefault('shuffleanswers', 1); $mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), qtype_multichoice::get_numbering_styles()); $mform->setDefault('answernumbering', 'abc'); $this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'), question_bank::fraction_options_full(), max(5, QUESTION_NUMANS_START)); $this->add_combined_feedback_fields(true); $mform->disabledIf('shownumcorrect', 'single', 'eq', 1); $this->add_interactive_settings(true, true); }
/** * Makes a calculated question about summing two numbers. * @return qtype_calculated_question */ public function make_calculated_question_sum() { question_bank::load_question_definition_classes('calculated'); $q = new qtype_calculated_question(); test_question_maker::initialise_a_question($q); $q->name = 'Simple sum'; $q->questiontext = 'What is {a} + {b}?'; $q->generalfeedback = 'Generalfeedback: {={a} + {b}} is the right answer.'; $q->answers = array( 13 => new qtype_numerical_answer(13, '{a} + {b}', 1.0, 'Very good.', FORMAT_HTML, 0), 14 => new qtype_numerical_answer(14, '{a} - {b}', 0.0, 'Add. not subtract!.', FORMAT_HTML, 0), 17 => new qtype_numerical_answer(17, '*', 0.0, 'Completely wrong.', FORMAT_HTML, 0), ); foreach ($q->answers as $answer) { $answer->correctanswerlength = 2; $answer->correctanswerformat = 1; } $q->qtype = question_bank::get_qtype('calculated'); $q->unitdisplay = qtype_numerical::UNITNONE; $q->unitgradingtype = 0; $q->unitpenalty = 0; $q->ap = new qtype_numerical_answer_processor(array()); $q->synchronised = false; $q->datasetloader = new qtype_calculated_test_dataset_loader(0, array( array('a' => 1, 'b' => 5), array('a' => 3, 'b' => 4), )); return $q; }
/** * Makes a calculated question about summing two numbers. * @return qtype_calculated_question */ public function get_calculated_question_data_sum() { question_bank::load_question_definition_classes('calculated'); $qdata = new stdClass(); test_question_maker::initialise_question_data($qdata); $qdata->qtype = 'calculated'; $qdata->name = 'Simple sum'; $qdata->questiontext = 'What is {a} + {b}?'; $qdata->generalfeedback = 'Generalfeedback: {={a} + {b}} is the right answer.'; $qdata->options = new stdClass(); $qdata->options->unitgradingtype = 0; $qdata->options->unitpenalty = 0.0; $qdata->options->showunits = qtype_numerical::UNITNONE; $qdata->options->unitsleft = 0; $qdata->options->synchronize = 0; $qdata->options->answers = array( 13 => new qtype_numerical_answer(13, '{a} + {b}', 1.0, 'Very good.', FORMAT_HTML, 0.001), 14 => new qtype_numerical_answer(14, '{a} - {b}', 0.0, 'Add. not subtract!.', FORMAT_HTML, 0.001), 17 => new qtype_numerical_answer(17, '*', 0.0, 'Completely wrong.', FORMAT_HTML, 0), ); foreach ($qdata->options->answers as $answer) { $answer->correctanswerlength = 2; $answer->correctanswerformat = 1; } $qdata->options->units = array(); return $qdata; }
public function test_render_missing() { $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, 'strangeunknown', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, '_order', '1,2,3'), array(1, 123, 1, 1, 'strangeunknown', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 2, 1, 'complete', 0.5, 1256233705, 1, '-submit', '1'), array(1, 123, 1, 1, 'strangeunknown', -1, 1, 2.0, 0.0, 1.0, 0, '', '', '', 1256233790, 2, 1, 'complete', 0.5, 1256233705, 1, 'choice0', '1'))); $question = test_question_maker::make_question('truefalse', 'true'); $question->id = -1; question_bank::start_unit_test(); question_bank::load_test_question_data($question); $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback'); question_bank::end_unit_test(); $this->assertEquals(2, $qa->get_num_steps()); $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('_order' => '1,2,3'), $step->get_all_data()); $step = $qa->get_step(1); $this->assertEquals(question_state::$complete, $step->get_state()); $this->assertEquals(0.5, $step->get_fraction()); $this->assertEquals(1256233705, $step->get_timecreated()); $this->assertEquals(1, $step->get_user_id()); $this->assertEquals(array('-submit' => '1', 'choice0' => '1'), $step->get_all_data()); $output = $qa->render(new question_display_options(), '1'); $this->assertRegExp('/' . preg_quote($qa->get_question()->questiontext, '/') . '/', $output); $this->assertRegExp('/' . preg_quote(get_string('questionusedunknownmodel', 'qbehaviour_missing'), '/') . '/', $output); $this->assertTag(array('tag' => 'div', 'attributes' => array('class' => 'warning')), $output); }
/** * Add question-type specific form fields. * * @param object $mform the form being built. */ protected function definition_inner($mform) { $mform->removeElement('defaultmark'); $mform->addElement('hidden', 'defaultmark', '1'); $mform->removeElement('generalfeedback'); $mform->addElement('advcheckbox', 'autoplay', get_string('autoplay', 'qtype_turmultiplechoice'), null, null, array(0, 1)); $mform->addHelpButton('autoplay', 'autoplay', 'qtype_turmultiplechoice'); $mform->setDefault('autoplay', 0); $menu = array(get_string('answersingleno', 'qtype_turmultiplechoice'), get_string('answersingleyes', 'qtype_turmultiplechoice')); $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_turmultiplechoice'), $menu); $mform->setDefault('single', 0); // 'Image to display' filemanager $mform->addElement('filemanager', 'questionimage', 'Image to display', null, array('maxfiles' => 1)); // TODO: Use lang string // 'Choose soundfile for question' filemanager $mform->addElement('filemanager', 'questionsound', 'Choose soundfile for question', null, array('maxfiles' => 1, 'accepted_types' => array('.mp3'))); // TODO: Use lang string $question_difficulties = array(); $question_difficulties[0] = get_string('q_easy1', 'qtype_turmultiplechoice'); $question_difficulties[1] = get_string('q_easy2', 'qtype_turmultiplechoice'); $question_difficulties[2] = get_string('q_easy3', 'qtype_turmultiplechoice'); $question_difficulties[3] = get_string('q_medium1', 'qtype_turmultiplechoice'); $question_difficulties[4] = get_string('q_medium2', 'qtype_turmultiplechoice'); $question_difficulties[5] = get_string('q_medium3', 'qtype_turmultiplechoice'); $question_difficulties[6] = get_string('q_hard1', 'qtype_turmultiplechoice'); $question_difficulties[7] = get_string('q_hard2', 'qtype_turmultiplechoice'); $question_difficulties[8] = get_string('q_hard3', 'qtype_turmultiplechoice'); $mform->addElement('select', 'qdifficulty', get_string('qdifficulty', 'qtype_turmultiplechoice'), $question_difficulties); $mform->setDefault('qdifficulty', 0); $mform->addElement('hidden', 'shuffleanswers', 1); $this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_turmultiplechoice', '{no}'), question_bank::fraction_options_full(), max(4, QUESTION_NUMANS_START), 4); $this->add_combined_feedback_fields(true); $mform->disabledIf('shownumcorrect', 'single', 'eq', 1); }
/** * Do the job. * Throw exceptions on errors (the job will be retried). */ public function execute() { global $CFG; // Run question bank clean-up. require_once $CFG->libdir . '/questionlib.php'; \question_bank::cron(); }
protected function definition_inner($mform) { global $PAGE, $CFG; $PAGE->requires->css('/question/type/easyoselectjs/easyoselectjs_styles.css'); $marvinjsconfig = get_config('qtype_easyoselectjs_options'); $marvinjspath = $marvinjsconfig->path; $protocol = (empty($_SERVER['HTTPS']) or $_SERVER['HTTPS'] == 'off') ? 'http://' : 'https://'; $PAGE->requires->js(new moodle_url($protocol . $_SERVER['HTTP_HOST'] . $marvinjspath . '/js/promise-0.1.1.min.js')); $PAGE->requires->js(new moodle_url($protocol . $_SERVER['HTTP_HOST'] . $marvinjspath . '/js/marvinjslauncher.js')); $mform->addElement('static', 'answersinstruct', get_string('correctanswers', 'qtype_easyoselectjs'), get_string('filloutoneanswer', 'qtype_easyoselectjs')); $mform->closeHeaderBefore('answersinstruct'); $mform->setType('structure', PARAM_RAW); $mform->addElement('hidden', 'structure', "", array('id' => 'id_structure')); $mform->addElement('html', html_writer::start_tag('div', array('id' => 'appletdiv', 'class' => 'easyomechjs resizable'))); $mform->addElement('html', html_writer::start_tag('div', array('style' => 'float: left;font-style: italic ;'))); $mform->addElement('html', html_writer::start_tag('small')); $easyoselectjshomeurl = 'http://www.chemaxon.com'; $mform->addElement('html', html_writer::link($easyoselectjshomeurl, get_string('easyoselectjseditor', 'qtype_easyoselectjs'))); $mform->addElement('html', html_writer::empty_tag('br')); $mform->addElement('html', html_writer::tag('span', get_string('author', 'qtype_easyoselectjs'), array('class' => 'easyoselectjsauthor'))); $mform->addElement('html', html_writer::end_tag('small')); $mform->addElement('html', html_writer::end_tag('div')); $mform->addElement('html', html_writer::end_tag('div')); $marvinconfig = get_config('qtype_easyoselectjs_options'); $marvinpath = $marvinconfig->path; $PAGE->requires->js_init_call('M.qtype_easyoselectjs.insert_applet', array($CFG->wwwroot, $marvinpath)); $this->add_per_answer_fields($mform, get_string('answerno', 'qtype_easyoselectjs', '{no}'), question_bank::fraction_options()); $this->add_interactive_settings(); $PAGE->requires->js_init_call('M.qtype_easyoselectjs.init_getanswerstring', array($CFG->version)); $PAGE->requires->js_init_call('M.qtype_easyoselectjs.init_viewanswerstring', array($CFG->version)); }
/** * Run all the question tests for all variants of all questions belonging to * a given context. * * Does output as we go along. * * @param context $context the context to run the tests for. * @return array with two elements: * bool true if all the tests passed, else false. * array of messages relating to the questions with failures. */ public function run_all_tests_for_context(context $context) { global $DB, $OUTPUT; // Load the necessary data. $categories = question_category_options(array($context)); $categories = reset($categories); $questiontestsurl = new moodle_url('/question/type/stack/questiontestrun.php'); if ($context->contextlevel == CONTEXT_COURSE) { $questiontestsurl->param('courseid', $context->instanceid); } else { if ($context->contextlevel == CONTEXT_MODULE) { $questiontestsurl->param('cmid', $context->instanceid); } } $allpassed = true; $failingtests = array(); foreach ($categories as $key => $category) { list($categoryid) = explode(',', $key); echo $OUTPUT->heading($category, 3); $questionids = $DB->get_records_menu('question', array('category' => $categoryid, 'qtype' => 'stack'), 'name', 'id,name'); if (!$questionids) { continue; } echo html_writer::tag('p', stack_string('replacedollarscount', count($questionids))); foreach ($questionids as $questionid => $name) { $tests = question_bank::get_qtype('stack')->load_question_tests($questionid); if (!$tests) { echo $OUTPUT->heading(html_writer::link(new moodle_url($questiontestsurl, array('questionid' => $questionid)), format_string($name)), 4); echo html_writer::tag('p', stack_string('bulktestnotests')); continue; } $question = question_bank::load_question($questionid); $questionname = format_string($name); $previewurl = new moodle_url($questiontestsurl, array('questionid' => $questionid)); if (empty($question->deployedseeds)) { $questionnamelink = html_writer::link($previewurl, $questionname); echo $OUTPUT->heading($questionnamelink, 4); list($ok, $message) = $this->qtype_stack_test_question($question, $tests); if (!$ok) { $allpassed = false; $failingtests[] = $questionnamelink . ': ' . $message; } } else { echo $OUTPUT->heading(format_string($name), 4); foreach ($question->deployedseeds as $seed) { $previewurl->param('seed', $seed); $questionnamelink = html_writer::link($previewurl, stack_string('seedx', $seed)); echo $OUTPUT->heading($questionnamelink, 4); list($ok, $message) = $this->qtype_stack_test_question($question, $tests, $seed); if (!$ok) { $allpassed = false; $failingtests[] = $questionname . ' ' . $questionnamelink . ': ' . $message; } } } } } return array($allpassed, $failingtests); }
/** * Create a quiz add questions to it, walk through quiz attempts and then check results. * * @param PHPUnit_Extensions_Database_DataSet_ITable[] of data read from csv file "questionsXX.csv", * "stepsXX.csv" and "resultsXX.csv". * @dataProvider get_data_for_walkthrough */ public function test_walkthrough_from_csv($quizsettings, $csvdata) { // CSV data files for these tests were generated using : // https://github.com/jamiepratt/moodle-quiz-tools/tree/master/responsegenerator $this->resetAfterTest(true); question_bank::get_qtype('random')->clear_caches_before_testing(); $this->create_quiz($quizsettings, $csvdata['questions']); $attemptids = $this->walkthrough_attempts($csvdata['steps']); $this->check_attempts_results($csvdata['results'], $attemptids); $this->report = new quiz_statistics_report(); $whichattempts = QUIZ_GRADEAVERAGE; $groupstudents = array(); $questions = $this->report->load_and_initialise_questions_for_calculations($this->quiz); list($quizstats, $questionstats, $subquestionstats) = $this->report->get_quiz_and_questions_stats($this->quiz, $whichattempts, $groupstudents, $questions); $qubaids = quiz_statistics_qubaids_condition($this->quiz->id, $groupstudents, $whichattempts); // We will create some quiz and question stat calculator instances and some response analyser instances, just in order // to check the time of the $quizcalc = new quiz_statistics_calculator(); // Should not be a delay of more than one second between the calculation of stats above and here. $this->assertTimeCurrent($quizcalc->get_last_calculated_time($qubaids)); $qcalc = new \core_question\statistics\questions\calculator($questions); $this->assertTimeCurrent($qcalc->get_last_calculated_time($qubaids)); foreach ($questions as $question) { if (!question_bank::get_qtype($question->qtype, false)->can_analyse_responses()) { continue; } $responesstats = new \core_question\statistics\responses\analyser($question); $this->assertTimeCurrent($responesstats->get_last_analysed_time($qubaids)); } // These quiz stats and the question stats found in qstats00.csv were calculated independently in spreadsheet which is // available in open document or excel format here : // https://github.com/jamiepratt/moodle-quiz-tools/tree/master/statsspreadsheet $quizstatsexpected = array('median' => 4.5, 'firstattemptsavg' => 4.617333332, 'allattemptsavg' => 4.617333332, 'firstattemptscount' => 25, 'allattemptscount' => 25, 'standarddeviation' => 0.8117265554, 'skewness' => -0.092502502, 'kurtosis' => -0.7073968557, 'cic' => -87.22309355420001, 'errorratio' => 136.8294900795, 'standarderror' => 1.1106813066); foreach ($quizstatsexpected as $statname => $statvalue) { $this->assertEquals($statvalue, $quizstats->{$statname}, $quizstats->{$statname}, abs($statvalue) * 1.5E-5); } for ($rowno = 0; $rowno < $csvdata['qstats']->getRowCount(); $rowno++) { $slotqstats = $csvdata['qstats']->getRow($rowno); foreach ($slotqstats as $statname => $slotqstat) { if ($statname !== 'slot') { switch ($statname) { case 'covariance': case 'discriminationindex': case 'discriminativeefficiency': case 'effectiveweight': $precision = 1.0E-5; break; default: $precision = 1.0E-6; } $slot = $slotqstats['slot']; $delta = abs($slotqstat) * $precision; $actual = $questionstats[$slot]->{$statname}; $this->assertEquals(floatval($slotqstat), $actual, "{$statname} for slot {$slot}", $delta); } } } }
protected function definition_inner($mform) { $menu = array(get_string('caseno', 'qtype_shortanswer'), get_string('caseyes', 'qtype_shortanswer')); $mform->addElement('select', 'usecase', get_string('casesensitive', 'qtype_shortanswer'), $menu); $mform->addElement('static', 'answersinstruct', get_string('correctanswers', 'qtype_shortanswer'), get_string('filloutoneanswer', 'qtype_shortanswer')); $mform->closeHeaderBefore('answersinstruct'); $this->add_per_answer_fields($mform, get_string('answerno', 'qtype_shortanswer', '{no}'), question_bank::fraction_options()); $this->add_interactive_settings(); }
public function __construct($plugintype, $pluginname, $step) { parent::__construct($plugintype, $pluginname, $step); $this->qtypeobj = question_bank::get_qtype($this->pluginname); $this->oldquestionid = -1; $this->newquestionid = -1; $this->questioncreated = false; $this->currentanswer = null; }
public function test_save_question_zero_name() { $this->resetAfterTest(); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(array()); $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id, 'name' => '0')); $actual = question_bank::load_question_data($saq->id); $this->assertSame('0', $actual->name); }
/** * 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 definition() { global $CFG, $PAGE; parent::definition(); $mform = $this->_form; $mform->addElement("hidden", self::EDITOR_INFO_ELEMENT_NAME); $mform->setType(self::EDITOR_INFO_ELEMENT_NAME, PARAM_RAW); $mform->setDefault(self::EDITOR_INFO_ELEMENT_NAME, json_encode(array("image_server" => get_config('omero', 'omero_restendpoint'), "viewer_model_server" => $CFG->omero_image_server, "image_info_container_id" => $this->image_info_container_id, "image_selector_id" => $this->image_selector_id, "answer_header" => "id_answerhdr", "fraction_options" => question_bank::fraction_options_full()))); $PAGE->requires->js_call_amd("qtype_omeromultichoice/question-editor-multichoice", "main", array(self::EDITOR_INFO_ELEMENT_NAME)); }
/** * Create a new instance of this class for holding/computing the statistics * for a particular question. * @param object $questiondata the data from the database defining this question. */ public function __construct($questiondata) { $this->questiondata = $questiondata; $this->responseclasses = question_bank::get_qtype($questiondata->qtype)->get_possible_responses($questiondata); foreach ($this->responseclasses as $subpartid => $responseclasses) { foreach ($responseclasses as $responseclassid => $notused) { $this->responses[$subpartid][$responseclassid] = array(); } } }