Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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 /** 18 * @package core_grades 19 * @category phpunit 20 * @copyright nicolas@moodle.com 21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 */ 23 24 defined('MOODLE_INTERNAL') || die(); 25 26 require_once (__DIR__.'/fixtures/lib.php'); 27 28 29 class core_grade_grade_testcase extends grade_base_testcase { 30 31 public function test_grade_grade() { 32 $this->sub_test_grade_grade_construct(); 33 $this->sub_test_grade_grade_insert(); 34 $this->sub_test_grade_grade_update(); 35 $this->sub_test_grade_grade_fetch(); 36 $this->sub_test_grade_grade_fetch_all(); 37 $this->sub_test_grade_grade_load_grade_item(); 38 $this->sub_test_grade_grade_standardise_score(); 39 $this->sub_test_grade_grade_is_locked(); 40 $this->sub_test_grade_grade_set_hidden(); 41 $this->sub_test_grade_grade_is_hidden(); 42 $this->sub_test_grade_grade_deleted(); 43 $this->sub_test_grade_grade_deleted_event(); 44 } 45 46 protected function sub_test_grade_grade_construct() { 47 $params = new stdClass(); 48 49 $params->itemid = $this->grade_items[0]->id; 50 $params->userid = 1; 51 $params->rawgrade = 88; 52 $params->rawgrademax = 110; 53 $params->rawgrademin = 18; 54 55 $grade_grade = new grade_grade($params, false); 56 $this->assertEquals($params->itemid, $grade_grade->itemid); 57 $this->assertEquals($params->rawgrade, $grade_grade->rawgrade); 58 } 59 60 protected function sub_test_grade_grade_insert() { 61 $grade_grade = new grade_grade(); 62 $this->assertTrue(method_exists($grade_grade, 'insert')); 63 64 $grade_grade->itemid = $this->grade_items[0]->id; 65 $grade_grade->userid = 10; 66 $grade_grade->rawgrade = 88; 67 $grade_grade->rawgrademax = 110; 68 $grade_grade->rawgrademin = 18; 69 70 // Check the grade_item's needsupdate variable first. 71 $grade_grade->load_grade_item(); 72 $this->assertEmpty($grade_grade->grade_item->needsupdate); 73 74 $grade_grade->insert(); 75 76 $last_grade_grade = end($this->grade_grades); 77 78 $this->assertEquals($grade_grade->id, $last_grade_grade->id + 1); 79 80 // Timecreated will only be set if the grade was submitted by an activity module. 81 $this->assertTrue(empty($grade_grade->timecreated)); 82 // Timemodified will only be set if the grade was submitted by an activity module. 83 $this->assertTrue(empty($grade_grade->timemodified)); 84 85 // Keep our collection the same as is in the database. 86 $this->grade_grades[] = $grade_grade; 87 } 88 89 protected function sub_test_grade_grade_update() { 90 $grade_grade = new grade_grade($this->grade_grades[0], false); 91 $this->assertTrue(method_exists($grade_grade, 'update')); 92 } 93 94 protected function sub_test_grade_grade_fetch() { 95 $grade_grade = new grade_grade(); 96 $this->assertTrue(method_exists($grade_grade, 'fetch')); 97 98 $grades = grade_grade::fetch(array('id'=>$this->grade_grades[0]->id)); 99 $this->assertEquals($this->grade_grades[0]->id, $grades->id); 100 $this->assertEquals($this->grade_grades[0]->rawgrade, $grades->rawgrade); 101 } 102 103 protected function sub_test_grade_grade_fetch_all() { 104 $grade_grade = new grade_grade(); 105 $this->assertTrue(method_exists($grade_grade, 'fetch_all')); 106 107 $grades = grade_grade::fetch_all(array()); 108 $this->assertEquals(count($this->grade_grades), count($grades)); 109 } 110 111 protected function sub_test_grade_grade_load_grade_item() { 112 $grade_grade = new grade_grade($this->grade_grades[0], false); 113 $this->assertTrue(method_exists($grade_grade, 'load_grade_item')); 114 $this->assertNull($grade_grade->grade_item); 115 $this->assertNotEmpty($grade_grade->itemid); 116 $this->assertNotNull($grade_grade->load_grade_item()); 117 $this->assertNotNull($grade_grade->grade_item); 118 $this->assertEquals($this->grade_items[0]->id, $grade_grade->grade_item->id); 119 } 120 121 122 protected function sub_test_grade_grade_standardise_score() { 123 $this->assertEquals(4, round(grade_grade::standardise_score(6, 0, 7, 0, 5))); 124 $this->assertEquals(40, grade_grade::standardise_score(50, 30, 80, 0, 100)); 125 } 126 127 128 /* 129 * Disabling this test: the set_locked() arguments have been modified, rendering these tests useless until they are re-written 130 131 protected function test_grade_grade_set_locked() { 132 $grade_item = new grade_item($this->grade_items[0]); 133 $grade = new grade_grade($grade_item->get_final(1)); 134 $this->assertTrue(method_exists($grade, 'set_locked')); 135 136 $this->assertTrue(empty($grade_item->locked)); 137 $this->assertTrue(empty($grade->locked)); 138 139 $this->assertTrue($grade->set_locked(true)); 140 $this->assertFalse(empty($grade->locked)); 141 $this->assertTrue($grade->set_locked(false)); 142 $this->assertTrue(empty($grade->locked)); 143 144 $this->assertTrue($grade_item->set_locked(true, true)); 145 $grade = new grade_grade($grade_item->get_final(1)); 146 147 $this->assertFalse(empty($grade->locked)); 148 $this->assertFalse($grade->set_locked(true, false)); 149 150 $this->assertTrue($grade_item->set_locked(true, false)); 151 $grade = new grade_grade($grade_item->get_final(1)); 152 153 $this->assertTrue($grade->set_locked(true, false)); 154 } 155 */ 156 157 protected function sub_test_grade_grade_is_locked() { 158 $grade = new grade_grade($this->grade_grades[0], false); 159 $this->assertTrue(method_exists($grade, 'is_locked')); 160 161 $this->assertFalse($grade->is_locked()); 162 $grade->locked = time(); 163 $this->assertTrue($grade->is_locked()); 164 } 165 166 protected function sub_test_grade_grade_set_hidden() { 167 $grade = new grade_grade($this->grade_grades[0], false); 168 $grade_item = new grade_item($this->grade_items[0], false); 169 $this->assertTrue(method_exists($grade, 'set_hidden')); 170 171 $this->assertEquals(0, $grade_item->hidden); 172 $this->assertEquals(0, $grade->hidden); 173 174 $grade->set_hidden(0); 175 $this->assertEquals(0, $grade->hidden); 176 177 $grade->set_hidden(1); 178 $this->assertEquals(1, $grade->hidden); 179 180 $grade->set_hidden(0); 181 $this->assertEquals(0, $grade->hidden); 182 } 183 184 protected function sub_test_grade_grade_is_hidden() { 185 $grade = new grade_grade($this->grade_grades[0], false); 186 $this->assertTrue(method_exists($grade, 'is_hidden')); 187 188 $this->assertFalse($grade->is_hidden()); 189 $grade->hidden = 1; 190 $this->assertTrue($grade->is_hidden()); 191 192 $grade->hidden = time()-666; 193 $this->assertFalse($grade->is_hidden()); 194 195 $grade->hidden = time()+666; 196 $this->assertTrue($grade->is_hidden()); 197 } 198 199 public function test_flatten_dependencies() { 200 // First test a simple normal case. 201 $a = array(1 => array(2, 3), 2 => array(), 3 => array(4), 4 => array()); 202 $b = array(); 203 $expecteda = array(1 => array(2, 3, 4), 2 => array(), 3 => array(4), 4 => array()); 204 $expectedb = array(1 => 1); 205 206 test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b); 207 $this->assertSame($expecteda, $a); 208 $this->assertSame($expectedb, $b); 209 210 // Edge case - empty arrays. 211 $a = $b = $expecteda = $expectedb = array(); 212 213 test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b); 214 $this->assertSame($expecteda, $a); 215 $this->assertSame($expectedb, $b); 216 217 // Circular dependency. 218 $a = array(1 => array(2), 2 => array(3), 3 => array(1)); 219 $b = array(); 220 $expecteda = array(1 => array(1, 2, 3), 2 => array(1, 2, 3), 3 => array(1, 2, 3)); 221 222 test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b); 223 $this->assertSame($expecteda, $a); 224 // Note - we don't test the depth when we got circular dependencies - the main thing we wanted to test was that there was 225 // no ka-boom. The result would be hard to understand and doesn't matter. 226 227 // Circular dependency 2. 228 $a = array(1 => array(2), 2 => array(3), 3 => array(4), 4 => array(2, 1)); 229 $b = array(); 230 $expecteda = array(1 => array(1, 2, 3, 4), 2 => array(1, 2, 3, 4), 3 => array(1, 2, 3, 4), 4 => array(1, 2, 3, 4)); 231 232 test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b); 233 $this->assertSame($expecteda, $a); 234 } 235 236 public function test_grade_grade_min_max() { 237 global $CFG; 238 $initialminmaxtouse = $CFG->grade_minmaxtouse; 239 240 $this->setAdminUser(); 241 $course = $this->getDataGenerator()->create_course(); 242 $user = $this->getDataGenerator()->create_user(); 243 $assignrecord = $this->getDataGenerator()->create_module('assign', array('course' => $course, 'grade' => 100)); 244 $cm = get_coursemodule_from_instance('assign', $assignrecord->id); 245 $assigncontext = context_module::instance($cm->id); 246 $assign = new assign($assigncontext, $cm, $course); 247 248 // Fetch the assignment item. 249 $giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $assignrecord->id, 250 'courseid' => $course->id, 'itemnumber' => 0); 251 $gi = grade_item::fetch($giparams); 252 $this->assertEquals(0, $gi->grademin); 253 $this->assertEquals(100, $gi->grademax); 254 255 // Give a grade to the student. 256 $usergrade = $assign->get_user_grade($user->id, true); 257 $usergrade->grade = 10; 258 $assign->update_grade($usergrade); 259 260 // Check the grade stored in gradebook. 261 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 262 $this->assertEquals(10, $gg->rawgrade); 263 $this->assertEquals(0, $gg->get_grade_min()); 264 $this->assertEquals(100, $gg->get_grade_max()); 265 266 // Change the min/max grade of the item. 267 $gi->grademax = 50; 268 $gi->grademin = 2; 269 $gi->update(); 270 271 // Fetch the updated item. 272 $gi = grade_item::fetch($giparams); 273 274 // Now check the grade grade min/max with system setting. 275 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM; 276 grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting. 277 278 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 279 $this->assertEquals(2, $gg->get_grade_min()); 280 $this->assertEquals(50, $gg->get_grade_max()); 281 282 // Now with other system setting. 283 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE; 284 grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache. 285 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 286 $this->assertEquals(0, $gg->get_grade_min()); 287 $this->assertEquals(100, $gg->get_grade_max()); 288 289 // Now with overriden setting in course. 290 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM; 291 grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE); 292 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 293 $this->assertEquals(0, $gg->get_grade_min()); 294 $this->assertEquals(100, $gg->get_grade_max()); 295 296 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE; 297 grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM); 298 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 299 $this->assertEquals(2, $gg->get_grade_min()); 300 $this->assertEquals(50, $gg->get_grade_max()); 301 302 $CFG->grade_minmaxtouse = $initialminmaxtouse; 303 } 304 305 public function test_grade_grade_min_max_with_course_item() { 306 global $CFG, $DB; 307 $initialminmaxtouse = $CFG->grade_minmaxtouse; 308 309 $this->setAdminUser(); 310 $course = $this->getDataGenerator()->create_course(); 311 $user = $this->getDataGenerator()->create_user(); 312 $gi = grade_item::fetch_course_item($course->id); 313 314 // Fetch the category item. 315 $this->assertEquals(0, $gi->grademin); 316 $this->assertEquals(100, $gi->grademax); 317 318 // Give a grade to the student. 319 $gi->update_final_grade($user->id, 10); 320 321 // Check the grade min/max stored in gradebook. 322 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 323 $this->assertEquals(0, $gg->get_grade_min()); 324 $this->assertEquals(100, $gg->get_grade_max()); 325 326 // Change the min/max grade of the item. 327 $gi->grademin = 2; 328 $gi->grademax = 50; 329 $gi->update(); 330 331 // Fetch the updated item. 332 $gi = grade_item::fetch_course_item($course->id); 333 334 // Now check the grade grade min/max with system setting. 335 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM; 336 grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting. 337 338 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 339 $this->assertEquals(0, $gg->get_grade_min()); 340 $this->assertEquals(100, $gg->get_grade_max()); 341 342 // Now with other system setting. 343 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE; 344 grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache. 345 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 346 $this->assertEquals(0, $gg->get_grade_min()); 347 $this->assertEquals(100, $gg->get_grade_max()); 348 349 // Now with overriden setting in course. 350 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM; 351 grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE); 352 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 353 $this->assertEquals(0, $gg->get_grade_min()); 354 $this->assertEquals(100, $gg->get_grade_max()); 355 356 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE; 357 grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM); 358 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 359 $this->assertEquals(0, $gg->get_grade_min()); 360 $this->assertEquals(100, $gg->get_grade_max()); 361 362 $CFG->grade_minmaxtouse = $initialminmaxtouse; 363 } 364 365 public function test_grade_grade_min_max_with_category_item() { 366 global $CFG, $DB; 367 $initialminmaxtouse = $CFG->grade_minmaxtouse; 368 369 $this->setAdminUser(); 370 $course = $this->getDataGenerator()->create_course(); 371 $user = $this->getDataGenerator()->create_user(); 372 $coursegi = grade_item::fetch_course_item($course->id); 373 374 // Create a category item. 375 $gc = new grade_category(array('courseid' => $course->id, 'fullname' => 'test'), false); 376 $gc->insert(); 377 $gi = $gc->get_grade_item(); 378 $gi->grademax = 100; 379 $gi->grademin = 0; 380 $gi->update(); 381 382 // Fetch the category item. 383 $giparams = array('itemtype' => 'category', 'iteminstance' => $gc->id); 384 $gi = grade_item::fetch($giparams); 385 $this->assertEquals(0, $gi->grademin); 386 $this->assertEquals(100, $gi->grademax); 387 388 // Give a grade to the student. 389 $gi->update_final_grade($user->id, 10); 390 391 // Check the grade min/max stored in gradebook. 392 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 393 $this->assertEquals(0, $gg->get_grade_min()); 394 $this->assertEquals(100, $gg->get_grade_max()); 395 396 // Change the min/max grade of the item. 397 $gi->grademin = 2; 398 $gi->grademax = 50; 399 $gi->update(); 400 401 // Fetch the updated item. 402 $gi = grade_item::fetch($giparams); 403 404 // Now check the grade grade min/max with system setting. 405 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM; 406 grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting. 407 408 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 409 $this->assertEquals(0, $gg->get_grade_min()); 410 $this->assertEquals(100, $gg->get_grade_max()); 411 412 // Now with other system setting. 413 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE; 414 grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache. 415 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 416 $this->assertEquals(0, $gg->get_grade_min()); 417 $this->assertEquals(100, $gg->get_grade_max()); 418 419 // Now with overriden setting in course. 420 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM; 421 grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE); 422 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 423 $this->assertEquals(0, $gg->get_grade_min()); 424 $this->assertEquals(100, $gg->get_grade_max()); 425 426 $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE; 427 grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM); 428 $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id)); 429 $this->assertEquals(0, $gg->get_grade_min()); 430 $this->assertEquals(100, $gg->get_grade_max()); 431 432 $CFG->grade_minmaxtouse = $initialminmaxtouse; 433 } 434 435 /** 436 * Tests when a grade_grade has been deleted. 437 */ 438 public function sub_test_grade_grade_deleted() { 439 $dg = $this->getDataGenerator(); 440 441 // Create the data we need for the tests. 442 $fs = new file_storage(); 443 $u1 = $dg->create_user(); 444 $c1 = $dg->create_course(); 445 $a1 = $dg->create_module('assign', ['course' => $c1->id]); 446 $a1context = context_module::instance($a1->cmid); 447 448 $gi = new grade_item($dg->create_grade_item( 449 [ 450 'courseid' => $c1->id, 451 'itemtype' => 'mod', 452 'itemmodule' => 'assign', 453 'iteminstance' => $a1->id 454 ] 455 ), false); 456 457 // Add feedback files to copy as our update. 458 $this->add_feedback_file_to_copy(); 459 460 $grades['feedback'] = 'Nice feedback!'; 461 $grades['feedbackformat'] = FORMAT_MOODLE; 462 $grades['feedbackfiles'] = [ 463 'contextid' => 1, 464 'component' => 'test', 465 'filearea' => 'testarea', 466 'itemid' => 1 467 ]; 468 469 $grades['userid'] = $u1->id; 470 grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance, 471 $gi->itemnumber, $grades); 472 473 // Feedback file area. 474 $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_FEEDBACK_FILEAREA); 475 $this->assertEquals(2, count($files)); 476 477 // History file area. 478 $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_HISTORY_FEEDBACK_FILEAREA); 479 $this->assertEquals(2, count($files)); 480 481 $gg = grade_grade::fetch(array('userid' => $u1->id, 'itemid' => $gi->id)); 482 483 $gg->delete(); 484 485 // Feedback file area. 486 $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_FEEDBACK_FILEAREA); 487 $this->assertEquals(0, count($files)); 488 489 // History file area. 490 $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_HISTORY_FEEDBACK_FILEAREA); 491 $this->assertEquals(2, count($files)); 492 } 493 494 /** 495 * Creates a feedback file to copy to the gradebook area. 496 */ 497 private function add_feedback_file_to_copy() { 498 $dummy = array( 499 'contextid' => 1, 500 'component' => 'test', 501 'filearea' => 'testarea', 502 'itemid' => 1, 503 'filepath' => '/', 504 'filename' => 'feedback1.txt' 505 ); 506 507 $fs = get_file_storage(); 508 $fs->create_file_from_string($dummy, ''); 509 } 510 511 /** 512 * Tests grade_deleted event. 513 */ 514 public function sub_test_grade_grade_deleted_event() { 515 global $DB; 516 $dg = $this->getDataGenerator(); 517 518 // Create the data we need for the tests. 519 $u1 = $dg->create_user(); 520 $u2 = $dg->create_user(); 521 $c1 = $dg->create_course(); 522 $a1 = $dg->create_module('assign', ['course' => $c1->id]); 523 524 $gi = new grade_item($dg->create_grade_item( 525 [ 526 'courseid' => $c1->id, 527 'itemtype' => 'mod', 528 'itemmodule' => 'assign', 529 'iteminstance' => $a1->id 530 ] 531 ), false); 532 533 grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance, 534 $gi->itemnumber, ['userid' => $u1->id]); 535 grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance, 536 $gi->itemnumber, ['userid' => $u2->id]); 537 538 $gg = grade_grade::fetch(array('userid' => $u1->id, 'itemid' => $gi->id)); 539 $this->assertEquals($u1->id, $gg->userid); 540 $gg->load_grade_item(); 541 $this->assertEquals($gi->id, $gg->grade_item->id); 542 543 // Delete user with valid grade item. 544 $sink = $this->redirectEvents(); 545 grade_user_delete($u1->id); 546 $events = $sink->get_events(); 547 $event = reset($events); 548 $sink->close(); 549 $this->assertInstanceOf('core\event\grade_deleted', $event); 550 551 $gg = grade_grade::fetch(array('userid' => $u2->id, 'itemid' => $gi->id)); 552 $this->assertEquals($u2->id, $gg->userid); 553 $gg->load_grade_item(); 554 $this->assertEquals($gi->id, $gg->grade_item->id); 555 556 // Delete grade item, mock up orphaned grade_grades. 557 $DB->delete_records('grade_items', ['id' => $gi->id]); 558 $gg = grade_grade::fetch(array('userid' => $u2->id, 'itemid' => $gi->id)); 559 $this->assertEquals($u2->id, $gg->userid); 560 561 // No event is triggered and there is a debugging message. 562 $sink = $this->redirectEvents(); 563 grade_user_delete($u2->id); 564 $this->assertDebuggingCalled("Missing grade item id $gi->id"); 565 $events = $sink->get_events(); 566 $sink->close(); 567 $this->assertEmpty($events); 568 569 // The grade should be deleted. 570 $gg = grade_grade::fetch(array('userid' => $u2->id, 'itemid' => $gi->id)); 571 $this->assertEmpty($gg); 572 } 573 574 /** 575 * Tests get_hiding_affected by locked category and overridden grades. 576 */ 577 public function test_category_get_hiding_affected() { 578 $generator = $this->getDataGenerator(); 579 580 // Create the data we need for the tests. 581 $course1 = $generator->create_course(); 582 $user1 = $generator->create_and_enrol($course1, 'student'); 583 $assignment2 = $generator->create_module('assign', ['course' => $course1->id]); 584 585 // Create a category item. 586 $gradecategory = new grade_category(array('courseid' => $course1->id, 'fullname' => 'test'), false); 587 $gradecategoryid = $gradecategory->insert(); 588 589 // Create one hidden grade item. 590 $gradeitem1a = new grade_item($generator->create_grade_item( 591 [ 592 'courseid' => $course1->id, 593 'itemtype' => 'mod', 594 'itemmodule' => 'assign', 595 'iteminstance' => $assignment2->id, 596 'categoryid' => $gradecategoryid, 597 'hidden' => 1, 598 ] 599 ), false); 600 grade_update('mod/assign', $gradeitem1a->courseid, $gradeitem1a->itemtype, $gradeitem1a->itemmodule, $gradeitem1a->iteminstance, 601 $gradeitem1a->itemnumber, ['userid' => $user1->id]); 602 603 // Get category grade item. 604 $gradeitem = $gradecategory->get_grade_item(); 605 // Reset needsupdate to allow set_locked. 606 $gradeitem->needsupdate = 0; 607 $gradeitem->update(); 608 // Lock category grade item. 609 $gradeitem->set_locked(1); 610 611 $hidingaffectedlocked = $this->call_get_hiding_affected($course1, $user1); 612 // Since locked category now should be recalculated. 613 // The number of unknown items is 2, this includes category item and course item. 614 $this->assertEquals(2, count($hidingaffectedlocked['unknown'])); 615 616 // Unlock category. 617 $gradeitem->set_locked(0); 618 $hidingaffectedunlocked = $this->call_get_hiding_affected($course1, $user1); 619 // When category unlocked, hidden item should exist in altered items. 620 $this->assertTrue(in_array($gradeitem1a->id, array_keys($hidingaffectedunlocked['altered']))); 621 622 // This creates all the grade_grades we need. 623 grade_regrade_final_grades($course1->id); 624 625 // Set grade override. 626 $gradegrade = grade_grade::fetch([ 627 'userid' => $user1->id, 628 'itemid' => $gradeitem->id, 629 ]); 630 // Set override grade grade, and check that grade submission has been overridden. 631 $gradegrade->set_overridden(true); 632 $this->assertEquals(true, $gradegrade->is_overridden()); 633 $hidingaffectedoverridden = $this->call_get_hiding_affected($course1, $user1); 634 // No need to recalculate overridden grades. 635 $this->assertTrue(in_array($gradegrade->itemid, array_keys($hidingaffectedoverridden['alteredaggregationstatus']))); 636 $this->assertEquals('used', $hidingaffectedoverridden['alteredaggregationstatus'][$gradegrade->itemid]); 637 } 638 639 /** 640 * Call get_hiding_affected(). 641 * @param stdClass $course The course object 642 * @param stdClass $user The student object 643 * @return array 644 */ 645 private function call_get_hiding_affected($course, $user) { 646 global $DB; 647 648 $items = grade_item::fetch_all(array('courseid' => $course->id)); 649 $grades = array(); 650 $sql = "SELECT g.* 651 FROM {grade_grades} g 652 JOIN {grade_items} gi ON gi.id = g.itemid 653 WHERE g.userid = :userid AND gi.courseid = :courseid"; 654 if ($gradesrecords = $DB->get_records_sql($sql, ['userid' => $user->id, 'courseid' => $course->id])) { 655 foreach ($gradesrecords as $grade) { 656 $grades[$grade->itemid] = new grade_grade($grade, false); 657 } 658 unset($gradesrecords); 659 } 660 foreach ($items as $itemid => $gradeitem) { 661 if (!isset($grades[$itemid])) { 662 $gradegrade = new grade_grade(); 663 $gradegrade->userid = $user->id; 664 $gradegrade->itemid = $gradeitem->id; 665 $grades[$itemid] = $gradegrade; 666 } 667 $gradeitem->grade_item = $gradeitem; 668 } 669 670 return grade_grade::get_hiding_affected($grades, $items); 671 } 672 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body