[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * @package core_grades 19 * @category phpunit 20 * @copyright nicolas@moodle.com 21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 */ 23 24 defined('MOODLE_INTERNAL') || die(); 25 26 require_once (__DIR__.'/fixtures/lib.php'); 27 28 29 class core_grade_category_testcase extends grade_base_testcase { 30 31 public function test_grade_category() { 32 $this->sub_test_grade_category_construct(); 33 $this->sub_test_grade_category_build_path(); 34 $this->sub_test_grade_category_fetch(); 35 $this->sub_test_grade_category_fetch_all(); 36 $this->sub_test_grade_category_update(); 37 $this->sub_test_grade_category_delete(); 38 $this->sub_test_grade_category_insert(); 39 $this->sub_test_grade_category_qualifies_for_regrading(); 40 $this->sub_test_grade_category_force_regrading(); 41 $this->sub_test_grade_category_aggregate_grades(); 42 $this->sub_test_grade_category_apply_limit_rules(); 43 $this->sub_test_grade_category_is_aggregationcoef_used(); 44 $this->sub_test_grade_category_aggregation_uses_aggregationcoef(); 45 $this->sub_test_grade_category_fetch_course_tree(); 46 $this->sub_test_grade_category_get_children(); 47 $this->sub_test_grade_category_load_grade_item(); 48 $this->sub_test_grade_category_get_grade_item(); 49 $this->sub_test_grade_category_load_parent_category(); 50 $this->sub_test_grade_category_get_parent_category(); 51 $this->sub_test_grade_category_get_name(); 52 $this->sub_test_grade_category_generate_grades_aggregationweight(); 53 $this->sub_test_grade_category_set_parent(); 54 $this->sub_test_grade_category_get_final(); 55 $this->sub_test_grade_category_get_sortorder(); 56 $this->sub_test_grade_category_set_sortorder(); 57 $this->sub_test_grade_category_is_editable(); 58 $this->sub_test_grade_category_move_after_sortorder(); 59 $this->sub_test_grade_category_is_course_category(); 60 $this->sub_test_grade_category_fetch_course_category(); 61 $this->sub_test_grade_category_is_locked(); 62 $this->sub_test_grade_category_set_locked(); 63 $this->sub_test_grade_category_is_hidden(); 64 $this->sub_test_grade_category_set_hidden(); 65 $this->sub_test_grade_category_can_control_visibility(); 66 67 // This won't work until MDL-11837 is complete. 68 // $this->sub_test_grade_category_generate_grades(); 69 70 // Do this last as adding a second course category messes up the data. 71 $this->sub_test_grade_category_insert_course_category(); 72 $this->sub_test_grade_category_is_extracredit_used(); 73 $this->sub_test_grade_category_aggregation_uses_extracredit(); 74 } 75 76 // Adds 3 new grade categories at various depths. 77 protected function sub_test_grade_category_construct() { 78 $course_category = grade_category::fetch_course_category($this->courseid); 79 80 $params = new stdClass(); 81 82 $params->courseid = $this->courseid; 83 $params->fullname = 'unittestcategory4'; 84 85 $grade_category = new grade_category($params, false); 86 $grade_category->insert(); 87 $this->grade_categories[] = $grade_category; 88 89 $this->assertEquals($params->courseid, $grade_category->courseid); 90 $this->assertEquals($params->fullname, $grade_category->fullname); 91 $this->assertEquals(2, $grade_category->depth); 92 $this->assertEquals("/$course_category->id/$grade_category->id/", $grade_category->path); 93 $parentpath = $grade_category->path; 94 95 // Test a child category. 96 $params->parent = $grade_category->id; 97 $params->fullname = 'unittestcategory5'; 98 $grade_category = new grade_category($params, false); 99 $grade_category->insert(); 100 $this->grade_categories[] = $grade_category; 101 102 $this->assertEquals(3, $grade_category->depth); 103 $this->assertEquals($parentpath.$grade_category->id."/", $grade_category->path); 104 $parentpath = $grade_category->path; 105 106 // Test a third depth category. 107 $params->parent = $grade_category->id; 108 $params->fullname = 'unittestcategory6'; 109 $grade_category = new grade_category($params, false); 110 $grade_category->insert(); 111 $this->grade_categories[50] = $grade_category;// Going to delete this one later hence the special index. 112 113 $this->assertEquals(4, $grade_category->depth); 114 $this->assertEquals($parentpath.$grade_category->id."/", $grade_category->path); 115 } 116 117 protected function sub_test_grade_category_build_path() { 118 $grade_category = new grade_category($this->grade_categories[1]); 119 $this->assertTrue(method_exists($grade_category, 'build_path')); 120 $path = grade_category::build_path($grade_category); 121 $this->assertEquals($grade_category->path, $path); 122 } 123 124 protected function sub_test_grade_category_fetch() { 125 $grade_category = new grade_category(); 126 $this->assertTrue(method_exists($grade_category, 'fetch')); 127 128 $grade_category = grade_category::fetch(array('id'=>$this->grade_categories[0]->id)); 129 $this->assertEquals($this->grade_categories[0]->id, $grade_category->id); 130 $this->assertEquals($this->grade_categories[0]->fullname, $grade_category->fullname); 131 } 132 133 protected function sub_test_grade_category_fetch_all() { 134 $grade_category = new grade_category(); 135 $this->assertTrue(method_exists($grade_category, 'fetch_all')); 136 137 $grade_categories = grade_category::fetch_all(array('courseid'=>$this->courseid)); 138 $this->assertEquals(count($this->grade_categories), count($grade_categories)-1); 139 } 140 141 protected function sub_test_grade_category_update() { 142 global $DB; 143 $grade_category = new grade_category($this->grade_categories[0]); 144 $this->assertTrue(method_exists($grade_category, 'update')); 145 146 $grade_category->fullname = 'Updated info for this unittest grade_category'; 147 $grade_category->path = null; // Path must be recalculated if missing. 148 $grade_category->depth = null; 149 $grade_category->aggregation = GRADE_AGGREGATE_MAX; // Should force regrading. 150 151 $grade_item = $grade_category->get_grade_item(); 152 $this->assertEquals(0, $grade_item->needsupdate); 153 154 $this->assertTrue($grade_category->update()); 155 156 $fullname = $DB->get_field('grade_categories', 'fullname', array('id' => $this->grade_categories[0]->id)); 157 $this->assertEquals($grade_category->fullname, $fullname); 158 159 $path = $DB->get_field('grade_categories', 'path', array('id' => $this->grade_categories[0]->id)); 160 $this->assertEquals($grade_category->path, $path); 161 162 $depth = $DB->get_field('grade_categories', 'depth', array('id' => $this->grade_categories[0]->id)); 163 $this->assertEquals($grade_category->depth, $depth); 164 165 $grade_item = $grade_category->get_grade_item(); 166 $this->assertEquals(1, $grade_item->needsupdate); 167 } 168 169 protected function sub_test_grade_category_delete() { 170 global $DB; 171 172 $grade_category = new grade_category($this->grade_categories[50]); 173 $this->assertTrue(method_exists($grade_category, 'delete')); 174 175 $this->assertTrue($grade_category->delete()); 176 $this->assertFalse($DB->get_record('grade_categories', array('id' => $grade_category->id))); 177 } 178 179 protected function sub_test_grade_category_insert() { 180 $course_category = grade_category::fetch_course_category($this->courseid); 181 182 $grade_category = new grade_category(); 183 $this->assertTrue(method_exists($grade_category, 'insert')); 184 185 $grade_category->fullname = 'unittestcategory4'; 186 $grade_category->courseid = $this->courseid; 187 $grade_category->aggregation = GRADE_AGGREGATE_MEAN; 188 $grade_category->aggregateonlygraded = 1; 189 $grade_category->keephigh = 100; 190 $grade_category->droplow = 10; 191 $grade_category->hidden = 0; 192 $grade_category->parent = $this->grade_categories[1]->id; // sub_test_grade_category_delete() removed the category at 0. 193 194 $grade_category->insert(); 195 196 $this->assertEquals('/'.$course_category->id.'/'.$this->grade_categories[1]->parent.'/'.$this->grade_categories[1]->id.'/'.$grade_category->id.'/', $grade_category->path); 197 $this->assertEquals(4, $grade_category->depth); 198 199 $last_grade_category = end($this->grade_categories); 200 201 $this->assertFalse(empty($grade_category->grade_item)); 202 $this->assertEquals($grade_category->id, $grade_category->grade_item->iteminstance); 203 $this->assertEquals('category', $grade_category->grade_item->itemtype); 204 205 $this->assertEquals($grade_category->id, $last_grade_category->id + 1); 206 $this->assertFalse(empty($grade_category->timecreated)); 207 $this->assertFalse(empty($grade_category->timemodified)); 208 } 209 210 protected function sub_test_grade_category_qualifies_for_regrading() { 211 $grade_category = new grade_category($this->grade_categories[1]); 212 $this->assertTrue(method_exists($grade_category, 'qualifies_for_regrading')); 213 $this->assertFalse($grade_category->qualifies_for_regrading()); 214 215 $grade_category->aggregation = GRADE_AGGREGATE_MAX; 216 $this->assertTrue($grade_category->qualifies_for_regrading()); 217 218 $grade_category = new grade_category($this->grade_categories[1]); 219 $grade_category->droplow = 99; 220 $this->assertTrue($grade_category->qualifies_for_regrading()); 221 222 $grade_category = new grade_category($this->grade_categories[1]); 223 $grade_category->keephigh = 99; 224 $this->assertTrue($grade_category->qualifies_for_regrading()); 225 } 226 227 protected function sub_test_grade_category_force_regrading() { 228 $grade_category = new grade_category($this->grade_categories[1]); 229 $this->assertTrue(method_exists($grade_category, 'force_regrading')); 230 231 $grade_category->load_grade_item(); 232 $this->assertEquals(0, $grade_category->grade_item->needsupdate); 233 234 $grade_category->force_regrading(); 235 236 $grade_category->grade_item = null; 237 $grade_category->load_grade_item(); 238 239 $this->assertEquals(1, $grade_category->grade_item->needsupdate); 240 } 241 242 /** 243 * Tests the setting of the grade_grades aggregationweight column. 244 * Currently, this is only a regression test for MDL-51715. 245 * This must be run before sub_test_grade_category_set_parent(), which alters 246 * the fixture. 247 */ 248 protected function sub_test_grade_category_generate_grades_aggregationweight() { 249 global $DB; 250 251 // Start of regression test for MDL-51715. 252 // grade_categories [1] and [2] are child categories of [0] 253 // Ensure that grades have been generated with fixture data. 254 $childcat1 = new grade_category($this->grade_categories[1]); 255 $childcat1itemid = $childcat1->load_grade_item()->id; 256 $childcat1->generate_grades(); 257 $childcat2 = new grade_category($this->grade_categories[2]); 258 $childcat2itemid = $childcat2->load_grade_item()->id; 259 $childcat2->generate_grades(); 260 $parentcat = new grade_category($this->grade_categories[0]); 261 $parentcat->generate_grades(); 262 263 // Drop low and and re-generate to produce 'dropped' aggregation status. 264 $parentcat->droplow = 1; 265 $parentcat->generate_grades(); 266 267 $this->assertTrue($DB->record_exists_select( 268 'grade_grades', 269 "aggregationstatus='dropped' and itemid in (?,?)", 270 array($childcat1itemid, $childcat2itemid))); 271 $this->assertFalse($DB->record_exists_select( 272 'grade_grades', 273 "aggregationstatus='dropped' and aggregationweight > 0.00"), 274 "aggregationweight should be 0.00 if aggregationstatus=='dropped'"); 275 276 // Reset grade data to be consistent with fixture data. 277 $parentcat->droplow = 0; 278 $parentcat->generate_grades(); 279 280 // Blank out the final grade for one of the child categories and re-generate 281 // to produce 'novalue' aggregationstatus. Direct DB update is testing shortcut. 282 $DB->set_field('grade_grades', 'finalgrade', null, array('itemid'=>$childcat1itemid)); 283 $parentcat->generate_grades(); 284 285 $this->assertFalse($DB->record_exists_select( 286 'grade_grades', 287 "aggregationstatus='dropped' and itemid in (?,?)", 288 array($childcat1itemid, $childcat2itemid))); 289 $this->assertTrue($DB->record_exists_select( 290 'grade_grades', 291 "aggregationstatus='novalue' and itemid = ?", 292 array($childcat1itemid))); 293 $this->assertFalse($DB->record_exists_select( 294 'grade_grades', 295 "aggregationstatus='novalue' and aggregationweight > 0.00"), 296 "aggregationweight should be 0.00 if aggregationstatus=='novalue'"); 297 298 // Re-generate to be consistent with fixture data. 299 $childcat1->generate_grades(); 300 $parentcat->generate_grades(); 301 // End of regression test for MDL-51715. 302 } 303 304 /** 305 * Tests the calculation of grades using the various aggregation methods with and without hidden grades 306 * This will not work entirely until MDL-11837 is done 307 */ 308 protected function sub_test_grade_category_generate_grades() { 309 global $DB; 310 311 // Inserting some special grade items to make testing the final grade calculation easier. 312 $params = new stdClass(); 313 $params->courseid = $this->courseid; 314 $params->fullname = 'unittestgradecalccategory'; 315 $params->aggregation = GRADE_AGGREGATE_MEAN; 316 $params->aggregateonlygraded = 0; 317 $grade_category = new grade_category($params, false); 318 $grade_category->insert(); 319 320 $this->assertTrue(method_exists($grade_category, 'generate_grades')); 321 322 $grade_category->load_grade_item(); 323 $cgi = $grade_category->get_grade_item(); 324 $cgi->grademin = 0; 325 $cgi->grademax = 20; // 3 grade items out of 10 but category is out of 20 to force scaling to occur. 326 $cgi->update(); 327 328 // 3 grade items each with a maximum grade of 10. 329 $grade_items = array(); 330 for ($i=0; $i<3; $i++) { 331 $grade_items[$i] = new grade_item(); 332 $grade_items[$i]->courseid = $this->courseid; 333 $grade_items[$i]->categoryid = $grade_category->id; 334 $grade_items[$i]->itemname = 'manual grade_item '.$i; 335 $grade_items[$i]->itemtype = 'manual'; 336 $grade_items[$i]->itemnumber = 0; 337 $grade_items[$i]->needsupdate = false; 338 $grade_items[$i]->gradetype = GRADE_TYPE_VALUE; 339 $grade_items[$i]->grademin = 0; 340 $grade_items[$i]->grademax = 10; 341 $grade_items[$i]->iteminfo = 'Manual grade item used for unit testing'; 342 $grade_items[$i]->timecreated = time(); 343 $grade_items[$i]->timemodified = time(); 344 345 // Used as the weight by weighted mean and as extra credit by mean with extra credit. 346 // Will be 0, 1 and 2. 347 $grade_items[$i]->aggregationcoef = $i; 348 349 $grade_items[$i]->insert(); 350 } 351 352 // A grade for each grade item. 353 $grade_grades = array(); 354 for ($i=0; $i<3; $i++) { 355 $grade_grades[$i] = new grade_grade(); 356 $grade_grades[$i]->itemid = $grade_items[$i]->id; 357 $grade_grades[$i]->userid = $this->userid; 358 $grade_grades[$i]->rawgrade = ($i+1)*2; // Produce grade grades of 2, 4 and 6. 359 $grade_grades[$i]->finalgrade = ($i+1)*2; 360 $grade_grades[$i]->timecreated = time(); 361 $grade_grades[$i]->timemodified = time(); 362 $grade_grades[$i]->information = '1 of 2 grade_grades'; 363 $grade_grades[$i]->informationformat = FORMAT_PLAIN; 364 $grade_grades[$i]->feedback = 'Good, but not good enough..'; 365 $grade_grades[$i]->feedbackformat = FORMAT_PLAIN; 366 367 $grade_grades[$i]->insert(); 368 } 369 370 // 3 grade items with 1 grade_grade each. 371 // grade grades have the values 2, 4 and 6. 372 373 // First correct answer is the aggregate with all 3 grades. 374 // Second correct answer is with the first grade (value 2) hidden. 375 376 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEDIAN, 'GRADE_AGGREGATE_MEDIAN', 8, 8); 377 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MAX, 'GRADE_AGGREGATE_MAX', 12, 12); 378 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MODE, 'GRADE_AGGREGATE_MODE', 12, 12); 379 380 // Weighted mean. note grade totals are rounded to an int to prevent rounding discrepancies. correct final grade isnt actually exactly 10 381 // 3 items with grades 2, 4 and 6 with weights 0, 1 and 2 and all out of 10. then doubled to be out of 20. 382 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN, 'GRADE_AGGREGATE_WEIGHTED_MEAN', 10, 10); 383 384 // Simple weighted mean. 385 // 3 items with grades 2, 4 and 6 equally weighted and all out of 10. then doubled to be out of 20. 386 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN2, 'GRADE_AGGREGATE_WEIGHTED_MEAN2', 8, 10); 387 388 // Mean of grades with extra credit. 389 // 3 items with grades 2, 4 and 6 with extra credit 0, 1 and 2 equally weighted and all out of 10. then doubled to be out of 20. 390 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_EXTRACREDIT_MEAN, 'GRADE_AGGREGATE_EXTRACREDIT_MEAN', 10, 13); 391 392 // Aggregation tests the are affected by a hidden grade currently dont work as we dont store the altered grade in the database 393 // instead an in memory recalculation is done. This should be remedied by MDL-11837. 394 395 // Fails with 1 grade hidden. still reports 8 as being correct. 396 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEAN, 'GRADE_AGGREGATE_MEAN', 8, 10); 397 398 // Fails with 1 grade hidden. still reports 4 as being correct. 399 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MIN, 'GRADE_AGGREGATE_MIN', 4, 8); 400 401 // Fails with 1 grade hidden. still reports 12 as being correct. 402 $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_SUM, 'GRADE_AGGREGATE_SUM', 12, 10); 403 } 404 405 /** 406 * Test grade category aggregation using the supplied grade objects and aggregation method 407 * @param grade_category $grade_category the category to be tested 408 * @param array $grade_items array of instance of grade_item 409 * @param array $grade_grades array of instances of grade_grade 410 * @param int $aggmethod the aggregation method to apply ie GRADE_AGGREGATE_MEAN 411 * @param string $aggmethodname the name of the aggregation method to apply. Used to display any test failure messages 412 * @param int $correct1 the correct final grade for the category with NO items hidden 413 * @param int $correct2 the correct final grade for the category with the grade at $grade_grades[0] hidden 414 * @return void 415 */ 416 protected function helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, $aggmethod, $aggmethodname, $correct1, $correct2) { 417 $grade_category->aggregation = $aggmethod; 418 $grade_category->update(); 419 420 // Check grade_item isnt hidden from a previous test. 421 $grade_items[0]->set_hidden(0, true); 422 $this->helper_test_grade_aggregation_result($grade_category, $correct1, 'Testing aggregation method('.$aggmethodname.') with no items hidden %s'); 423 424 // Hide the grade item with grade of 2. 425 $grade_items[0]->set_hidden(1, true); 426 $this->helper_test_grade_aggregation_result($grade_category, $correct2, 'Testing aggregation method('.$aggmethodname.') with 1 item hidden %s'); 427 } 428 429 /** 430 * Verify the value of the category grade item for $this->userid 431 * @param grade_category $grade_category the category to be tested 432 * @param int $correctgrade the expected grade 433 * @param string msg The message that should be displayed if the correct grade is not found 434 * @return void 435 */ 436 protected function helper_test_grade_aggregation_result($grade_category, $correctgrade, $msg) { 437 global $DB; 438 439 $category_grade_item = $grade_category->get_grade_item(); 440 441 // This creates all the grade_grades we need. 442 grade_regrade_final_grades($this->courseid); 443 444 $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid)); 445 $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax); 446 $this->assertEquals(intval($correctgrade), intval($grade->finalgrade), $msg); 447 448 /* 449 * TODO this doesnt work as the grade_grades created by $grade_category->generate_grades(); dont 450 * observe the category's max grade 451 // delete the grade_grades for the category itself and check they get recreated correctly. 452 $DB->delete_records('grade_grades', array('itemid'=>$category_grade_item->id)); 453 $grade_category->generate_grades(); 454 455 $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid)); 456 $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax); 457 $this->assertEquals(intval($correctgrade), intval($grade->finalgrade), $msg); 458 * 459 */ 460 } 461 462 protected function sub_test_grade_category_aggregate_grades() { 463 $category = new grade_category($this->grade_categories[0]); 464 $this->assertTrue(method_exists($category, 'aggregate_grades')); 465 // Tested more fully via test_grade_category_generate_grades(). 466 } 467 468 protected function sub_test_grade_category_apply_limit_rules() { 469 $items[$this->grade_items[0]->id] = new grade_item($this->grade_items[0], false); 470 $items[$this->grade_items[1]->id] = new grade_item($this->grade_items[1], false); 471 $items[$this->grade_items[2]->id] = new grade_item($this->grade_items[2], false); 472 $items[$this->grade_items[4]->id] = new grade_item($this->grade_items[4], false); 473 474 // Test excluding the lowest 2 out of 4 grades from aggregation with no 0 grades. 475 $category = new grade_category(); 476 $category->droplow = 2; 477 $grades = array($this->grade_items[0]->id=>5.374, 478 $this->grade_items[1]->id=>9.4743, 479 $this->grade_items[2]->id=>2.5474, 480 $this->grade_items[4]->id=>7.3754); 481 $category->apply_limit_rules($grades, $items); 482 $this->assertEquals(count($grades), 2); 483 $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743); 484 $this->assertEquals($grades[$this->grade_items[4]->id], 7.3754); 485 486 // Test aggregating only the highest 1 out of 4 grades. 487 $category = new grade_category(); 488 $category->keephigh = 1; 489 $category->droplow = 0; 490 $grades = array($this->grade_items[0]->id=>5.374, 491 $this->grade_items[1]->id=>9.4743, 492 $this->grade_items[2]->id=>2.5474, 493 $this->grade_items[4]->id=>7.3754); 494 $category->apply_limit_rules($grades, $items); 495 $this->assertEquals(count($grades), 1); 496 $grade = reset($grades); 497 $this->assertEquals(9.4743, $grade); 498 499 // Test excluding the lowest 2 out of 4 grades from aggregation with no 0 grades. 500 // An extra credit grade item should be kept even if droplow means it would otherwise be excluded. 501 $category = new grade_category(); 502 $category->droplow = 2; 503 $category->aggregation = GRADE_AGGREGATE_SUM; 504 $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit". 505 $grades = array($this->grade_items[0]->id=>5.374, 506 $this->grade_items[1]->id=>9.4743, 507 $this->grade_items[2]->id=>2.5474, 508 $this->grade_items[4]->id=>7.3754); 509 $category->apply_limit_rules($grades, $items); 510 $this->assertEquals(count($grades), 2); 511 $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743); 512 $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474); 513 514 // Test only aggregating the highest 1 out of 4 grades. 515 // An extra credit grade item is retained in addition to the highest grade. 516 $category = new grade_category(); 517 $category->keephigh = 1; 518 $category->droplow = 0; 519 $category->aggregation = GRADE_AGGREGATE_SUM; 520 $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit". 521 $grades = array($this->grade_items[0]->id=>5.374, 522 $this->grade_items[1]->id=>9.4743, 523 $this->grade_items[2]->id=>2.5474, 524 $this->grade_items[4]->id=>7.3754); 525 $category->apply_limit_rules($grades, $items); 526 $this->assertEquals(count($grades), 2); 527 $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743); 528 $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474); 529 530 // Test excluding the lowest 1 out of 4 grades from aggregation with two 0 grades. 531 $items[$this->grade_items[2]->id]->aggregationcoef = 0; // Undo marking grade item 2 as "extra credit". 532 $category = new grade_category(); 533 $category->droplow = 1; 534 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean. 535 $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation. 536 $this->grade_items[1]->id=>5, // 5 out of 100. 537 $this->grade_items[2]->id=>2, // 0 out of 6. 538 $this->grade_items[4]->id=>0); // 0 out of 100. 539 $category->apply_limit_rules($grades, $items); 540 $this->assertEquals(count($grades), 3); 541 $this->assertEquals($grades[$this->grade_items[1]->id], 5); 542 $this->assertEquals($grades[$this->grade_items[2]->id], 2); 543 $this->assertEquals($grades[$this->grade_items[4]->id], 0); 544 545 // Test excluding the lowest 2 out of 4 grades from aggregation with three 0 grades. 546 $category = new grade_category(); 547 $category->droplow = 2; 548 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean. 549 $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation. 550 $this->grade_items[1]->id=>5, // 5 out of 100. 551 $this->grade_items[2]->id=>0, // 0 out of 6. 552 $this->grade_items[4]->id=>0); // 0 out of 100. Should be excluded from aggregation. 553 $category->apply_limit_rules($grades, $items); 554 $this->assertEquals(count($grades), 2); 555 $this->assertEquals($grades[$this->grade_items[1]->id], 5); 556 $this->assertEquals($grades[$this->grade_items[2]->id], 0); 557 558 // Test excluding the lowest 5 out of 4 grades from aggregation. 559 // Just to check we handle this sensibly. 560 $category = new grade_category(); 561 $category->droplow = 5; 562 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean. 563 $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation. 564 $this->grade_items[1]->id=>5, // 5 out of 100. 565 $this->grade_items[2]->id=>6, // 6 out of 6. 566 $this->grade_items[4]->id=>1);// 1 out of 100. Should be excluded from aggregation. 567 $category->apply_limit_rules($grades, $items); 568 $this->assertEquals(count($grades), 0); 569 570 // Test excluding the lowest 4 out of 4 grades from aggregation with one marked as extra credit. 571 $category = new grade_category(); 572 $category->droplow = 4; 573 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean. 574 $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit". 575 $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation. 576 $this->grade_items[1]->id=>5, // 5 out of 100. Should be excluded from aggregation. 577 $this->grade_items[2]->id=>6, // 6 out of 6. Extra credit. Should be retained. 578 $this->grade_items[4]->id=>1);// 1 out of 100. Should be excluded from aggregation. 579 $category->apply_limit_rules($grades, $items); 580 $this->assertEquals(count($grades), 1); 581 $this->assertEquals($grades[$this->grade_items[2]->id], 6); 582 583 // MDL-35667 - There was an infinite loop if several items had the same grade and at least one was extra credit. 584 $category = new grade_category(); 585 $category->droplow = 1; 586 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // Simple weighted mean. 587 $items[$this->grade_items[1]->id]->aggregationcoef = 1; // Mark grade item 1 as "extra credit". 588 $grades = array($this->grade_items[0]->id=>1, // 1 out of 110. Should be excluded from aggregation. 589 $this->grade_items[1]->id=>1, // 1 out of 100. Extra credit. Should be retained. 590 $this->grade_items[2]->id=>1, // 1 out of 6. Should be retained. 591 $this->grade_items[4]->id=>1);// 1 out of 100. Should be retained. 592 $category->apply_limit_rules($grades, $items); 593 $this->assertEquals(count($grades), 3); 594 $this->assertEquals($grades[$this->grade_items[1]->id], 1); 595 $this->assertEquals($grades[$this->grade_items[2]->id], 1); 596 $this->assertEquals($grades[$this->grade_items[4]->id], 1); 597 598 } 599 600 protected function sub_test_grade_category_is_aggregationcoef_used() { 601 $category = new grade_category(); 602 // Following use aggregationcoef. 603 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN; 604 $this->assertTrue($category->is_aggregationcoef_used()); 605 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; 606 $this->assertTrue($category->is_aggregationcoef_used()); 607 $category->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN; 608 $this->assertTrue($category->is_aggregationcoef_used()); 609 $category->aggregation = GRADE_AGGREGATE_SUM; 610 $this->assertTrue($category->is_aggregationcoef_used()); 611 612 // Following don't use aggregationcoef. 613 $category->aggregation = GRADE_AGGREGATE_MAX; 614 $this->assertFalse($category->is_aggregationcoef_used()); 615 $category->aggregation = GRADE_AGGREGATE_MEAN; 616 $this->assertFalse($category->is_aggregationcoef_used()); 617 $category->aggregation = GRADE_AGGREGATE_MEDIAN; 618 $this->assertFalse($category->is_aggregationcoef_used()); 619 $category->aggregation = GRADE_AGGREGATE_MIN; 620 $this->assertFalse($category->is_aggregationcoef_used()); 621 $category->aggregation = GRADE_AGGREGATE_MODE; 622 $this->assertFalse($category->is_aggregationcoef_used()); 623 } 624 625 protected function sub_test_grade_category_aggregation_uses_aggregationcoef() { 626 627 $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_WEIGHTED_MEAN)); 628 $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_WEIGHTED_MEAN2)); 629 $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_EXTRACREDIT_MEAN)); 630 $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_SUM)); 631 632 $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MAX)); 633 $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MEAN)); 634 $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MEDIAN)); 635 $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MIN)); 636 $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MODE)); 637 } 638 639 protected function sub_test_grade_category_fetch_course_tree() { 640 $category = new grade_category(); 641 $this->assertTrue(method_exists($category, 'fetch_course_tree')); 642 // TODO: add some tests. 643 } 644 645 protected function sub_test_grade_category_get_children() { 646 $course_category = grade_category::fetch_course_category($this->courseid); 647 648 $category = new grade_category($this->grade_categories[0]); 649 $this->assertTrue(method_exists($category, 'get_children')); 650 651 $children_array = $category->get_children(0); 652 653 $this->assertTrue(is_array($children_array)); 654 $this->assertFalse(empty($children_array[2])); 655 $this->assertFalse(empty($children_array[2]['object'])); 656 $this->assertFalse(empty($children_array[2]['children'])); 657 $this->assertEquals($this->grade_categories[1]->id, $children_array[2]['object']->id); 658 $this->assertEquals($this->grade_categories[2]->id, $children_array[5]['object']->id); 659 $this->assertEquals($this->grade_items[0]->id, $children_array[2]['children'][3]['object']->id); 660 $this->assertEquals($this->grade_items[1]->id, $children_array[2]['children'][4]['object']->id); 661 $this->assertEquals($this->grade_items[2]->id, $children_array[5]['children'][6]['object']->id); 662 } 663 664 protected function sub_test_grade_category_load_grade_item() { 665 $category = new grade_category($this->grade_categories[0]); 666 $this->assertTrue(method_exists($category, 'load_grade_item')); 667 $this->assertEquals(null, $category->grade_item); 668 $category->load_grade_item(); 669 $this->assertEquals($this->grade_items[3]->id, $category->grade_item->id); 670 } 671 672 protected function sub_test_grade_category_get_grade_item() { 673 $category = new grade_category($this->grade_categories[0]); 674 $this->assertTrue(method_exists($category, 'get_grade_item')); 675 $grade_item = $category->get_grade_item(); 676 $this->assertEquals($this->grade_items[3]->id, $grade_item->id); 677 } 678 679 protected function sub_test_grade_category_load_parent_category() { 680 $category = new grade_category($this->grade_categories[1]); 681 $this->assertTrue(method_exists($category, 'load_parent_category')); 682 $this->assertEquals(null, $category->parent_category); 683 $category->load_parent_category(); 684 $this->assertEquals($this->grade_categories[0]->id, $category->parent_category->id); 685 } 686 687 protected function sub_test_grade_category_get_parent_category() { 688 $category = new grade_category($this->grade_categories[1]); 689 $this->assertTrue(method_exists($category, 'get_parent_category')); 690 $parent_category = $category->get_parent_category(); 691 $this->assertEquals($this->grade_categories[0]->id, $parent_category->id); 692 } 693 694 protected function sub_test_grade_category_get_name() { 695 $category = new grade_category($this->grade_categories[0]); 696 $this->assertTrue(method_exists($category, 'get_name')); 697 $this->assertEquals($this->grade_categories[0]->fullname, $category->get_name()); 698 } 699 700 protected function sub_test_grade_category_set_parent() { 701 $category = new grade_category($this->grade_categories[1]); 702 $this->assertTrue(method_exists($category, 'set_parent')); 703 // TODO: implement detailed tests. 704 705 $course_category = grade_category::fetch_course_category($this->courseid); 706 $this->assertTrue($category->set_parent($course_category->id)); 707 $this->assertEquals($course_category->id, $category->parent); 708 } 709 710 protected function sub_test_grade_category_get_final() { 711 $category = new grade_category($this->grade_categories[0]); 712 $this->assertTrue(method_exists($category, 'get_final')); 713 $category->load_grade_item(); 714 $this->assertEquals($category->get_final(), $category->grade_item->get_final()); 715 } 716 717 protected function sub_test_grade_category_get_sortorder() { 718 $category = new grade_category($this->grade_categories[0]); 719 $this->assertTrue(method_exists($category, 'get_sortorder')); 720 $category->load_grade_item(); 721 $this->assertEquals($category->get_sortorder(), $category->grade_item->get_sortorder()); 722 } 723 724 protected function sub_test_grade_category_set_sortorder() { 725 $category = new grade_category($this->grade_categories[0]); 726 $this->assertTrue(method_exists($category, 'set_sortorder')); 727 $category->load_grade_item(); 728 $this->assertEquals($category->set_sortorder(10), $category->grade_item->set_sortorder(10)); 729 } 730 731 protected function sub_test_grade_category_move_after_sortorder() { 732 $category = new grade_category($this->grade_categories[0]); 733 $this->assertTrue(method_exists($category, 'move_after_sortorder')); 734 $category->load_grade_item(); 735 $this->assertEquals($category->move_after_sortorder(10), $category->grade_item->move_after_sortorder(10)); 736 } 737 738 protected function sub_test_grade_category_is_course_category() { 739 $category = grade_category::fetch_course_category($this->courseid); 740 $this->assertTrue(method_exists($category, 'is_course_category')); 741 $this->assertTrue($category->is_course_category()); 742 } 743 744 protected function sub_test_grade_category_fetch_course_category() { 745 $category = new grade_category(); 746 $this->assertTrue(method_exists($category, 'fetch_course_category')); 747 $category = grade_category::fetch_course_category($this->courseid); 748 $this->assertTrue(empty($category->parent)); 749 } 750 /** 751 * TODO implement 752 */ 753 protected function sub_test_grade_category_is_editable() { 754 755 } 756 757 protected function sub_test_grade_category_is_locked() { 758 $category = new grade_category($this->grade_categories[0]); 759 $this->assertTrue(method_exists($category, 'is_locked')); 760 $category->load_grade_item(); 761 $this->assertEquals($category->is_locked(), $category->grade_item->is_locked()); 762 } 763 764 protected function sub_test_grade_category_set_locked() { 765 $category = new grade_category($this->grade_categories[0]); 766 $this->assertTrue(method_exists($category, 'set_locked')); 767 768 // Will return false as cannot lock a grade that needs updating. 769 $this->assertFalse($category->set_locked(1)); 770 grade_regrade_final_grades($this->courseid); 771 772 // Get the category from the db again. 773 $category = new grade_category($this->grade_categories[0]); 774 $this->assertTrue($category->set_locked(1)); 775 } 776 777 protected function sub_test_grade_category_is_hidden() { 778 $category = new grade_category($this->grade_categories[0]); 779 $this->assertTrue(method_exists($category, 'is_hidden')); 780 $category->load_grade_item(); 781 $this->assertEquals($category->is_hidden(), $category->grade_item->is_hidden()); 782 } 783 784 protected function sub_test_grade_category_set_hidden() { 785 $category = new grade_category($this->grade_categories[0]); 786 $this->assertTrue(method_exists($category, 'set_hidden')); 787 $category->set_hidden(1); 788 $category->load_grade_item(); 789 $this->assertEquals(true, $category->grade_item->is_hidden()); 790 } 791 792 protected function sub_test_grade_category_can_control_visibility() { 793 $category = new grade_category($this->grade_categories[0]); 794 $this->assertTrue($category->can_control_visibility()); 795 } 796 797 protected function sub_test_grade_category_insert_course_category() { 798 // Beware: adding a duplicate course category messes up the data in a way that's hard to recover from. 799 $grade_category = new grade_category(); 800 $this->assertTrue(method_exists($grade_category, 'insert_course_category')); 801 802 $id = $grade_category->insert_course_category($this->courseid); 803 $this->assertNotNull($id); 804 $this->assertEquals('?', $grade_category->fullname); 805 $this->assertEquals(GRADE_AGGREGATE_WEIGHTED_MEAN2, $grade_category->aggregation); 806 $this->assertEquals("/$id/", $grade_category->path); 807 $this->assertEquals(1, $grade_category->depth); 808 $this->assertNull($grade_category->parent); 809 } 810 811 protected function generate_random_raw_grade($item, $userid) { 812 $grade = new grade_grade(); 813 $grade->itemid = $item->id; 814 $grade->userid = $userid; 815 $grade->grademin = 0; 816 $grade->grademax = 1; 817 $valuetype = "grade$item->gradetype"; 818 $grade->rawgrade = rand(0, 1000) / 1000; 819 $grade->insert(); 820 return $grade->rawgrade; 821 } 822 823 protected function sub_test_grade_category_is_extracredit_used() { 824 $category = new grade_category(); 825 // Following use aggregationcoef. 826 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; 827 $this->assertTrue($category->is_extracredit_used()); 828 $category->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN; 829 $this->assertTrue($category->is_extracredit_used()); 830 $category->aggregation = GRADE_AGGREGATE_SUM; 831 $this->assertTrue($category->is_extracredit_used()); 832 833 // Following don't use aggregationcoef. 834 $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN; 835 $this->assertFalse($category->is_extracredit_used()); 836 $category->aggregation = GRADE_AGGREGATE_MAX; 837 $this->assertFalse($category->is_extracredit_used()); 838 $category->aggregation = GRADE_AGGREGATE_MEAN; 839 $this->assertFalse($category->is_extracredit_used()); 840 $category->aggregation = GRADE_AGGREGATE_MEDIAN; 841 $this->assertFalse($category->is_extracredit_used()); 842 $category->aggregation = GRADE_AGGREGATE_MIN; 843 $this->assertFalse($category->is_extracredit_used()); 844 $category->aggregation = GRADE_AGGREGATE_MODE; 845 $this->assertFalse($category->is_extracredit_used()); 846 } 847 848 protected function sub_test_grade_category_aggregation_uses_extracredit() { 849 850 $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_WEIGHTED_MEAN2)); 851 $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_EXTRACREDIT_MEAN)); 852 $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_SUM)); 853 854 $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_WEIGHTED_MEAN)); 855 $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MAX)); 856 $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MEAN)); 857 $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MEDIAN)); 858 $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MIN)); 859 $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MODE)); 860 } 861 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |