[ Index ]

PHP Cross Reference of Unnamed Project

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1