[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/grade/tests/ -> grade_item_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  class core_grade_item_testcase extends grade_base_testcase {
  29      public function test_grade_item() {
  30          $this->sub_test_grade_item_construct();
  31          $this->sub_test_grade_item_insert();
  32          $this->sub_test_grade_item_delete();
  33          $this->sub_test_grade_item_update();
  34          $this->sub_test_grade_item_load_scale();
  35          $this->sub_test_grade_item_load_outcome();
  36          $this->sub_test_grade_item_qualifies_for_regrading();
  37          $this->sub_test_grade_item_force_regrading();
  38          $this->sub_test_grade_item_fetch();
  39          $this->sub_test_grade_item_fetch_all();
  40          $this->sub_test_grade_item_get_all_finals();
  41          $this->sub_test_grade_item_get_final();
  42          $this->sub_test_grade_item_get_sortorder();
  43          $this->sub_test_grade_item_set_sortorder();
  44          $this->sub_test_grade_item_move_after_sortorder();
  45          $this->sub_test_grade_item_get_name();
  46          $this->sub_test_grade_item_set_parent();
  47          $this->sub_test_grade_item_get_parent_category();
  48          $this->sub_test_grade_item_load_parent_category();
  49          $this->sub_test_grade_item_get_item_category();
  50          $this->sub_test_grade_item_load_item_category();
  51          $this->sub_test_grade_item_regrade_final_grades();
  52          $this->sub_test_grade_item_adjust_raw_grade();
  53          $this->sub_test_grade_item_rescale_grades_keep_percentage();
  54          $this->sub_test_grade_item_set_locked();
  55          $this->sub_test_grade_item_is_locked();
  56          $this->sub_test_grade_item_set_hidden();
  57          $this->sub_test_grade_item_is_hidden();
  58          $this->sub_test_grade_item_is_category_item();
  59          $this->sub_test_grade_item_is_course_item();
  60          $this->sub_test_grade_item_fetch_course_item();
  61          $this->sub_test_grade_item_depends_on();
  62          $this->sub_test_refresh_grades();
  63          $this->sub_test_grade_item_is_calculated();
  64          $this->sub_test_grade_item_set_calculation();
  65          $this->sub_test_grade_item_get_calculation();
  66          $this->sub_test_grade_item_compute();
  67          $this->sub_test_update_final_grade();
  68          $this->sub_test_grade_item_can_control_visibility();
  69          $this->sub_test_grade_item_fix_sortorder();
  70      }
  71  
  72      protected function sub_test_grade_item_construct() {
  73          $params = new stdClass();
  74  
  75          $params->courseid = $this->courseid;
  76          $params->categoryid = $this->grade_categories[1]->id;
  77          $params->itemname = 'unittestgradeitem4';
  78          $params->itemtype = 'mod';
  79          $params->itemmodule = 'database';
  80          $params->iteminfo = 'Grade item used for unit testing';
  81  
  82          $grade_item = new grade_item($params, false);
  83  
  84          $this->assertEquals($params->courseid, $grade_item->courseid);
  85          $this->assertEquals($params->categoryid, $grade_item->categoryid);
  86          $this->assertEquals($params->itemmodule, $grade_item->itemmodule);
  87      }
  88  
  89      protected function sub_test_grade_item_insert() {
  90          $grade_item = new grade_item();
  91          $this->assertTrue(method_exists($grade_item, 'insert'));
  92  
  93          $grade_item->courseid = $this->courseid;
  94          $grade_item->categoryid = $this->grade_categories[1]->id;
  95          $grade_item->itemname = 'unittestgradeitem4';
  96          $grade_item->itemtype = 'mod';
  97          $grade_item->itemmodule = 'quiz';
  98          $grade_item->iteminfo = 'Grade item used for unit testing';
  99  
 100          $grade_item->insert();
 101  
 102          $last_grade_item = end($this->grade_items);
 103  
 104          $this->assertEquals($grade_item->id, $last_grade_item->id + 1);
 105          $this->assertEquals(18, $grade_item->sortorder);
 106  
 107          // Keep our reference collection the same as what is in the database.
 108          $this->grade_items[] = $grade_item;
 109      }
 110  
 111      protected function sub_test_grade_item_delete() {
 112          global $DB;
 113          $grade_item = new grade_item($this->grade_items[7], false); // Use a grade item not touched by previous (or future) tests.
 114          $this->assertTrue(method_exists($grade_item, 'delete'));
 115  
 116          $this->assertTrue($grade_item->delete());
 117  
 118          $this->assertFalse($DB->get_record('grade_items', array('id' => $grade_item->id)));
 119  
 120          // Keep our reference collection the same as the database.
 121          unset($this->grade_items[7]);
 122      }
 123  
 124      protected function sub_test_grade_item_update() {
 125          global $DB;
 126          $grade_item = new grade_item($this->grade_items[0], false);
 127          $this->assertTrue(method_exists($grade_item, 'update'));
 128  
 129          $grade_item->iteminfo = 'Updated info for this unittest grade_item';
 130  
 131          $this->assertTrue($grade_item->update());
 132  
 133          $grade_item->grademin = 14;
 134          $this->assertTrue($grade_item->qualifies_for_regrading());
 135          $this->assertTrue($grade_item->update());
 136  
 137          $iteminfo = $DB->get_field('grade_items', 'iteminfo', array('id' => $this->grade_items[0]->id));
 138          $this->assertEquals($grade_item->iteminfo, $iteminfo);
 139      }
 140  
 141      protected function sub_test_grade_item_load_scale() {
 142          $grade_item = new grade_item($this->grade_items[2], false);
 143          $this->assertTrue(method_exists($grade_item, 'load_scale'));
 144          $scale = $grade_item->load_scale();
 145          $this->assertFalse(empty($grade_item->scale));
 146          $this->assertEquals($scale->id, $this->grade_items[2]->scaleid);
 147      }
 148  
 149      protected function sub_test_grade_item_load_outcome() {
 150          $grade_item = new grade_item($this->grade_items[0], false);
 151          $this->assertTrue(method_exists($grade_item, 'load_outcome'));
 152          // TODO: add tests.
 153      }
 154  
 155      protected function sub_test_grade_item_qualifies_for_regrading() {
 156          $grade_item = new grade_item($this->grade_items[3], false); // Use a grade item not touched by previous tests.
 157          $this->assertTrue(method_exists($grade_item, 'qualifies_for_regrading'));
 158  
 159          $this->assertFalse($grade_item->qualifies_for_regrading());
 160  
 161          $grade_item->iteminfo = 'Updated info for this unittest grade_item';
 162  
 163          $this->assertFalse($grade_item->qualifies_for_regrading());
 164  
 165          $grade_item->grademin = 14;
 166  
 167          $this->assertTrue($grade_item->qualifies_for_regrading());
 168      }
 169  
 170      protected function sub_test_grade_item_force_regrading() {
 171          $grade_item = new grade_item($this->grade_items[3], false); // Use a grade item not touched by previous tests.
 172          $this->assertTrue(method_exists($grade_item, 'force_regrading'));
 173  
 174          $this->assertEquals(0, $grade_item->needsupdate);
 175  
 176          $grade_item->force_regrading();
 177          $this->assertEquals(1, $grade_item->needsupdate);
 178          $grade_item->update_from_db();
 179          $this->assertEquals(1, $grade_item->needsupdate);
 180      }
 181  
 182      protected function sub_test_grade_item_fetch() {
 183          $grade_item = new grade_item();
 184          $this->assertTrue(method_exists($grade_item, 'fetch'));
 185  
 186          // Not using $this->grade_items[0] as it's iteminfo was modified by sub_test_grade_item_qualifies_for_regrading().
 187          $grade_item = grade_item::fetch(array('id'=>$this->grade_items[1]->id));
 188          $this->assertEquals($this->grade_items[1]->id, $grade_item->id);
 189          $this->assertEquals($this->grade_items[1]->iteminfo, $grade_item->iteminfo);
 190  
 191          $grade_item = grade_item::fetch(array('itemtype'=>$this->grade_items[1]->itemtype, 'itemmodule'=>$this->grade_items[1]->itemmodule));
 192          $this->assertEquals($this->grade_items[1]->id, $grade_item->id);
 193          $this->assertEquals($this->grade_items[1]->iteminfo, $grade_item->iteminfo);
 194      }
 195  
 196      protected function sub_test_grade_item_fetch_all() {
 197          $grade_item = new grade_item();
 198          $this->assertTrue(method_exists($grade_item, 'fetch_all'));
 199  
 200          $grade_items = grade_item::fetch_all(array('courseid'=>$this->courseid));
 201          $this->assertEquals(count($this->grade_items), count($grade_items)-1); // -1 to account for the course grade item.
 202      }
 203  
 204      // Retrieve all final scores for a given grade_item.
 205      protected function sub_test_grade_item_get_all_finals() {
 206          $grade_item = new grade_item($this->grade_items[0], false);
 207          $this->assertTrue(method_exists($grade_item, 'get_final'));
 208  
 209          $final_grades = $grade_item->get_final();
 210          $this->assertEquals(3, count($final_grades));
 211      }
 212  
 213  
 214      // Retrieve all final scores for a specific userid.
 215      protected function sub_test_grade_item_get_final() {
 216          $grade_item = new grade_item($this->grade_items[0], false);
 217          $this->assertTrue(method_exists($grade_item, 'get_final'));
 218          $final_grade = $grade_item->get_final($this->user[1]->id);
 219          $this->assertEquals($this->grade_grades[0]->finalgrade, $final_grade->finalgrade);
 220      }
 221  
 222      protected function sub_test_grade_item_get_sortorder() {
 223          $grade_item = new grade_item($this->grade_items[0], false);
 224          $this->assertTrue(method_exists($grade_item, 'get_sortorder'));
 225          $sortorder = $grade_item->get_sortorder();
 226          $this->assertEquals($this->grade_items[0]->sortorder, $sortorder);
 227      }
 228  
 229      protected function sub_test_grade_item_set_sortorder() {
 230          $grade_item = new grade_item($this->grade_items[0], false);
 231          $this->assertTrue(method_exists($grade_item, 'set_sortorder'));
 232          $grade_item->set_sortorder(999);
 233          $this->assertEquals($grade_item->sortorder, 999);
 234      }
 235  
 236      protected function sub_test_grade_item_move_after_sortorder() {
 237          $grade_item = new grade_item($this->grade_items[0], false);
 238          $this->assertTrue(method_exists($grade_item, 'move_after_sortorder'));
 239          $grade_item->move_after_sortorder(5);
 240          $this->assertEquals($grade_item->sortorder, 6);
 241  
 242          $grade_item = grade_item::fetch(array('id'=>$this->grade_items[0]->id));
 243          $this->assertEquals($grade_item->sortorder, 6);
 244  
 245          $after = grade_item::fetch(array('id'=>$this->grade_items[6]->id));
 246          $this->assertEquals($after->sortorder, 8);
 247      }
 248  
 249      protected function sub_test_grade_item_get_name() {
 250          $grade_item = new grade_item($this->grade_items[0], false);
 251          $this->assertTrue(method_exists($grade_item, 'get_name'));
 252  
 253          $name = $grade_item->get_name();
 254          $this->assertEquals($this->grade_items[0]->itemname, $name);
 255      }
 256  
 257      protected function sub_test_grade_item_set_parent() {
 258          $grade_item = new grade_item($this->grade_items[0], false);
 259          $this->assertTrue(method_exists($grade_item, 'set_parent'));
 260  
 261          $old = $grade_item->get_parent_category();
 262          $new = new grade_category($this->grade_categories[3], false);
 263          $new_item = $new->get_grade_item();
 264  
 265          $this->assertTrue($grade_item->set_parent($new->id));
 266  
 267          $new_item->update_from_db();
 268          $grade_item->update_from_db();
 269  
 270          $this->assertEquals($grade_item->categoryid, $new->id);
 271      }
 272  
 273      protected function sub_test_grade_item_get_parent_category() {
 274          $grade_item = new grade_item($this->grade_items[0], false);
 275          $this->assertTrue(method_exists($grade_item, 'get_parent_category'));
 276  
 277          $category = $grade_item->get_parent_category();
 278          $this->assertEquals($this->grade_categories[1]->fullname, $category->fullname);
 279      }
 280  
 281      protected function sub_test_grade_item_load_parent_category() {
 282          $grade_item = new grade_item($this->grade_items[0], false);
 283          $this->assertTrue(method_exists($grade_item, 'load_parent_category'));
 284  
 285          $category = $grade_item->load_parent_category();
 286          $this->assertEquals($this->grade_categories[1]->fullname, $category->fullname);
 287          $this->assertEquals($this->grade_categories[1]->fullname, $grade_item->parent_category->fullname);
 288      }
 289  
 290      protected function sub_test_grade_item_get_item_category() {
 291          $grade_item = new grade_item($this->grade_items[3], false);
 292          $this->assertTrue(method_exists($grade_item, 'get_item_category'));
 293  
 294          $category = $grade_item->get_item_category();
 295          $this->assertEquals($this->grade_categories[0]->fullname, $category->fullname);
 296      }
 297  
 298      protected function sub_test_grade_item_load_item_category() {
 299          $grade_item = new grade_item($this->grade_items[3], false);
 300          $this->assertTrue(method_exists($grade_item, 'load_item_category'));
 301  
 302          $category = $grade_item->load_item_category();
 303          $this->assertEquals($this->grade_categories[0]->fullname, $category->fullname);
 304          $this->assertEquals($this->grade_categories[0]->fullname, $grade_item->item_category->fullname);
 305      }
 306  
 307      protected function sub_test_grade_item_regrade_final_grades() {
 308          $grade_item = new grade_item($this->grade_items[0], false);
 309          $this->assertTrue(method_exists($grade_item, 'regrade_final_grades'));
 310          $this->assertEquals(true, $grade_item->regrade_final_grades());
 311          // TODO: add more tests.
 312      }
 313  
 314      protected function sub_test_grade_item_adjust_raw_grade() {
 315          $grade_item = new grade_item($this->grade_items[2], false); // Anything but assignment module!
 316          $this->assertTrue(method_exists($grade_item, 'adjust_raw_grade'));
 317  
 318          $grade_raw = new stdClass();
 319          $grade_raw->rawgrade = 40;
 320          $grade_raw->grademax = 100;
 321          $grade_raw->grademin = 0;
 322  
 323          $grade_item->gradetype = GRADE_TYPE_VALUE;
 324          $grade_item->multfactor = 1;
 325          $grade_item->plusfactor = 0;
 326          $grade_item->grademax = 50;
 327          $grade_item->grademin = 0;
 328  
 329          $original_grade_raw  = clone($grade_raw);
 330          $original_grade_item = clone($grade_item);
 331  
 332          $this->assertEquals(20, $grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax));
 333  
 334          // Try a larger maximum grade.
 335          $grade_item->grademax = 150;
 336          $grade_item->grademin = 0;
 337          $this->assertEquals(60, $grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax));
 338  
 339          // Try larger minimum grade.
 340          $grade_item->grademin = 50;
 341  
 342          $this->assertEquals(90, $grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax));
 343  
 344          // Rescaling from a small scale (0-50) to a larger scale (0-100).
 345          $grade_raw->grademax = 50;
 346          $grade_raw->grademin = 0;
 347          $grade_item->grademax = 100;
 348          $grade_item->grademin = 0;
 349  
 350          $this->assertEquals(80, $grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax));
 351  
 352          // Rescaling from a small scale (0-50) to a larger scale with offset (40-100).
 353          $grade_item->grademax = 100;
 354          $grade_item->grademin = 40;
 355  
 356          $this->assertEquals(88, $grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax));
 357  
 358          // Try multfactor and plusfactor.
 359          $grade_raw = clone($original_grade_raw);
 360          $grade_item = clone($original_grade_item);
 361          $grade_item->multfactor = 1.23;
 362          $grade_item->plusfactor = 3;
 363  
 364          $this->assertEquals(27.6, $grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax));
 365  
 366          // Try multfactor below 0 and a negative plusfactor.
 367          $grade_raw = clone($original_grade_raw);
 368          $grade_item = clone($original_grade_item);
 369          $grade_item->multfactor = 0.23;
 370          $grade_item->plusfactor = -3;
 371  
 372          $this->assertEquals(round(1.6), round($grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax)));
 373      }
 374  
 375      protected function sub_test_grade_item_rescale_grades_keep_percentage() {
 376          global $DB;
 377          $gradeitem = new grade_item($this->grade_items[10], false); // 10 is the manual grade item.
 378  
 379          // Create some grades to go with the grade item.
 380          $gradeids = array();
 381          $grade = new stdClass();
 382          $grade->itemid = $gradeitem->id;
 383          $grade->userid = $this->user[2]->id;
 384          $grade->finalgrade = 10;
 385          $grade->rawgrademax = $gradeitem->grademax;
 386          $grade->rawgrademin = $gradeitem->grademin;
 387          $grade->timecreated = time();
 388          $grade->timemodified = time();
 389          $gradeids[] = $DB->insert_record('grade_grades', $grade);
 390  
 391          $grade->userid = $this->user[3]->id;
 392          $grade->finalgrade = 50;
 393          $grade->rawgrademax = $gradeitem->grademax;
 394          $grade->rawgrademin = $gradeitem->grademin;
 395          $gradeids[] = $DB->insert_record('grade_grades', $grade);
 396  
 397          // Run the function.
 398          $gradeitem->grademax = 33;
 399          $gradeitem->grademin = 3;
 400          $gradeitem->update();
 401          $gradeitem->rescale_grades_keep_percentage(0, 100, 3, 33, 'test');
 402  
 403          // Check that the grades were updated to match the grade item.
 404          $grade = $DB->get_record('grade_grades', array('id' => $gradeids[0]));
 405          $this->assertEquals($gradeitem->grademax, $grade->rawgrademax, 'Max grade mismatch', 0.0001);
 406          $this->assertEquals($gradeitem->grademin, $grade->rawgrademin, 'Min grade mismatch', 0.0001);
 407          $this->assertEquals(6, $grade->finalgrade, 'Min grade mismatch', 0.0001);
 408  
 409          $grade = $DB->get_record('grade_grades', array('id' => $gradeids[1]));
 410          $this->assertEquals($gradeitem->grademax, $grade->rawgrademax, 'Max grade mismatch', 0.0001);
 411          $this->assertEquals($gradeitem->grademin, $grade->rawgrademin, 'Min grade mismatch', 0.0001);
 412          $this->assertEquals(18, $grade->finalgrade, 'Min grade mismatch', 0.0001);
 413      }
 414  
 415      protected function sub_test_grade_item_set_locked() {
 416          // Getting a grade_item from the DB as set_locked() will fail if the grade items needs to be updated
 417          // also needs to have at least one grade_grade or $grade_item->get_final(1) returns null.
 418          // $grade_item = new grade_item($this->grade_items[8]);
 419          $grade_item = grade_item::fetch(array('id'=>$this->grade_items[8]->id));
 420  
 421          $this->assertTrue(method_exists($grade_item, 'set_locked'));
 422  
 423          $grade_grade = new grade_grade($grade_item->get_final($this->user[1]->id), false);
 424          $this->assertTrue(empty($grade_item->locked));// Not locked.
 425          $this->assertTrue(empty($grade_grade->locked));// Not locked.
 426  
 427          $this->assertTrue($grade_item->set_locked(true, true, false));
 428          $grade_grade = new grade_grade($grade_item->get_final($this->user[1]->id), false);
 429  
 430          $this->assertFalse(empty($grade_item->locked));// Locked.
 431          $this->assertFalse(empty($grade_grade->locked)); // Individual grades should be locked too.
 432  
 433          $this->assertTrue($grade_item->set_locked(false, true, false));
 434          $grade = new grade_grade($grade_item->get_final($this->user[1]->id), false);
 435  
 436          $this->assertTrue(empty($grade_item->locked));
 437          $this->assertTrue(empty($grade->locked)); // Individual grades should be unlocked too.
 438      }
 439  
 440      protected function sub_test_grade_item_is_locked() {
 441          $grade_item = new grade_item($this->grade_items[10], false);
 442          $this->assertTrue(method_exists($grade_item, 'is_locked'));
 443  
 444          $this->assertFalse($grade_item->is_locked());
 445          $this->assertFalse($grade_item->is_locked($this->user[1]->id));
 446          $this->assertTrue($grade_item->set_locked(true, true, false));
 447          $this->assertTrue($grade_item->is_locked());
 448          $this->assertTrue($grade_item->is_locked($this->user[1]->id));
 449      }
 450  
 451      protected function sub_test_grade_item_set_hidden() {
 452          $grade_item = new grade_item($this->grade_items[0], false);
 453          $this->assertTrue(method_exists($grade_item, 'set_hidden'));
 454  
 455          $grade = new grade_grade($grade_item->get_final($this->user[1]->id), false);
 456          $this->assertEquals(0, $grade_item->hidden);
 457          $this->assertEquals(0, $grade->hidden);
 458  
 459          $grade_item->set_hidden(666, true);
 460          $grade = new grade_grade($grade_item->get_final($this->user[1]->id), false);
 461  
 462          $this->assertEquals(666, $grade_item->hidden);
 463          $this->assertEquals(666, $grade->hidden);
 464      }
 465  
 466      protected function sub_test_grade_item_is_hidden() {
 467          $grade_item = new grade_item($this->grade_items[0], false);
 468          $this->assertTrue(method_exists($grade_item, 'is_hidden'));
 469  
 470          $this->assertFalse($grade_item->is_hidden());
 471          $this->assertFalse($grade_item->is_hidden(1));
 472  
 473          $grade_item->set_hidden(1);
 474          $this->assertTrue($grade_item->is_hidden());
 475          $this->assertTrue($grade_item->is_hidden(1));
 476  
 477          $grade_item->set_hidden(666);
 478          $this->assertFalse($grade_item->is_hidden());
 479          $this->assertFalse($grade_item->is_hidden(1));
 480  
 481          $grade_item->set_hidden(time()+666);
 482          $this->assertTrue($grade_item->is_hidden());
 483          $this->assertTrue($grade_item->is_hidden(1));
 484      }
 485  
 486      protected function sub_test_grade_item_is_category_item() {
 487          $grade_item = new grade_item($this->grade_items[3], false);
 488          $this->assertTrue(method_exists($grade_item, 'is_category_item'));
 489          $this->assertTrue($grade_item->is_category_item());
 490      }
 491  
 492      protected function sub_test_grade_item_is_course_item() {
 493          $grade_item = grade_item::fetch_course_item($this->courseid);
 494          $this->assertTrue(method_exists($grade_item, 'is_course_item'));
 495          $this->assertTrue($grade_item->is_course_item());
 496      }
 497  
 498      protected function sub_test_grade_item_fetch_course_item() {
 499          $grade_item = grade_item::fetch_course_item($this->courseid);
 500          $this->assertTrue(method_exists($grade_item, 'fetch_course_item'));
 501          $this->assertEquals($grade_item->itemtype, 'course');
 502      }
 503  
 504      protected function sub_test_grade_item_depends_on() {
 505          global $CFG;
 506  
 507          $origenableoutcomes = $CFG->enableoutcomes;
 508          $CFG->enableoutcomes = 0;
 509          $grade_item = new grade_item($this->grade_items[1], false);
 510  
 511          // Calculated grade dependency.
 512          $deps = $grade_item->depends_on();
 513          sort($deps, SORT_NUMERIC); // For comparison.
 514          $this->assertEquals(array($this->grade_items[0]->id), $deps);
 515  
 516          // Simulate depends on returns none when locked.
 517          $grade_item->locked = time();
 518          $grade_item->update();
 519          $deps = $grade_item->depends_on();
 520          sort($deps, SORT_NUMERIC); // For comparison.
 521          $this->assertEquals(array(), $deps);
 522  
 523          // Category dependency.
 524          $grade_item = new grade_item($this->grade_items[3], false);
 525          $deps = $grade_item->depends_on();
 526          sort($deps, SORT_NUMERIC); // For comparison.
 527          $res = array($this->grade_items[4]->id, $this->grade_items[5]->id);
 528          $this->assertEquals($res, $deps);
 529      }
 530  
 531      protected function scales_outcomes_test_grade_item_depends_on() {
 532          $CFG->enableoutcomes = 1;
 533          $origgradeincludescalesinaggregation = $CFG->grade_includescalesinaggregation;
 534          $CFG->grade_includescalesinaggregation = 1;
 535  
 536          // Scale item in category with $CFG->grade_includescalesinaggregation = 1.
 537          $grade_item = new grade_item($this->grade_items[14], false);
 538          $deps = $grade_item->depends_on();
 539          sort($deps, SORT_NUMERIC);
 540          $res = array($this->grade_items[16]->id);
 541          $this->assertEquals($res, $deps);
 542  
 543          // Scale item in category with $CFG->grade_includescalesinaggregation = 0.
 544          $CFG->grade_includescalesinaggregation = 0;
 545          $grade_item = new grade_item($this->grade_items[14], false);
 546          $deps = $grade_item->depends_on();
 547          $res = array();
 548          $this->assertEquals($res, $deps);
 549          $CFG->grade_includescalesinaggregation = 1;
 550  
 551          // Outcome item in category with outcomes disabled.
 552          $CFG->enableoutcomes = 0;
 553          $grade_item = new grade_item($this->grade_items[14], false);
 554          $deps = $grade_item->depends_on();
 555          sort($deps, SORT_NUMERIC);
 556          $res = array($this->grade_items[16]->id, $this->grade_items[17]->id);
 557          $this->assertEquals($res, $deps);
 558  
 559          $CFG->enableoutcomes = $origenableoutcomes;
 560          $CFG->grade_includescalesinaggregation = $origgradeincludescalesinaggregation;
 561      }
 562  
 563      protected function sub_test_refresh_grades() {
 564          // Testing with the grade item for a mod_assignment instance.
 565          $grade_item = new grade_item($this->grade_items[0], false);
 566          $this->assertTrue(method_exists($grade_item, 'refresh_grades'));
 567          $this->assertTrue($grade_item->refresh_grades());
 568  
 569          // Break the grade item and check error handling.
 570          $grade_item->iteminstance = 123456789;
 571          $this->assertFalse($grade_item->refresh_grades());
 572          $this->assertDebuggingCalled();
 573      }
 574  
 575      protected function sub_test_grade_item_is_calculated() {
 576          $grade_item = new grade_item($this->grade_items[1], false);
 577          $this->assertTrue(method_exists($grade_item, 'is_calculated'));
 578          $this->assertTrue($grade_item->is_calculated());
 579  
 580          $grade_item = new grade_item($this->grade_items[0], false);
 581          $this->assertFalse($grade_item->is_calculated());
 582      }
 583  
 584      protected function sub_test_grade_item_set_calculation() {
 585          $grade_item = new grade_item($this->grade_items[1], false);
 586          $this->assertTrue(method_exists($grade_item, 'set_calculation'));
 587          $grade_itemsource = new grade_item($this->grade_items[0], false);
 588  
 589          $grade_item->set_calculation('=[['.$grade_itemsource->idnumber.']]');
 590  
 591          $this->assertTrue(!empty($grade_item->needsupdate));
 592          $this->assertEquals('=##gi'.$grade_itemsource->id.'##', $grade_item->calculation);
 593      }
 594  
 595      protected function sub_test_grade_item_get_calculation() {
 596          $grade_item = new grade_item($this->grade_items[1], false);
 597          $this->assertTrue(method_exists($grade_item, 'get_calculation'));
 598          $grade_itemsource = new grade_item($this->grade_items[0], false);
 599  
 600          $denormalizedformula = str_replace('##gi'.$grade_itemsource->id.'##', '[['.$grade_itemsource->idnumber.']]', $this->grade_items[1]->calculation);
 601  
 602          $formula = $grade_item->get_calculation();
 603          $this->assertTrue(!empty($grade_item->needsupdate));
 604          $this->assertEquals($denormalizedformula, $formula);
 605      }
 606  
 607      public function sub_test_grade_item_compute() {
 608          $grade_item = grade_item::fetch(array('id'=>$this->grade_items[1]->id));
 609          $this->assertTrue(method_exists($grade_item, 'compute'));
 610  
 611          // Check the grade_grades in the array match those in the DB then delete $this->grade_items[1]'s grade_grades.
 612          $this->grade_grades[3] = grade_grade::fetch(array('id'=>$this->grade_grades[3]->id));
 613          $grade_grade = grade_grade::fetch(array('id'=>$this->grade_grades[3]->id));
 614          $grade_grade->delete();
 615  
 616          $this->grade_grades[4] = grade_grade::fetch(array('id'=>$this->grade_grades[4]->id));
 617          $grade_grade = grade_grade::fetch(array('id'=>$this->grade_grades[4]->id));
 618          $grade_grade->delete();
 619  
 620          $this->grade_grades[5] = grade_grade::fetch(array('id'=>$this->grade_grades[5]->id));
 621          $grade_grade = grade_grade::fetch(array('id'=>$this->grade_grades[5]->id));
 622          $grade_grade->delete();
 623  
 624          // Recalculate the grades (its a calculation so pulls values from other grade_items) and reinsert them.
 625          $grade_item->compute();
 626  
 627          $grade_grade = grade_grade::fetch(array('userid'=>$this->grade_grades[3]->userid, 'itemid'=>$this->grade_grades[3]->itemid));
 628          $this->assertEquals($this->grade_grades[3]->finalgrade, $grade_grade->finalgrade);
 629  
 630          $grade_grade = grade_grade::fetch(array('userid'=>$this->grade_grades[4]->userid, 'itemid'=>$this->grade_grades[4]->itemid));
 631          $this->assertEquals($this->grade_grades[4]->finalgrade, $grade_grade->finalgrade);
 632  
 633          $grade_grade = grade_grade::fetch(array('userid'=>$this->grade_grades[5]->userid, 'itemid'=>$this->grade_grades[5]->itemid));
 634          $this->assertEquals($this->grade_grades[5]->finalgrade, $grade_grade->finalgrade);
 635      }
 636  
 637      protected function sub_test_update_final_grade() {
 638  
 639          // MDL-31713 Check that min and max are set on the grade_grade instance
 640          // if the grade is overridden before the activity has supplied a grade.
 641          $min = 2;
 642          $max = 8;
 643  
 644          // Create a brand new grade item.
 645          $grade_item = new grade_item();
 646          $this->assertTrue(method_exists($grade_item, 'insert'));
 647  
 648          $grade_item->courseid = $this->courseid;
 649          $grade_item->categoryid = $this->grade_categories[1]->id;
 650          $grade_item->itemname = 'brand new unit test grade item';
 651          $grade_item->itemtype = 'mod';
 652          $grade_item->itemmodule = 'quiz';
 653          $grade_item->iteminfo = 'Grade item used for unit testing';
 654          $grade_item->iteminstance = $this->activities[7]->id;
 655          $grade_item->grademin = $min;
 656          $grade_item->grademax = $max;
 657          $grade_item->insert();
 658  
 659          // Override the student grade.
 660          $grade_item->update_final_grade($this->user[1]->id, 7, 'gradebook', '', FORMAT_MOODLE);
 661  
 662          // Check the student's grade has the correct min and max grade.
 663          $grade_grade = grade_grade::fetch(array('userid'=>$this->user[1]->id, 'itemid'=>$grade_item->id));
 664          $this->assertEquals($min, $grade_grade->rawgrademin);
 665          $this->assertEquals($max, $grade_grade->rawgrademax);
 666      }
 667  
 668      protected function sub_test_grade_item_can_control_visibility() {
 669          // Grade item 0 == Course module 0 == Assignment.
 670          $grade_item = new grade_item($this->grade_items[0], false);
 671          $this->assertTrue($grade_item->can_control_visibility());
 672  
 673          // Grade item  == Course module 7 == Quiz.
 674          $grade_item = new grade_item($this->grade_items[11], false);
 675          $this->assertFalse($grade_item->can_control_visibility());
 676      }
 677  
 678      /**
 679       * Test the {@link grade_item::fix_duplicate_sortorder() function with
 680       * faked duplicate sortorder data.
 681       */
 682      public function sub_test_grade_item_fix_sortorder() {
 683          global $DB;
 684  
 685          $this->resetAfterTest(true);
 686  
 687          // Each set is used for filling the db with fake data and will be representing the result of query:
 688          // "SELECT sortorder from {grade_items} WHERE courseid=? ORDER BY id".
 689          $testsets = array(
 690              // Items that need no action.
 691              array(1,2,3),
 692              array(5,6,7),
 693              array(7,6,1,3,2,5),
 694              // Items with sortorder duplicates
 695              array(1,2,2,3,3,4,5),
 696              // Only one sortorder duplicate.
 697              array(1,1),
 698              array(3,3),
 699              // Non-sequential sortorders with one or multiple duplicates.
 700              array(3,3,7,5,6,6,9,10,8,3),
 701              array(7,7,3),
 702              array(3,4,5,3,5,4,7,1)
 703          );
 704          $origsequence = array();
 705  
 706          // Generate the data and remember the initial sequence or items.
 707          foreach ($testsets as $testset) {
 708              $course = $this->getDataGenerator()->create_course();
 709              foreach ($testset as $sortorder) {
 710                  $this->insert_fake_grade_item_sortorder($course->id, $sortorder);
 711              }
 712              $DB->get_records('grade_items');
 713              $origsequence[$course->id] = $DB->get_fieldset_sql("SELECT id FROM {grade_items} ".
 714                  "WHERE courseid = ? ORDER BY sortorder, id", array($course->id));
 715          }
 716  
 717          $duplicatedetectionsql = "SELECT courseid, sortorder
 718                                      FROM {grade_items}
 719                                  WHERE courseid = :courseid
 720                                  GROUP BY courseid, sortorder
 721                                    HAVING COUNT(id) > 1";
 722  
 723          // Do the work.
 724          foreach ($origsequence as $courseid => $ignore) {
 725              grade_item::fix_duplicate_sortorder($courseid);
 726              // Verify that no duplicates are left in the database.
 727              $dupes = $DB->record_exists_sql($duplicatedetectionsql, array('courseid' => $courseid));
 728              $this->assertFalse($dupes);
 729          }
 730  
 731          // Verify that sequences are exactly the same as they were before upgrade script.
 732          $idx = 0;
 733          foreach ($origsequence as $courseid => $sequence) {
 734              if (count(($testsets[$idx])) == count(array_unique($testsets[$idx]))) {
 735                  // If there were no duplicates for this course verify that sortorders are not modified.
 736                  $newsortorders = $DB->get_fieldset_sql("SELECT sortorder from {grade_items} WHERE courseid=? ORDER BY id", array($courseid));
 737                  $this->assertEquals($testsets[$idx], $newsortorders);
 738              }
 739              $newsequence = $DB->get_fieldset_sql("SELECT id FROM {grade_items} ".
 740                  "WHERE courseid = ? ORDER BY sortorder, id", array($courseid));
 741              $this->assertEquals($sequence, $newsequence,
 742                      "Sequences do not match for test set $idx : ".join(',', $testsets[$idx]));
 743              $idx++;
 744          }
 745      }
 746  
 747      /**
 748       * Populate some fake grade items into the database with specified
 749       * sortorder and course id.
 750       *
 751       * NOTE: This function doesn't make much attempt to respect the
 752       * gradebook internals, its simply used to fake some data for
 753       * testing the upgradelib function. Please don't use it for other
 754       * purposes.
 755       *
 756       * @param int $courseid id of course
 757       * @param int $sortorder numeric sorting order of item
 758       * @return stdClass grade item object from the database.
 759       */
 760      private function insert_fake_grade_item_sortorder($courseid, $sortorder) {
 761          global $DB, $CFG;
 762          require_once($CFG->libdir.'/gradelib.php');
 763  
 764          $item = new stdClass();
 765          $item->courseid = $courseid;
 766          $item->sortorder = $sortorder;
 767          $item->gradetype = GRADE_TYPE_VALUE;
 768          $item->grademin = 30;
 769          $item->grademax = 110;
 770          $item->itemnumber = 1;
 771          $item->iteminfo = '';
 772          $item->timecreated = time();
 773          $item->timemodified = time();
 774  
 775          $item->id = $DB->insert_record('grade_items', $item);
 776  
 777          return $DB->get_record('grade_items', array('id' => $item->id));
 778      }
 779  
 780      public function test_set_aggregation_fields_for_aggregation() {
 781          $course = $this->getDataGenerator()->create_course();
 782          $gi = new grade_item(array('courseid' => $course->id, 'itemtype' => 'manual'), false);
 783  
 784          $methods = array(GRADE_AGGREGATE_MEAN, GRADE_AGGREGATE_MEDIAN, GRADE_AGGREGATE_MIN, GRADE_AGGREGATE_MAX,
 785              GRADE_AGGREGATE_MODE, GRADE_AGGREGATE_WEIGHTED_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN2,
 786              GRADE_AGGREGATE_EXTRACREDIT_MEAN, GRADE_AGGREGATE_SUM);
 787  
 788          // Switching from and to the same aggregation using the defaults.
 789          foreach ($methods as $method) {
 790              $defaults = grade_category::get_default_aggregation_coefficient_values($method);
 791              $gi->aggregationcoef = $defaults['aggregationcoef'];
 792              $gi->aggregationcoef2 = $defaults['aggregationcoef2'];
 793              $gi->weightoverride = $defaults['weightoverride'];
 794              $this->assertFalse($gi->set_aggregation_fields_for_aggregation($method, $method));
 795              $this->assertEquals($defaults['aggregationcoef'], $gi->aggregationcoef);
 796              $this->assertEquals($defaults['aggregationcoef2'], $gi->aggregationcoef2);
 797              $this->assertEquals($defaults['weightoverride'], $gi->weightoverride);
 798          }
 799  
 800          // Extra credit is kept across aggregation methods that support it.
 801          foreach ($methods as $from) {
 802              $fromsupportsec = grade_category::aggregation_uses_extracredit($from);
 803              $fromdefaults = grade_category::get_default_aggregation_coefficient_values($from);
 804  
 805              foreach ($methods as $to) {
 806                  $tosupportsec = grade_category::aggregation_uses_extracredit($to);
 807                  $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 808  
 809                  // Set the item to be extra credit, if supported.
 810                  if ($fromsupportsec) {
 811                      $gi->aggregationcoef = 1;
 812                  } else {
 813                      $gi->aggregationcoef = $fromdefaults['aggregationcoef'];
 814                  }
 815  
 816                  // We ignore those fields, we know it is never used for extra credit.
 817                  $gi->aggregationcoef2 = $todefaults['aggregationcoef2'];
 818                  $gi->weightoverride = $todefaults['weightoverride'];
 819  
 820                  if ($fromsupportsec && $tosupportsec) {
 821                      $this->assertFalse($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 822                      $this->assertEquals(1, $gi->aggregationcoef);
 823  
 824                  } else if ($fromsupportsec && !$tosupportsec) {
 825                      if ($to == GRADE_AGGREGATE_WEIGHTED_MEAN) {
 826                          // Special case, aggregationcoef is used but for weights.
 827                          $this->assertFalse($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 828                          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 829                      } else {
 830                          $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 831                          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 832                      }
 833                  } else {
 834                      // The source does not support extra credit, everything will be reset.
 835                      if (($from == GRADE_AGGREGATE_WEIGHTED_MEAN || $to == GRADE_AGGREGATE_WEIGHTED_MEAN) && $from != $to) {
 836                          // Special case, aggregationcoef is used but for weights.
 837                          $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 838                          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 839                      } else {
 840                          $this->assertFalse($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 841                          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 842                      }
 843                  }
 844              }
 845          }
 846  
 847          // Extra credit can be higher than one for GRADE_AGGREGATE_EXTRACREDIT_MEAN, but will be normalised for others.
 848          $from = GRADE_AGGREGATE_EXTRACREDIT_MEAN;
 849          $fromdefaults = grade_category::get_default_aggregation_coefficient_values($from);
 850  
 851          foreach ($methods as $to) {
 852              if (!grade_category::aggregation_uses_extracredit($to)) {
 853                  continue;
 854              }
 855  
 856              $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 857              $gi->aggregationcoef = 8;
 858  
 859              // Ignore those fields, they are not used for extra credit.
 860              $gi->aggregationcoef2 = $todefaults['aggregationcoef2'];
 861              $gi->weightoverride = $todefaults['weightoverride'];
 862  
 863              if ($to == $from) {
 864                  $this->assertFalse($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 865                  $this->assertEquals(8, $gi->aggregationcoef);
 866              } else {
 867                  $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 868                  $this->assertEquals(1, $gi->aggregationcoef);
 869              }
 870          }
 871  
 872          // Weights are reset.
 873          $from = GRADE_AGGREGATE_SUM;
 874          $fromdefaults = grade_category::get_default_aggregation_coefficient_values($from);
 875  
 876          $gi->aggregationcoef = $fromdefaults['aggregationcoef'];
 877          $gi->aggregationcoef2 = 0.321;
 878          $gi->weightoverride = $fromdefaults['weightoverride'];
 879  
 880          $to = GRADE_AGGREGATE_WEIGHTED_MEAN;
 881          $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 882  
 883          $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 884          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 885          $this->assertEquals($todefaults['aggregationcoef2'], $gi->aggregationcoef2);
 886          $this->assertEquals($todefaults['weightoverride'], $gi->weightoverride);
 887  
 888          $gi->aggregationcoef = $fromdefaults['aggregationcoef'];
 889          $gi->aggregationcoef2 = 0.321;
 890          $gi->weightoverride = $fromdefaults['weightoverride'];
 891  
 892          $to = GRADE_AGGREGATE_SUM;
 893          $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 894  
 895          $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 896          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 897          $this->assertEquals($todefaults['aggregationcoef2'], $gi->aggregationcoef2);
 898          $this->assertEquals($todefaults['weightoverride'], $gi->weightoverride);
 899  
 900          // Weight is kept when using SUM with weight override.
 901          $from = GRADE_AGGREGATE_SUM;
 902          $fromdefaults = grade_category::get_default_aggregation_coefficient_values($from);
 903  
 904          $gi->aggregationcoef = $fromdefaults['aggregationcoef'];
 905          $gi->aggregationcoef2 = 0.321;
 906          $gi->weightoverride = 1;
 907  
 908          $to = GRADE_AGGREGATE_SUM;
 909          $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 910  
 911          $this->assertFalse($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 912          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 913          $this->assertEquals(0.321, $gi->aggregationcoef2);
 914          $this->assertEquals(1, $gi->weightoverride);
 915  
 916          $gi->aggregationcoef2 = 0.321;
 917          $gi->aggregationcoef = $fromdefaults['aggregationcoef'];
 918          $gi->weightoverride = 1;
 919  
 920          $to = GRADE_AGGREGATE_WEIGHTED_MEAN;
 921          $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 922  
 923          $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 924          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 925          $this->assertEquals($todefaults['aggregationcoef2'], $gi->aggregationcoef2);
 926          $this->assertEquals($todefaults['weightoverride'], $gi->weightoverride);
 927  
 928          // Weight is kept when staying in weighted mean.
 929          $from = GRADE_AGGREGATE_WEIGHTED_MEAN;
 930          $fromdefaults = grade_category::get_default_aggregation_coefficient_values($from);
 931  
 932          $gi->aggregationcoef = 18;
 933          $gi->aggregationcoef2 = $fromdefaults['aggregationcoef2'];
 934          $gi->weightoverride = $fromdefaults['weightoverride'];
 935  
 936          $to = GRADE_AGGREGATE_WEIGHTED_MEAN;
 937          $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 938  
 939          $this->assertFalse($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 940          $this->assertEquals(18, $gi->aggregationcoef);
 941          $this->assertEquals($todefaults['aggregationcoef2'], $gi->aggregationcoef2);
 942          $this->assertEquals($todefaults['weightoverride'], $gi->weightoverride);
 943  
 944          $gi->aggregationcoef = 18;
 945          $gi->aggregationcoef2 = $fromdefaults['aggregationcoef2'];
 946          $gi->weightoverride = $fromdefaults['weightoverride'];
 947  
 948          $to = GRADE_AGGREGATE_SUM;
 949          $todefaults = grade_category::get_default_aggregation_coefficient_values($to);
 950  
 951          $this->assertTrue($gi->set_aggregation_fields_for_aggregation($from, $to), "From: $from, to: $to");
 952          $this->assertEquals($todefaults['aggregationcoef'], $gi->aggregationcoef);
 953          $this->assertEquals($todefaults['aggregationcoef2'], $gi->aggregationcoef2);
 954          $this->assertEquals($todefaults['weightoverride'], $gi->weightoverride);
 955      }
 956  
 957  }


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