MDL-20636 And fix XML import unit tests too.

This commit is contained in:
Tim Hunt 2011-01-18 16:06:05 +00:00
parent 5f7cfba7fa
commit fe0412432f
8 changed files with 271 additions and 136 deletions

View File

@ -422,8 +422,8 @@ class qbehaviour_interactive_walkthrough_test extends qbehaviour_walkthrough_tes
$this->check_current_mark(3);
// Now change the quiestion so that answer is only partially right, and regrade.
$q->answers[0]->fraction = 0.6666667;
$q->answers[1]->fraction = 1;
$q->answers[13]->fraction = 0.6666667;
$q->answers[14]->fraction = 1;
$this->quba->regrade_all_questions(false);
@ -455,8 +455,8 @@ class qbehaviour_interactive_walkthrough_test extends qbehaviour_walkthrough_tes
$this->check_current_mark(3);
// Now change the quiestion so that answer is only partially right, and regrade.
$q->answers[0]->fraction = 0.6666667;
$q->answers[1]->fraction = 1;
$q->answers[13]->fraction = 0.6666667;
$q->answers[14]->fraction = 1;
$this->quba->regrade_all_questions(true);

View File

@ -237,11 +237,11 @@ class test_question_maker {
$num->questiontext = 'What is pi to two d.p.?';
$num->generalfeedback = 'Generalfeedback: 3.14 is the right answer.';
$num->answers = array(
new qtype_numerical_answer('3.14', 1.0, 'Very good.', 0),
new qtype_numerical_answer('3.142', 0.0, 'Too accurate.', 0.005),
new qtype_numerical_answer('3.1', 0.0, 'Not accurate enough.', 0.05),
new qtype_numerical_answer('3', 0.0, 'Not accurate enough.', 0.5),
new qtype_numerical_answer('*', 0.0, 'Completely wrong.', 0),
13 => new qtype_numerical_answer(13, '3.14', 1.0, 'Very good.', FORMAT_HTML, 0),
14 => new qtype_numerical_answer(14, '3.142', 0.0, 'Too accurate.', FORMAT_HTML, 0.005),
15 => new qtype_numerical_answer(15, '3.1', 0.0, 'Not accurate enough.', FORMAT_HTML, 0.05),
16 => new qtype_numerical_answer(16, '3', 0.0, 'Not accurate enough.', FORMAT_HTML, 0.5),
17 => new qtype_numerical_answer(17, '*', 0.0, 'Completely wrong.', FORMAT_HTML, 0),
);
$num->qtype = question_bank::get_qtype('numerical');
$num->ap = new qtype_numerical_answer_processor(array());

View File

@ -282,12 +282,25 @@ class qformat_xml extends qformat_default {
* @param boolean $withshownumpartscorrect include the shownumcorrect field.
*/
public function import_combined_feedback($qo, $questionxml, $withshownumpartscorrect = false) {
$qo->correctfeedback = $this->getpath($questionxml,
array('#', 'correctfeedback', 0, '#', 'text', 0, '#'), '', true);
$qo->partiallycorrectfeedback = $this->getpath($questionxml,
array('#', 'partiallycorrectfeedback', 0, '#', 'text', 0, '#'), '', true);
$qo->incorrectfeedback = $this->getpath($questionxml,
array('#', 'incorrectfeedback', 0, '#', 'text', 0, '#'), '', true);
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $field) {
$text = array();
$text['text'] = $this->getpath($questionxml,
array('#', $field, 0, '#', 'text', 0, '#'), '', true);
$text['format'] = $this->trans_format($this->getpath($questionxml,
array('#', $field, 0, '@', 'format'), 'moodle_auto_format'));
$text['files'] = array();
$files = $this->getpath($questionxml, array('#', $field, 0, '#','file'), array(), false);
foreach ($files as $file) {
$data = new stdClass();
$data->content = $file['#'];
$data->encoding = $file['@']['encoding'];
$data->name = $file['@']['name'];
$text['files'][] = $data;
}
$qo->$field = $text;
}
if ($withshownumpartscorrect) {
$qo->shownumcorrect = array_key_exists('shownumcorrect', $questionxml['#']);
@ -341,7 +354,8 @@ class qformat_xml extends qformat_default {
if (!isset($questionxml['#']['hint'])) {
return;
}
// TODO files in hints.
// TODO Handle files in hints.
foreach ($questionxml['#']['hint'] as $hintxml) {
$hint = $this->import_hint($hintxml);
$qo->hint[] = $hint->hint;
@ -374,52 +388,6 @@ class qformat_xml extends qformat_default {
$qo->answernumbering = $this->getpath($question, array('#', 'answernumbering', 0, '#'), 'abc');
$qo->shuffleanswers = $this->trans_single($shuffleanswers);
// TODO move into import_combined_feedback
$qo->correctfeedback = array();
$qo->correctfeedback['text'] = $this->getpath($question, array('#', 'correctfeedback', 0, '#', 'text', 0, '#'), '', true);
$qo->correctfeedback['format'] = $this->trans_format(
$this->getpath($question, array('#', 'correctfeedback', 0, '@', 'format'), 'moodle_auto_format'));
$qo->correctfeedback['files'] = array();
// restore files in correctfeedback
$files = $this->getpath($question, array('#', 'correctfeedback', 0, '#','file'), array(), false);
foreach ($files as $file) {
$data = new stdclass;
$data->content = $file['#'];
$data->encoding = $file['@']['encoding'];
$data->name = $file['@']['name'];
$qo->correctfeedback['files'][] = $data;
}
$qo->partiallycorrectfeedback = array();
$qo->partiallycorrectfeedback['text'] = $this->getpath( $question, array('#','partiallycorrectfeedback',0,'#','text',0,'#'), '', true );
$qo->partiallycorrectfeedback['format'] = $this->trans_format(
$this->getpath($question, array('#', 'partiallycorrectfeedback', 0, '@', 'format'), 'moodle_auto_format'));
$qo->partiallycorrectfeedback['files'] = array();
// restore files in partiallycorrectfeedback
$files = $this->getpath($question, array('#', 'partiallycorrectfeedback', 0, '#','file'), array(), false);
foreach ($files as $file) {
$data = new stdclass;
$data->content = $file['#'];
$data->encoding = $file['@']['encoding'];
$data->name = $file['@']['name'];
$qo->partiallycorrectfeedback['files'][] = $data;
}
$qo->incorrectfeedback = array();
$qo->incorrectfeedback['text'] = $this->getpath( $question, array('#','incorrectfeedback',0,'#','text',0,'#'), '', true );
$qo->incorrectfeedback['format'] = $this->trans_format(
$this->getpath($question, array('#', 'incorrectfeedback', 0, '@', 'format'), 'moodle_auto_format'));
$qo->incorrectfeedback['files'] = array();
// restore files in incorrectfeedback
$files = $this->getpath($question, array('#', 'incorrectfeedback', 0, '#','file'), array(), false);
foreach ($files as $file) {
$data = new stdclass;
$data->content = $file['#'];
$data->encoding = $file['@']['encoding'];
$data->name = $file['@']['name'];
$qo->incorrectfeedback['files'][] = $data;
}
// There was a time on the 1.8 branch when it could output an empty answernumbering tag, so fix up any found.
if (empty($qo->answernumbering)) {
$qo->answernumbering = 'abc';
@ -530,16 +498,14 @@ class qformat_xml extends qformat_default {
$qo->feedbacktrue = array();
$qo->feedbacktrue['text'] = $feedback;
$qo->feedbacktrue['format'] = $this->trans_format($feedbackformat);
$qo->feedbacktrue['itemid'] = null;
$qo->feedbacktruefiles = $files;
$qo->feedbacktrue['files'] = $files;
} else {
$qo->answer = ($answer['@']['fraction'] != 100);
$qo->correctanswer = $qo->answer;
$qo->feedbackfalse = array();
$qo->feedbackfalse['text'] = $feedback;
$qo->feedbackfalse['format'] = $this->trans_format($feedbackformat);
$qo->feedbackfalse['itemid'] = null;
$qo->feedbackfalsefiles = $files;
$qo->feedbackfalse['files'] = $files;
}
$first = false;
}
@ -576,7 +542,7 @@ class qformat_xml extends qformat_default {
$acount = 0;
foreach ($answers as $answer) {
$ans = $this->import_answer($answer);
$qo->answer[$acount] = $ans->answer;
$qo->answer[$acount] = $ans->answer['text'];
$qo->fraction[$acount] = $ans->fraction;
$qo->feedback[$acount] = $ans->feedback;
++$acount;
@ -688,30 +654,27 @@ class qformat_xml extends qformat_default {
$qo->shuffleanswers = $this->trans_single($this->getpath($question,
array('#', 'shuffleanswers', 0, '#'), 1));
// get subquestions
$subquestions = $question['#']['subquestion'];
// run through subquestions
$qo->subquestions = array();
$qo->subanswers = array();
foreach ($question['#']['subquestion'] as $subqxml) {
$subquestion = array();
$subquestion['text'] = $this->getpath($subqxml, array('#', 'text', 0, '#'), '', true);
$subquestion['format'] = $this->trans_format(
$this->getpath($subqxml, array('@', 'format'), 'moodle_auto_format'));
$subquestion['files'] = array();
// run through subquestions
foreach ($subquestions as $subquestion) {
$question = array();
$question['text'] = $this->getpath($subquestion, array('#', 'text', 0, '#'), '', true);
$question['format'] = $this->trans_format(
$this->getpath($subquestion, array('@', 'format'), 'moodle_auto_format'));
$question['files'] = array();
$files = $this->getpath($subquestion, array('#', 'file'), array());
$files = $this->getpath($subqxml, array('#', 'file'), array());
foreach ($files as $file) {
$data = new stdclass();
$data->content = $file['#'];
$data->encoding = $file['@']['encoding'];
$data->name = $file['@']['name'];
$question['files'][] = $data;
$subquestion['files'][] = $data;
}
$qo->subquestions[] = $question;
$answers = $this->getpath($subquestion, array('#', 'answer'), array());
$qo->subanswers[] = $this->getpath($subquestion, array('#','answer',0,'#','text',0,'#'), '', true);
$qo->subquestions[] = $subquestion;
$answers = $this->getpath($subqxml, array('#', 'answer'), array());
$qo->subanswers[] = $this->getpath($subqxml, array('#','answer',0,'#','text',0,'#'), '', true);
}
$this->import_combined_feedback($qo, $question, true);
@ -1122,16 +1085,16 @@ class qformat_xml extends qformat_default {
$fs = get_file_storage();
$contextid = $question->contextid;
// files used by questiontext
$files = $fs->get_area_files($contextid, 'question', 'questiontext', $question->id);
$question->questiontextfiles = $files;
// files used by generalfeedback
$files = $fs->get_area_files($contextid, 'question', 'generalfeedback', $question->id);
$question->generalfeedbackfiles = $files;
// Get files used by the questiontext.
$question->questiontextfiles = $fs->get_area_files(
$contextid, 'question', 'questiontext', $question->id);
// Get files used by the generalfeedback.
$question->generalfeedbackfiles = $fs->get_area_files(
$contextid, 'question', 'generalfeedback', $question->id);
if (!empty($question->options->answers)) {
foreach ($question->options->answers as $answer) {
$files = $fs->get_area_files($contextid, 'question', 'answerfeedback', $answer->id);
$answer->feedbackfiles = $files;
$answer->feedbackfiles = $fs->get_area_files(
$contextid, 'question', 'answerfeedback', $answer->id);
}
}

View File

@ -330,7 +330,7 @@ END;
$this->assert_same_xml($expectedxml, $xml);
}
public function test_import_match() {
public function test_import_match_19() {
$xml = ' <question type="matching">
<name>
<text>Matching question</text>
@ -398,16 +398,21 @@ END;
$expectedq->name = 'Matching question';
$expectedq->questiontext = 'Match the upper and lower case letters.';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->correctfeedback = 'Well done.';
$expectedq->partiallycorrectfeedback = 'Not entirely.';
$expectedq->correctfeedback = array('text' => 'Well done.', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->partiallycorrectfeedback = array('text' => 'Not entirely.', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->shownumcorrect = false;
$expectedq->incorrectfeedback = 'Completely wrong!';
$expectedq->incorrectfeedback = array('text' => 'Completely wrong!', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->generalfeedback = 'The answer is A -> a, B -> b and C -> c.';
$expectedq->generalfeedbackformat = FORMAT_MOODLE;
$expectedq->defaultmark = 1;
$expectedq->length = 1;
$expectedq->penalty = 0.3333333;
$expectedq->shuffleanswers = 0;
$expectedq->subquestions = array('A', 'B', 'C', '');
$expectedq->subquestions = array(
array('text' => 'A', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => 'B', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => 'C', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '', 'format' => FORMAT_MOODLE, 'files' => array()));
$expectedq->subanswers = array('a', 'b', 'c', 'd');
$expectedq->hint = array('Hint 1', '');
$expectedq->hintshownumcorrect = array(true, true);
@ -539,7 +544,7 @@ END;
$this->assert_same_xml($expectedxml, $xml);
}
public function test_import_multichoice() {
public function test_import_multichoice_19() {
$xml = ' <question type="multichoice">
<name>
<text>Multiple choice question</text>
@ -607,10 +612,11 @@ END;
$expectedq->name = 'Multiple choice question';
$expectedq->questiontext = 'Which are the even numbers?';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->correctfeedback = '<p>Your answer is correct.</p>';
$expectedq->partiallycorrectfeedback = '<p>Your answer is partially correct.</p>';
$expectedq->correctfeedback = array('text' => '<p>Your answer is correct.</p>', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->shownumcorrect = false;
$expectedq->partiallycorrectfeedback = array('text' => '<p>Your answer is partially correct.</p>', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->shownumcorrect = true;
$expectedq->incorrectfeedback = '<p>Your answer is incorrect.</p>';
$expectedq->incorrectfeedback = array('text' => '<p>Your answer is incorrect.</p>', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->generalfeedback = 'The even numbers are 2 and 4.';
$expectedq->defaultmark = 2;
$expectedq->length = 1;
@ -618,9 +624,17 @@ END;
$expectedq->shuffleanswers = 0;
$expectedq->single = false;
$expectedq->answer = array('1', '2', '3', '4');
$expectedq->answer = array(
array('text' => '1', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '2', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '3', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '4', 'format' => FORMAT_MOODLE, 'files' => array()));
$expectedq->fraction = array(0, 1, 0, 1);
$expectedq->feedback = array('', '', '', '');
$expectedq->feedback = array(
array('text' => '', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => '', 'format' => FORMAT_MOODLE, 'files' => array()));
$expectedq->hint = array('Hint 1.', 'Hint 2.');
$expectedq->hintshownumcorrect = array(false, false);
@ -734,7 +748,7 @@ END;
$this->assert_same_xml($expectedxml, $xml);
}
public function test_import_numerical() {
public function test_import_numerical_19() {
$xml = ' <question type="numerical">
<name>
<text>Numerical question</text>
@ -781,13 +795,17 @@ END;
$expectedq->questiontext = 'What is the answer?';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.';
$expectedq->generalfeedbackformat = FORMAT_MOODLE;
$expectedq->defaultmark = 1;
$expectedq->length = 1;
$expectedq->penalty = 0.1;
$expectedq->answer = array('42', '13', '*');
$expectedq->fraction = array(1, 0, 0);
$expectedq->feedback = array('Well done!', 'What were you thinking?!', 'Completely wrong.');
$expectedq->feedback = array(
array('text' => 'Well done!', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => 'What were you thinking?!', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => 'Completely wrong.', 'format' => FORMAT_MOODLE, 'files' => array()));
$expectedq->tolerance = array(0.001, 1, 0);
$this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q);
@ -798,20 +816,22 @@ END;
$qdata = new stdClass;
$qdata->id = 123;
$qdata->contextid = 0;
$qdata->qtype = 'numerical';
$qdata->name = 'Numerical question';
$qdata->questiontext = 'What is the answer?';
$qdata->questiontextformat = FORMAT_HTML;
$qdata->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.';
$qdata->generalfeedbackformat = FORMAT_HTML;
$qdata->defaultmark = 1;
$qdata->length = 1;
$qdata->penalty = 0.1;
$qdata->hidden = 0;
$qdata->options->answers = array(
new qtype_numerical_answer('42', 1, 'Well done!', 0.001),
new qtype_numerical_answer('13', 0, 'What were you thinking?!', 1),
new qtype_numerical_answer('*', 0, 'Completely wrong.', ''),
13 => new qtype_numerical_answer(13, '42', 1, 'Well done!', FORMAT_HTML, 0.001),
14 => new qtype_numerical_answer(14, '13', 0, 'What were you thinking?!', FORMAT_HTML, 1),
15 => new qtype_numerical_answer(15, '*', 0, 'Completely wrong.', FORMAT_HTML, ''),
);
$qdata->options->units = array();
@ -827,7 +847,7 @@ END;
<questiontext format="html">
<text>What is the answer?</text>
</questiontext>
<generalfeedback>
<generalfeedback format="html">
<text>General feedback: Think Hitch-hikers guide to the Galaxy.</text>
</generalfeedback>
<defaultgrade>1</defaultgrade>
@ -835,21 +855,21 @@ END;
<hidden>0</hidden>
<answer fraction="100">
<text>42</text>
<feedback>
<feedback format="html">
<text>Well done!</text>
</feedback>
<tolerance>0.001</tolerance>
</answer>
<answer fraction="0">
<text>13</text>
<feedback>
<feedback format="html">
<text>What were you thinking?!</text>
</feedback>
<tolerance>1</tolerance>
</answer>
<answer fraction="0">
<text>*</text>
<feedback>
<feedback format="html">
<text>Completely wrong.</text>
</feedback>
<tolerance>0</tolerance>
@ -860,7 +880,7 @@ END;
$this->assert_same_xml($expectedxml, $xml);
}
public function test_import_shortanswer() {
public function test_import_shortanswer_19() {
$xml = ' <question type="shortanswer">
<name>
<text>Short answer question</text>
@ -912,7 +932,9 @@ END;
$expectedq->answer = array('Beta', '*');
$expectedq->fraction = array(1, 0);
$expectedq->feedback = array('Well done!', 'Doh!');
$expectedq->feedback = array(
array('text' => 'Well done!', 'format' => FORMAT_MOODLE, 'files' => array()),
array('text' => 'Doh!', 'format' => FORMAT_MOODLE, 'files' => array()));
$this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q);
}
@ -955,7 +977,7 @@ END;
<questiontext format="html">
<text>Fill in the gap in this sequence: Alpha, ________, Gamma.</text>
</questiontext>
<generalfeedback>
<generalfeedback format="html">
<text>The answer is Beta.</text>
</generalfeedback>
<defaultgrade>1</defaultgrade>
@ -964,20 +986,20 @@ END;
<usecase>0</usecase>
<answer fraction="100">
<text>Beta</text>
<feedback>
<feedback format="html">
<text>Well done!</text>
</feedback>
</answer>
<answer fraction="0">
<text>*</text>
<feedback>
<feedback format="html">
<text>Doh!</text>
</feedback>
</answer>
<hint>
<hint format="html">
<text>Hint 1</text>
</hint>
<hint>
<hint format="html">
<text>Hint 2</text>
</hint>
</question>
@ -986,7 +1008,7 @@ END;
$this->assert_same_xml($expectedxml, $xml);
}
public function test_import_truefalse() {
public function test_import_truefalse_19() {
$xml = ' <question type="truefalse">
<name>
<text>True false question</text>
@ -1028,8 +1050,8 @@ END;
$expectedq->length = 1;
$expectedq->penalty = 1;
$expectedq->feedbacktrue = 'Well done!';
$expectedq->feedbackfalse = 'Doh!';
$expectedq->feedbacktrue = array('text' => 'Well done!', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->feedbackfalse = array('text' => 'Doh!', 'format' => FORMAT_MOODLE, 'files' => array());
$expectedq->correctanswer = true;
$this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q);

View File

@ -160,9 +160,13 @@ DONE mod/quiz/protect_js.php | 56 -
mod/quiz/report/statistics/statistics_table.php | 335 +++
mod/quiz/report/statistics/version.php | 26 +
pix/i/flagged.png | Bin 0 -> 193 bytes
pix/i/ne_red_mark.png | Bin 0 -> 121 bytes
pix/i/unflagged.png | Bin 0 -> 197 bytes
theme/standard/styles_color.css | 72 +-
theme/standard/styles_fonts.css | 20 +-
theme/standard/styles_layout.css | 265 ++-
DONE pix/i/flagged.png | Bin 0 -> 193 bytes
DONE pix/i/ne_red_mark.png | Bin 0 -> 121 bytes
DONE pix/i/unflagged.png | Bin 0 -> 197 bytes
question/backuplib.php | 26 +-
DONE question/comment.html | 25 -
@ -246,10 +250,10 @@ DONE question/behaviour/informationitem/lang/en_utf8/qbehaviour_informationitem.
DONE question/behaviour/informationitem/renderer.php | 42 +
DONE question/behaviour/informationitem/simpletest/testwalkthrough.php | 78 +
DONE question/behaviour/interactive/behaviour.php | 232 ++
question/behaviour/interactive/behaviour.php | 232 ++
DONE question/behaviour/interactive/lang/en_utf8/qbehaviour_interactive.php | 6 +
DONE question/behaviour/interactive/renderer.php | 62 +
DONE question/behaviour/interactive/interactive/simpletest/testwalkthrough.php | 470 ++++
question/behaviour/interactive/interactive/simpletest/testwalkthrough.php | 470 ++++
DONE question/behaviour/interactivecountback/behaviour.php | 91 +
DONE question/behaviour/interactivecountback/en_utf8/qbehaviour_interactivecountback.php | 3 +
@ -276,8 +280,8 @@ DONE question/format/blackboard/format.php | 2 +-
DONE question/format/gift/format.php | 6 +-
DONE question/format/hotpot/format.php | 10 +-
DONE question/format/webct/format.php | 4 +-
question/format/xml/format.php | 985 ++++---
question/format/xml/simpletest/testxmlformat.php | 1064 ++++++++
DONE question/format/xml/format.php | 985 ++++---
DONE question/format/xml/simpletest/testxmlformat.php | 1064 ++++++++
question/type/calculated/db/upgrade.php | 2 -
question/type/calculated/edit_calculated_form.php | 5 +-
@ -441,8 +445,3 @@ DONE question/type/truefalse/renderer.php | 142 +
DONE question/type/truefalse/simpletest/testquestion.php | 99 +
DONE question/type/truefalse/simpletest/testquestiontype.php | 73 +
DONE question/type/truefalse/version.php | 4 +-
theme/standard/styles_color.css | 72 +-
theme/standard/styles_fonts.css | 20 +-
theme/standard/styles_layout.css | 265 ++-

View File

@ -0,0 +1,151 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Numerical question definition class.
*
* @package qtype_numerical
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
/**
* Represents a numerical question.
*
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_numerical_question extends question_graded_by_strategy
implements question_response_answer_comparer {
/** @var array of question_answer. */
public $answers = array();
/** @var qtype_numerical_answer_processor */
public $ap;
public function __construct() {
parent::__construct(new question_first_matching_answer_grading_strategy($this));
}
public function get_expected_data() {
return array('answer' => PARAM_TRIM);
}
public function init_first_step(question_attempt_step $step) {
if ($step->has_qt_var('_separators')) {
list($point, $separator) = explode('$', $step->get_qt_var('_separators'));
$this->ap->set_characters($point, $separator);
} else {
$step->set_qt_var('_separators',
$this->ap->get_point() . '$' . $this->ap->get_separator());
}
}
public function summarise_response(array $response) {
if (isset($response['answer'])) {
return $response['answer'];
} else {
return null;
}
}
public function is_complete_response(array $response) {
return array_key_exists('answer', $response) &&
($response['answer'] || $response['answer'] === '0' || $response['answer'] === 0);
}
public function get_validation_error(array $response) {
if ($this->is_gradable_response($response)) {
return '';
}
return get_string('pleaseenterananswer', 'qtype_numerical');
}
public function is_same_response(array $prevresponse, array $newresponse) {
return question_utils::arrays_same_at_key_missing_is_blank(
$prevresponse, $newresponse, 'answer');
}
public function get_answers() {
return $this->answers;
}
public function compare_response_with_answer(array $response, question_answer $answer) {
list($value, $unit) = $this->ap->apply_units($response['answer']);
return $answer->within_tolerance($value);
}
}
/**
* Subclass of {@link question_answer} with the extra information required by
* the numerical question type.
*
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_numerical_answer extends question_answer {
/** @var float allowable margin of error. */
public $tolerance;
/** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */
public $tolerancetype = 2;
public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {
parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);
$this->tolerance = abs($tolerance);
}
public function get_tolerance_interval() {
if ($this->answer === '*') {
throw new Exception('Cannot work out tolerance interval for answer *.');
}
// We need to add a tiny fraction depending on the set precision to make
// the comparison work correctly, otherwise seemingly equal values can
// yield false. See MDL-3225.
$tolerance = (float) $this->tolerance + pow(10, -1 * ini_get('precision'));
switch ($this->tolerancetype) {
case 1: case 'relative':
$range = abs($this->answer) * $tolerance;
return array($this->answer - $range, $this->answer + $range);
case 2: case 'nominal':
$tolerance = $this->tolerance + pow(10, -1 * ini_get('precision')) *
max(1, abs($this->answer));
return array($this->answer - $tolerance, $this->answer + $tolerance);
case 3: case 'geometric':
$quotient = 1 + abs($tolerance);
return array($this->answer / $quotient, $this->answer * $quotient);
default:
throw new Exception('Unknown tolerance type ' . $this->tolerancetype);
}
}
public function within_tolerance($value) {
if ($this->answer === '*') {
return true;
}
list($min, $max) = $this->get_tolerance_interval();
return $min <= $value && $value <= $max;
}
}

View File

@ -131,13 +131,13 @@ class qtype_shortanswer_question_test extends UnitTestCase {
$sa->init_first_step(new question_attempt_step());
$this->assertEqual(array(
new question_classified_response(0, 'frog', 1.0)),
new question_classified_response(13, 'frog', 1.0)),
$sa->classify_response(array('answer' => 'frog')));
$this->assertEqual(array(
new question_classified_response(1, 'toad', 0.8)),
new question_classified_response(14, 'toad', 0.8)),
$sa->classify_response(array('answer' => 'toad')));
$this->assertEqual(array(
new question_classified_response(2, 'cat', 0.0)),
new question_classified_response(15, 'cat', 0.0)),
$sa->classify_response(array('answer' => 'cat')));
$this->assertEqual(array(
question_classified_response::no_response()),

View File

@ -72,7 +72,7 @@ class question_first_matching_answer_grading_strategy_test extends UnitTestCase
public function test_matching_answer_returned2() {
$answer = new question_answer(0, 'frog', 1, '', FORMAT_HTML);
$answer2 = new question_answer(0, 'frog', 0.5, '');
$answer2 = new question_answer(0, 'frog', 0.5, '', FORMAT_HTML);
$question = new test_response_answer_comparer(array($answer, $answer2));
$strategy = new question_first_matching_answer_grading_strategy($question);
$this->assertIdentical($answer, $strategy->grade(array('answer' => 'frog')));