mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
Merge branch 'MDL-3782_multichoice_multiple' of git://github.com/davosmith/moodle
This commit is contained in:
commit
be97f38188
@ -347,22 +347,38 @@ class qtype_multianswer_edit_form extends question_edit_form {
|
||||
|
||||
if ($subquestion->qtype == 'multichoice') {
|
||||
$defaultvalues[$prefix.'layout'] = $subquestion->layout;
|
||||
switch ($subquestion->layout) {
|
||||
case '0':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
if ($subquestion->single == 1) {
|
||||
switch ($subquestion->layout) {
|
||||
case '0':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layoutselectinline', 'qtype_multianswer');
|
||||
break;
|
||||
case '1':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
break;
|
||||
case '1':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layoutvertical', 'qtype_multianswer');
|
||||
break;
|
||||
case '2':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
break;
|
||||
case '2':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layouthorizontal', 'qtype_multianswer');
|
||||
break;
|
||||
default:
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
break;
|
||||
default:
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layoutundefined', 'qtype_multianswer');
|
||||
}
|
||||
} else {
|
||||
switch ($subquestion->layout) {
|
||||
case '1':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layoutmultiple_vertical', 'qtype_multianswer');
|
||||
break;
|
||||
case '2':
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layoutmultiple_horizontal', 'qtype_multianswer');
|
||||
break;
|
||||
default:
|
||||
$defaultvalues[$prefix.'layout'] =
|
||||
get_string('layoutundefined', 'qtype_multianswer');
|
||||
}
|
||||
}
|
||||
if ($subquestion->shuffleanswers ) {
|
||||
$defaultvalues[$prefix.'shuffleanswers'] = get_string('yes', 'moodle');
|
||||
@ -393,6 +409,11 @@ class qtype_multianswer_edit_form extends question_edit_form {
|
||||
if ($subquestion->fraction[$key] > $maxfraction) {
|
||||
$maxfraction = $subquestion->fraction[$key];
|
||||
}
|
||||
// For 'multiresponse' we are OK if there is at least one fraction > 0.
|
||||
if ($subquestion->qtype == 'multichoice' && $subquestion->single == 0 &&
|
||||
$subquestion->fraction[$key] > 0) {
|
||||
$maxgrade = true;
|
||||
}
|
||||
}
|
||||
|
||||
$defaultvalues[$prefix.'answer['.$key.']'] =
|
||||
@ -484,6 +505,11 @@ class qtype_multianswer_edit_form extends question_edit_form {
|
||||
if ($subquestion->fraction[$key] > $maxfraction) {
|
||||
$maxfraction = $subquestion->fraction[$key];
|
||||
}
|
||||
// For 'multiresponse' we are OK if there is at least one fraction > 0.
|
||||
if ($subquestion->qtype == 'multichoice' && $subquestion->single == 0 &&
|
||||
$subquestion->fraction[$key] > 0) {
|
||||
$maxgrade = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($answercount == 0) {
|
||||
|
@ -30,6 +30,8 @@ $string['correctanswerandfeedback'] = 'Correct answer and feedback';
|
||||
$string['decodeverifyquestiontext'] = 'Decode and verify the question text';
|
||||
$string['layout'] = 'Layout';
|
||||
$string['layouthorizontal'] = 'Horizontal row of radio-buttons';
|
||||
$string['layoutmultiple_horizontal'] = 'Horizontal row of checkboxes';
|
||||
$string['layoutmultiple_vertical'] = 'Vertical column of checkboxes';
|
||||
$string['layoutselectinline'] = 'Dropdown menu in-line in the text';
|
||||
$string['layoutundefined'] = 'Undefined layout';
|
||||
$string['layoutvertical'] = 'Vertical column of radio buttons';
|
||||
|
@ -279,7 +279,8 @@ define('NUMERICAL_ABS_ERROR_MARGIN', 6);
|
||||
define('ANSWER_TYPE_DEF_REGEX',
|
||||
'(NUMERICAL|NM)|(MULTICHOICE|MC)|(MULTICHOICE_V|MCV)|(MULTICHOICE_H|MCH)|' .
|
||||
'(SHORTANSWER|SA|MW)|(SHORTANSWER_C|SAC|MWC)|' .
|
||||
'(MULTICHOICE_S|MCS)|(MULTICHOICE_VS|MCVS)|(MULTICHOICE_HS|MCHS)');
|
||||
'(MULTICHOICE_S|MCS)|(MULTICHOICE_VS|MCVS)|(MULTICHOICE_HS|MCHS)|'.
|
||||
'(MULTIRESPONSE|MR)|(MULTIRESPONSE_H|MRH)|(MULTIRESPONSE_S|MRS)|(MULTIRESPONSE_HS|MRHS)');
|
||||
define('ANSWER_START_REGEX',
|
||||
'\{([0-9]*):(' . ANSWER_TYPE_DEF_REGEX . '):');
|
||||
|
||||
@ -301,7 +302,11 @@ define('ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER_C', 8);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_SHUFFLED', 9);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_REGULAR_SHUFFLED', 10);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_HORIZONTAL_SHUFFLED', 11);
|
||||
define('ANSWER_REGEX_ALTERNATIVES', 12);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE', 12);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE_HORIZONTAL', 13);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE_SHUFFLED', 14);
|
||||
define('ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE_HORIZONTAL_SHUFFLED', 15);
|
||||
define('ANSWER_REGEX_ALTERNATIVES', 16);
|
||||
|
||||
/**
|
||||
* Initialise subquestion fields that are constant across all MULTICHOICE
|
||||
@ -387,6 +392,26 @@ function qtype_multianswer_extract_question($text) {
|
||||
qtype_multianswer_initialise_multichoice_subquestion($wrapped);
|
||||
$wrapped->shuffleanswers = 1;
|
||||
$wrapped->layout = qtype_multichoice_base::LAYOUT_HORIZONTAL;
|
||||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE])) {
|
||||
qtype_multianswer_initialise_multichoice_subquestion($wrapped);
|
||||
$wrapped->single = 0;
|
||||
$wrapped->shuffleanswers = 0;
|
||||
$wrapped->layout = qtype_multichoice_base::LAYOUT_VERTICAL;
|
||||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE_HORIZONTAL])) {
|
||||
qtype_multianswer_initialise_multichoice_subquestion($wrapped);
|
||||
$wrapped->single = 0;
|
||||
$wrapped->shuffleanswers = 0;
|
||||
$wrapped->layout = qtype_multichoice_base::LAYOUT_HORIZONTAL;
|
||||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE_SHUFFLED])) {
|
||||
qtype_multianswer_initialise_multichoice_subquestion($wrapped);
|
||||
$wrapped->single = 0;
|
||||
$wrapped->shuffleanswers = 1;
|
||||
$wrapped->layout = qtype_multichoice_base::LAYOUT_VERTICAL;
|
||||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTIRESPONSE_HORIZONTAL_SHUFFLED])) {
|
||||
qtype_multianswer_initialise_multichoice_subquestion($wrapped);
|
||||
$wrapped->single = 0;
|
||||
$wrapped->shuffleanswers = 1;
|
||||
$wrapped->layout = qtype_multichoice_base::LAYOUT_HORIZONTAL;
|
||||
} else {
|
||||
print_error('unknownquestiontype', 'question', '', $answerregs[2]);
|
||||
return false;
|
||||
@ -403,12 +428,14 @@ function qtype_multianswer_extract_question($text) {
|
||||
$wrapped->questiontext['itemid'] = '';
|
||||
$answerindex = 0;
|
||||
|
||||
$hasspecificfraction = false;
|
||||
$remainingalts = $answerregs[ANSWER_REGEX_ALTERNATIVES];
|
||||
while (preg_match('/~?'.ANSWER_ALTERNATIVE_REGEX.'/s', $remainingalts, $altregs)) {
|
||||
if ('=' == $altregs[ANSWER_ALTERNATIVE_REGEX_FRACTION]) {
|
||||
$wrapped->fraction["{$answerindex}"] = '1';
|
||||
} else if ($percentile = $altregs[ANSWER_ALTERNATIVE_REGEX_PERCENTILE_FRACTION]) {
|
||||
$wrapped->fraction["{$answerindex}"] = .01 * $percentile;
|
||||
$hasspecificfraction = true;
|
||||
} else {
|
||||
$wrapped->fraction["{$answerindex}"] = '0';
|
||||
}
|
||||
@ -453,6 +480,26 @@ function qtype_multianswer_extract_question($text) {
|
||||
$answerindex++;
|
||||
}
|
||||
|
||||
// Fix the score for multichoice_multi questions (as positive scores should add up to 1, not have a maximum of 1).
|
||||
if (isset($wrapped->single) && $wrapped->single == 0) {
|
||||
$total = 0;
|
||||
foreach ($wrapped->fraction as $idx => $fraction) {
|
||||
if ($fraction > 0) {
|
||||
$total += $fraction;
|
||||
}
|
||||
}
|
||||
if ($total) {
|
||||
foreach ($wrapped->fraction as $idx => $fraction) {
|
||||
if ($fraction > 0) {
|
||||
$wrapped->fraction[$idx] = $fraction / $total;
|
||||
} else if (!$hasspecificfraction) {
|
||||
// If no specific fractions are given, set incorrect answers to each cancel out one correct answer.
|
||||
$wrapped->fraction[$idx] = -(1.0 / $total);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$question->defaultmark += $wrapped->defaultmark;
|
||||
$question->options->questions[$positionkey] = clone($wrapped);
|
||||
$question->questiontext['text'] = implode("{#$positionkey}",
|
||||
|
@ -84,12 +84,20 @@ class qtype_multianswer_renderer extends qtype_renderer {
|
||||
if ($subtype == 'numerical' || $subtype == 'shortanswer') {
|
||||
$subrenderer = 'textfield';
|
||||
} else if ($subtype == 'multichoice') {
|
||||
if ($subq->layout == qtype_multichoice_base::LAYOUT_DROPDOWN) {
|
||||
$subrenderer = 'multichoice_inline';
|
||||
} else if ($subq->layout == qtype_multichoice_base::LAYOUT_HORIZONTAL) {
|
||||
$subrenderer = 'multichoice_horizontal';
|
||||
if ($subq instanceof qtype_multichoice_multi_question) {
|
||||
if ($subq->layout == qtype_multichoice_base::LAYOUT_VERTICAL) {
|
||||
$subrenderer = 'multiresponse_vertical';
|
||||
} else {
|
||||
$subrenderer = 'multiresponse_horizontal';
|
||||
}
|
||||
} else {
|
||||
$subrenderer = 'multichoice_vertical';
|
||||
if ($subq->layout == qtype_multichoice_base::LAYOUT_DROPDOWN) {
|
||||
$subrenderer = 'multichoice_inline';
|
||||
} else if ($subq->layout == qtype_multichoice_base::LAYOUT_HORIZONTAL) {
|
||||
$subrenderer = 'multichoice_horizontal';
|
||||
} else {
|
||||
$subrenderer = 'multichoice_vertical';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new coding_exception('Unexpected subquestion type.', $subq);
|
||||
@ -470,3 +478,187 @@ class qtype_multianswer_multichoice_horizontal_renderer
|
||||
html_writer::end_tag('table');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class qtype_multianswer_multiresponse_renderer
|
||||
*
|
||||
* @copyright 2016 Davo Smith, Synergy Learning
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_multianswer_multiresponse_vertical_renderer extends qtype_multianswer_subq_renderer_base {
|
||||
|
||||
/**
|
||||
* Output the content of the subquestion.
|
||||
*
|
||||
* @param question_attempt $qa
|
||||
* @param question_display_options $options
|
||||
* @param int $index
|
||||
* @param question_graded_automatically $subq
|
||||
* @return string
|
||||
*/
|
||||
public function subquestion(question_attempt $qa, question_display_options $options,
|
||||
$index, question_graded_automatically $subq) {
|
||||
|
||||
if (!$subq instanceof qtype_multichoice_multi_question) {
|
||||
throw new coding_exception('Expecting subquestion of type qtype_multichoice_multi_question');
|
||||
}
|
||||
|
||||
$fieldprefix = 'sub' . $index . '_';
|
||||
$fieldname = $fieldprefix . 'choice';
|
||||
|
||||
// Extract the responses that related to this question + strip off the prefix.
|
||||
$fieldprefixlen = strlen($fieldprefix);
|
||||
$response = [];
|
||||
foreach ($qa->get_last_qt_data() as $name => $val) {
|
||||
if (substr($name, 0, $fieldprefixlen) == $fieldprefix) {
|
||||
$name = substr($name, $fieldprefixlen);
|
||||
$response[$name] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
$basename = $qa->get_qt_field_name($fieldname);
|
||||
$inputattributes = array(
|
||||
'type' => 'checkbox',
|
||||
'value' => 1,
|
||||
);
|
||||
if ($options->readonly) {
|
||||
$inputattributes['disabled'] = 'disabled';
|
||||
}
|
||||
|
||||
$result = $this->all_choices_wrapper_start();
|
||||
|
||||
// Calculate the total score (as we need to know if choices should be marked as 'correct' or 'partial').
|
||||
$fraction = 0;
|
||||
foreach ($subq->get_order($qa) as $value => $ansid) {
|
||||
$ans = $subq->answers[$ansid];
|
||||
if ($subq->is_choice_selected($response, $value)) {
|
||||
$fraction += $ans->fraction;
|
||||
}
|
||||
}
|
||||
// Display 'correct' answers as correct, if we are at 100%, otherwise mark them as 'partial'.
|
||||
$answerfraction = ($fraction > 0.999) ? 1.0 : 0.5;
|
||||
|
||||
foreach ($subq->get_order($qa) as $value => $ansid) {
|
||||
$ans = $subq->answers[$ansid];
|
||||
|
||||
$name = $basename.$value;
|
||||
$inputattributes['name'] = $name;
|
||||
$inputattributes['id'] = $name;
|
||||
|
||||
$isselected = $subq->is_choice_selected($response, $value);
|
||||
if ($isselected) {
|
||||
$inputattributes['checked'] = 'checked';
|
||||
} else {
|
||||
unset($inputattributes['checked']);
|
||||
}
|
||||
|
||||
$class = 'r' . ($value % 2);
|
||||
if ($options->correctness && $isselected) {
|
||||
$thisfrac = ($ans->fraction > 0) ? $answerfraction : 0;
|
||||
$feedbackimg = $this->feedback_image($thisfrac);
|
||||
$class .= ' ' . $this->feedback_class($thisfrac);
|
||||
} else {
|
||||
$feedbackimg = '';
|
||||
}
|
||||
|
||||
$result .= $this->choice_wrapper_start($class);
|
||||
$result .= html_writer::empty_tag('input', $inputattributes);
|
||||
$result .= html_writer::tag('label', $subq->format_text($ans->answer,
|
||||
$ans->answerformat, $qa, 'question', 'answer', $ansid),
|
||||
array('for' => $inputattributes['id']));
|
||||
$result .= $feedbackimg;
|
||||
|
||||
if ($options->feedback && $isselected && trim($ans->feedback)) {
|
||||
$result .= html_writer::tag('div',
|
||||
$subq->format_text($ans->feedback, $ans->feedbackformat,
|
||||
$qa, 'question', 'answerfeedback', $ansid),
|
||||
array('class' => 'specificfeedback'));
|
||||
}
|
||||
|
||||
$result .= $this->choice_wrapper_end();
|
||||
}
|
||||
|
||||
$result .= $this->all_choices_wrapper_end();
|
||||
|
||||
$feedback = array();
|
||||
if ($options->feedback && $options->marks >= question_display_options::MARK_AND_MAX &&
|
||||
$subq->maxmark > 0) {
|
||||
$a = new stdClass();
|
||||
$a->mark = format_float($fraction * $subq->maxmark, $options->markdp);
|
||||
$a->max = format_float($subq->maxmark, $options->markdp);
|
||||
|
||||
$feedback[] = html_writer::tag('div', get_string('markoutofmax', 'question', $a));
|
||||
}
|
||||
|
||||
if ($options->rightanswer) {
|
||||
$correct = [];
|
||||
foreach ($subq->answers as $ans) {
|
||||
if (question_state::graded_state_for_fraction($ans->fraction) == question_state::$gradedpartial) {
|
||||
$correct[] = $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ans->id);
|
||||
}
|
||||
}
|
||||
$correct = '<ul><li>'.implode('</li><li>', $correct).'</li></ul>';
|
||||
$feedback[] = get_string('correctansweris', 'qtype_multichoice', $correct);
|
||||
}
|
||||
|
||||
$result .= html_writer::nonempty_tag('div', implode('<br />', $feedback), array('class' => 'outcome'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class class attribute value.
|
||||
* @return string HTML to go before each choice.
|
||||
*/
|
||||
protected function choice_wrapper_start($class) {
|
||||
return html_writer::start_tag('div', array('class' => $class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string HTML to go after each choice.
|
||||
*/
|
||||
protected function choice_wrapper_end() {
|
||||
return html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string HTML to go before all the choices.
|
||||
*/
|
||||
protected function all_choices_wrapper_start() {
|
||||
return html_writer::start_tag('div', array('class' => 'answer'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string HTML to go after all the choices.
|
||||
*/
|
||||
protected function all_choices_wrapper_end() {
|
||||
return html_writer::end_tag('div');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an embedded multiple-response question horizontally.
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_multianswer_multiresponse_horizontal_renderer
|
||||
extends qtype_multianswer_multiresponse_vertical_renderer {
|
||||
|
||||
protected function choice_wrapper_start($class) {
|
||||
return html_writer::start_tag('td', array('class' => $class));
|
||||
}
|
||||
|
||||
protected function choice_wrapper_end() {
|
||||
return html_writer::end_tag('td');
|
||||
}
|
||||
|
||||
protected function all_choices_wrapper_start() {
|
||||
return html_writer::start_tag('table', array('class' => 'answer')) .
|
||||
html_writer::start_tag('tbody') . html_writer::start_tag('tr');
|
||||
}
|
||||
|
||||
protected function all_choices_wrapper_end() {
|
||||
return html_writer::end_tag('tr') . html_writer::end_tag('tbody') .
|
||||
html_writer::end_tag('table');
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ require_once($CFG->dirroot . '/question/type/multianswer/question.php');
|
||||
*/
|
||||
class qtype_multianswer_test_helper extends question_test_helper {
|
||||
public function get_test_questions() {
|
||||
return array('twosubq', 'fourmc', 'numericalzero', 'dollarsigns');
|
||||
return array('twosubq', 'fourmc', 'numericalzero', 'dollarsigns', 'multiple');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,4 +387,96 @@ class qtype_multianswer_test_helper extends question_test_helper {
|
||||
return $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a multianswer question with multichoice_multiple questions in it.
|
||||
* @return qtype_multianswer_question
|
||||
*/
|
||||
public function make_multianswer_question_multiple() {
|
||||
question_bank::load_question_definition_classes('multianswer');
|
||||
$q = new qtype_multianswer_question();
|
||||
test_question_maker::initialise_a_question($q);
|
||||
$q->name = 'Multichoice multiple';
|
||||
$q->questiontext = 'Please select the fruits {#1} and vegetables {#2}';
|
||||
$q->generalfeedback = 'You should know which foods are fruits or vegetables.';
|
||||
$q->qtype = question_bank::get_qtype('multianswer');
|
||||
|
||||
$q->textfragments = array(
|
||||
'Please select the fruits ',
|
||||
' and vegetables ',
|
||||
''
|
||||
);
|
||||
$q->places = array('1' => '1', '2' => '2');
|
||||
|
||||
// Multiple-choice subquestion.
|
||||
question_bank::load_question_definition_classes('multichoice');
|
||||
$mc = new qtype_multichoice_multi_question();
|
||||
test_question_maker::initialise_a_question($mc);
|
||||
$mc->name = 'Multianswer 1';
|
||||
$mc->questiontext = '{1:MULTIRESPONSE:=Apple#Good~%-50%Burger~%-50%Hot dog#Not a fruit~%-50%Pizza' .
|
||||
'~=Orange#Correct~=Banana}';
|
||||
$mc->questiontextformat = FORMAT_HTML;
|
||||
$mc->generalfeedback = '';
|
||||
$mc->generalfeedbackformat = FORMAT_HTML;
|
||||
|
||||
$mc->shuffleanswers = 0;
|
||||
$mc->answernumbering = 'none';
|
||||
$mc->layout = qtype_multichoice_base::LAYOUT_VERTICAL;
|
||||
$mc->single = 0;
|
||||
|
||||
$mc->answers = array(
|
||||
16 => new question_answer(16, 'Apple', 0.3333333,
|
||||
'Good', FORMAT_HTML),
|
||||
17 => new question_answer(17, 'Burger', -0.5,
|
||||
'', FORMAT_HTML),
|
||||
18 => new question_answer(18, 'Hot dog', -0.5,
|
||||
'Not a fruit', FORMAT_HTML),
|
||||
19 => new question_answer(19, 'Pizza', -0.5,
|
||||
'', FORMAT_HTML),
|
||||
20 => new question_answer(20, 'Orange', 0.3333333,
|
||||
'Correct', FORMAT_HTML),
|
||||
21 => new question_answer(21, 'Banana', 0.3333333,
|
||||
'', FORMAT_HTML),
|
||||
);
|
||||
$mc->qtype = question_bank::get_qtype('multichoice');
|
||||
$mc->maxmark = 1;
|
||||
|
||||
// Multiple-choice subquestion.
|
||||
question_bank::load_question_definition_classes('multichoice');
|
||||
$mc2 = new qtype_multichoice_multi_question();
|
||||
test_question_maker::initialise_a_question($mc2);
|
||||
$mc2->name = 'Multichoice 2';
|
||||
$mc2->questiontext = '{1:MULTIRESPONSE:=Raddish#Good~%-50%Chocolate~%-50%Biscuit#Not a vegetable~%-50%Cheese' .
|
||||
'~=Carrot#Correct}';
|
||||
$mc2->questiontextformat = FORMAT_HTML;
|
||||
$mc2->generalfeedback = '';
|
||||
$mc2->generalfeedbackformat = FORMAT_HTML;
|
||||
|
||||
$mc2->shuffleanswers = 0;
|
||||
$mc2->answernumbering = 'none';
|
||||
$mc2->layout = qtype_multichoice_base::LAYOUT_VERTICAL;
|
||||
$mc2->single = 0;
|
||||
|
||||
$mc2->answers = array(
|
||||
22 => new question_answer(22, 'Raddish', 0.5,
|
||||
'Good', FORMAT_HTML),
|
||||
23 => new question_answer(23, 'Chocolate', -0.5,
|
||||
'', FORMAT_HTML),
|
||||
24 => new question_answer(24, 'Biscuit', -0.5,
|
||||
'Not a vegetable', FORMAT_HTML),
|
||||
25 => new question_answer(25, 'Cheese', -0.5,
|
||||
'', FORMAT_HTML),
|
||||
26 => new question_answer(26, 'Carrot', 0.5,
|
||||
'Correct', FORMAT_HTML),
|
||||
);
|
||||
$mc2->qtype = question_bank::get_qtype('multichoice');
|
||||
$mc2->maxmark = 1;
|
||||
|
||||
$q->subquestions = array(
|
||||
1 => $mc,
|
||||
2 => $mc2,
|
||||
);
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -465,4 +465,61 @@ class qtype_multianswer_walkthrough_test extends qbehaviour_walkthrough_test_bas
|
||||
$this->get_contains_correct_expectation(),
|
||||
new question_no_pattern_expectation('/class="control\b[^"]*\bpartiallycorrect"/'));
|
||||
}
|
||||
|
||||
public function test_deferred_feedback_multiple() {
|
||||
|
||||
// Create a multianswer question.
|
||||
$q = test_question_maker::make_question('multianswer', 'multiple');
|
||||
$this->start_attempt_at_question($q, 'deferredfeedback', 2);
|
||||
|
||||
// Check the initial state.
|
||||
$this->check_current_state(question_state::$todo);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
$this->get_contains_marked_out_of_summary(),
|
||||
$this->get_does_not_contain_feedback_expectation(),
|
||||
$this->get_does_not_contain_validation_error_expectation());
|
||||
|
||||
// Save in incomplete answer.
|
||||
$this->process_submission(array('sub1_choice0' => '1', 'sub1_choice1' => '1',
|
||||
'sub1_choice2' => '', 'sub1_choice3' => '',
|
||||
'sub1_choice4' => '', 'sub1_choice5' => '1',
|
||||
));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$invalid);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
$this->get_contains_marked_out_of_summary(),
|
||||
$this->get_does_not_contain_feedback_expectation(),
|
||||
$this->get_contains_validation_error_expectation());
|
||||
|
||||
// Save a partially correct answer.
|
||||
$this->process_submission(array('sub1_choice0' => '1', 'sub1_choice1' => '',
|
||||
'sub1_choice2' => '', 'sub1_choice3' => '',
|
||||
'sub1_choice4' => '1', 'sub1_choice5' => '1',
|
||||
'sub2_choice0' => '', 'sub2_choice1' => '',
|
||||
'sub2_choice2' => '', 'sub2_choice3' => '',
|
||||
'sub2_choice4' => '1',
|
||||
));
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$complete);
|
||||
$this->check_current_mark(null);
|
||||
$this->check_current_output(
|
||||
$this->get_contains_marked_out_of_summary(),
|
||||
$this->get_does_not_contain_feedback_expectation(),
|
||||
$this->get_does_not_contain_validation_error_expectation());
|
||||
|
||||
// Now submit all and finish.
|
||||
$this->finish();
|
||||
|
||||
// Verify.
|
||||
$this->check_current_state(question_state::$gradedpartial);
|
||||
$this->check_current_mark(1.5);
|
||||
$this->check_current_output(
|
||||
$this->get_contains_mark_summary(1.5),
|
||||
$this->get_contains_partcorrect_expectation(),
|
||||
$this->get_does_not_contain_validation_error_expectation());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user