[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/grade/tests/ -> grade_category_test.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * @package    core_grades
  19   * @category   phpunit
  20   * @copyright  [email protected]
  21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  defined('MOODLE_INTERNAL') || die();
  25  
  26  require_once (__DIR__.'/fixtures/lib.php');
  27  
  28  
  29  class core_grade_category_testcase extends grade_base_testcase {
  30  
  31      public function test_grade_category() {
  32          $this->sub_test_grade_category_construct();
  33          $this->sub_test_grade_category_build_path();
  34          $this->sub_test_grade_category_fetch();
  35          $this->sub_test_grade_category_fetch_all();
  36          $this->sub_test_grade_category_update();
  37          $this->sub_test_grade_category_delete();
  38          $this->sub_test_grade_category_insert();
  39          $this->sub_test_grade_category_qualifies_for_regrading();
  40          $this->sub_test_grade_category_force_regrading();
  41          $this->sub_test_grade_category_aggregate_grades();
  42          $this->sub_test_grade_category_apply_limit_rules();
  43          $this->sub_test_grade_category_is_aggregationcoef_used();
  44          $this->sub_test_grade_category_aggregation_uses_aggregationcoef();
  45          $this->sub_test_grade_category_fetch_course_tree();
  46          $this->sub_test_grade_category_get_children();
  47          $this->sub_test_grade_category_load_grade_item();
  48          $this->sub_test_grade_category_get_grade_item();
  49          $this->sub_test_grade_category_load_parent_category();
  50          $this->sub_test_grade_category_get_parent_category();
  51          $this->sub_test_grade_category_get_name();
  52          $this->sub_test_grade_category_set_parent();
  53          $this->sub_test_grade_category_get_final();
  54          $this->sub_test_grade_category_get_sortorder();
  55          $this->sub_test_grade_category_set_sortorder();
  56          $this->sub_test_grade_category_is_editable();
  57          $this->sub_test_grade_category_move_after_sortorder();
  58          $this->sub_test_grade_category_is_course_category();
  59          $this->sub_test_grade_category_fetch_course_category();
  60          $this->sub_test_grade_category_is_locked();
  61          $this->sub_test_grade_category_set_locked();
  62          $this->sub_test_grade_category_is_hidden();
  63          $this->sub_test_grade_category_set_hidden();
  64          $this->sub_test_grade_category_can_control_visibility();
  65  
  66          // This won't work until MDL-11837 is complete.
  67          // $this->sub_test_grade_category_generate_grades();
  68  
  69          // Do this last as adding a second course category messes up the data.
  70          $this->sub_test_grade_category_insert_course_category();
  71          $this->sub_test_grade_category_is_extracredit_used();
  72          $this->sub_test_grade_category_aggregation_uses_extracredit();
  73      }
  74  
  75      // Adds 3 new grade categories at various depths.
  76      protected function sub_test_grade_category_construct() {
  77          $course_category = grade_category::fetch_course_category($this->courseid);
  78  
  79          $params = new stdClass();
  80  
  81          $params->courseid = $this->courseid;
  82          $params->fullname = 'unittestcategory4';
  83  
  84          $grade_category = new grade_category($params, false);
  85          $grade_category->insert();
  86          $this->grade_categories[] = $grade_category;
  87  
  88          $this->assertEquals($params->courseid, $grade_category->courseid);
  89          $this->assertEquals($params->fullname, $grade_category->fullname);
  90          $this->assertEquals(2, $grade_category->depth);
  91          $this->assertEquals("/$course_category->id/$grade_category->id/", $grade_category->path);
  92          $parentpath = $grade_category->path;
  93  
  94          // Test a child category.
  95          $params->parent = $grade_category->id;
  96          $params->fullname = 'unittestcategory5';
  97          $grade_category = new grade_category($params, false);
  98          $grade_category->insert();
  99          $this->grade_categories[] = $grade_category;
 100  
 101          $this->assertEquals(3, $grade_category->depth);
 102          $this->assertEquals($parentpath.$grade_category->id."/", $grade_category->path);
 103          $parentpath = $grade_category->path;
 104  
 105          // Test a third depth category.
 106          $params->parent = $grade_category->id;
 107          $params->fullname = 'unittestcategory6';
 108          $grade_category = new grade_category($params, false);
 109          $grade_category->insert();
 110          $this->grade_categories[50] = $grade_category;// Going to delete this one later hence the special index.
 111  
 112          $this->assertEquals(4, $grade_category->depth);
 113          $this->assertEquals($parentpath.$grade_category->id."/", $grade_category->path);
 114      }
 115  
 116      protected function sub_test_grade_category_build_path() {
 117          $grade_category = new grade_category($this->grade_categories[1]);
 118          $this->assertTrue(method_exists($grade_category, 'build_path'));
 119          $path = grade_category::build_path($grade_category);
 120          $this->assertEquals($grade_category->path, $path);
 121      }
 122  
 123      protected function sub_test_grade_category_fetch() {
 124          $grade_category = new grade_category();
 125          $this->assertTrue(method_exists($grade_category, 'fetch'));
 126  
 127          $grade_category = grade_category::fetch(array('id'=>$this->grade_categories[0]->id));
 128          $this->assertEquals($this->grade_categories[0]->id, $grade_category->id);
 129          $this->assertEquals($this->grade_categories[0]->fullname, $grade_category->fullname);
 130      }
 131  
 132      protected function sub_test_grade_category_fetch_all() {
 133          $grade_category = new grade_category();
 134          $this->assertTrue(method_exists($grade_category, 'fetch_all'));
 135  
 136          $grade_categories = grade_category::fetch_all(array('courseid'=>$this->courseid));
 137          $this->assertEquals(count($this->grade_categories), count($grade_categories)-1);
 138      }
 139  
 140      protected function sub_test_grade_category_update() {
 141          global $DB;
 142          $grade_category = new grade_category($this->grade_categories[0]);
 143          $this->assertTrue(method_exists($grade_category, 'update'));
 144  
 145          $grade_category->fullname = 'Updated info for this unittest grade_category';
 146          $grade_category->path = null; // Path must be recalculated if missing.
 147          $grade_category->depth = null;
 148          $grade_category->aggregation = GRADE_AGGREGATE_MAX; // Should force regrading.
 149  
 150          $grade_item = $grade_category->get_grade_item();
 151          $this->assertEquals(0, $grade_item->needsupdate);
 152  
 153          $this->assertTrue($grade_category->update());
 154  
 155          $fullname = $DB->get_field('grade_categories', 'fullname', array('id' => $this->grade_categories[0]->id));
 156          $this->assertEquals($grade_category->fullname, $fullname);
 157  
 158          $path = $DB->get_field('grade_categories', 'path', array('id' => $this->grade_categories[0]->id));
 159          $this->assertEquals($grade_category->path, $path);
 160  
 161          $depth = $DB->get_field('grade_categories', 'depth', array('id' => $this->grade_categories[0]->id));
 162          $this->assertEquals($grade_category->depth, $depth);
 163  
 164          $grade_item = $grade_category->get_grade_item();
 165          $this->assertEquals(1, $grade_item->needsupdate);
 166      }
 167  
 168      protected function sub_test_grade_category_delete() {
 169          global $DB;
 170  
 171          $grade_category = new grade_category($this->grade_categories[50]);
 172          $this->assertTrue(method_exists($grade_category, 'delete'));
 173  
 174          $this->assertTrue($grade_category->delete());
 175          $this->assertFalse($DB->get_record('grade_categories', array('id' => $grade_category->id)));
 176      }
 177  
 178      protected function sub_test_grade_category_insert() {
 179          $course_category = grade_category::fetch_course_category($this->courseid);
 180  
 181          $grade_category = new grade_category();
 182          $this->assertTrue(method_exists($grade_category, 'insert'));
 183  
 184          $grade_category->fullname    = 'unittestcategory4';
 185          $grade_category->courseid    = $this->courseid;
 186          $grade_category->aggregation = GRADE_AGGREGATE_MEAN;
 187          $grade_category->aggregateonlygraded = 1;
 188          $grade_category->keephigh    = 100;
 189          $grade_category->droplow     = 10;
 190          $grade_category->hidden      = 0;
 191          $grade_category->parent      = $this->grade_categories[1]->id; // sub_test_grade_category_delete() removed the category at 0.
 192  
 193          $grade_category->insert();
 194  
 195          $this->assertEquals('/'.$course_category->id.'/'.$this->grade_categories[1]->parent.'/'.$this->grade_categories[1]->id.'/'.$grade_category->id.'/', $grade_category->path);
 196          $this->assertEquals(4, $grade_category->depth);
 197  
 198          $last_grade_category = end($this->grade_categories);
 199  
 200          $this->assertFalse(empty($grade_category->grade_item));
 201          $this->assertEquals($grade_category->id, $grade_category->grade_item->iteminstance);
 202          $this->assertEquals('category', $grade_category->grade_item->itemtype);
 203  
 204          $this->assertEquals($grade_category->id, $last_grade_category->id + 1);
 205          $this->assertFalse(empty($grade_category->timecreated));
 206          $this->assertFalse(empty($grade_category->timemodified));
 207      }
 208  
 209      protected function sub_test_grade_category_qualifies_for_regrading() {
 210          $grade_category = new grade_category($this->grade_categories[1]);
 211          $this->assertTrue(method_exists($grade_category, 'qualifies_for_regrading'));
 212          $this->assertFalse($grade_category->qualifies_for_regrading());
 213  
 214          $grade_category->aggregation = GRADE_AGGREGATE_MAX;
 215          $this->assertTrue($grade_category->qualifies_for_regrading());
 216  
 217          $grade_category = new grade_category($this->grade_categories[1]);
 218          $grade_category->droplow = 99;
 219          $this->assertTrue($grade_category->qualifies_for_regrading());
 220  
 221          $grade_category = new grade_category($this->grade_categories[1]);
 222          $grade_category->keephigh = 99;
 223          $this->assertTrue($grade_category->qualifies_for_regrading());
 224      }
 225  
 226      protected function sub_test_grade_category_force_regrading() {
 227          $grade_category = new grade_category($this->grade_categories[1]);
 228          $this->assertTrue(method_exists($grade_category, 'force_regrading'));
 229  
 230          $grade_category->load_grade_item();
 231          $this->assertEquals(0, $grade_category->grade_item->needsupdate);
 232  
 233          $grade_category->force_regrading();
 234  
 235          $grade_category->grade_item = null;
 236          $grade_category->load_grade_item();
 237  
 238          $this->assertEquals(1, $grade_category->grade_item->needsupdate);
 239      }
 240  
 241      /**
 242       * Tests the calculation of grades using the various aggregation methods with and without hidden grades
 243       * This will not work entirely until MDL-11837 is done
 244       */
 245      protected function sub_test_grade_category_generate_grades() {
 246          global $DB;
 247  
 248          // Inserting some special grade items to make testing the final grade calculation easier.
 249          $params = new stdClass();
 250          $params->courseid = $this->courseid;
 251          $params->fullname = 'unittestgradecalccategory';
 252          $params->aggregation = GRADE_AGGREGATE_MEAN;
 253          $params->aggregateonlygraded = 0;
 254          $grade_category = new grade_category($params, false);
 255          $grade_category->insert();
 256  
 257          $this->assertTrue(method_exists($grade_category, 'generate_grades'));
 258  
 259          $grade_category->load_grade_item();
 260          $cgi = $grade_category->get_grade_item();
 261          $cgi->grademin = 0;
 262          $cgi->grademax = 20; // 3 grade items out of 10 but category is out of 20 to force scaling to occur.
 263          $cgi->update();
 264  
 265          // 3 grade items each with a maximum grade of 10.
 266          $grade_items = array();
 267          for ($i=0; $i<3; $i++) {
 268              $grade_items[$i] = new grade_item();
 269              $grade_items[$i]->courseid = $this->courseid;
 270              $grade_items[$i]->categoryid = $grade_category->id;
 271              $grade_items[$i]->itemname = 'manual grade_item '.$i;
 272              $grade_items[$i]->itemtype = 'manual';
 273              $grade_items[$i]->itemnumber = 0;
 274              $grade_items[$i]->needsupdate = false;
 275              $grade_items[$i]->gradetype = GRADE_TYPE_VALUE;
 276              $grade_items[$i]->grademin = 0;
 277              $grade_items[$i]->grademax = 10;
 278              $grade_items[$i]->iteminfo = 'Manual grade item used for unit testing';
 279              $grade_items[$i]->timecreated = time();
 280              $grade_items[$i]->timemodified = time();
 281  
 282              // Used as the weight by weighted mean and as extra credit by mean with extra credit.
 283              // Will be 0, 1 and 2.
 284              $grade_items[$i]->aggregationcoef = $i;
 285  
 286              $grade_items[$i]->insert();
 287          }
 288  
 289          // A grade for each grade item.
 290          $grade_grades = array();
 291          for ($i=0; $i<3; $i++) {
 292              $grade_grades[$i] = new grade_grade();
 293              $grade_grades[$i]->itemid = $grade_items[$i]->id;
 294              $grade_grades[$i]->userid = $this->userid;
 295              $grade_grades[$i]->rawgrade = ($i+1)*2; // Produce grade grades of 2, 4 and 6.
 296              $grade_grades[$i]->finalgrade = ($i+1)*2;
 297              $grade_grades[$i]->timecreated = time();
 298              $grade_grades[$i]->timemodified = time();
 299              $grade_grades[$i]->information = '1 of 2 grade_grades';
 300              $grade_grades[$i]->informationformat = FORMAT_PLAIN;
 301              $grade_grades[$i]->feedback = 'Good, but not good enough..';
 302              $grade_grades[$i]->feedbackformat = FORMAT_PLAIN;
 303  
 304              $grade_grades[$i]->insert();
 305          }
 306  
 307          // 3 grade items with 1 grade_grade each.
 308          // grade grades have the values 2, 4 and 6.
 309  
 310          // First correct answer is the aggregate with all 3 grades.
 311          // Second correct answer is with the first grade (value 2) hidden.
 312  
 313          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEDIAN, 'GRADE_AGGREGATE_MEDIAN', 8, 8);
 314          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MAX, 'GRADE_AGGREGATE_MAX', 12, 12);
 315          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MODE, 'GRADE_AGGREGATE_MODE', 12, 12);
 316  
 317          // Weighted mean. note grade totals are rounded to an int to prevent rounding discrepancies. correct final grade isnt actually exactly 10
 318          // 3 items with grades 2, 4 and 6 with weights 0, 1 and 2 and all out of 10. then doubled to be out of 20.
 319          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN, 'GRADE_AGGREGATE_WEIGHTED_MEAN', 10, 10);
 320  
 321          // Simple weighted mean.
 322          // 3 items with grades 2, 4 and 6 equally weighted and all out of 10. then doubled to be out of 20.
 323          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN2, 'GRADE_AGGREGATE_WEIGHTED_MEAN2', 8, 10);
 324  
 325          // Mean of grades with extra credit.
 326          // 3 items with grades 2, 4 and 6 with extra credit 0, 1 and 2 equally weighted and all out of 10. then doubled to be out of 20.
 327          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_EXTRACREDIT_MEAN, 'GRADE_AGGREGATE_EXTRACREDIT_MEAN', 10, 13);
 328  
 329          // Aggregation tests the are affected by a hidden grade currently dont work as we dont store the altered grade in the database
 330          // instead an in memory recalculation is done. This should be remedied by MDL-11837.
 331  
 332          // Fails with 1 grade hidden. still reports 8 as being correct.
 333          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEAN, 'GRADE_AGGREGATE_MEAN', 8, 10);
 334  
 335          // Fails with 1 grade hidden. still reports 4 as being correct.
 336          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MIN, 'GRADE_AGGREGATE_MIN', 4, 8);
 337  
 338          // Fails with 1 grade hidden. still reports 12 as being correct.
 339          $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_SUM, 'GRADE_AGGREGATE_SUM', 12, 10);
 340      }
 341  
 342      /**
 343       * Test grade category aggregation using the supplied grade objects and aggregation method
 344       * @param grade_category $grade_category the category to be tested
 345       * @param array $grade_items array of instance of grade_item
 346       * @param array $grade_grades array of instances of grade_grade
 347       * @param int $aggmethod the aggregation method to apply ie GRADE_AGGREGATE_MEAN
 348       * @param string $aggmethodname the name of the aggregation method to apply. Used to display any test failure messages
 349       * @param int $correct1 the correct final grade for the category with NO items hidden
 350       * @param int $correct2 the correct final grade for the category with the grade at $grade_grades[0] hidden
 351       * @return void
 352       */
 353      protected function helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, $aggmethod, $aggmethodname, $correct1, $correct2) {
 354          $grade_category->aggregation = $aggmethod;
 355          $grade_category->update();
 356  
 357          // Check grade_item isnt hidden from a previous test.
 358          $grade_items[0]->set_hidden(0, true);
 359          $this->helper_test_grade_aggregation_result($grade_category, $correct1, 'Testing aggregation method('.$aggmethodname.') with no items hidden %s');
 360  
 361          // Hide the grade item with grade of 2.
 362          $grade_items[0]->set_hidden(1, true);
 363          $this->helper_test_grade_aggregation_result($grade_category, $correct2, 'Testing aggregation method('.$aggmethodname.') with 1 item hidden %s');
 364      }
 365  
 366      /**
 367       * Verify the value of the category grade item for $this->userid
 368       * @param grade_category $grade_category the category to be tested
 369       * @param int $correctgrade the expected grade
 370       * @param string msg The message that should be displayed if the correct grade is not found
 371       * @return void
 372       */
 373      protected function helper_test_grade_aggregation_result($grade_category, $correctgrade, $msg) {
 374          global $DB;
 375  
 376          $category_grade_item = $grade_category->get_grade_item();
 377  
 378          // This creates all the grade_grades we need.
 379          grade_regrade_final_grades($this->courseid);
 380  
 381          $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid));
 382          $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
 383          $this->assertEquals(intval($correctgrade), intval($grade->finalgrade), $msg);
 384  
 385          /*
 386           * TODO this doesnt work as the grade_grades created by $grade_category->generate_grades(); dont
 387           * observe the category's max grade
 388          // delete the grade_grades for the category itself and check they get recreated correctly.
 389          $DB->delete_records('grade_grades', array('itemid'=>$category_grade_item->id));
 390          $grade_category->generate_grades();
 391  
 392          $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid));
 393          $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
 394          $this->assertEquals(intval($correctgrade), intval($grade->finalgrade), $msg);
 395           *
 396           */
 397      }
 398  
 399      protected function sub_test_grade_category_aggregate_grades() {
 400          $category = new grade_category($this->grade_categories[0]);
 401          $this->assertTrue(method_exists($category, 'aggregate_grades'));
 402          // Tested more fully via test_grade_category_generate_grades().
 403      }
 404  
 405      protected function sub_test_grade_category_apply_limit_rules() {
 406          $items[$this->grade_items[0]->id] = new grade_item($this->grade_items[0], false);
 407          $items[$this->grade_items[1]->id] = new grade_item($this->grade_items[1], false);
 408          $items[$this->grade_items[2]->id] = new grade_item($this->grade_items[2], false);
 409          $items[$this->grade_items[4]->id] = new grade_item($this->grade_items[4], false);
 410  
 411          // Test excluding the lowest 2 out of 4 grades from aggregation with no 0 grades.
 412          $category = new grade_category();
 413          $category->droplow = 2;
 414          $grades = array($this->grade_items[0]->id=>5.374,
 415                          $this->grade_items[1]->id=>9.4743,
 416                          $this->grade_items[2]->id=>2.5474,
 417                          $this->grade_items[4]->id=>7.3754);
 418          $category->apply_limit_rules($grades, $items);
 419          $this->assertEquals(count($grades), 2);
 420          $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
 421          $this->assertEquals($grades[$this->grade_items[4]->id], 7.3754);
 422  
 423          // Test aggregating only the highest 1 out of 4 grades.
 424          $category = new grade_category();
 425          $category->keephigh = 1;
 426          $category->droplow = 0;
 427          $grades = array($this->grade_items[0]->id=>5.374,
 428                          $this->grade_items[1]->id=>9.4743,
 429                          $this->grade_items[2]->id=>2.5474,
 430                          $this->grade_items[4]->id=>7.3754);
 431          $category->apply_limit_rules($grades, $items);
 432          $this->assertEquals(count($grades), 1);
 433          $grade = reset($grades);
 434          $this->assertEquals(9.4743, $grade);
 435  
 436          // Test excluding the lowest 2 out of 4 grades from aggregation with no 0 grades.
 437          // An extra credit grade item should be kept even if droplow means it would otherwise be excluded.
 438          $category = new grade_category();
 439          $category->droplow     = 2;
 440          $category->aggregation = GRADE_AGGREGATE_SUM;
 441          $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit".
 442          $grades = array($this->grade_items[0]->id=>5.374,
 443                          $this->grade_items[1]->id=>9.4743,
 444                          $this->grade_items[2]->id=>2.5474,
 445                          $this->grade_items[4]->id=>7.3754);
 446          $category->apply_limit_rules($grades, $items);
 447          $this->assertEquals(count($grades), 2);
 448          $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
 449          $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474);
 450  
 451          // Test only aggregating the highest 1 out of 4 grades.
 452          // An extra credit grade item is retained in addition to the highest grade.
 453          $category = new grade_category();
 454          $category->keephigh = 1;
 455          $category->droplow = 0;
 456          $category->aggregation = GRADE_AGGREGATE_SUM;
 457          $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit".
 458          $grades = array($this->grade_items[0]->id=>5.374,
 459                          $this->grade_items[1]->id=>9.4743,
 460                          $this->grade_items[2]->id=>2.5474,
 461                          $this->grade_items[4]->id=>7.3754);
 462          $category->apply_limit_rules($grades, $items);
 463          $this->assertEquals(count($grades), 2);
 464          $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
 465          $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474);
 466  
 467          // Test excluding the lowest 1 out of 4 grades from aggregation with two 0 grades.
 468          $items[$this->grade_items[2]->id]->aggregationcoef = 0; // Undo marking grade item 2 as "extra credit".
 469          $category = new grade_category();
 470          $category->droplow     = 1;
 471          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean.
 472          $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
 473                          $this->grade_items[1]->id=>5, // 5 out of 100.
 474                          $this->grade_items[2]->id=>2, // 0 out of 6.
 475                          $this->grade_items[4]->id=>0); // 0 out of 100.
 476          $category->apply_limit_rules($grades, $items);
 477          $this->assertEquals(count($grades), 3);
 478          $this->assertEquals($grades[$this->grade_items[1]->id], 5);
 479          $this->assertEquals($grades[$this->grade_items[2]->id], 2);
 480          $this->assertEquals($grades[$this->grade_items[4]->id], 0);
 481  
 482          // Test excluding the lowest 2 out of 4 grades from aggregation with three 0 grades.
 483          $category = new grade_category();
 484          $category->droplow     = 2;
 485          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean.
 486          $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
 487                          $this->grade_items[1]->id=>5, // 5 out of 100.
 488                          $this->grade_items[2]->id=>0, // 0 out of 6.
 489                          $this->grade_items[4]->id=>0); // 0 out of 100. Should be excluded from aggregation.
 490          $category->apply_limit_rules($grades, $items);
 491          $this->assertEquals(count($grades), 2);
 492          $this->assertEquals($grades[$this->grade_items[1]->id], 5);
 493          $this->assertEquals($grades[$this->grade_items[2]->id], 0);
 494  
 495          // Test excluding the lowest 5 out of 4 grades from aggregation.
 496          // Just to check we handle this sensibly.
 497          $category = new grade_category();
 498          $category->droplow     = 5;
 499          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean.
 500          $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
 501                          $this->grade_items[1]->id=>5, // 5 out of 100.
 502                          $this->grade_items[2]->id=>6, // 6 out of 6.
 503                          $this->grade_items[4]->id=>1);// 1 out of 100. Should be excluded from aggregation.
 504          $category->apply_limit_rules($grades, $items);
 505          $this->assertEquals(count($grades), 0);
 506  
 507          // Test excluding the lowest 4 out of 4 grades from aggregation with one marked as extra credit.
 508          $category = new grade_category();
 509          $category->droplow     = 4;
 510          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean.
 511          $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit".
 512          $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
 513                          $this->grade_items[1]->id=>5, // 5 out of 100. Should be excluded from aggregation.
 514                          $this->grade_items[2]->id=>6, // 6 out of 6. Extra credit. Should be retained.
 515                          $this->grade_items[4]->id=>1);// 1 out of 100. Should be excluded from aggregation.
 516          $category->apply_limit_rules($grades, $items);
 517          $this->assertEquals(count($grades), 1);
 518          $this->assertEquals($grades[$this->grade_items[2]->id], 6);
 519  
 520          // MDL-35667 - There was an infinite loop if several items had the same grade and at least one was extra credit.
 521          $category = new grade_category();
 522          $category->droplow     = 1;
 523          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean.
 524          $items[$this->grade_items[1]->id]->aggregationcoef = 1; // Mark grade item 1 as "extra credit".
 525          $grades = array($this->grade_items[0]->id=>1, // 1 out of 110. Should be excluded from aggregation.
 526                          $this->grade_items[1]->id=>1, // 1 out of 100. Extra credit. Should be retained.
 527                          $this->grade_items[2]->id=>1, // 1 out of 6. Should be retained.
 528                          $this->grade_items[4]->id=>1);// 1 out of 100. Should be retained.
 529          $category->apply_limit_rules($grades, $items);
 530          $this->assertEquals(count($grades), 3);
 531          $this->assertEquals($grades[$this->grade_items[1]->id], 1);
 532          $this->assertEquals($grades[$this->grade_items[2]->id], 1);
 533          $this->assertEquals($grades[$this->grade_items[4]->id], 1);
 534  
 535      }
 536  
 537      protected function sub_test_grade_category_is_aggregationcoef_used() {
 538          $category = new grade_category();
 539          // Following use aggregationcoef.
 540          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN;
 541          $this->assertTrue($category->is_aggregationcoef_used());
 542          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2;
 543          $this->assertTrue($category->is_aggregationcoef_used());
 544          $category->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN;
 545          $this->assertTrue($category->is_aggregationcoef_used());
 546          $category->aggregation = GRADE_AGGREGATE_SUM;
 547          $this->assertTrue($category->is_aggregationcoef_used());
 548  
 549          // Following don't use aggregationcoef.
 550          $category->aggregation = GRADE_AGGREGATE_MAX;
 551          $this->assertFalse($category->is_aggregationcoef_used());
 552          $category->aggregation = GRADE_AGGREGATE_MEAN;
 553          $this->assertFalse($category->is_aggregationcoef_used());
 554          $category->aggregation = GRADE_AGGREGATE_MEDIAN;
 555          $this->assertFalse($category->is_aggregationcoef_used());
 556          $category->aggregation = GRADE_AGGREGATE_MIN;
 557          $this->assertFalse($category->is_aggregationcoef_used());
 558          $category->aggregation = GRADE_AGGREGATE_MODE;
 559          $this->assertFalse($category->is_aggregationcoef_used());
 560      }
 561  
 562      protected function sub_test_grade_category_aggregation_uses_aggregationcoef() {
 563  
 564          $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_WEIGHTED_MEAN));
 565          $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_WEIGHTED_MEAN2));
 566          $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_EXTRACREDIT_MEAN));
 567          $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_SUM));
 568  
 569          $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MAX));
 570          $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MEAN));
 571          $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MEDIAN));
 572          $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MIN));
 573          $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MODE));
 574      }
 575  
 576      protected function sub_test_grade_category_fetch_course_tree() {
 577          $category = new grade_category();
 578          $this->assertTrue(method_exists($category, 'fetch_course_tree'));
 579          // TODO: add some tests.
 580      }
 581  
 582      protected function sub_test_grade_category_get_children() {
 583          $course_category = grade_category::fetch_course_category($this->courseid);
 584  
 585          $category = new grade_category($this->grade_categories[0]);
 586          $this->assertTrue(method_exists($category, 'get_children'));
 587  
 588          $children_array = $category->get_children(0);
 589  
 590          $this->assertTrue(is_array($children_array));
 591          $this->assertFalse(empty($children_array[2]));
 592          $this->assertFalse(empty($children_array[2]['object']));
 593          $this->assertFalse(empty($children_array[2]['children']));
 594          $this->assertEquals($this->grade_categories[1]->id, $children_array[2]['object']->id);
 595          $this->assertEquals($this->grade_categories[2]->id, $children_array[5]['object']->id);
 596          $this->assertEquals($this->grade_items[0]->id, $children_array[2]['children'][3]['object']->id);
 597          $this->assertEquals($this->grade_items[1]->id, $children_array[2]['children'][4]['object']->id);
 598          $this->assertEquals($this->grade_items[2]->id, $children_array[5]['children'][6]['object']->id);
 599      }
 600  
 601      protected function sub_test_grade_category_load_grade_item() {
 602          $category = new grade_category($this->grade_categories[0]);
 603          $this->assertTrue(method_exists($category, 'load_grade_item'));
 604          $this->assertEquals(null, $category->grade_item);
 605          $category->load_grade_item();
 606          $this->assertEquals($this->grade_items[3]->id, $category->grade_item->id);
 607      }
 608  
 609      protected function sub_test_grade_category_get_grade_item() {
 610          $category = new grade_category($this->grade_categories[0]);
 611          $this->assertTrue(method_exists($category, 'get_grade_item'));
 612          $grade_item = $category->get_grade_item();
 613          $this->assertEquals($this->grade_items[3]->id, $grade_item->id);
 614      }
 615  
 616      protected function sub_test_grade_category_load_parent_category() {
 617          $category = new grade_category($this->grade_categories[1]);
 618          $this->assertTrue(method_exists($category, 'load_parent_category'));
 619          $this->assertEquals(null, $category->parent_category);
 620          $category->load_parent_category();
 621          $this->assertEquals($this->grade_categories[0]->id, $category->parent_category->id);
 622      }
 623  
 624      protected function sub_test_grade_category_get_parent_category() {
 625          $category = new grade_category($this->grade_categories[1]);
 626          $this->assertTrue(method_exists($category, 'get_parent_category'));
 627          $parent_category = $category->get_parent_category();
 628          $this->assertEquals($this->grade_categories[0]->id, $parent_category->id);
 629      }
 630  
 631      protected function sub_test_grade_category_get_name() {
 632          $category = new grade_category($this->grade_categories[0]);
 633          $this->assertTrue(method_exists($category, 'get_name'));
 634          $this->assertEquals($this->grade_categories[0]->fullname, $category->get_name());
 635      }
 636  
 637      protected function sub_test_grade_category_set_parent() {
 638          $category = new grade_category($this->grade_categories[1]);
 639          $this->assertTrue(method_exists($category, 'set_parent'));
 640          // TODO: implement detailed tests.
 641  
 642          $course_category = grade_category::fetch_course_category($this->courseid);
 643          $this->assertTrue($category->set_parent($course_category->id));
 644          $this->assertEquals($course_category->id, $category->parent);
 645      }
 646  
 647      protected function sub_test_grade_category_get_final() {
 648          $category = new grade_category($this->grade_categories[0]);
 649          $this->assertTrue(method_exists($category, 'get_final'));
 650          $category->load_grade_item();
 651          $this->assertEquals($category->get_final(), $category->grade_item->get_final());
 652      }
 653  
 654      protected function sub_test_grade_category_get_sortorder() {
 655          $category = new grade_category($this->grade_categories[0]);
 656          $this->assertTrue(method_exists($category, 'get_sortorder'));
 657          $category->load_grade_item();
 658          $this->assertEquals($category->get_sortorder(), $category->grade_item->get_sortorder());
 659      }
 660  
 661      protected function sub_test_grade_category_set_sortorder() {
 662          $category = new grade_category($this->grade_categories[0]);
 663          $this->assertTrue(method_exists($category, 'set_sortorder'));
 664          $category->load_grade_item();
 665          $this->assertEquals($category->set_sortorder(10), $category->grade_item->set_sortorder(10));
 666      }
 667  
 668      protected function sub_test_grade_category_move_after_sortorder() {
 669          $category = new grade_category($this->grade_categories[0]);
 670          $this->assertTrue(method_exists($category, 'move_after_sortorder'));
 671          $category->load_grade_item();
 672          $this->assertEquals($category->move_after_sortorder(10), $category->grade_item->move_after_sortorder(10));
 673      }
 674  
 675      protected function sub_test_grade_category_is_course_category() {
 676          $category = grade_category::fetch_course_category($this->courseid);
 677          $this->assertTrue(method_exists($category, 'is_course_category'));
 678          $this->assertTrue($category->is_course_category());
 679      }
 680  
 681      protected function sub_test_grade_category_fetch_course_category() {
 682          $category = new grade_category();
 683          $this->assertTrue(method_exists($category, 'fetch_course_category'));
 684          $category = grade_category::fetch_course_category($this->courseid);
 685          $this->assertTrue(empty($category->parent));
 686      }
 687      /**
 688       * TODO implement
 689       */
 690      protected function sub_test_grade_category_is_editable() {
 691  
 692      }
 693  
 694      protected function sub_test_grade_category_is_locked() {
 695          $category = new grade_category($this->grade_categories[0]);
 696          $this->assertTrue(method_exists($category, 'is_locked'));
 697          $category->load_grade_item();
 698          $this->assertEquals($category->is_locked(), $category->grade_item->is_locked());
 699      }
 700  
 701      protected function sub_test_grade_category_set_locked() {
 702          $category = new grade_category($this->grade_categories[0]);
 703          $this->assertTrue(method_exists($category, 'set_locked'));
 704  
 705          // Will return false as cannot lock a grade that needs updating.
 706          $this->assertFalse($category->set_locked(1));
 707          grade_regrade_final_grades($this->courseid);
 708  
 709          // Get the category from the db again.
 710          $category = new grade_category($this->grade_categories[0]);
 711          $this->assertTrue($category->set_locked(1));
 712      }
 713  
 714      protected function sub_test_grade_category_is_hidden() {
 715          $category = new grade_category($this->grade_categories[0]);
 716          $this->assertTrue(method_exists($category, 'is_hidden'));
 717          $category->load_grade_item();
 718          $this->assertEquals($category->is_hidden(), $category->grade_item->is_hidden());
 719      }
 720  
 721      protected function sub_test_grade_category_set_hidden() {
 722          $category = new grade_category($this->grade_categories[0]);
 723          $this->assertTrue(method_exists($category, 'set_hidden'));
 724          $category->set_hidden(1);
 725          $category->load_grade_item();
 726          $this->assertEquals(true, $category->grade_item->is_hidden());
 727      }
 728  
 729      protected function sub_test_grade_category_can_control_visibility() {
 730          $category = new grade_category($this->grade_categories[0]);
 731          $this->assertTrue($category->can_control_visibility());
 732      }
 733  
 734      protected function sub_test_grade_category_insert_course_category() {
 735          // Beware: adding a duplicate course category messes up the data in a way that's hard to recover from.
 736          $grade_category = new grade_category();
 737          $this->assertTrue(method_exists($grade_category, 'insert_course_category'));
 738  
 739          $id = $grade_category->insert_course_category($this->courseid);
 740          $this->assertNotNull($id);
 741          $this->assertEquals('?', $grade_category->fullname);
 742          $this->assertEquals(GRADE_AGGREGATE_WEIGHTED_MEAN2, $grade_category->aggregation);
 743          $this->assertEquals("/$id/", $grade_category->path);
 744          $this->assertEquals(1, $grade_category->depth);
 745          $this->assertNull($grade_category->parent);
 746      }
 747  
 748      protected function generate_random_raw_grade($item, $userid) {
 749          $grade = new grade_grade();
 750          $grade->itemid = $item->id;
 751          $grade->userid = $userid;
 752          $grade->grademin = 0;
 753          $grade->grademax = 1;
 754          $valuetype = "grade$item->gradetype";
 755          $grade->rawgrade = rand(0, 1000) / 1000;
 756          $grade->insert();
 757          return $grade->rawgrade;
 758      }
 759  
 760      protected function sub_test_grade_category_is_extracredit_used() {
 761          $category = new grade_category();
 762          // Following use aggregationcoef.
 763          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2;
 764          $this->assertTrue($category->is_extracredit_used());
 765          $category->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN;
 766          $this->assertTrue($category->is_extracredit_used());
 767          $category->aggregation = GRADE_AGGREGATE_SUM;
 768          $this->assertTrue($category->is_extracredit_used());
 769  
 770          // Following don't use aggregationcoef.
 771          $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN;
 772          $this->assertFalse($category->is_extracredit_used());
 773          $category->aggregation = GRADE_AGGREGATE_MAX;
 774          $this->assertFalse($category->is_extracredit_used());
 775          $category->aggregation = GRADE_AGGREGATE_MEAN;
 776          $this->assertFalse($category->is_extracredit_used());
 777          $category->aggregation = GRADE_AGGREGATE_MEDIAN;
 778          $this->assertFalse($category->is_extracredit_used());
 779          $category->aggregation = GRADE_AGGREGATE_MIN;
 780          $this->assertFalse($category->is_extracredit_used());
 781          $category->aggregation = GRADE_AGGREGATE_MODE;
 782          $this->assertFalse($category->is_extracredit_used());
 783      }
 784  
 785      protected function sub_test_grade_category_aggregation_uses_extracredit() {
 786  
 787          $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_WEIGHTED_MEAN2));
 788          $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_EXTRACREDIT_MEAN));
 789          $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_SUM));
 790  
 791          $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_WEIGHTED_MEAN));
 792          $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MAX));
 793          $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MEAN));
 794          $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MEDIAN));
 795          $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MIN));
 796          $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MODE));
 797      }
 798  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1