[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |