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