Merge branch 'MDL-27418' of git://github.com/timhunt/moodle
This commit is contained in:
@@ -207,7 +207,7 @@ class qtype_calculated_qe2_attempt_updater extends question_qtype_attempt_update
|
||||
* @param $x
|
||||
*/
|
||||
public function format_float($x, $length = null, $format = null) {
|
||||
if (!is_null($format) && !is_null($format)) {
|
||||
if (!is_null($length) && !is_null($format)) {
|
||||
if ($format == 1) {
|
||||
// Decimal places.
|
||||
$x = sprintf('%.' . $length . 'F', $x);
|
||||
|
||||
@@ -310,7 +310,7 @@ class qtype_calculated_variable_substituter {
|
||||
* @param $x
|
||||
*/
|
||||
public function format_float($x, $length = null, $format = null) {
|
||||
if (!is_null($format) && !is_null($format)) {
|
||||
if (!is_null($length) && !is_null($format)) {
|
||||
if ($format == 1) {
|
||||
// Decimal places.
|
||||
$x = sprintf('%.' . $length . 'F', $x);
|
||||
|
||||
@@ -231,7 +231,7 @@ class qtype_calculatedmulti_qe2_attempt_updater extends question_qtype_attempt_u
|
||||
* @param $x
|
||||
*/
|
||||
public function format_float($x, $length = null, $format = null) {
|
||||
if (!is_null($format) && !is_null($format)) {
|
||||
if (!is_null($length) && !is_null($format)) {
|
||||
if ($format == 1) {
|
||||
// Decimal places.
|
||||
$x = sprintf('%.' . $length . 'F', $x);
|
||||
|
||||
@@ -168,6 +168,8 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
|
||||
$response = $qa->get_last_qt_var($fieldname);
|
||||
if ($subq->qtype->name() == 'shortanswer') {
|
||||
$matchinganswer = $subq->get_matching_answer(array('answer' => $response));
|
||||
} else if ($subq->qtype->name() == 'numerical') {
|
||||
$matchinganswer = $subq->get_matching_answer($response, 1);
|
||||
} else {
|
||||
$matchinganswer = $subq->get_matching_answer($response);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/type/edit_question_form.php');
|
||||
require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
|
||||
|
||||
|
||||
@@ -36,6 +37,7 @@ require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_numerical_edit_form extends question_edit_form {
|
||||
protected $ap = null;
|
||||
|
||||
protected function definition_inner($mform) {
|
||||
$this->add_per_answer_fields($mform, get_string('answerno', 'qtype_numerical', '{no}'),
|
||||
@@ -54,6 +56,7 @@ class qtype_numerical_edit_form extends question_edit_form {
|
||||
$tolerance = $mform->createElement('text', 'tolerance',
|
||||
get_string('acceptederror', 'qtype_numerical'));
|
||||
$repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
|
||||
$repeatedoptions['tolerance']['default'] = 0;
|
||||
array_splice($repeated, 3, 0, array($tolerance));
|
||||
$repeated[1]->setSize(10);
|
||||
|
||||
@@ -256,7 +259,7 @@ class qtype_numerical_edit_form extends question_edit_form {
|
||||
if ($trimmedanswer != '') {
|
||||
$answercount++;
|
||||
if (!$this->is_valid_answer($trimmedanswer, $data)) {
|
||||
$errors['answer[' . $key . ']'] = $this->valid_answer_message();
|
||||
$errors['answer[' . $key . ']'] = $this->valid_answer_message($trimmedanswer);
|
||||
}
|
||||
if ($data['fraction'][$key] == 1) {
|
||||
$maxgrade = true;
|
||||
@@ -267,7 +270,7 @@ class qtype_numerical_edit_form extends question_edit_form {
|
||||
}
|
||||
} else if ($data['fraction'][$key] != 0 ||
|
||||
!html_is_blank($data['feedback'][$key]['text'])) {
|
||||
$errors['answer[' . $key . ']'] = $this->valid_answer_message();
|
||||
$errors['answer[' . $key . ']'] = $this->valid_answer_message($trimmedanswer);
|
||||
$answercount++;
|
||||
}
|
||||
}
|
||||
@@ -277,6 +280,8 @@ class qtype_numerical_edit_form extends question_edit_form {
|
||||
if ($maxgrade == false) {
|
||||
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +291,22 @@ class qtype_numerical_edit_form extends question_edit_form {
|
||||
* @return bool whether this is a valid answer.
|
||||
*/
|
||||
protected function is_valid_answer($answer, $data) {
|
||||
return $answer == '*' || is_numeric($answer);
|
||||
return $answer == '*' || $this->is_valid_number($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a string is a nubmer formatted correctly for the current locale.
|
||||
* @param string $x a string
|
||||
* @return bool whether $x is a number that the numerical question type can interpret.
|
||||
*/
|
||||
protected function is_valid_number($x) {
|
||||
if (is_null($this->ap)) {
|
||||
$this->ap = new qtype_numerical_answer_processor(array());
|
||||
}
|
||||
|
||||
list($value, $unit) = $this->ap->apply_units($x);
|
||||
|
||||
return !is_null($value) && !$unit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ $string['acceptederror'] = 'Accepted error';
|
||||
$string['addingnumerical'] = 'Adding a Numerical question';
|
||||
$string['addmoreanswerblanks'] = 'Blanks for {no} More Answers';
|
||||
$string['addmoreunitblanks'] = 'Blanks for {no} More Units';
|
||||
$string['answermustbenumberorstar'] = 'The answer must be a number, or \'*\'.';
|
||||
$string['answermustbenumberorstar'] = 'The answer must be a number, for example -1.234 or 3e8, or \'*\'.';
|
||||
$string['answerno'] = 'Answer {$a}';
|
||||
$string['decfractionofquestiongrade'] = 'as a fraction (0-1) of the question grade';
|
||||
$string['decfractionofresponsegrade'] = 'as a fraction (0-1) of the response grade';
|
||||
@@ -64,6 +64,7 @@ $string['nominal'] = 'Nominal';
|
||||
$string['onlynumerical'] = 'Units are not used at all. Only the numerical value is graded.';
|
||||
$string['oneunitshown'] = 'Unit 1 is automatically displayed beside the answer box.';
|
||||
$string['pleaseenterananswer'] = 'Please enter an answer.';
|
||||
$string['pleaseenteranswerwithoutthousandssep'] = 'Please enter your answer without using the thousand separator ({$a}).';
|
||||
$string['relative'] = 'Relative';
|
||||
$string['rightexample'] = 'on the right, for example 1.00cm or 1.00km';
|
||||
$string['selectunits'] = 'Select units';
|
||||
|
||||
@@ -109,6 +109,10 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->ap->contains_thousands_seaparator($response['answer'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -130,6 +134,11 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
return get_string('unitnotselected', 'qtype_numerical');
|
||||
}
|
||||
|
||||
if ($this->ap->contains_thousands_seaparator($response['answer'])) {
|
||||
return get_string('pleaseenteranswerwithoutthousandssep', 'qtype_numerical',
|
||||
$this->ap->get_separator());
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -153,7 +162,7 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
return array();
|
||||
}
|
||||
|
||||
$response = array('answer' => $answer->answer);
|
||||
$response = array('answer' => str_replace('.', $this->ap->get_point(), $answer->answer));
|
||||
|
||||
if ($this->has_separate_unit_field()) {
|
||||
$response['unit'] = $this->ap->get_default_unit();
|
||||
@@ -168,12 +177,22 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
* 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.
|
||||
* @param number $multiplier for the unit the student gave, if any. When no
|
||||
* unit was given, or an unrecognised unit was given, $multiplier will be null.
|
||||
* @return question_answer the matching answer.
|
||||
*/
|
||||
public function get_matching_answer($value) {
|
||||
public function get_matching_answer($value, $multiplier) {
|
||||
if (!is_null($multiplier)) {
|
||||
$scaledvalue = $value * $multiplier;
|
||||
} else {
|
||||
$scaledvalue = $value;
|
||||
}
|
||||
foreach ($this->answers as $aid => $answer) {
|
||||
if ($answer->within_tolerance($value)) {
|
||||
$answer->id = $aid;
|
||||
if ($answer->within_tolerance($scaledvalue)) {
|
||||
$answer->unitisright = !is_null($multiplier);
|
||||
return $answer;
|
||||
} else if ($answer->within_tolerance($value)) {
|
||||
$answer->unitisright = false;
|
||||
return $answer;
|
||||
}
|
||||
}
|
||||
@@ -190,8 +209,14 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function apply_unit_penalty($fraction, $unit) {
|
||||
if (!empty($unit) && $this->ap->is_known_unit($unit)) {
|
||||
/**
|
||||
* Adjust the fraction based on whether the unit was correct.
|
||||
* @param number $fraction
|
||||
* @param bool $unitisright
|
||||
* @return number
|
||||
*/
|
||||
public function apply_unit_penalty($fraction, $unitisright) {
|
||||
if ($unitisright) {
|
||||
return $fraction;
|
||||
}
|
||||
|
||||
@@ -209,13 +234,15 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
} else {
|
||||
$selectedunit = null;
|
||||
}
|
||||
list($value, $unit) = $this->ap->apply_units($response['answer'], $selectedunit);
|
||||
$answer = $this->get_matching_answer($value);
|
||||
list($value, $unit, $multiplier) = $this->ap->apply_units(
|
||||
$response['answer'], $selectedunit);
|
||||
|
||||
$answer = $this->get_matching_answer($value, $multiplier);
|
||||
if (!$answer) {
|
||||
return array(0, question_state::$gradedwrong);
|
||||
}
|
||||
|
||||
$fraction = $this->apply_unit_penalty($answer->fraction, $unit);
|
||||
$fraction = $this->apply_unit_penalty($answer->fraction, $answer->unitisright);
|
||||
return array($fraction, question_state::graded_state_for_fraction($fraction));
|
||||
}
|
||||
|
||||
@@ -229,8 +256,8 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
} else {
|
||||
$selectedunit = null;
|
||||
}
|
||||
list($value, $unit) = $this->ap->apply_units($response['answer'], $selectedunit);
|
||||
$ans = $this->get_matching_answer($value);
|
||||
list($value, $unit, $multiplier) = $this->ap->apply_units($response['answer'], $selectedunit);
|
||||
$ans = $this->get_matching_answer($value, $multiplier);
|
||||
if (!$ans) {
|
||||
return array($this->id => question_classified_response::no_response());
|
||||
}
|
||||
@@ -242,14 +269,22 @@ class qtype_numerical_question extends question_graded_automatically {
|
||||
|
||||
return array($this->id => new question_classified_response($ans->id,
|
||||
$resp,
|
||||
$this->apply_unit_penalty($ans->fraction, $unit)));
|
||||
$this->apply_unit_penalty($ans->fraction, $ans->unitisright)));
|
||||
}
|
||||
|
||||
public function check_file_access($qa, $options, $component, $filearea, $args,
|
||||
$forcedownload) {
|
||||
if ($component == 'question' && $filearea == 'answerfeedback') {
|
||||
$question = $qa->get_question();
|
||||
$currentanswer = $qa->get_last_qt_var('answer');
|
||||
$answer = $qa->get_question()->get_matching_answer(array('answer' => $currentanswer));
|
||||
if ($this->has_separate_unit_field()) {
|
||||
$selectedunit = $qa->get_last_qt_var('unit');
|
||||
} else {
|
||||
$selectedunit = null;
|
||||
}
|
||||
list($value, $unit, $multiplier) = $question->ap->apply_units(
|
||||
$currentanswer, $selectedunit);
|
||||
$answer = $question->get_matching_answer($value, $multiplier);
|
||||
$answerid = reset($args); // itemid is answer id.
|
||||
return $options->feedback && $answerid == $answer->id;
|
||||
|
||||
|
||||
@@ -449,7 +449,10 @@ class qtype_numerical extends question_type {
|
||||
*/
|
||||
public function apply_unit($rawresponse, $units, $unitsleft) {
|
||||
$ap = $this->make_answer_processor($units, $unitsleft);
|
||||
list($value, $unit) = $ap->apply_units($rawresponse);
|
||||
list($value, $unit, $multiplier) = $ap->apply_units($rawresponse);
|
||||
if (!is_null($multiplier)) {
|
||||
$value *= $multiplier;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -524,6 +527,19 @@ class qtype_numerical_answer_processor {
|
||||
return $this->thousandssep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return book If the student's response contains a '.' or a ',' that
|
||||
* matches the thousands separator in the current locale. In this case, the
|
||||
* parsing in apply_unit can give a result that the student did not expect.
|
||||
*/
|
||||
public function contains_thousands_seaparator($value) {
|
||||
if (!in_array($this->thousandssep, array('.', ','))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strpos($value, $this->thousandssep) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the regular expression that {@link parse_response()} requires.
|
||||
* @return string
|
||||
@@ -550,6 +566,11 @@ class qtype_numerical_answer_processor {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used for more locale-strict parsing of repsonses. At the
|
||||
* moment we don't use it, and instead use the more lax parsing in apply_units.
|
||||
* This is just a note that this funciton was used in the past, so if you are
|
||||
* intersted, look through version control history.
|
||||
*
|
||||
* Take a string which is a number with or without a decimal point and exponent,
|
||||
* and possibly followed by one of the units, and split it into bits.
|
||||
* @param string $response a value, optionally with a unit.
|
||||
@@ -585,25 +606,44 @@ class qtype_numerical_answer_processor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a number in localised form, that is, using the decsep and thousandssep
|
||||
* defined in the lanuage pack, and possibly with a unit after it. It separates
|
||||
* off the unit, if present, and converts to the default unit, by using the
|
||||
* given unit multiplier.
|
||||
* Takes a number in almost any localised form, and possibly with a unit
|
||||
* after it. It separates off the unit, if present, and converts to the
|
||||
* default unit, by using the given unit multiplier.
|
||||
*
|
||||
* @param string $response a value, optionally with a unit.
|
||||
* @return array(numeric, sting) the value with the unit stripped, and normalised
|
||||
* by the unit multiplier, if any, and the unit string, for reference.
|
||||
*/
|
||||
public function apply_units($response, $separateunit = null) {
|
||||
list($beforepoint, $decimals, $exponent, $unit) = $this->parse_response($response);
|
||||
// Strip spaces (which may be thousands separators) and change other forms
|
||||
// of writing e to e.
|
||||
$response = str_replace(' ', '', $response);
|
||||
$response = preg_replace('~(?:e|E|(?:x|\*|×)10(?:\^|\*\*))([+-]?\d+)~', 'e$1', $response);
|
||||
|
||||
if (is_null($beforepoint)) {
|
||||
return array(null, null);
|
||||
// If a . is present or there are multiple , (i.e. 2,456,789 ) assume ,
|
||||
// is a thouseands separator, and strip it, else assume it is a decimal
|
||||
// separator, and change it to ..
|
||||
if (strpos($response, '.') !== false || substr_count($response, ',') > 1) {
|
||||
$response = str_replace(',', '', $response);
|
||||
} else {
|
||||
$response = str_replace(',', '.', $response);
|
||||
}
|
||||
|
||||
$numberstring = $beforepoint . '.' . $decimals;
|
||||
if ($exponent) {
|
||||
$numberstring .= 'e' . $exponent;
|
||||
$regex = '[+-]?(?:\d+(?:\\.\d*)?|\\.\d+)(?:e[-+]?\d+)?';
|
||||
if ($this->unitsbefore) {
|
||||
$regex = "/$regex$/";
|
||||
} else {
|
||||
$regex = "/^$regex/";
|
||||
}
|
||||
if (!preg_match($regex, $response, $matches)) {
|
||||
return array(null, null, null);
|
||||
}
|
||||
|
||||
$numberstring = $matches[0];
|
||||
if ($this->unitsbefore) {
|
||||
$unit = substr($response, 0, -strlen($numberstring));
|
||||
} else {
|
||||
$unit = substr($response, strlen($numberstring));
|
||||
}
|
||||
|
||||
if (!is_null($separateunit)) {
|
||||
@@ -611,12 +651,12 @@ class qtype_numerical_answer_processor {
|
||||
}
|
||||
|
||||
if ($unit && $this->is_known_unit($unit)) {
|
||||
$value = $numberstring / $this->units[$unit];
|
||||
$multiplier = 1 / $this->units[$unit];
|
||||
} else {
|
||||
$value = $numberstring * 1;
|
||||
$multiplier = null;
|
||||
}
|
||||
|
||||
return array($value, $unit);
|
||||
return array($numberstring + 0, $unit, $multiplier); // + 0 to convert to number.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,10 +57,11 @@ class qtype_numerical_renderer extends qtype_renderer {
|
||||
|
||||
$feedbackimg = '';
|
||||
if ($options->correctness) {
|
||||
list($value, $unit) = $question->ap->apply_units($currentanswer, $selectedunit);
|
||||
$answer = $question->get_matching_answer($value);
|
||||
list($value, $unit, $multiplier) = $question->ap->apply_units(
|
||||
$currentanswer, $selectedunit);
|
||||
$answer = $question->get_matching_answer($value, $multiplier);
|
||||
if ($answer) {
|
||||
$fraction = $question->apply_unit_penalty($answer->fraction, $unit);
|
||||
$fraction = $question->apply_unit_penalty($answer->fraction, $answer->unitisright);
|
||||
} else {
|
||||
$fraction = 0;
|
||||
}
|
||||
@@ -140,9 +141,9 @@ class qtype_numerical_renderer extends qtype_renderer {
|
||||
} else {
|
||||
$selectedunit = null;
|
||||
}
|
||||
list($value, $unit) = $question->ap->apply_units(
|
||||
list($value, $unit, $multiplier) = $question->ap->apply_units(
|
||||
$qa->get_last_qt_var('answer'), $selectedunit);
|
||||
$answer = $question->get_matching_answer($value);
|
||||
$answer = $question->get_matching_answer($value, $multiplier);
|
||||
|
||||
if ($answer && $answer->feedback) {
|
||||
$feedback = $question->format_text($answer->feedback, $answer->feedbackformat,
|
||||
@@ -165,7 +166,7 @@ class qtype_numerical_renderer extends qtype_renderer {
|
||||
return '';
|
||||
}
|
||||
|
||||
$response = $answer->answer;
|
||||
$response = str_replace('.', $question->ap->get_point(), $answer->answer);
|
||||
if ($question->unitdisplay != qtype_numerical::UNITNONE) {
|
||||
$response = $question->ap->add_unit($response);
|
||||
}
|
||||
|
||||
@@ -82,15 +82,20 @@ class qtype_numerical_answer_processor_test extends UnitTestCase {
|
||||
$this->assertEqual(array(null, null, null, null), $ap->parse_response(','));
|
||||
}
|
||||
|
||||
protected function verify_value_and_unit($exectedval, $expectedunit,
|
||||
protected function verify_value_and_unit($exectedval, $expectedunit, $expectedmultiplier,
|
||||
qtype_numerical_answer_processor $ap, $input, $separateunit = null) {
|
||||
list($val, $unit) = $ap->apply_units($input, $separateunit);
|
||||
list($val, $unit, $multiplier) = $ap->apply_units($input, $separateunit);
|
||||
if (is_null($exectedval)) {
|
||||
$this->assertNull($val);
|
||||
} else {
|
||||
$this->assertWithinMargin($exectedval, $val, 0.0001);
|
||||
}
|
||||
$this->assertEqual($expectedunit, $unit);
|
||||
if (is_null($expectedmultiplier)) {
|
||||
$this->assertNull($multiplier);
|
||||
} else {
|
||||
$this->assertWithinMargin($expectedmultiplier, $multiplier, 0.0001);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_apply_units() {
|
||||
@@ -98,13 +103,13 @@ class qtype_numerical_answer_processor_test extends UnitTestCase {
|
||||
array('m/s' => 1, 'c' => 3.3356409519815E-9,
|
||||
'mph' => 2.2369362920544), false, '.', ',');
|
||||
|
||||
$this->verify_value_and_unit(3e8, 'm/s', $ap, '3x10^8 m/s');
|
||||
$this->verify_value_and_unit(3e8, '', $ap, '3x10^8');
|
||||
$this->verify_value_and_unit(299792458, 'c', $ap, '1c');
|
||||
$this->verify_value_and_unit(0.44704, 'mph', $ap, '0001.000 mph');
|
||||
$this->verify_value_and_unit(3e8, 'm/s', 1, $ap, '3x10^8 m/s');
|
||||
$this->verify_value_and_unit(3e8, '', null, $ap, '3x10^8');
|
||||
$this->verify_value_and_unit(1, 'c', 299792458, $ap, '1c');
|
||||
$this->verify_value_and_unit(1, 'mph', 0.44704, $ap, '0001.000 mph');
|
||||
|
||||
$this->verify_value_and_unit(1, 'frogs', $ap, '1 frogs');
|
||||
$this->verify_value_and_unit(null, null, $ap, '. m/s');
|
||||
$this->verify_value_and_unit(1, 'frogs', null, $ap, '1 frogs');
|
||||
$this->verify_value_and_unit(null, null, null, $ap, '. m/s');
|
||||
}
|
||||
|
||||
public function test_apply_units_separate_unit() {
|
||||
@@ -112,39 +117,39 @@ class qtype_numerical_answer_processor_test extends UnitTestCase {
|
||||
array('m/s' => 1, 'c' => 3.3356409519815E-9,
|
||||
'mph' => 2.2369362920544), false, '.', ',');
|
||||
|
||||
$this->verify_value_and_unit(3e8, 'm/s', $ap, '3x10^8', 'm/s');
|
||||
$this->verify_value_and_unit(3e8, '', $ap, '3x10^8', '');
|
||||
$this->verify_value_and_unit(299792458, 'c', $ap, '1', 'c');
|
||||
$this->verify_value_and_unit(0.44704, 'mph', $ap, '0001.000', 'mph');
|
||||
$this->verify_value_and_unit(3e8, 'm/s', 1, $ap, '3x10^8', 'm/s');
|
||||
$this->verify_value_and_unit(3e8, '', null, $ap, '3x10^8', '');
|
||||
$this->verify_value_and_unit(1, 'c', 299792458, $ap, '1', 'c');
|
||||
$this->verify_value_and_unit(1, 'mph', 0.44704, $ap, '0001.000', 'mph');
|
||||
|
||||
$this->verify_value_and_unit(1, 'frogs', $ap, '1', 'frogs');
|
||||
$this->verify_value_and_unit(null, null, $ap, '.', 'm/s');
|
||||
$this->verify_value_and_unit(1, 'frogs', null, $ap, '1', 'frogs');
|
||||
$this->verify_value_and_unit(null, null, null, $ap, '.', 'm/s');
|
||||
}
|
||||
|
||||
public function test_euro_style() {
|
||||
$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'));
|
||||
$this->assertEqual(array(-1000, '', null), $ap->apply_units('-1 000'));
|
||||
$this->assertEqual(array(3.14159, '', null), $ap->apply_units('3,14159'));
|
||||
}
|
||||
|
||||
public function test_percent() {
|
||||
$ap = new qtype_numerical_answer_processor(array('%' => 100), 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'));
|
||||
$this->assertEqual(array('3', '%', 0.01), $ap->apply_units('3%'));
|
||||
$this->assertEqual(array('1e-6', '%', 0.01), $ap->apply_units('1e-6 %'));
|
||||
$this->assertEqual(array('100', '', null), $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'));
|
||||
$this->assertEqual(array('100', 'frog'), $ap->apply_units('frog 100'));
|
||||
$this->assertEqual(array('1234.56', '£', 1), $ap->apply_units('£1,234.56'));
|
||||
$this->assertEqual(array('100', '$', 1), $ap->apply_units('$100'));
|
||||
$this->assertEqual(array('100', '$', 1), $ap->apply_units('$100.'));
|
||||
$this->assertEqual(array('100.00', '$', 1), $ap->apply_units('$100.00'));
|
||||
$this->assertEqual(array('100', '', null), $ap->apply_units('100'));
|
||||
$this->assertEqual(array('100', 'frog', null), $ap->apply_units('frog 100'));
|
||||
}
|
||||
}
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for (some of) question/type/numerical/edit_numerical_form.php.
|
||||
*
|
||||
* @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();
|
||||
|
||||
require_once($CFG->dirroot . '/question/type/numerical/edit_numerical_form.php');
|
||||
|
||||
|
||||
/**
|
||||
* Test sub-class, so we can force the locale.
|
||||
*
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class test_qtype_numerical_edit_form extends qtype_numerical_edit_form {
|
||||
public function __construct() {
|
||||
// Warning, avoid running the parent constructor. That means the form is
|
||||
// not properly tested but for now that is OK, we are only testing a few
|
||||
// methods.
|
||||
$this->ap = new qtype_numerical_answer_processor(array(), false, ',', ' ');
|
||||
}
|
||||
public function is_valid_number($x) {
|
||||
return parent::is_valid_number($x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for question/type/numerical/edit_numerical_form.php.
|
||||
*
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_numerical_form_test extends UnitTestCase {
|
||||
public static $includecoverage = array(
|
||||
'question/type/numerical/edit_numerical_form.php'
|
||||
);
|
||||
|
||||
protected $form;
|
||||
|
||||
public function setUp() {
|
||||
$this->form = new test_qtype_numerical_edit_form();
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
$this->form = null;
|
||||
}
|
||||
|
||||
public function test_is_valid_number() {
|
||||
$this->assertTrue($this->form->is_valid_number('1,001'));
|
||||
$this->assertTrue($this->form->is_valid_number('1.001'));
|
||||
$this->assertTrue($this->form->is_valid_number('1'));
|
||||
$this->assertTrue($this->form->is_valid_number('1,e8'));
|
||||
$this->assertFalse($this->form->is_valid_number('1001 xxx'));
|
||||
$this->assertTrue($this->form->is_valid_number('1.e8'));
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ class qtype_numerical_question_test extends UnitTestCase {
|
||||
|
||||
public function test_grading_with_units() {
|
||||
$question = test_question_maker::make_question('numerical');
|
||||
$question->unitgradingtype = qtype_numerical::UNITOPTIONAL;
|
||||
$question->ap = new qtype_numerical_answer_processor(
|
||||
array('m' => 1, 'cm' => 100), false, '.', ',');
|
||||
|
||||
@@ -79,6 +80,28 @@ class qtype_numerical_question_test extends UnitTestCase {
|
||||
$question->grade_response(array('answer' => '314000000x10^-8m')));
|
||||
}
|
||||
|
||||
public function test_grading_with_units_graded() {
|
||||
$question = test_question_maker::make_question('numerical');
|
||||
$question->unitgradingtype = qtype_numerical::UNITGRADED;
|
||||
$question->ap = new qtype_numerical_answer_processor(
|
||||
array('m' => 1, 'cm' => 100), false, '.', ',');
|
||||
|
||||
$this->assertEqual(array(0.8, question_state::$gradedpartial),
|
||||
$question->grade_response(array('answer' => '3.14 frogs')));
|
||||
$this->assertEqual(array(0.8, question_state::$gradedpartial),
|
||||
$question->grade_response(array('answer' => '3.14')));
|
||||
$this->assertEqual(array(1, question_state::$gradedright),
|
||||
$question->grade_response(array('answer' => '3.14 m')));
|
||||
$this->assertEqual(array(1, question_state::$gradedright),
|
||||
$question->grade_response(array('answer' => '314cm')));
|
||||
$this->assertEqual(array(1, question_state::$gradedright),
|
||||
$question->grade_response(array('answer' => '314000000x10^-8m')));
|
||||
$this->assertEqual(array(0.8, question_state::$gradedpartial),
|
||||
$question->grade_response(array('answer' => '3.14 cm')));
|
||||
$this->assertEqual(array(0, question_state::$gradedwrong),
|
||||
$question->grade_response(array('answer' => '314 m')));
|
||||
}
|
||||
|
||||
public function test_grading_unit() {
|
||||
$question = test_question_maker::make_question('numerical', 'unit');
|
||||
|
||||
@@ -110,17 +133,17 @@ class qtype_numerical_question_test extends UnitTestCase {
|
||||
$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')));
|
||||
$question->grade_response(array('answer' => '$ 1332')));
|
||||
$this->assertEqual(array(0.8, question_state::$gradedpartial),
|
||||
$question->grade_response(array('answer' => 'frog 1332')));
|
||||
$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')));
|
||||
$question->grade_response(array('answer' => ' 1332')));
|
||||
$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')));
|
||||
$question->grade_response(array('answer' => '1332 frogs')));
|
||||
$this->assertEqual(array(0, question_state::$gradedwrong),
|
||||
$question->grade_response(array('answer' => '$1')));
|
||||
}
|
||||
@@ -225,7 +248,7 @@ class qtype_numerical_question_test extends UnitTestCase {
|
||||
new question_classified_response(14, '$100', 0)),
|
||||
$num->classify_response(array('answer' => '$100')));
|
||||
$this->assertEqual(array(
|
||||
new question_classified_response(13, '1,332', 0.8)),
|
||||
$num->classify_response(array('answer' => '1,332')));
|
||||
new question_classified_response(13, '1 332', 0.8)),
|
||||
$num->classify_response(array('answer' => '1 332')));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user