MDL-32323 add grade tests
[moodle.git] / lib / grade / tests / grade_category_test.php
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/>.
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  */
24 defined('MOODLE_INTERNAL') || die();
26 require_once(__DIR__.'/fixtures/lib.php');
29 class grade_category_testcase extends grade_base_testcase {
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_fetch_course_tree();
45         $this->sub_test_grade_category_get_children();
46         $this->sub_test_grade_category_load_grade_item();
47         $this->sub_test_grade_category_get_grade_item();
48         $this->sub_test_grade_category_load_parent_category();
49         $this->sub_test_grade_category_get_parent_category();
50         $this->sub_test_grade_category_get_name();
51         $this->sub_test_grade_category_set_parent();
52         $this->sub_test_grade_category_get_final();
53         $this->sub_test_grade_category_get_sortorder();
54         $this->sub_test_grade_category_set_sortorder();
55         $this->sub_test_grade_category_is_editable();
56         $this->sub_test_grade_category_move_after_sortorder();
57         $this->sub_test_grade_category_is_course_category();
58         $this->sub_test_grade_category_fetch_course_category();
59         $this->sub_test_grade_category_is_locked();
60         $this->sub_test_grade_category_set_locked();
61         $this->sub_test_grade_category_is_hidden();
62         $this->sub_test_grade_category_set_hidden();
64         //this won't work until MDL-11837 is complete
65         //$this->sub_test_grade_category_generate_grades();
67         //do this last as adding a second course category messes up the data
68         $this->sub_test_grade_category_insert_course_category();
69     }
71     //adds 3 new grade categories at various depths
72     protected function sub_test_grade_category_construct() {
73         $course_category = grade_category::fetch_course_category($this->courseid);
75         $params = new stdClass();
77         $params->courseid = $this->courseid;
78         $params->fullname = 'unittestcategory4';
80         $grade_category = new grade_category($params, false);
81         $grade_category->insert();
82         $this->grade_categories[] = $grade_category;
84         $this->assertEquals($params->courseid, $grade_category->courseid);
85         $this->assertEquals($params->fullname, $grade_category->fullname);
86         $this->assertEquals(2, $grade_category->depth);
87         $this->assertEquals("/$course_category->id/$grade_category->id/", $grade_category->path);
88         $parentpath = $grade_category->path;
90         // Test a child category
91         $params->parent = $grade_category->id;
92         $params->fullname = 'unittestcategory5';
93         $grade_category = new grade_category($params, false);
94         $grade_category->insert();
95         $this->grade_categories[] = $grade_category;
97         $this->assertEquals(3, $grade_category->depth);
98         $this->assertEquals($parentpath.$grade_category->id."/", $grade_category->path);
99         $parentpath = $grade_category->path;
101         // Test a third depth category
102         $params->parent = $grade_category->id;
103         $params->fullname = 'unittestcategory6';
104         $grade_category = new grade_category($params, false);
105         $grade_category->insert();
106         $this->grade_categories[50] = $grade_category;//going to delete this one later hence the special index
108         $this->assertEquals(4, $grade_category->depth);
109         $this->assertEquals($parentpath.$grade_category->id."/", $grade_category->path);
110     }
112     protected function sub_test_grade_category_build_path() {
113         $grade_category = new grade_category($this->grade_categories[1]);
114         $this->assertTrue(method_exists($grade_category, 'build_path'));
115         $path = grade_category::build_path($grade_category);
116         $this->assertEquals($grade_category->path, $path);
117     }
119     protected function sub_test_grade_category_fetch() {
120         $grade_category = new grade_category();
121         $this->assertTrue(method_exists($grade_category, 'fetch'));
123         $grade_category = grade_category::fetch(array('id'=>$this->grade_categories[0]->id));
124         $this->assertEquals($this->grade_categories[0]->id, $grade_category->id);
125         $this->assertEquals($this->grade_categories[0]->fullname, $grade_category->fullname);
126     }
128     protected function sub_test_grade_category_fetch_all() {
129         $grade_category = new grade_category();
130         $this->assertTrue(method_exists($grade_category, 'fetch_all'));
132         $grade_categories = grade_category::fetch_all(array('courseid'=>$this->courseid));
133         $this->assertEquals(count($this->grade_categories), count($grade_categories)-1);
134     }
136     protected function sub_test_grade_category_update() {
137         global $DB;
138         $grade_category = new grade_category($this->grade_categories[0]);
139         $this->assertTrue(method_exists($grade_category, 'update'));
141         $grade_category->fullname = 'Updated info for this unittest grade_category';
142         $grade_category->path = null; // path must be recalculated if missing
143         $grade_category->depth = null;
144         $grade_category->aggregation = GRADE_AGGREGATE_MAX; // should force regrading
146         $grade_item = $grade_category->get_grade_item();
147         $this->assertEquals(0, $grade_item->needsupdate);
149         $this->assertTrue($grade_category->update());
151         $fullname = $DB->get_field('grade_categories', 'fullname', array('id' => $this->grade_categories[0]->id));
152         $this->assertEquals($grade_category->fullname, $fullname);
154         $path = $DB->get_field('grade_categories', 'path', array('id' => $this->grade_categories[0]->id));
155         $this->assertEquals($grade_category->path, $path);
157         $depth = $DB->get_field('grade_categories', 'depth', array('id' => $this->grade_categories[0]->id));
158         $this->assertEquals($grade_category->depth, $depth);
160         $grade_item = $grade_category->get_grade_item();
161         $this->assertEquals(1, $grade_item->needsupdate);
162     }
164     protected function sub_test_grade_category_delete() {
165         global $DB;
167         $grade_category = new grade_category($this->grade_categories[50]);
168         $this->assertTrue(method_exists($grade_category, 'delete'));
170         $this->assertTrue($grade_category->delete());
171         $this->assertFalse($DB->get_record('grade_categories', array('id' => $grade_category->id)));
172     }
174     protected function sub_test_grade_category_insert() {
175         $course_category = grade_category::fetch_course_category($this->courseid);
177         $grade_category = new grade_category();
178         $this->assertTrue(method_exists($grade_category, 'insert'));
180         $grade_category->fullname    = 'unittestcategory4';
181         $grade_category->courseid    = $this->courseid;
182         $grade_category->aggregation = GRADE_AGGREGATE_MEAN;
183         $grade_category->aggregateonlygraded = 1;
184         $grade_category->keephigh    = 100;
185         $grade_category->droplow     = 10;
186         $grade_category->hidden      = 0;
187         $grade_category->parent      = $this->grade_categories[1]->id; //sub_test_grade_category_delete() removed the category at 0
189         $grade_category->insert();
191         $this->assertEquals('/'.$course_category->id.'/'.$this->grade_categories[1]->parent.'/'.$this->grade_categories[1]->id.'/'.$grade_category->id.'/', $grade_category->path);
192         $this->assertEquals(4, $grade_category->depth);
194         $last_grade_category = end($this->grade_categories);
196         $this->assertFalse(empty($grade_category->grade_item));
197         $this->assertEquals($grade_category->id, $grade_category->grade_item->iteminstance);
198         $this->assertEquals('category', $grade_category->grade_item->itemtype);
200         $this->assertEquals($grade_category->id, $last_grade_category->id + 1);
201         $this->assertFalse(empty($grade_category->timecreated));
202         $this->assertFalse(empty($grade_category->timemodified));
203     }
205     protected function sub_test_grade_category_qualifies_for_regrading() {
206         $grade_category = new grade_category($this->grade_categories[1]);
207         $this->assertTrue(method_exists($grade_category, 'qualifies_for_regrading'));
208         $this->assertFalse($grade_category->qualifies_for_regrading());
210         $grade_category->aggregation = GRADE_AGGREGATE_MAX;
211         $this->assertTrue($grade_category->qualifies_for_regrading());
213         $grade_category = new grade_category($this->grade_categories[1]);
214         $grade_category->droplow = 99;
215         $this->assertTrue($grade_category->qualifies_for_regrading());
217         $grade_category = new grade_category($this->grade_categories[1]);
218         $grade_category->keephigh = 99;
219         $this->assertTrue($grade_category->qualifies_for_regrading());
220     }
222     protected function sub_test_grade_category_force_regrading() {
223         $grade_category = new grade_category($this->grade_categories[1]);
224         $this->assertTrue(method_exists($grade_category, 'force_regrading'));
226         $grade_category->load_grade_item();
227         $this->assertEquals(0, $grade_category->grade_item->needsupdate);
229         $grade_category->force_regrading();
231         $grade_category->grade_item = null;
232         $grade_category->load_grade_item();
234         $this->assertEquals(1, $grade_category->grade_item->needsupdate);
235     }
237     /**
238      * Tests the calculation of grades using the various aggregation methods with and without hidden grades
239      * This will not work entirely until MDL-11837 is done
240      * @global type $DB
241      */
242     protected function sub_test_grade_category_generate_grades() {
243         global $DB;
245         //inserting some special grade items to make testing the final grade calculation easier
246         $params->courseid = $this->courseid;
247         $params->fullname = 'unittestgradecalccategory';
248         $params->aggregation = GRADE_AGGREGATE_MEAN;
249         $params->aggregateonlygraded = 0;
250         $grade_category = new grade_category($params, false);
251         $grade_category->insert();
253         $this->assertTrue(method_exists($grade_category, 'generate_grades'));
255         $grade_category->load_grade_item();
256         $cgi = $grade_category->get_grade_item();
257         $cgi->grademin = 0;
258         $cgi->grademax = 20;//3 grade items out of 10 but category is out of 20 to force scaling to occur
259         $cgi->update();
261         //3 grade items each with a maximum grade of 10
262         $grade_items = array();
263         for ($i=0; $i<3; $i++) {
264             $grade_items[$i] = new grade_item();
265             $grade_items[$i]->courseid = $this->courseid;
266             $grade_items[$i]->categoryid = $grade_category->id;
267             $grade_items[$i]->itemname = 'manual grade_item '.$i;
268             $grade_items[$i]->itemtype = 'manual';
269             $grade_items[$i]->itemnumber = 0;
270             $grade_items[$i]->needsupdate = false;
271             $grade_items[$i]->gradetype = GRADE_TYPE_VALUE;
272             $grade_items[$i]->grademin = 0;
273             $grade_items[$i]->grademax = 10;
274             $grade_items[$i]->iteminfo = 'Manual grade item used for unit testing';
275             $grade_items[$i]->timecreated = time();
276             $grade_items[$i]->timemodified = time();
278             //used as the weight by weighted mean and as extra credit by mean with extra credit
279             //Will be 0, 1 and 2
280             $grade_items[$i]->aggregationcoef = $i;
282             $grade_items[$i]->insert();
283         }
285         //a grade for each grade item
286         $grade_grades = array();
287         for ($i=0; $i<3; $i++) {
288             $grade_grades[$i] = new grade_grade();
289             $grade_grades[$i]->itemid = $grade_items[$i]->id;
290             $grade_grades[$i]->userid = $this->userid;
291             $grade_grades[$i]->rawgrade = ($i+1)*2;//produce grade grades of 2, 4 and 6
292             $grade_grades[$i]->finalgrade = ($i+1)*2;
293             $grade_grades[$i]->timecreated = time();
294             $grade_grades[$i]->timemodified = time();
295             $grade_grades[$i]->information = '1 of 2 grade_grades';
296             $grade_grades[$i]->informationformat = FORMAT_PLAIN;
297             $grade_grades[$i]->feedback = 'Good, but not good enough..';
298             $grade_grades[$i]->feedbackformat = FORMAT_PLAIN;
300             $grade_grades[$i]->insert();
301         }
303         //3 grade items with 1 grade_grade each.
304         //grade grades have the values 2, 4 and 6
306         //First correct answer is the aggregate with all 3 grades
307         //Second correct answer is with the first grade (value 2) hidden
309         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEDIAN, 'GRADE_AGGREGATE_MEDIAN', 8, 8);
310         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MAX, 'GRADE_AGGREGATE_MAX', 12, 12);
311         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MODE, 'GRADE_AGGREGATE_MODE', 12, 12);
313         //weighted mean. note grade totals are rounded to an int to prevent rounding discrepancies. correct final grade isnt actually exactly 10
314         //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.
315         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN, 'GRADE_AGGREGATE_WEIGHTED_MEAN', 10, 10);
317         //simple weighted mean
318         //3 items with grades 2, 4 and 6 equally weighted and all out of 10. then doubled to be out of 20.
319         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN2, 'GRADE_AGGREGATE_WEIGHTED_MEAN2', 8, 10);
321         //mean of grades with extra credit
322         //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.
323         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_EXTRACREDIT_MEAN, 'GRADE_AGGREGATE_EXTRACREDIT_MEAN', 10, 13);
325         //aggregation tests the are affected by a hidden grade currently dont work as we dont store the altered grade in the database
326         //instead an in memory recalculation is done. This should be remedied by MDL-11837
328         //fails with 1 grade hidden. still reports 8 as being correct
329         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEAN, 'GRADE_AGGREGATE_MEAN', 8, 10);
331         //fails with 1 grade hidden. still reports 4 as being correct
332         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MIN, 'GRADE_AGGREGATE_MIN', 4, 8);
334         //fails with 1 grade hidden. still reports 12 as being correct
335         $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_SUM, 'GRADE_AGGREGATE_SUM', 12, 10);
336     }
338     /**
339      * Test grade category aggregation using the supplied grade objects and aggregation method
340      * @param grade_category $grade_category the category to be tested
341      * @param array $grade_items array of instance of grade_item
342      * @param array $grade_grades array of instances of grade_grade
343      * @param int $aggmethod the aggregation method to apply ie GRADE_AGGREGATE_MEAN
344      * @param string $aggmethodname the name of the aggregation method to apply. Used to display any test failure messages
345      * @param int $correct1 the correct final grade for the category with NO items hidden
346      * @param int $correct2 the correct final grade for the category with the grade at $grade_grades[0] hidden
347      * @return void
348     */
349     protected function helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, $aggmethod, $aggmethodname, $correct1, $correct2) {
350         global $DB;
352         $grade_category->aggregation = $aggmethod;
353         $grade_category->update();
355         //check grade_item isnt hidden from a previous test
356         $grade_items[0]->set_hidden(0, true);
357         $this->helper_test_grade_aggregation_result($grade_category, $correct1, 'Testing aggregation method('.$aggmethodname.') with no items hidden %s');
359         //hide the grade item with grade of 2
360         $grade_items[0]->set_hidden(1, true);
361         $this->helper_test_grade_aggregation_result($grade_category, $correct2, 'Testing aggregation method('.$aggmethodname.') with 1 item hidden %s');
362     }
364     /**
365      * Verify the value of the category grade item for $this->userid
366      * @param grade_category $grade_category the category to be tested
367      * @param int $correctgrade the expected grade
368      * @param string msg The message that should be displayed if the correct grade is not found
369      * @return void
370      */
371     protected function helper_test_grade_aggregation_result($grade_category, $correctgrade, $msg) {
372         global $DB;
374         $category_grade_item = $grade_category->get_grade_item();
376         //this creates all the grade_grades we need
377         grade_regrade_final_grades($this->courseid);
379         $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid));
380         $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
381         $this->assertEquals(intval($correctgrade), intval($grade->finalgrade), $msg);
383         /*
384          * TODO this doesnt work as the grade_grades created by $grade_category->generate_grades(); dont
385          * observe the category's max grade
386         //delete the grade_grades for the category itself and check they get recreated correctly
387         $DB->delete_records('grade_grades', array('itemid'=>$category_grade_item->id));
388         $grade_category->generate_grades();
390         $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid));
391         $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
392         $this->assertEquals(intval($correctgrade), intval($grade->finalgrade), $msg);
393          *
394          */
395     }
397     protected function sub_test_grade_category_aggregate_grades() {
398         $category = new grade_category($this->grade_categories[0]);
399         $this->assertTrue(method_exists($category, 'aggregate_grades'));
400         // tested more fully via test_grade_category_generate_grades()
401     }
403     protected function sub_test_grade_category_apply_limit_rules() {
404         $items[$this->grade_items[0]->id] = new grade_item($this->grade_items[0], false);
405         $items[$this->grade_items[1]->id] = new grade_item($this->grade_items[1], false);
406         $items[$this->grade_items[2]->id] = new grade_item($this->grade_items[2], false);
407         $items[$this->grade_items[4]->id] = new grade_item($this->grade_items[4], false);
409         $category = new grade_category();
410         $category->droplow = 2;
411         $grades = array($this->grade_items[0]->id=>5.374,
412                         $this->grade_items[1]->id=>9.4743,
413                         $this->grade_items[2]->id=>2.5474,
414                         $this->grade_items[4]->id=>7.3754);
415         $category->apply_limit_rules($grades, $items);
416         $this->assertEquals(count($grades), 2);
417         $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
418         $this->assertEquals($grades[$this->grade_items[4]->id], 7.3754);
420         $category = new grade_category();
421         $category->keephigh = 1;
422         $category->droplow = 0;
423         $grades = array($this->grade_items[0]->id=>5.374,
424                         $this->grade_items[1]->id=>9.4743,
425                         $this->grade_items[2]->id=>2.5474,
426                         $this->grade_items[4]->id=>7.3754);
427         $category->apply_limit_rules($grades, $items);
428         $this->assertEquals(count($grades), 1);
429         $grade = reset($grades);
430         $this->assertEquals(9.4743, $grade);
432         $category = new grade_category();
433         $category->droplow     = 2;
434         $category->aggregation = GRADE_AGGREGATE_SUM;
435         $items[$this->grade_items[2]->id]->aggregationcoef = 1;
436         $grades = array($this->grade_items[0]->id=>5.374,
437                         $this->grade_items[1]->id=>9.4743,
438                         $this->grade_items[2]->id=>2.5474,
439                         $this->grade_items[4]->id=>7.3754);
441         $category->apply_limit_rules($grades, $items);
442         $this->assertEquals(count($grades), 2);
443         $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
444         $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474);
446         $category = new grade_category();
447         $category->keephigh = 1;
448         $category->droplow = 0;
449         $category->aggregation = GRADE_AGGREGATE_SUM;
450         $items[$this->grade_items[2]->id]->aggregationcoef = 1;
451         $grades = array($this->grade_items[0]->id=>5.374,
452                         $this->grade_items[1]->id=>9.4743,
453                         $this->grade_items[2]->id=>2.5474,
454                         $this->grade_items[4]->id=>7.3754);
455         $category->apply_limit_rules($grades, $items);
456         $this->assertEquals(count($grades), 2);
457         $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
458         $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474);
459     }
461     /**
462      * TODO implement
463      */
464     protected function sub_test_grade_category_is_aggregationcoef_used() {
466     }
468     protected function sub_test_grade_category_fetch_course_tree() {
469         $category = new grade_category();
470         $this->assertTrue(method_exists($category, 'fetch_course_tree'));
471         //TODO: add some tests
472     }
474     protected function sub_test_grade_category_get_children() {
475         $course_category = grade_category::fetch_course_category($this->courseid);
477         $category = new grade_category($this->grade_categories[0]);
478         $this->assertTrue(method_exists($category, 'get_children'));
480         $children_array = $category->get_children(0);
482         $this->assertTrue(is_array($children_array));
483         $this->assertFalse(empty($children_array[2]));
484         $this->assertFalse(empty($children_array[2]['object']));
485         $this->assertFalse(empty($children_array[2]['children']));
486         $this->assertEquals($this->grade_categories[1]->id, $children_array[2]['object']->id);
487         $this->assertEquals($this->grade_categories[2]->id, $children_array[5]['object']->id);
488         $this->assertEquals($this->grade_items[0]->id, $children_array[2]['children'][3]['object']->id);
489         $this->assertEquals($this->grade_items[1]->id, $children_array[2]['children'][4]['object']->id);
490         $this->assertEquals($this->grade_items[2]->id, $children_array[5]['children'][6]['object']->id);
491     }
493     protected function sub_test_grade_category_load_grade_item() {
494         $category = new grade_category($this->grade_categories[0]);
495         $this->assertTrue(method_exists($category, 'load_grade_item'));
496         $this->assertEquals(null, $category->grade_item);
497         $category->load_grade_item();
498         $this->assertEquals($this->grade_items[3]->id, $category->grade_item->id);
499     }
501     protected function sub_test_grade_category_get_grade_item() {
502         $category = new grade_category($this->grade_categories[0]);
503         $this->assertTrue(method_exists($category, 'get_grade_item'));
504         $grade_item = $category->get_grade_item();
505         $this->assertEquals($this->grade_items[3]->id, $grade_item->id);
506     }
508     protected function sub_test_grade_category_load_parent_category() {
509         $category = new grade_category($this->grade_categories[1]);
510         $this->assertTrue(method_exists($category, 'load_parent_category'));
511         $this->assertEquals(null, $category->parent_category);
512         $category->load_parent_category();
513         $this->assertEquals($this->grade_categories[0]->id, $category->parent_category->id);
514     }
516     protected function sub_test_grade_category_get_parent_category() {
517         $category = new grade_category($this->grade_categories[1]);
518         $this->assertTrue(method_exists($category, 'get_parent_category'));
519         $parent_category = $category->get_parent_category();
520         $this->assertEquals($this->grade_categories[0]->id, $parent_category->id);
521     }
523     protected function sub_test_grade_category_get_name() {
524         $category = new grade_category($this->grade_categories[0]);
525         $this->assertTrue(method_exists($category, 'get_name'));
526         $this->assertEquals($this->grade_categories[0]->fullname, $category->get_name());
527     }
529     protected function sub_test_grade_category_set_parent() {
530         $category = new grade_category($this->grade_categories[1]);
531         $this->assertTrue(method_exists($category, 'set_parent'));
532         // TODO: implement detailed tests
534         $course_category = grade_category::fetch_course_category($this->courseid);
535         $this->assertTrue($category->set_parent($course_category->id));
536         $this->assertEquals($course_category->id, $category->parent);
537     }
539     protected function sub_test_grade_category_get_final() {
540         $category = new grade_category($this->grade_categories[0]);
541         $this->assertTrue(method_exists($category, 'get_final'));
542         $category->load_grade_item();
543         $this->assertEquals($category->get_final(), $category->grade_item->get_final());
544     }
546     protected function sub_test_grade_category_get_sortorder() {
547         $category = new grade_category($this->grade_categories[0]);
548         $this->assertTrue(method_exists($category, 'get_sortorder'));
549         $category->load_grade_item();
550         $this->assertEquals($category->get_sortorder(), $category->grade_item->get_sortorder());
551     }
553     protected function sub_test_grade_category_set_sortorder() {
554         $category = new grade_category($this->grade_categories[0]);
555         $this->assertTrue(method_exists($category, 'set_sortorder'));
556         $category->load_grade_item();
557         $this->assertEquals($category->set_sortorder(10), $category->grade_item->set_sortorder(10));
558     }
560     protected function sub_test_grade_category_move_after_sortorder() {
561         $category = new grade_category($this->grade_categories[0]);
562         $this->assertTrue(method_exists($category, 'move_after_sortorder'));
563         $category->load_grade_item();
564         $this->assertEquals($category->move_after_sortorder(10), $category->grade_item->move_after_sortorder(10));
565     }
567     protected function sub_test_grade_category_is_course_category() {
568         $category = grade_category::fetch_course_category($this->courseid);
569         $this->assertTrue(method_exists($category, 'is_course_category'));
570         $this->assertTrue($category->is_course_category());
571     }
573     protected function sub_test_grade_category_fetch_course_category() {
574         $category = new grade_category();
575         $this->assertTrue(method_exists($category, 'fetch_course_category'));
576         $category = grade_category::fetch_course_category($this->courseid);
577         $this->assertTrue(empty($category->parent));
578     }
579     /**
580      * TODO implement
581      */
582     protected function sub_test_grade_category_is_editable() {
584     }
586     protected function sub_test_grade_category_is_locked() {
587         $category = new grade_category($this->grade_categories[0]);
588         $this->assertTrue(method_exists($category, 'is_locked'));
589         $category->load_grade_item();
590         $this->assertEquals($category->is_locked(), $category->grade_item->is_locked());
591     }
593     protected function sub_test_grade_category_set_locked() {
594         $category = new grade_category($this->grade_categories[0]);
595         $this->assertTrue(method_exists($category, 'set_locked'));
597         //will return false as cannot lock a grade that needs updating
598         $this->assertFalse($category->set_locked(1));
599         grade_regrade_final_grades($this->courseid);
601         //get the category from the db again
602         $category = new grade_category($this->grade_categories[0]);
603         $this->assertTrue($category->set_locked(1));
604     }
606     protected function sub_test_grade_category_is_hidden() {
607         $category = new grade_category($this->grade_categories[0]);
608         $this->assertTrue(method_exists($category, 'is_hidden'));
609         $category->load_grade_item();
610         $this->assertEquals($category->is_hidden(), $category->grade_item->is_hidden());
611     }
613     protected function sub_test_grade_category_set_hidden() {
614         $category = new grade_category($this->grade_categories[0]);
615         $this->assertTrue(method_exists($category, 'set_hidden'));
616         $category->set_hidden(1);
617         $category->load_grade_item();
618         $this->assertEquals(true, $category->grade_item->is_hidden());
619     }
621     //beware: adding a duplicate course category messes up the data in a way that's hard to recover from
622     protected function sub_test_grade_category_insert_course_category() {
623         $grade_category = new grade_category();
624         $this->assertTrue(method_exists($grade_category, 'insert_course_category'));
626         $id = $grade_category->insert_course_category($this->courseid);
627         $this->assertNotNull($id);
628         $this->assertEquals('?', $grade_category->fullname);
629         $this->assertEquals(GRADE_AGGREGATE_WEIGHTED_MEAN2, $grade_category->aggregation);
630         $this->assertEquals("/$id/", $grade_category->path);
631         $this->assertEquals(1, $grade_category->depth);
632         $this->assertNull($grade_category->parent);
633     }
635     protected function generate_random_raw_grade($item, $userid) {
636         $grade = new grade_grade();
637         $grade->itemid = $item->id;
638         $grade->userid = $userid;
639         $grade->grademin = 0;
640         $grade->grademax = 1;
641         $valuetype = "grade$item->gradetype";
642         $grade->rawgrade = rand(0, 1000) / 1000;
643         $grade->insert();
644         return $grade->rawgrade;
645     }