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