MDL-35055 question import: slight error with the Match grades option.

Even in the 'Error if grade not listed case', it was applying a small
tolerance. In the case of a fuzzy match, it was returning the inexact
grade from the import file, rather than the precise grade that Moodle
was expecting.

That causes problems when the editing form is displayed, because the
value from the database does not match any of the available options, so
the grade is changed to 0%.
This commit is contained in:
Tim Hunt
2012-08-24 15:34:20 +01:00
parent d71c486507
commit aa5f05110f
2 changed files with 38 additions and 18 deletions

View File

@@ -209,39 +209,44 @@ function get_grade_options() {
} }
/** /**
* match grade options * Check whether a given grade is one of a list of allowed options. If not,
* if no match return error or match nearest * depending on $matchgrades, either return the nearest match, or return false
* to signal an error.
* @param array $gradeoptionsfull list of valid options * @param array $gradeoptionsfull list of valid options
* @param int $grade grade to be tested * @param int $grade grade to be tested
* @param string $matchgrades 'error' or 'nearest' * @param string $matchgrades 'error' or 'nearest'
* @return mixed either 'fixed' value or false if erro * @return mixed either 'fixed' value or false if error.
*/ */
function match_grade_options($gradeoptionsfull, $grade, $matchgrades='error') { function match_grade_options($gradeoptionsfull, $grade, $matchgrades = 'error') {
if ($matchgrades == 'error') { if ($matchgrades == 'error') {
// if we just need an error... // (Almost) exact match, or an error.
foreach ($gradeoptionsfull as $value => $option) { foreach ($gradeoptionsfull as $value => $option) {
// slightly fuzzy test, never check floats for equality :-) // Slightly fuzzy test, never check floats for equality.
if (abs($grade - $value) < 0.00001) { if (abs($grade - $value) < 0.00001) {
return $grade; return $value; // Be sure the return the proper value.
} }
} }
// didn't find a match so that's an error // Didn't find a match so that's an error.
return false; return false;
} else if ($matchgrades == 'nearest') { } else if ($matchgrades == 'nearest') {
// work out nearest value // Work out nearest value
$hownear = array(); $best = false;
$bestmismatch = 2;
foreach ($gradeoptionsfull as $value => $option) { foreach ($gradeoptionsfull as $value => $option) {
if ($grade==$value) { $newmismatch = abs($grade - $value);
return $grade; if ($newmismatch < $bestmismatch) {
$best = $value;
$bestmismatch = $newmismatch;
} }
$hownear[ $value ] = abs( $grade - $value );
} }
// reverse sort list of deltas and grab the last (smallest) return $best;
asort( $hownear, SORT_NUMERIC );
reset( $hownear );
return key( $hownear );
} else { } else {
return false; // Unknow option passed.
throw new coding_exception('Unknown $matchgrades ' . $matchgrades .
' passed to match_grade_options');
} }
} }

View File

@@ -55,4 +55,19 @@ class questionlib_testcase extends basic_testcase {
array(0 => 't1', 1 => 't2', 2 => 't3')); array(0 => 't1', 1 => 't2', 2 => 't3'));
} }
public function test_match_grade_options() {
$gradeoptions = question_bank::fraction_options_full();
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.3333333, 'error'));
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.333333, 'error'));
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.33333, 'error'));
$this->assertFalse(match_grade_options($gradeoptions, 0.3333, 'error'));
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.3333333, 'nearest'));
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.333333, 'nearest'));
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.33333, 'nearest'));
$this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.33, 'nearest'));
$this->assertEquals(-0.1428571, match_grade_options($gradeoptions, -0.15, 'nearest'));
}
} }