mirror of
https://github.com/moodle/moodle.git
synced 2025-08-03 16:13:28 +02:00
MDL-27413 qtype_multianswer upgrade. First passing test.
This commit is contained in:
parent
dcedbb0e25
commit
1cacb05989
3 changed files with 300 additions and 45 deletions
|
@ -37,5 +37,206 @@ require_once($CFG->dirroot . '/question/engine/upgrade/simpletest/helper.php');
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_test_base {
|
||||
// TODO
|
||||
public function test_multianswer_adaptivenopenalty_qsession104() {
|
||||
$quiz = (object) array(
|
||||
'id' => '5',
|
||||
'course' => '2',
|
||||
'name' => 'Multianswer quiz',
|
||||
'intro' => '',
|
||||
'introformat' => '1',
|
||||
'timeopen' => '0',
|
||||
'timeclose' => '0',
|
||||
'attempts' => '0',
|
||||
'attemptonlast' => '0',
|
||||
'grademethod' => '1',
|
||||
'decimalpoints' => '2',
|
||||
'questiondecimalpoints' => '-1',
|
||||
'review' => '4459503',
|
||||
'questionsperpage' => '1',
|
||||
'shufflequestions' => '0',
|
||||
'shuffleanswers' => '1',
|
||||
'questions' => '28,19,0',
|
||||
'sumgrades' => '14.00000',
|
||||
'grade' => '10.00000',
|
||||
'timecreated' => '0',
|
||||
'timemodified' => '1306424728',
|
||||
'timelimit' => '0',
|
||||
'password' => '',
|
||||
'subnet' => '',
|
||||
'popup' => '0',
|
||||
'delay1' => '0',
|
||||
'delay2' => '0',
|
||||
'showuserpicture' => '0',
|
||||
'showblocks' => '0',
|
||||
'preferredbehaviour' => 'adaptivenopenalty',
|
||||
);
|
||||
$attempt = (object) array(
|
||||
'id' => '16',
|
||||
'uniqueid' => '16',
|
||||
'quiz' => '5',
|
||||
'userid' => '4',
|
||||
'attempt' => '1',
|
||||
'sumgrades' => '6.00000',
|
||||
'timestart' => '1306425691',
|
||||
'timefinish' => '1306425746',
|
||||
'timemodified' => '1306425746',
|
||||
'layout' => '28,19,0',
|
||||
'preview' => '0',
|
||||
'needsupgradetonewqe' => 1,
|
||||
);
|
||||
$question = (object) array(
|
||||
'id' => '28',
|
||||
'category' => '2',
|
||||
'parent' => '0',
|
||||
'name' => 'Very simple cloze',
|
||||
'questiontext' => '<p>An answer {#1}.</p>',
|
||||
'questiontextformat' => '1',
|
||||
'generalfeedback' => '',
|
||||
'generalfeedbackformat' => '1',
|
||||
'penalty' => '0.1000000',
|
||||
'qtype' => 'multianswer',
|
||||
'length' => '1',
|
||||
'stamp' => 'tjh238.vledev2.open.ac.uk+110526154631+XQLcXi',
|
||||
'version' => 'tjh238.vledev2.open.ac.uk+110526154631+T8hPiI',
|
||||
'hidden' => '0',
|
||||
'timecreated' => '1306424791',
|
||||
'timemodified' => '1306424791',
|
||||
'createdby' => '2',
|
||||
'modifiedby' => '2',
|
||||
'maxmark' => '1.0000000',
|
||||
'options' => (object) array(
|
||||
'questions' => array(
|
||||
1 => (object) array(
|
||||
'id' => '29',
|
||||
'category' => '2',
|
||||
'parent' => '28',
|
||||
'name' => 'Very simple cloze',
|
||||
'questiontext' => '{1:SHORTANSWER:=frog#Yay!}',
|
||||
'questiontextformat' => '0',
|
||||
'generalfeedback' => '',
|
||||
'generalfeedbackformat' => '1',
|
||||
'defaultgrade' => '1.0000000',
|
||||
'penalty' => '0.0000000',
|
||||
'qtype' => 'shortanswer',
|
||||
'length' => '1',
|
||||
'stamp' => 'tjh238.vledev2.open.ac.uk+110526154631+j3BYTL',
|
||||
'version' => 'tjh238.vledev2.open.ac.uk+110526154631+lxNwQv',
|
||||
'hidden' => '0',
|
||||
'timecreated' => '1306424791',
|
||||
'timemodified' => '1306424791',
|
||||
'createdby' => '2',
|
||||
'modifiedby' => '2',
|
||||
'options' => (object) array(
|
||||
'answers' => array(
|
||||
52 => (object) array(
|
||||
'id' => '52',
|
||||
'question' => '29',
|
||||
'answer' => 'frog',
|
||||
'answerformat' => '0',
|
||||
'fraction' => '1.0000000',
|
||||
'feedback' => 'Yay!',
|
||||
'feedbackformat' => '1',
|
||||
),
|
||||
),
|
||||
'usecase' => '0',
|
||||
),
|
||||
'maxgrade' => '1.0000000',
|
||||
),
|
||||
),
|
||||
),
|
||||
'defaultmark' => '1.0000000',
|
||||
);
|
||||
$qsession = (object) array(
|
||||
'id' => '104',
|
||||
'attemptid' => '16',
|
||||
'questionid' => '28',
|
||||
'newest' => '285',
|
||||
'newgraded' => '285',
|
||||
'sumpenalty' => '0.1000000',
|
||||
'manualcomment' => '',
|
||||
'manualcommentformat' => '1',
|
||||
'flagged' => '0',
|
||||
);
|
||||
$qstates = array(
|
||||
281 => (object) array(
|
||||
'id' => '281',
|
||||
'attempt' => '16',
|
||||
'question' => '28',
|
||||
'seq_number' => '0',
|
||||
'answer' => '1-',
|
||||
'timestamp' => '1306425691',
|
||||
'event' => '0',
|
||||
'grade' => '0.0000000',
|
||||
'raw_grade' => '0.0000000',
|
||||
'penalty' => '0.0000000',
|
||||
),
|
||||
283 => (object) array(
|
||||
'id' => '283',
|
||||
'attempt' => '16',
|
||||
'question' => '28',
|
||||
'seq_number' => '1',
|
||||
'answer' => '1-frog',
|
||||
'timestamp' => '1306425739',
|
||||
'event' => '2',
|
||||
'grade' => '0.0000000',
|
||||
'raw_grade' => '1.0000000',
|
||||
'penalty' => '0.1000000',
|
||||
),
|
||||
285 => (object) array(
|
||||
'id' => '285',
|
||||
'attempt' => '16',
|
||||
'question' => '28',
|
||||
'seq_number' => '2',
|
||||
'answer' => '1-frog',
|
||||
'timestamp' => '1306425739',
|
||||
'event' => '6',
|
||||
'grade' => '1.0000000',
|
||||
'raw_grade' => '1.0000000',
|
||||
'penalty' => '0.1000000',
|
||||
),
|
||||
);
|
||||
|
||||
$qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
|
||||
|
||||
$expectedqa = (object) array(
|
||||
'behaviour' => 'adaptivenopenalty',
|
||||
'questionid' => 28,
|
||||
'maxmark' => 1.0000000,
|
||||
'minfraction' => 0,
|
||||
'flagged' => 0,
|
||||
'questionsummary' => 'An answer _____.',
|
||||
'rightanswer' => 'part 1: frog',
|
||||
'responsesummary' => 'part 1: frog',
|
||||
'timemodified' => 1306425739,
|
||||
'steps' => array(
|
||||
0 => (object) array(
|
||||
'sequencenumber' => 0,
|
||||
'state' => 'todo',
|
||||
'fraction' => null,
|
||||
'timecreated' => 1306425691,
|
||||
'userid' => 4,
|
||||
'data' => array('-_try' => 1),
|
||||
),
|
||||
1 => (object) array(
|
||||
'sequencenumber' => 1,
|
||||
'state' => 'complete',
|
||||
'fraction' => null,
|
||||
'timecreated' => 1306425739,
|
||||
'userid' => 4,
|
||||
'data' => array('sub1_answer' => 'frog'),
|
||||
),
|
||||
2 => (object) array(
|
||||
'sequencenumber' => 2,
|
||||
'state' => 'gradedright',
|
||||
'fraction' => 1.0,
|
||||
'timecreated' => 1306425739,
|
||||
'userid' => 4,
|
||||
'data' => array('sub1_answer' => 'frog', '-finish' => '1',
|
||||
'-_try' => '1', '-_rawfraction' => 1.0),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEqual($expectedqa, $qa);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,55 +37,77 @@ defined('MOODLE_INTERNAL') || die();
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_multianswer_qe2_attempt_updater extends question_qtype_attempt_updater {
|
||||
// TODO
|
||||
public function right_answer() {
|
||||
foreach ($this->question->options->answers as $ans) {
|
||||
if ($ans->fraction > 0.999) {
|
||||
return $ans->answer;
|
||||
|
||||
public function question_summary() {
|
||||
$summary = $this->to_text($this->question->questiontext);
|
||||
foreach ($this->question->options->questions as $i => $subq) {
|
||||
switch ($subq->qtype) {
|
||||
case 'multichoice':
|
||||
$choices = array();
|
||||
foreach ($subq->options->answers as $ans) {
|
||||
$choices[] = $this->to_text($ans->answer);
|
||||
}
|
||||
$answerbit = '{' . implode('; ', $choices) . '}';
|
||||
break;
|
||||
case 'numerical':
|
||||
case 'shortanswer':
|
||||
$answerbit = '_____';
|
||||
break;
|
||||
default:
|
||||
$answerbit = '{ERR unknown sub-question type}';
|
||||
}
|
||||
$summary = str_replace('{#' . $i . '}', $answerbit, $summary);
|
||||
}
|
||||
return $summary;
|
||||
}
|
||||
|
||||
// public function restore_session_and_responses(&$question, &$state) {
|
||||
// $responses = explode(',', $state->responses['']);
|
||||
// $state->responses = array();
|
||||
// foreach ($responses as $response) {
|
||||
// $tmp = explode("-", $response);
|
||||
// // restore encoded characters
|
||||
// $state->responses[$tmp[0]] = str_replace(array(",", "-"),
|
||||
// array(",", "-"), $tmp[1]);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// public function save_session_and_responses(&$question, &$state) {
|
||||
// global $DB;
|
||||
// $responses = $state->responses;
|
||||
// // encode - (hyphen) and , (comma) to - because they are used as
|
||||
// // delimiters
|
||||
// array_walk($responses, create_function('&$val, $key',
|
||||
// '$val = str_replace(array(",", "-"), array(",", "-"), $val);
|
||||
// $val = "$key-$val";'));
|
||||
// $responses = implode(',', $responses);
|
||||
//
|
||||
// // Set the legacy answer field
|
||||
// $DB->set_field('question_states', 'answer', $responses, array('id' => $state->id));
|
||||
// return true;
|
||||
// }
|
||||
public function right_answer() {
|
||||
$right = array();
|
||||
|
||||
foreach ($this->question->options->questions as $i => $subq) {
|
||||
foreach ($subq->options->answers as $ans) {
|
||||
if ($ans->fraction > 0.999) {
|
||||
$right[$i] = $ans->answer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->display_response($right);
|
||||
}
|
||||
|
||||
public function explode_answer($answer) {
|
||||
$response = array();
|
||||
|
||||
foreach (explode(',', $answer) as $part) {
|
||||
list($index, $partanswer) = explode('-', $part, 2);
|
||||
$response[$index] = str_replace(
|
||||
array(",", "-"), array(',', '-'), $partanswer);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function display_response($response) {
|
||||
$summary = array();
|
||||
foreach ($this->question->options->questions as $i => $subq) {
|
||||
$a = new stdClass();
|
||||
$a->i = $i;
|
||||
$a->response = $this->to_text($response[$i]);
|
||||
$summary[] = get_string('subqresponse', 'qtype_multianswer', $a);
|
||||
}
|
||||
|
||||
return implode('; ', $summary);
|
||||
}
|
||||
|
||||
public function response_summary($state) {
|
||||
if (is_numeric($state->answer)) {
|
||||
if (array_key_exists($state->answer, $this->question->options->answers)) {
|
||||
return $this->question->options->answers[$state->answer]->answer;
|
||||
} else {
|
||||
$this->logger->log_assumption("Dealing with a place where the
|
||||
student selected a choice that was later deleted for
|
||||
true/false question {$this->question->id}");
|
||||
return null;
|
||||
$response = $this->explode_answer($state->answer);
|
||||
foreach ($this->question->options->questions as $i => $subq) {
|
||||
if ($response[$i] && $subq->qtype == 'multichoice') {
|
||||
$response[$i] = $subq->options->answers[$response[$i]];
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return $this->display_response($response);
|
||||
}
|
||||
|
||||
public function was_answered($state) {
|
||||
|
@ -99,8 +121,38 @@ class qtype_multianswer_qe2_attempt_updater extends question_qtype_attempt_updat
|
|||
}
|
||||
|
||||
public function set_data_elements_for_step($state, &$data) {
|
||||
if (is_numeric($state->answer)) {
|
||||
$data['answer'] = (int) ($state->answer == $this->question->options->trueanswer);
|
||||
$response = $this->explode_answer($state->answer);
|
||||
foreach ($this->question->options->questions as $i => $subq) {
|
||||
if (empty($response[$i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($subq->qtype) {
|
||||
case 'multichoice':
|
||||
$choices = array();
|
||||
foreach ($subq->options->answers as $ans) {
|
||||
$choices[] = $this->to_text($ans->answer);
|
||||
}
|
||||
$answerbit = '{' . implode('; ', $choices) . '}';
|
||||
break;
|
||||
case 'numerical':
|
||||
case 'shortanswer':
|
||||
$data[$this->add_prefix('answer', $i)] = $response[$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function add_prefix($field, $i) {
|
||||
$prefix = 'sub' . $i . '_';
|
||||
if (substr($field, 0, 2) === '!_') {
|
||||
return '-_' . $prefix . substr($field, 2);
|
||||
} else if (substr($field, 0, 1) === '-') {
|
||||
return '-' . $prefix . substr($field, 1);
|
||||
} else if (substr($field, 0, 1) === '_') {
|
||||
return '_' . $prefix . substr($field, 1);
|
||||
} else {
|
||||
return $prefix . $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -318,6 +318,7 @@ function qtype_multianswer_extract_question($text) {
|
|||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE])) {
|
||||
$wrapped->qtype = 'multichoice';
|
||||
$wrapped->single = 1;
|
||||
$wrapped->shuffleanswers = 1;
|
||||
$wrapped->answernumbering = 0;
|
||||
$wrapped->correctfeedback['text'] = '';
|
||||
$wrapped->correctfeedback['format'] = '1';
|
||||
|
@ -332,6 +333,7 @@ function qtype_multianswer_extract_question($text) {
|
|||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_REGULAR])) {
|
||||
$wrapped->qtype = 'multichoice';
|
||||
$wrapped->single = 1;
|
||||
$wrapped->shuffleanswers = 0;
|
||||
$wrapped->answernumbering = 0;
|
||||
$wrapped->correctfeedback['text'] = '';
|
||||
$wrapped->correctfeedback['format'] = '1';
|
||||
|
@ -346,6 +348,7 @@ function qtype_multianswer_extract_question($text) {
|
|||
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_HORIZONTAL])) {
|
||||
$wrapped->qtype = 'multichoice';
|
||||
$wrapped->single = 1;
|
||||
$wrapped->shuffleanswers = 0;
|
||||
$wrapped->answernumbering = 0;
|
||||
$wrapped->correctfeedback['text'] = '';
|
||||
$wrapped->correctfeedback['format'] = '1';
|
||||
|
@ -368,7 +371,6 @@ function qtype_multianswer_extract_question($text) {
|
|||
$wrapped->answer = array();
|
||||
$wrapped->fraction = array();
|
||||
$wrapped->feedback = array();
|
||||
$wrapped->shuffleanswers = 1;
|
||||
$wrapped->questiontext['text'] = $answerregs[0];
|
||||
$wrapped->questiontext['format'] = 0;
|
||||
$wrapped->questiontext['itemid'] = '';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue