From: nicolasconnault Date: Mon, 30 Apr 2007 09:09:32 +0000 (+0000) Subject: MDL-9506 Lots more unit tests, and work on grade_item::update method and associated... X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=b3f111607f11325fcdc11aa6aa0fe4b4125d0289;p=moodle.git MDL-9506 Lots more unit tests, and work on grade_item::update method and associated functionality. 3 unit tests currently fail, so more work needed. --- diff --git a/lib/grade/grade_calculation.php b/lib/grade/grade_calculation.php index f05cf04827..beb786962f 100644 --- a/lib/grade/grade_calculation.php +++ b/lib/grade/grade_calculation.php @@ -59,7 +59,22 @@ class grade_calculation extends grade_object { * @var int $usermodified */ var $usermodified; + + /** + * A formula parser object. + * @var object $parser + * @TODO implement parsing of formula and calculation MDL-9643 + */ + var $parser; + /** + * Applies the formula represented by this object to the value given, and returns the result. + * @param float $oldvalue + * @return float result + */ + function compute($oldvalue) { + return $oldvalue; // TODO implement computation using parser + } /** * Finds and returns a grade_calculation object based on 1-3 field values. diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php index b46c11cc2c..4fbc9cc94d 100644 --- a/lib/grade/grade_item.php +++ b/lib/grade/grade_item.php @@ -174,6 +174,12 @@ class grade_item extends grade_object { */ var $grade_grades_raw = array(); + /** + * Array of grade_grades_final objects linked to this grade_item. They are indexed by userid. + * @var array $grade_grades_final + */ + var $grade_grades_final = array(); + /** * Finds and returns a grade_item object based on 1-3 field values. * @@ -364,22 +370,95 @@ class grade_item extends grade_object { * requested. Also resets the needs_update flag once successfully performed. * * @param int $userid - * @param string $howmodified What caused the modification? manual/module/import/cron... - * @param string $note A note attached to this modification. - * @return boolean Success or failure + * @return int Number of grades updated, or false if error */ - function update_final_grade($userid=NULL, $howmodified='manual', $note=NULL) { + function update_final_grade($userid=NULL) { if (empty($this->grade_grades_final)) { $this->load_final(); } + if (empty($this->grade_grades_raw)) { + $this->load_raw(); + } - // TODO implement parsing of formula and calculation MDL-9643 - foreach ($this->grade_grades_final as $f) { - $newgradevalue = 0; // TODO replace '0' with calculated value - $f->update($newgradevalue, $howmodified, $note); + $count = 0; + + $grade_final_array = array(); + + if (!empty($userid)) { + $grade_final_array[$userid] = $this->grade_grades_final[$userid]; + } else { + $grade_final_array = $this->grade_grades_final; } - return true; + foreach ($grade_raw_array as $userid => $raw) { + $newgradevalue = $raw->gradevalue; + + if (!empty($this->calculation)) { + $this->upgrade_calculation_to_object(); + $newgradevalue = $this->calculation->compute($raw->gradevalue); + } + + $final = $this->grade_grades_final[$userid]; + + $final->gradevalue = $this->adjust_grade($raw, $newgradevalue); + if ($final->update($newgradevalue)) { + $count++; + } else { + return false; + } + } + + return $count; + } + + /** + * Use this when the calculation object is a stdClass (rare) and you need it to have full + * object status (with methods and all). + */ + function upgrade_calculation_to_object() { + if (!is_a($this->calculation, 'grade_calculation')) { + $this->calculation = new grade_calculation($this->calculation, false); + } + } + + /** + * Given a float grade value or integer grade scale, applies a number of adjustment based on + * grade_item variables and returns the result. + * @param object $grade_raw The raw object to compare with this grade_item's rules + * @param mixed $gradevalue The new gradevalue (after calculations are performed) + * @return mixed + */ + function adjust_grade($grade_raw, $gradevalue=NULL) { + if (!empty($grade_raw->gradevalue)) { // Dealing with numerical grade + if (empty($gradevalue)) { + $gradevalue = $grade_raw->gradevalue; + } + } elseif(!empty($grade_raw->gradescale)) { // Dealing with a scale value + if (empty($gradevalue)) { + $gradevalue = $grade_raw->gradescale; + } + + } else { // Something's wrong, the raw grade has no value!? + + } + + $raw_diff = $grade_raw->grademax - $grade_raw->grademin; + $item_diff = $this->grademax - $this->grademin; + $min_diff = $grade_raw->grademin - $this->grademin; + + $diff_factor = max($raw_diff, $item_diff) / min($raw_diff, $item_diff); + + if ($raw_diff > $item_diff) { + $gradevalue = $gradevalue / $diff_factor; + } else { + $gradevalue = $gradevalue * $diff_factor; + } + + // Apply factors + $gradevalue *= $this->multfactor; + $gradevalue += $this->plusfactor; + + return $gradevalue; } } ?> diff --git a/lib/simpletest/testgradelib.php b/lib/simpletest/testgradelib.php index e554f8cef6..73d8401fc7 100644 --- a/lib/simpletest/testgradelib.php +++ b/lib/simpletest/testgradelib.php @@ -695,6 +695,67 @@ class gradelib_test extends UnitTestCase { $this->assertEqual($this->grade_categories[0]->fullname, $category->fullname); } + /** + * Test update of all final grades + */ + function test_grade_item_update_final_grades() { + $grade_item = new grade_item($this->grade_items[0]); + $this->assertTrue(method_exists($grade_item, 'update_final_grade')); + $this->assertEqual(3, $grade_item->update_final_grade()); + $this->assertEqual(1, $grade_item->update_final_grade(1)); + } + + /** + * Test loading of raw and final items into grade_item. + */ + function test_grade_item_load() { + $grade_item = new grade_item($this->grade_items[0]); + $this->assertTrue(method_exists($grade_item, 'load_final')); + $this->assertTrue(method_exists($grade_item, 'load_raw')); + + // Check that final and raw items are not yet loaded + $this->assertTrue(empty($grade_item->grade_grades_final)); + $this->assertTrue(empty($grade_item->grade_grades_raw)); + + // Load raw and final grades + $grade_item->load_final(); + $grade_item->load_raw(); + + // Check that final and raw grades are now loaded + $this->assertFalse(empty($grade_item->grade_grades_final)); + $this->assertFalse(empty($grade_item->grade_grades_raw)); + $this->assertEqual($this->grade_grades_final[0]->gradevalue, $grade_item->grade_grades_final[1]->gradevalue); + $this->assertEqual($this->grade_grades_raw[0]->gradevalue, $grade_item->grade_grades_raw[1]->gradevalue); + } + + /** + * Test the adjust_grade method + */ + function test_grade_item_adjust_grade() { + $grade_item = new grade_item($this->grade_items[0]); + $this->assertTrue(method_exists($grade_item, 'adjust_grade')); + $grade_raw = new stdClass(); + $grade_raw->gradevalue = 40; + $grade_raw->grademax = 100; + $grade_raw->grademin = 0; + $grade_item->multfactor = 1; + $grade_item->plusfactor = 0; + $grade_item->grademax = 50; + $grade_item->grademin = 0; + + $this->assertEqual(20, $grade_item->adjust_grade($grade_raw)); + + $grade_item->grademax = 150; + $grade_item->grademin = 0; + + $this->assertEqual(60, $grade_item->adjust_grade($grade_raw)); + + $grade_item->grademax = 150; + $grade_item->grademin = 50; + + $this->assertEqual(40, $grade_item->adjust_grade($grade_raw)); + } + // GRADE_CATEGORY OBJECT function test_grade_category_construct() {