MDL-20636 Lots of work on numerical answer matching.

Still more to do. Not all the unit tests pass at the moment.
This commit is contained in:
Tim Hunt 2011-03-29 18:31:45 +01:00
parent 91d431240f
commit 544de1c035
9 changed files with 349 additions and 99 deletions

View File

@ -104,12 +104,12 @@ class qtype_numerical_edit_form extends question_edit_form {
$mform->addElement('select', 'multichoicedisplay',
get_string('studentunitanswer', 'qtype_numerical'), $unitinputoptions);
$unitslefts = array(
$unitsleftoptions = array(
0 => get_string('rightexample', 'qtype_numerical'),
1 => get_string('leftexample', 'qtype_numerical')
);
$mform->addElement('select', 'unitsleft',
get_string('unitposition', 'qtype_numerical'), $unitslefts);
get_string('unitposition', 'qtype_numerical'), $unitsleftoptions);
$mform->setDefault('unitsleft', 0);
$mform->addElement('editor', 'instructions',

View File

@ -36,15 +36,22 @@ require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
* @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 {
class qtype_numerical_question extends question_graded_automatically {
/** @var array of question_answer. */
public $answers = array();
/** @var int one of the constants UNITNONE, UNITDISPLAY, UNITSELECT or UNITINPUT. */
public $unitdisplay;
/** @var int one of the constants UNITGRADEDOUTOFMARK or UNITGRADEDOUTOFMAX. */
public $unitgradingtype;
/** @var number the penalty for a missing or unrecognised unit. */
public $unitpenalty;
/** @var qtype_numerical_answer_processor */
public $ap;
public function __construct() {
parent::__construct(new question_first_matching_answer_grading_strategy($this));
parent::__construct();
}
public function get_expected_data() {
@ -86,13 +93,73 @@ class qtype_numerical_question extends question_graded_by_strategy
$prevresponse, $newresponse, 'answer');
}
public function get_answers() {
return $this->answers;
public function get_correct_response() {
$answer = $this->get_correct_answer();
if (!$answer) {
return array();
}
return array('answer' => $answer->answer);
}
public function compare_response_with_answer(array $response, question_answer $answer) {
/**
* Get an answer that contains the feedback and fraction that should be
* awarded for this resonse.
* @param number $value the numerical value of a response.
* @return question_answer the matching answer.
*/
public function get_matching_answer($value) {
foreach ($this->answers as $aid => $answer) {
if ($answer->within_tolerance($value)) {
$answer->id = $aid;
return $answer;
}
}
return null;
}
public function get_correct_answer() {
foreach ($this->answers as $answer) {
$state = question_state::graded_state_for_fraction($answer->fraction);
if ($state == question_state::$gradedright) {
return $answer;
}
}
return null;
}
public function grade_response(array $response) {
list($value, $unit) = $this->ap->apply_units($response['answer']);
return $answer->within_tolerance($value);
$answer = $this->get_matching_answer($value);
if (!$answer) {
return array(0, question_state::$gradedwrong);
}
$fraction = $answer->fraction;
if (empty($unit)) {
if ($this->unitgradingtype == qtype_numerical::UNITGRADEDOUTOFMARK) {
$fraction -= $this->unitpenalty * $fraction;
} else if ($this->unitgradingtype == qtype_numerical::UNITGRADEDOUTOFMAX) {
$fraction -= $this->unitpenalty;
}
$fraction = max($fraction, 0);
}
return array($fraction, question_state::graded_state_for_fraction($fraction));
}
public function classify_response(array $response) {
if (empty($response['answer'])) {
return array($this->id => question_classified_response::no_response());
}
list($value, $unit) = $this->ap->apply_units($response['answer']);
$ans = $this->get_matching_answer($value);
if (!$ans) {
return array($this->id => question_classified_response::no_response());
}
return array($this->id => new question_classified_response(
$ans->id, $response['answer'], $ans->fraction));
}
}

View File

@ -363,6 +363,9 @@ class qtype_numerical extends question_type {
protected function initialise_question_instance(question_definition $question, $questiondata) {
parent::initialise_question_instance($question, $questiondata);
$this->initialise_numerical_answers($question, $questiondata);
$question->unitdisplay = $questiondata->options->showunits;
$question->unitgradingtype = $questiondata->options->unitgradingtype;
$question->unitpenalty = $questiondata->options->unitpenalty;
$this->initialise_numerical_units($question, $questiondata);
}
@ -372,8 +375,8 @@ class qtype_numerical extends question_type {
return;
}
foreach ($questiondata->options->answers as $a) {
$question->answers[$a->id] = new qtype_numerical_answer($a->answer,
$a->fraction, $a->feedback, $a->tolerance);
$question->answers[$a->id] = new qtype_numerical_answer($a->id, $a->answer,
$a->fraction, $a->feedback, $a->feedbackformat, $a->tolerance);
}
}
@ -386,7 +389,8 @@ class qtype_numerical extends question_type {
foreach ($questiondata->options->units as $unit) {
$units[$unit->unit] = $unit->multiplier;
}
$question->ap = new qtype_numerical_answer_processor($units);
$question->ap = new qtype_numerical_answer_processor($units,
$questiondata->options->unitsleft);
}
function delete_question($questionid, $contextid) {
@ -836,6 +840,28 @@ class qtype_numerical extends question_type {
return 0;
}
/**
* @param object $questiondata the data defining the quetsion.
* @param string $answer a response.
* @param object $unit a unit. If null, {@link get_default_numerical_unit()}
* is used.
*/
public function add_unit($questiondata, $answer, $unit = null) {
if (is_null($unit)) {
$unit = $this->get_default_numerical_unit($questiondata);
}
if (!$unit) {
return $answer;
}
if (!empty($questiondata->options->unitsleft)) {
return $unit->unit . ' ' . $answer;
} else {
return $answer . ' ' . $unit->unit;
}
}
public function get_possible_responses($questiondata) {
$responses = array();
@ -845,9 +871,7 @@ class qtype_numerical extends question_type {
$responseclass = $answer->answer;
if ($responseclass != '*') {
if ($unit) {
$responseclass .= ' ' . $unit->unit;
}
$responseclass = $this->add_unit($questiondata, $responseclass, $unit);
$ans = new qtype_numerical_answer($answer->id, $answer->answer, $answer->fraction,
$answer->feedback, $answer->feedbackformat, $answer->tolerance);
@ -863,57 +887,6 @@ class qtype_numerical extends question_type {
return array($questiondata->id => $responses);
}
function get_tolerance_interval(&$answer) {
// No tolerance
if (empty($answer->tolerance)) {
$answer->tolerance = 0;
}
// Calculate the interval of correct responses (min/max)
if (!isset($answer->tolerancetype)) {
$answer->tolerancetype = 2; // nominal
}
// 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. (fixes bug #3225)
$tolerance = (float)$answer->tolerance + ("1.0e-".ini_get('precision'));
switch ($answer->tolerancetype) {
case '1': case 'relative':
/// Recalculate the tolerance and fall through
/// to the nominal case:
$tolerance = $answer->answer * $tolerance;
// Do not fall through to the nominal case because the tiny fraction is a factor of the answer
$tolerance = abs($tolerance); // important - otherwise min and max are swapped
$max = $answer->answer + $tolerance;
$min = $answer->answer - $tolerance;
break;
case '2': case 'nominal':
$tolerance = abs($tolerance); // important - otherwise min and max are swapped
// $answer->tolerance 0 or something else
if ((float)$answer->tolerance == 0.0 && abs((float)$answer->answer) <= $tolerance ) {
$tolerance = (float) ("1.0e-".ini_get('precision')) * abs((float)$answer->answer) ; //tiny fraction
} else if ((float)$answer->tolerance != 0.0 && abs((float)$answer->tolerance) < abs((float)$answer->answer) && abs((float)$answer->answer) <= $tolerance) {
$tolerance = (1+("1.0e-".ini_get('precision')) )* abs((float) $answer->tolerance) ;//tiny fraction
}
$max = $answer->answer + $tolerance;
$min = $answer->answer - $tolerance;
break;
case '3': case 'geometric':
$quotient = 1 + abs($tolerance);
$max = $answer->answer * $quotient;
$min = $answer->answer / $quotient;
break;
default:
print_error('unknowntolerance', 'question', '', $answer->tolerancetype);
}
$answer->min = $min;
$answer->max = $max;
return true;
}
/**
* Checks if the $rawresponse has a unit and applys it if appropriate.
*
@ -1091,10 +1064,12 @@ class qtype_numerical_answer_processor {
protected $decsep;
/** @var string character used as thousands separator. */
protected $thousandssep;
/** @var boolean whether the units come before or after the number. */
protected $unitsbefore;
protected $regex = null;
public function __construct($units, $decsep = null, $thousandssep = null) {
public function __construct($units, $unitsbefore = false, $decsep = null, $thousandssep = null) {
if (is_null($decsep)) {
$decsep = get_string('decsep', 'langconfig');
}
@ -1106,6 +1081,7 @@ class qtype_numerical_answer_processor {
$this->thousandssep = $thousandssep;
$this->units = $units;
$this->unitsbefore = $unitsbefore;
}
/**
@ -1138,17 +1114,20 @@ class qtype_numerical_answer_processor {
return $this->regex;
}
$beforepointre = '([+-]?[' . preg_quote($this->thousandssep, '/') . '\d]*)';
$decimalsre = preg_quote($this->decsep, '/') . '(\d*)';
$decsep = preg_quote($this->decsep, '/');
$thousandssep = preg_quote($this->thousandssep, '/');
$beforepointre = '([+-]?[' . $thousandssep . '\d]*)';
$decimalsre = $decsep . '(\d*)';
$exponentre = '(?:e|E|(?:x|\*|×)10(?:\^|\*\*))([+-]?\d+)';
$escapedunits = array();
foreach ($this->units as $unit => $notused) {
$escapedunits[] = preg_quote($unit, '/');
$validunitendchars = "[^-$decsep\deEx*×^+$thousandssep]";
if ($this->unitsbefore) {
$unitre = "(.*)(?:(?=\s)|(?<=$validunitendchars))\s*";
$this->regex = "/^(?:$unitre)?$beforepointre(?:$decimalsre)?(?:$exponentre)?$/U";
} else {
$unitre = "\s*(?:(?<=\s)|(?=$validunitendchars))(.*)";
$this->regex = "/^$beforepointre(?:$decimalsre)?(?:$exponentre)?(?:$unitre)?$/U";
}
$unitre = '(' . implode('|', $escapedunits) . ')';
$this->regex = "/^$beforepointre(?:$decimalsre)?(?:$exponentre)?\s*(?:$unitre)?$/U";
return $this->regex;
}
@ -1166,7 +1145,11 @@ class qtype_numerical_answer_processor {
}
$matches += array('', '', '', '', ''); // Fill in any missing matches.
list($notused, $beforepoint, $decimals, $exponent, $unit) = $matches;
if ($this->unitsbefore) {
list($notused, $unit, $beforepoint, $decimals, $exponent) = $matches;
} else {
list($notused, $beforepoint, $decimals, $exponent, $unit) = $matches;
}
// Strip out thousands separators.
$beforepoint = str_replace($this->thousandssep, '', $beforepoint);
@ -1177,6 +1160,11 @@ class qtype_numerical_answer_processor {
return array(null, null, null, null);
}
$unit = trim($unit);
if ($unit && !array_key_exists($unit, $this->units)) {
$unit = '';
}
return array($beforepoint, $decimals, $exponent, $unit);
}
@ -1210,4 +1198,20 @@ class qtype_numerical_answer_processor {
return array($value, $unit);
}
/**
* @param string $answer a response.
* @param string $unit a unit.
*/
public function add_unit($answer, $unit) {
if (!$unit) {
return $answer;
}
if ($this->unitsbefore) {
return $unit . ' ' . $answer;
} else {
return $answer . ' ' . $unit;
}
}
}

View File

@ -53,7 +53,8 @@ class qtype_numerical_renderer extends qtype_renderer {
$feedbackimg = '';
if ($options->correctness) {
$answer = $question->get_matching_answer(array('answer' => $currentanswer));
list($value, $unit) = $question->ap->apply_units($currentanswer);
$answer = $question->get_matching_answer($value);
if ($answer) {
$fraction = $answer->fraction;
} else {
@ -63,7 +64,7 @@ class qtype_numerical_renderer extends qtype_renderer {
$feedbackimg = $this->feedback_image($fraction);
}
$questiontext = $question->format_questiontext();
$questiontext = $question->format_questiontext($qa);
$placeholder = false;
if (preg_match('/_____+/', $questiontext, $matches)) {
$placeholder = $matches[0];
@ -98,13 +99,14 @@ class qtype_numerical_renderer extends qtype_renderer {
public function specific_feedback(question_attempt $qa) {
$question = $qa->get_question();
$answer = $question->get_matching_answer(
array('answer' => $qa->get_last_qt_var('answer')));
list($value, $unit) = $question->ap->apply_units($qa->get_last_qt_var('answer'));
$answer = $question->get_matching_answer($value);
if (!$answer || !$answer->feedback) {
return '';
}
return $question->format_text($answer->feedback);
return $question->format_text($answer->feedback, $answer->feedbackformat,
$qa, 'question', 'answerfeedback', $answer->id);
}
public function correct_response(question_attempt $qa) {

View File

@ -0,0 +1,120 @@
<?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/>.
/**
* Test helpers for the drag-and-drop words into sentences question type.
*
* @package qtype
* @subpackage numerical
* @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Test helper class for the drag-and-drop words into sentences question type.
*
* @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_numerical_test_helper extends question_test_helper {
public function get_test_questions() {
return array('pi', 'unit', 'currency');
}
/**
* Makes a numerical question with correct ansewer 3.14, and various incorrect
* answers with different feedback.
* @return qtype_numerical_question
*/
public function make_numerical_question_pi() {
question_bank::load_question_definition_classes('numerical');
$num = new qtype_numerical_question();
test_question_maker::initialise_a_question($num);
$num->name = 'Pi to two d.p.';
$num->questiontext = 'What is pi to two d.p.?';
$num->generalfeedback = 'Generalfeedback: 3.14 is the right answer.';
$num->answers = array(
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->unitdisplay = qtype_numerical::UNITOPTIONAL;
$num->unitgradingtype = 0;
$num->unitpenalty = 0.2;
$num->ap = new qtype_numerical_answer_processor(array());
return $num;
}
/**
* Makes a numerical question with correct ansewer 3.14, and various incorrect
* answers with different feedback.
* @return qtype_numerical_question
*/
public function make_numerical_question_unit() {
question_bank::load_question_definition_classes('numerical');
$num = new qtype_numerical_question();
test_question_maker::initialise_a_question($num);
$num->name = 'Numerical with units';
$num->questiontext = 'What is 1 m + 25 cm?';
$num->generalfeedback = 'Generalfeedback: 1.25m or 125cm is the right answer.';
$num->answers = array(
13 => new qtype_numerical_answer(13, '1.25', 1.0, 'Very good.', FORMAT_HTML, 0),
14 => new qtype_numerical_answer(14, '1.25', 0.5, 'Vaguely right.', FORMAT_HTML, 0.05),
17 => new qtype_numerical_answer(17, '*', 0.0, 'Completely wrong.', FORMAT_HTML, 0),
);
$num->qtype = question_bank::get_qtype('numerical');
$num->unitdisplay = qtype_numerical::UNITSELECT;
$num->unitgradingtype = qtype_numerical::UNITGRADEDOUTOFMARK;
$num->unitpenalty = 0.5;
$num->ap = new qtype_numerical_answer_processor(array('m' => 1, 'cm' => 0.01));
return $num;
}
/**
* Makes a numerical question with correct ansewer 3.14, and various incorrect
* answers with different feedback.
* @return qtype_numerical_question
*/
public function make_numerical_question_currency() {
question_bank::load_question_definition_classes('numerical');
$num = new qtype_numerical_question();
test_question_maker::initialise_a_question($num);
$num->name = 'Add money';
$num->questiontext = 'What is $666 + $666?';
$num->generalfeedback = 'Generalfeedback: $1,332 is the right answer.';
$num->answers = array(
13 => new qtype_numerical_answer(13, '1332', 1.0, 'Very good.', FORMAT_HTML, 0),
14 => new qtype_numerical_answer(14, '*', 0.0, 'Wrong.', FORMAT_HTML, 0),
);
$num->qtype = question_bank::get_qtype('numerical');
$num->unitdisplay = qtype_numerical::UNITINPUT;
$num->unitgradingtype = qtype_numerical::UNITGRADEDOUTOFMAX;
$num->unitpenalty = 0.2;
$num->ap = new qtype_numerical_answer_processor(array('$' => 1), true);
return $num;
}
}

View File

@ -36,7 +36,7 @@ class testable_qtype_numerical_answer_processor extends qtype_numerical_answer_p
class qtype_numerical_answer_processor_test extends UnitTestCase {
public function test_parse_response() {
$ap = new testable_qtype_numerical_answer_processor(
array('m' => 1, 'cm' => 0.01), '.', ',');
array('m' => 1, 'cm' => 0.01), false, '.', ',');
$this->assertEqual(array('3', '142', '', ''), $ap->parse_response('3.142'));
$this->assertEqual(array('', '2', '', ''), $ap->parse_response('.2'));
@ -77,7 +77,7 @@ class qtype_numerical_answer_processor_test extends UnitTestCase {
$ap->parse_response('1,000.00 m'));
$this->assertEqual(array(null, null, null, null), $ap->parse_response('frog'));
$this->assertEqual(array(null, null, null, null), $ap->parse_response('3 frogs'));
$this->assertEqual(array('3', '', '', ''), $ap->parse_response('3 frogs'));
$this->assertEqual(array(null, null, null, null), $ap->parse_response('. m'));
$this->assertEqual(array(null, null, null, null), $ap->parse_response('.e8 m'));
$this->assertEqual(array(null, null, null, null), $ap->parse_response(','));
@ -85,30 +85,40 @@ class qtype_numerical_answer_processor_test extends UnitTestCase {
public function test_apply_units() {
$ap = new qtype_numerical_answer_processor(
array('m/s' => 1, 'c' => 299792458, 'mph' => 0.44704), '.', ',');
array('m/s' => 1, 'c' => 299792458, 'mph' => 0.44704), false, '.', ',');
$this->assertEqual(array(3e8, 'm/s'), $ap->apply_units('3x10^8 m/s'));
$this->assertEqual(array(3e8, ''), $ap->apply_units('3x10^8'));
$this->assertEqual(array(299792458, 'c'), $ap->apply_units('1c'));
$this->assertEqual(array(0.44704, 'mph'), $ap->apply_units('0001.000 mph'));
$this->assertEqual(array(null, null), $ap->apply_units('1 frogs'));
$this->assertEqual(array(1, ''), $ap->apply_units('1 frogs'));
$this->assertEqual(array(null, null), $ap->apply_units('. m/s'));
}
public function test_euro_style() {
$ap = new qtype_numerical_answer_processor(array(), ',', ' ');
$ap = new qtype_numerical_answer_processor(array(), false, ',', ' ');
$this->assertEqual(array(-1000, ''), $ap->apply_units('-1 000'));
$this->assertEqual(array(3.14159, ''), $ap->apply_units('3,14159'));
}
public function test_percent() {
$ap = new qtype_numerical_answer_processor(array('%' => 0.01), '.', ',');
$ap = new qtype_numerical_answer_processor(array('%' => 0.01), false, '.', ',');
$this->assertEqual(array('0.03', '%'), $ap->apply_units('3%'));
$this->assertEqual(array('1e-8', '%'), $ap->apply_units('1e-6 %'));
$this->assertEqual(array('100', ''), $ap->apply_units('100'));
}
public function test_currency() {
$ap = new qtype_numerical_answer_processor(array('$' => 1, '£' => 1), true, '.', ',');
$this->assertEqual(array('1234.56', '£'), $ap->apply_units('£1,234.56'));
$this->assertEqual(array('100', '$'), $ap->apply_units('$100'));
$this->assertEqual(array('100', '$'), $ap->apply_units('$100.'));
$this->assertEqual(array('100.00', '$'), $ap->apply_units('$100.00'));
$this->assertEqual(array('100', ''), $ap->apply_units('100'));
}
}

View File

@ -34,7 +34,7 @@ require_once($CFG->dirroot . '/question/engine/simpletest/helpers.php');
*/
class qtype_numerical_question_test extends UnitTestCase {
public function test_is_complete_response() {
$question = test_question_maker::make_a_numerical_question();
$question = test_question_maker::make_question('numerical');
$this->assertFalse($question->is_complete_response(array()));
$this->assertTrue($question->is_complete_response(array('answer' => '0')));
@ -43,7 +43,7 @@ class qtype_numerical_question_test extends UnitTestCase {
}
public function test_is_gradable_response() {
$question = test_question_maker::make_a_numerical_question();
$question = test_question_maker::make_question('numerical');
$this->assertFalse($question->is_gradable_response(array()));
$this->assertTrue($question->is_gradable_response(array('answer' => '0')));
@ -52,7 +52,7 @@ class qtype_numerical_question_test extends UnitTestCase {
}
public function test_grading() {
$question = test_question_maker::make_a_numerical_question();
$question = test_question_maker::make_question('numerical');
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '1.0')));
@ -61,11 +61,11 @@ class qtype_numerical_question_test extends UnitTestCase {
}
public function test_grading_with_units() {
$question = test_question_maker::make_a_numerical_question();
$question = test_question_maker::make_question('numerical');
$question->ap = new qtype_numerical_answer_processor(
array('m' => 1, 'cm' => 0.01), '.', ',');
array('m' => 1, 'cm' => 0.01), false, '.', ',');
$this->assertEqual(array(0, question_state::$gradedwrong),
$this->assertEqual(array(1, question_state::$gradedright),
$question->grade_response(array('answer' => '3.14 frogs')));
$this->assertEqual(array(1, question_state::$gradedright),
$question->grade_response(array('answer' => '3.14')));
@ -77,27 +77,74 @@ class qtype_numerical_question_test extends UnitTestCase {
$question->grade_response(array('answer' => '314000000x10^-8m')));
}
public function test_grading_unit() {
$question = test_question_maker::make_question('numerical', 'unit');
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '2 m')));
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '2cm')));
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '2')));
$this->assertEqual(array(1, question_state::$gradedright),
$question->grade_response(array('answer' => '1.25 m')));
$this->assertEqual(array(1, question_state::$gradedright),
$question->grade_response(array('answer' => '125 cm')));
$this->assertEqual(array(0.5, question_state::$gradedpartial),
$question->grade_response(array('answer' => '1.25')));
$this->assertEqual(array(0.5, question_state::$gradedpartial),
$question->grade_response(array('answer' => '1.23m')));
$this->assertEqual(array(0.5, question_state::$gradedpartial),
$question->grade_response(array('answer' => '123 cm')));
$this->assertEqual(array(0.25, question_state::$gradedpartial),
$question->grade_response(array('answer' => '1.23')));
$this->assertEqual(array(0.25, question_state::$gradedpartial),
$question->grade_response(array('answer' => '1.23 frogs')));
}
public function test_grading_currency() {
$question = test_question_maker::make_question('numerical', 'currency');
$this->assertEqual(array(1, question_state::$gradedright),
$question->grade_response(array('answer' => '$1332')));
$this->assertEqual(array(1, question_state::$gradedright),
$question->grade_response(array('answer' => '$ 1,332')));
$this->assertEqual(array(0.8, question_state::$gradedpartial),
$question->grade_response(array('answer' => '1332')));
$this->assertEqual(array(0.8, question_state::$gradedpartial),
$question->grade_response(array('answer' => ' 1,332')));
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '1332 $')));
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '1,332 frogs')));
$this->assertEqual(array(0, question_state::$gradedwrong),
$question->grade_response(array('answer' => '$1')));
}
public function test_get_correct_response() {
$question = test_question_maker::make_a_numerical_question();
$question = test_question_maker::make_question('numerical');
$this->assertEqual(array('answer' => '3.14'),
$question->get_correct_response());
}
public function test_get_question_summary() {
$num = test_question_maker::make_a_numerical_question();
$num = test_question_maker::make_question('numerical');
$qsummary = $num->get_question_summary();
$this->assertEqual('What is pi to two d.p.?', $qsummary);
}
public function test_summarise_response() {
$num = test_question_maker::make_a_numerical_question();
$num = test_question_maker::make_question('numerical');
$summary = $num->summarise_response(array('answer' => '3.1'));
$this->assertEqual('3.1', $summary);
}
public function test_classify_response() {
$num = test_question_maker::make_a_numerical_question();
$num = test_question_maker::make_question('numerical');
$num->start_attempt(new question_attempt_step());
$this->assertEqual(array(

View File

@ -4,5 +4,5 @@
display: inline;
}
.que.numerical .answer input {
width: 99%;
width: 30%;
}

View File

@ -4,5 +4,5 @@
display: inline;
}
.que.shortanswer .answer input {
width: 99%;
width: 80%;
}