PageRenderTime 79ms CodeModel.GetById 16ms app.highlight 56ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/grade/simpletest/testgradecategory.php

http://github.com/moodle/moodle
PHP | 669 lines | 445 code | 118 blank | 106 comment | 3 complexity | a33a8625dd6b3d5a7e90546004cd2eeb MD5 | raw file
  1<?php
  2
  3///////////////////////////////////////////////////////////////////////////
  4//                                                                       //
  5// NOTICE OF COPYRIGHT                                                   //
  6//                                                                       //
  7// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
  8//          http://moodle.org                                            //
  9//                                                                       //
 10// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
 11//                                                                       //
 12// This program is free software; you can redistribute it and/or modify  //
 13// it under the terms of the GNU General Public License as published by  //
 14// the Free Software Foundation; either version 2 of the License, or     //
 15// (at your option) any later version.                                   //
 16//                                                                       //
 17// This program is distributed in the hope that it will be useful,       //
 18// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
 19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
 20// GNU General Public License for more details:                          //
 21//                                                                       //
 22//          http://www.gnu.org/copyleft/gpl.html                         //
 23//                                                                       //
 24///////////////////////////////////////////////////////////////////////////
 25
 26/**
 27 * Unit tests for grade_category object.
 28 *
 29 * @author nicolas@moodle.com
 30 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 31 * @package moodlecore
 32 */
 33
 34if (!defined('MOODLE_INTERNAL')) {
 35    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
 36}
 37
 38require_once($CFG->libdir.'/simpletest/fixtures/gradetest.php');
 39
 40class grade_category_test extends grade_test {
 41
 42    public function __construct() {
 43        $this->starttime = time();
 44        parent::__construct();
 45    }
 46
 47    public function __destruct() {
 48        $this->endtime = time();
 49        //var_dump($this->endtime-$this->starttime);
 50        
 51        parent::__destruct();
 52    }
 53
 54    function test_grade_category() {
 55        $this->sub_test_grade_category_construct();
 56        $this->sub_test_grade_category_build_path();
 57        $this->sub_test_grade_category_fetch();
 58        $this->sub_test_grade_category_fetch_all();
 59        $this->sub_test_grade_category_update();
 60        $this->sub_test_grade_category_delete();
 61        $this->sub_test_grade_category_insert();
 62        $this->sub_test_grade_category_qualifies_for_regrading();
 63        $this->sub_test_grade_category_force_regrading();
 64        $this->sub_test_grade_category_aggregate_grades();
 65        $this->sub_test_grade_category_apply_limit_rules();
 66        $this->sub_test_grade_category_is_aggregationcoef_used();
 67        $this->sub_test_grade_category_fetch_course_tree();
 68        $this->sub_test_grade_category_get_children();
 69        $this->sub_test_grade_category_load_grade_item();
 70        $this->sub_test_grade_category_get_grade_item();
 71        $this->sub_test_grade_category_load_parent_category();
 72        $this->sub_test_grade_category_get_parent_category();
 73        $this->sub_test_grade_category_get_name();
 74        $this->sub_test_grade_category_set_parent();
 75        $this->sub_test_grade_category_get_final();
 76        $this->sub_test_grade_category_get_sortorder();
 77        $this->sub_test_grade_category_set_sortorder();
 78        $this->sub_test_grade_category_is_editable();
 79        $this->sub_test_grade_category_move_after_sortorder();
 80        $this->sub_test_grade_category_is_course_category();
 81        $this->sub_test_grade_category_fetch_course_category();
 82        $this->sub_test_grade_category_is_locked();
 83        $this->sub_test_grade_category_set_locked();
 84        $this->sub_test_grade_category_is_hidden();
 85        $this->sub_test_grade_category_set_hidden();
 86
 87        //this won't work until MDL-11837 is complete
 88        //$this->sub_test_grade_category_generate_grades();
 89
 90        //do this last as adding a second course category messes up the data
 91        $this->sub_test_grade_category_insert_course_category();
 92    }
 93
 94    //adds 3 new grade categories at various depths
 95    function sub_test_grade_category_construct() {
 96        $course_category = grade_category::fetch_course_category($this->courseid);
 97
 98        $params = new stdClass();
 99
100        $params->courseid = $this->courseid;
101        $params->fullname = 'unittestcategory4';
102
103        $grade_category = new grade_category($params, false);
104        $grade_category->insert();
105        $this->grade_categories[] = $grade_category;
106
107        $this->assertEqual($params->courseid, $grade_category->courseid);
108        $this->assertEqual($params->fullname, $grade_category->fullname);
109        $this->assertEqual(2, $grade_category->depth);
110        $this->assertEqual("/$course_category->id/$grade_category->id/", $grade_category->path);
111        $parentpath = $grade_category->path;
112
113        // Test a child category
114        $params->parent = $grade_category->id;
115        $params->fullname = 'unittestcategory5';
116        $grade_category = new grade_category($params, false);
117        $grade_category->insert();
118        $this->grade_categories[] = $grade_category;
119
120        $this->assertEqual(3, $grade_category->depth);
121        $this->assertEqual($parentpath.$grade_category->id."/", $grade_category->path);
122        $parentpath = $grade_category->path;
123
124        // Test a third depth category
125        $params->parent = $grade_category->id;
126        $params->fullname = 'unittestcategory6';
127        $grade_category = new grade_category($params, false);
128        $grade_category->insert();
129        $this->grade_categories[50] = $grade_category;//going to delete this one later hence the special index
130        
131        $this->assertEqual(4, $grade_category->depth);
132        $this->assertEqual($parentpath.$grade_category->id."/", $grade_category->path);
133    }
134
135    function sub_test_grade_category_build_path() {
136        $grade_category = new grade_category($this->grade_categories[1]);
137        $this->assertTrue(method_exists($grade_category, 'build_path'));
138        $path = grade_category::build_path($grade_category);
139        $this->assertEqual($grade_category->path, $path);
140    }
141
142    function sub_test_grade_category_fetch() {
143        $grade_category = new grade_category();
144        $this->assertTrue(method_exists($grade_category, 'fetch'));
145
146        $grade_category = grade_category::fetch(array('id'=>$this->grade_categories[0]->id));
147        $this->assertEqual($this->grade_categories[0]->id, $grade_category->id);
148        $this->assertEqual($this->grade_categories[0]->fullname, $grade_category->fullname);
149    }
150
151    function sub_test_grade_category_fetch_all() {
152        $grade_category = new grade_category();
153        $this->assertTrue(method_exists($grade_category, 'fetch_all'));
154
155        $grade_categories = grade_category::fetch_all(array('courseid'=>$this->courseid));
156        $this->assertEqual(count($this->grade_categories), count($grade_categories)-1);
157    }
158
159    function sub_test_grade_category_update() {
160        global $DB;
161        $grade_category = new grade_category($this->grade_categories[0]);
162        $this->assertTrue(method_exists($grade_category, 'update'));
163
164        $grade_category->fullname = 'Updated info for this unittest grade_category';
165        $grade_category->path = null; // path must be recalculated if missing
166        $grade_category->depth = null;
167        $grade_category->aggregation = GRADE_AGGREGATE_MAX; // should force regrading
168
169        $grade_item = $grade_category->get_grade_item();
170        $this->assertEqual(0, $grade_item->needsupdate);
171
172        $this->assertTrue($grade_category->update());
173
174        $fullname = $DB->get_field('grade_categories', 'fullname', array('id' => $this->grade_categories[0]->id));
175        $this->assertEqual($grade_category->fullname, $fullname);
176
177        $path = $DB->get_field('grade_categories', 'path', array('id' => $this->grade_categories[0]->id));
178        $this->assertEqual($grade_category->path, $path);
179
180        $depth = $DB->get_field('grade_categories', 'depth', array('id' => $this->grade_categories[0]->id));
181        $this->assertEqual($grade_category->depth, $depth);
182
183        $grade_item = $grade_category->get_grade_item();
184        $this->assertEqual(1, $grade_item->needsupdate);
185    }
186
187    function sub_test_grade_category_delete() {
188        global $DB;
189
190        $grade_category = new grade_category($this->grade_categories[50]);
191        $this->assertTrue(method_exists($grade_category, 'delete'));
192
193        $this->assertTrue($grade_category->delete());
194        $this->assertFalse($DB->get_record('grade_categories', array('id' => $grade_category->id)));
195    }
196
197    function sub_test_grade_category_insert() {
198        $course_category = grade_category::fetch_course_category($this->courseid);
199
200        $grade_category = new grade_category();
201        $this->assertTrue(method_exists($grade_category, 'insert'));
202
203        $grade_category->fullname    = 'unittestcategory4';
204        $grade_category->courseid    = $this->courseid;
205        $grade_category->aggregation = GRADE_AGGREGATE_MEAN;
206        $grade_category->aggregateonlygraded = 1;
207        $grade_category->keephigh    = 100;
208        $grade_category->droplow     = 10;
209        $grade_category->hidden      = 0;
210        $grade_category->parent      = $this->grade_categories[1]->id; //sub_test_grade_category_delete() removed the category at 0
211
212        $grade_category->insert();
213
214        $this->assertEqual('/'.$course_category->id.'/'.$this->grade_categories[1]->parent.'/'.$this->grade_categories[1]->id.'/'.$grade_category->id.'/', $grade_category->path);
215        $this->assertEqual(4, $grade_category->depth);
216
217        $last_grade_category = end($this->grade_categories);
218
219        $this->assertFalse(empty($grade_category->grade_item));
220        $this->assertEqual($grade_category->id, $grade_category->grade_item->iteminstance);
221        $this->assertEqual('category', $grade_category->grade_item->itemtype);
222
223        $this->assertEqual($grade_category->id, $last_grade_category->id + 1);
224        $this->assertFalse(empty($grade_category->timecreated));
225        $this->assertFalse(empty($grade_category->timemodified));
226    }
227
228    function sub_test_grade_category_qualifies_for_regrading() {
229        $grade_category = new grade_category($this->grade_categories[1]);
230        $this->assertTrue(method_exists($grade_category, 'qualifies_for_regrading'));
231        $this->assertFalse($grade_category->qualifies_for_regrading());
232
233        $grade_category->aggregation = GRADE_AGGREGATE_MAX;
234        $this->assertTrue($grade_category->qualifies_for_regrading());
235
236        $grade_category = new grade_category($this->grade_categories[1]);
237        $grade_category->droplow = 99;
238        $this->assertTrue($grade_category->qualifies_for_regrading());
239
240        $grade_category = new grade_category($this->grade_categories[1]);
241        $grade_category->keephigh = 99;
242        $this->assertTrue($grade_category->qualifies_for_regrading());
243    }
244
245    function sub_test_grade_category_force_regrading() {
246        $grade_category = new grade_category($this->grade_categories[1]);
247        $this->assertTrue(method_exists($grade_category, 'force_regrading'));
248
249        $grade_category->load_grade_item();
250        $this->assertEqual(0, $grade_category->grade_item->needsupdate);
251
252        $grade_category->force_regrading();
253
254        $grade_category->grade_item = null;
255        $grade_category->load_grade_item();
256
257        $this->assertEqual(1, $grade_category->grade_item->needsupdate);
258    }
259
260    /**
261     * Tests the calculation of grades using the various aggregation methods with and without hidden grades
262     * This will not work entirely until MDL-11837 is done
263     * @global type $DB 
264     */
265    function sub_test_grade_category_generate_grades() {
266        global $DB;
267
268        //inserting some special grade items to make testing the final grade calculation easier
269        $params->courseid = $this->courseid;
270        $params->fullname = 'unittestgradecalccategory';
271        $params->aggregation = GRADE_AGGREGATE_MEAN;
272        $params->aggregateonlygraded = 0;
273        $grade_category = new grade_category($params, false);
274        $grade_category->insert();
275
276        $this->assertTrue(method_exists($grade_category, 'generate_grades'));
277
278        $grade_category->load_grade_item();
279        $cgi = $grade_category->get_grade_item();
280        $cgi->grademin = 0;
281        $cgi->grademax = 20;//3 grade items out of 10 but category is out of 20 to force scaling to occur
282        $cgi->update();
283
284        //3 grade items each with a maximum grade of 10
285        $grade_items = array();
286        for ($i=0; $i<3; $i++) {
287            $grade_items[$i] = new grade_item();
288            $grade_items[$i]->courseid = $this->courseid;
289            $grade_items[$i]->categoryid = $grade_category->id;
290            $grade_items[$i]->itemname = 'manual grade_item '.$i;
291            $grade_items[$i]->itemtype = 'manual';
292            $grade_items[$i]->itemnumber = 0;
293            $grade_items[$i]->needsupdate = false;
294            $grade_items[$i]->gradetype = GRADE_TYPE_VALUE;
295            $grade_items[$i]->grademin = 0;
296            $grade_items[$i]->grademax = 10;
297            $grade_items[$i]->iteminfo = 'Manual grade item used for unit testing';
298            $grade_items[$i]->timecreated = mktime();
299            $grade_items[$i]->timemodified = mktime();
300            
301            //used as the weight by weighted mean and as extra credit by mean with extra credit
302            //Will be 0, 1 and 2
303            $grade_items[$i]->aggregationcoef = $i;
304            
305            $grade_items[$i]->insert();
306        }
307
308        //a grade for each grade item
309        $grade_grades = array();
310        for ($i=0; $i<3; $i++) {
311            $grade_grades[$i] = new grade_grade();
312            $grade_grades[$i]->itemid = $grade_items[$i]->id;
313            $grade_grades[$i]->userid = $this->userid;
314            $grade_grades[$i]->rawgrade = ($i+1)*2;//produce grade grades of 2, 4 and 6
315            $grade_grades[$i]->finalgrade = ($i+1)*2;
316            $grade_grades[$i]->timecreated = mktime();
317            $grade_grades[$i]->timemodified = mktime();
318            $grade_grades[$i]->information = '1 of 2 grade_grades';
319            $grade_grades[$i]->informationformat = FORMAT_PLAIN;
320            $grade_grades[$i]->feedback = 'Good, but not good enough..';
321            $grade_grades[$i]->feedbackformat = FORMAT_PLAIN;
322
323            $grade_grades[$i]->insert();
324        }
325
326        //3 grade items with 1 grade_grade each.
327        //grade grades have the values 2, 4 and 6
328        
329        //First correct answer is the aggregate with all 3 grades
330        //Second correct answer is with the first grade (value 2) hidden
331        
332        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEDIAN, 'GRADE_AGGREGATE_MEDIAN', 8, 8);
333        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MAX, 'GRADE_AGGREGATE_MAX', 12, 12);
334        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MODE, 'GRADE_AGGREGATE_MODE', 12, 12);
335        
336        //weighted mean. note grade totals are rounded to an int to prevent rounding discrepancies. correct final grade isnt actually exactly 10
337        //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.
338        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN, 'GRADE_AGGREGATE_WEIGHTED_MEAN', 10, 10);
339
340        //simple weighted mean
341        //3 items with grades 2, 4 and 6 equally weighted and all out of 10. then doubled to be out of 20.
342        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_WEIGHTED_MEAN2, 'GRADE_AGGREGATE_WEIGHTED_MEAN2', 8, 10);
343
344        //mean of grades with extra credit
345        //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.
346        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_EXTRACREDIT_MEAN, 'GRADE_AGGREGATE_EXTRACREDIT_MEAN', 10, 13);
347        
348        //aggregation tests the are affected by a hidden grade currently dont work as we dont store the altered grade in the database
349        //instead an in memory recalculation is done. This should be remedied by MDL-11837
350
351        //fails with 1 grade hidden. still reports 8 as being correct
352        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MEAN, 'GRADE_AGGREGATE_MEAN', 8, 10);
353        
354        //fails with 1 grade hidden. still reports 4 as being correct
355        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_MIN, 'GRADE_AGGREGATE_MIN', 4, 8);
356        
357        //fails with 1 grade hidden. still reports 12 as being correct
358        $this->helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, GRADE_AGGREGATE_SUM, 'GRADE_AGGREGATE_SUM', 12, 10);
359    }
360
361    /**
362     * Test grade category aggregation using the supplied grade objects and aggregation method
363     * @param grade_category $grade_category the category to be tested
364     * @param array $grade_items array of instance of grade_item
365     * @param array $grade_grades array of instances of grade_grade
366     * @param int $aggmethod the aggregation method to apply ie GRADE_AGGREGATE_MEAN
367     * @param string $aggmethodname the name of the aggregation method to apply. Used to display any test failure messages
368     * @param int $correct1 the correct final grade for the category with NO items hidden
369     * @param int $correct2 the correct final grade for the category with the grade at $grade_grades[0] hidden
370     * @return void
371    */
372    function helper_test_grade_agg_method($grade_category, $grade_items, $grade_grades, $aggmethod, $aggmethodname, $correct1, $correct2) {
373        global $DB;
374
375        $grade_category->aggregation = $aggmethod;
376        $grade_category->update();
377
378        //check grade_item isnt hidden from a previous test
379        $grade_items[0]->set_hidden(0, true);
380        $this->helper_test_grade_aggregation_result($grade_category, $correct1, 'Testing aggregation method('.$aggmethodname.') with no items hidden %s');
381
382        //hide the grade item with grade of 2
383        $grade_items[0]->set_hidden(1, true);
384        $this->helper_test_grade_aggregation_result($grade_category, $correct2, 'Testing aggregation method('.$aggmethodname.') with 1 item hidden %s');
385    }
386
387    /**
388     * Verify the value of the category grade item for $this->userid
389     * @param grade_category $grade_category the category to be tested
390     * @param int $correctgrade the expected grade
391     * @param string msg The message that should be displayed if the correct grade is not found
392     * @return void
393     */
394    function helper_test_grade_aggregation_result($grade_category, $correctgrade, $msg) {
395        global $DB;
396        
397        $category_grade_item = $grade_category->get_grade_item();
398        
399        //this creates all the grade_grades we need
400        grade_regrade_final_grades($this->courseid);
401        
402        $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid));
403        $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
404        $this->assertEqual(intval($correctgrade), intval($grade->finalgrade), $msg);
405        
406        /*
407         * TODO this doesnt work as the grade_grades created by $grade_category->generate_grades(); dont
408         * observe the category's max grade
409        //delete the grade_grades for the category itself and check they get recreated correctly
410        $DB->delete_records('grade_grades', array('itemid'=>$category_grade_item->id));
411        $grade_category->generate_grades();
412        
413        $grade = $DB->get_record('grade_grades', array('itemid'=>$category_grade_item->id, 'userid'=>$this->userid));
414        $this->assertWithinMargin($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
415        $this->assertEqual(intval($correctgrade), intval($grade->finalgrade), $msg);
416         * 
417         */
418    }
419
420    function sub_test_grade_category_aggregate_grades() {
421        $category = new grade_category($this->grade_categories[0]);
422        $this->assertTrue(method_exists($category, 'aggregate_grades'));
423        // tested more fully via test_grade_category_generate_grades()
424    }
425
426    function sub_test_grade_category_apply_limit_rules() {
427        $items[$this->grade_items[0]->id] = new grade_item($this->grade_items[0], false);
428        $items[$this->grade_items[1]->id] = new grade_item($this->grade_items[1], false);
429        $items[$this->grade_items[2]->id] = new grade_item($this->grade_items[2], false);
430        $items[$this->grade_items[4]->id] = new grade_item($this->grade_items[4], false);
431
432        $category = new grade_category();
433        $category->droplow = 2;
434        $grades = array($this->grade_items[0]->id=>5.374,
435                        $this->grade_items[1]->id=>9.4743,
436                        $this->grade_items[2]->id=>2.5474,
437                        $this->grade_items[4]->id=>7.3754);
438        $category->apply_limit_rules($grades, $items);
439        $this->assertEqual(count($grades), 2);
440        $this->assertEqual($grades[$this->grade_items[1]->id], 9.4743);
441        $this->assertEqual($grades[$this->grade_items[4]->id], 7.3754);
442
443        $category = new grade_category();
444        $category->keephigh = 1;
445        $category->droplow = 0;
446        $grades = array($this->grade_items[0]->id=>5.374,
447                        $this->grade_items[1]->id=>9.4743,
448                        $this->grade_items[2]->id=>2.5474,
449                        $this->grade_items[4]->id=>7.3754);
450        $category->apply_limit_rules($grades, $items);
451        $this->assertEqual(count($grades), 1);
452        $grade = reset($grades);
453        $this->assertEqual(9.4743, $grade);
454
455        $category = new grade_category();
456        $category->droplow     = 2;
457        $category->aggregation = GRADE_AGGREGATE_SUM;
458        $items[$this->grade_items[2]->id]->aggregationcoef = 1;
459        $grades = array($this->grade_items[0]->id=>5.374,
460                        $this->grade_items[1]->id=>9.4743,
461                        $this->grade_items[2]->id=>2.5474,
462                        $this->grade_items[4]->id=>7.3754);
463
464        $category->apply_limit_rules($grades, $items);
465        $this->assertEqual(count($grades), 2);
466        $this->assertEqual($grades[$this->grade_items[1]->id], 9.4743);
467        $this->assertEqual($grades[$this->grade_items[2]->id], 2.5474);
468
469        $category = new grade_category();
470        $category->keephigh = 1;
471        $category->droplow = 0;
472        $category->aggregation = GRADE_AGGREGATE_SUM;
473        $items[$this->grade_items[2]->id]->aggregationcoef = 1;
474        $grades = array($this->grade_items[0]->id=>5.374,
475                        $this->grade_items[1]->id=>9.4743,
476                        $this->grade_items[2]->id=>2.5474,
477                        $this->grade_items[4]->id=>7.3754);
478        $category->apply_limit_rules($grades, $items);
479        $this->assertEqual(count($grades), 2);
480        $this->assertEqual($grades[$this->grade_items[1]->id], 9.4743);
481        $this->assertEqual($grades[$this->grade_items[2]->id], 2.5474);
482    }
483
484    /**
485     * TODO implement
486     */
487    function sub_test_grade_category_is_aggregationcoef_used() {
488
489    }
490
491    function sub_test_grade_category_fetch_course_tree() {
492        $category = new grade_category();
493        $this->assertTrue(method_exists($category, 'fetch_course_tree'));
494        //TODO: add some tests
495    }
496
497    function sub_test_grade_category_get_children() {
498        $course_category = grade_category::fetch_course_category($this->courseid);
499
500        $category = new grade_category($this->grade_categories[0]);
501        $this->assertTrue(method_exists($category, 'get_children'));
502
503        $children_array = $category->get_children(0);
504
505        $this->assertTrue(is_array($children_array));
506        $this->assertFalse(empty($children_array[2]));
507        $this->assertFalse(empty($children_array[2]['object']));
508        $this->assertFalse(empty($children_array[2]['children']));
509        $this->assertEqual($this->grade_categories[1]->id, $children_array[2]['object']->id);
510        $this->assertEqual($this->grade_categories[2]->id, $children_array[5]['object']->id);
511        $this->assertEqual($this->grade_items[0]->id, $children_array[2]['children'][3]['object']->id);
512        $this->assertEqual($this->grade_items[1]->id, $children_array[2]['children'][4]['object']->id);
513        $this->assertEqual($this->grade_items[2]->id, $children_array[5]['children'][6]['object']->id);
514    }
515
516    function sub_test_grade_category_load_grade_item() {
517        $category = new grade_category($this->grade_categories[0]);
518        $this->assertTrue(method_exists($category, 'load_grade_item'));
519        $this->assertEqual(null, $category->grade_item);
520        $category->load_grade_item();
521        $this->assertEqual($this->grade_items[3]->id, $category->grade_item->id);
522    }
523
524    function sub_test_grade_category_get_grade_item() {
525        $category = new grade_category($this->grade_categories[0]);
526        $this->assertTrue(method_exists($category, 'get_grade_item'));
527        $grade_item = $category->get_grade_item();
528        $this->assertEqual($this->grade_items[3]->id, $grade_item->id);
529    }
530
531    function sub_test_grade_category_load_parent_category() {
532        $category = new grade_category($this->grade_categories[1]);
533        $this->assertTrue(method_exists($category, 'load_parent_category'));
534        $this->assertEqual(null, $category->parent_category);
535        $category->load_parent_category();
536        $this->assertEqual($this->grade_categories[0]->id, $category->parent_category->id);
537    }
538
539    function sub_test_grade_category_get_parent_category() {
540        $category = new grade_category($this->grade_categories[1]);
541        $this->assertTrue(method_exists($category, 'get_parent_category'));
542        $parent_category = $category->get_parent_category();
543        $this->assertEqual($this->grade_categories[0]->id, $parent_category->id);
544    }
545
546    function sub_test_grade_category_get_name() {
547        $category = new grade_category($this->grade_categories[0]);
548        $this->assertTrue(method_exists($category, 'get_name'));
549        $this->assertEqual($this->grade_categories[0]->fullname, $category->get_name());
550    }
551
552    function sub_test_grade_category_set_parent() {
553        $category = new grade_category($this->grade_categories[1]);
554        $this->assertTrue(method_exists($category, 'set_parent'));
555        // TODO: implement detailed tests
556
557        $course_category = grade_category::fetch_course_category($this->courseid);
558        $this->assertTrue($category->set_parent($course_category->id));
559        $this->assertEqual($course_category->id, $category->parent);
560    }
561
562    function sub_test_grade_category_get_final() {
563        $category = new grade_category($this->grade_categories[0]);
564        $this->assertTrue(method_exists($category, 'get_final'));
565        $category->load_grade_item();
566        $this->assertEqual($category->get_final(), $category->grade_item->get_final());
567    }
568
569    function sub_test_grade_category_get_sortorder() {
570        $category = new grade_category($this->grade_categories[0]);
571        $this->assertTrue(method_exists($category, 'get_sortorder'));
572        $category->load_grade_item();
573        $this->assertEqual($category->get_sortorder(), $category->grade_item->get_sortorder());
574    }
575
576    function sub_test_grade_category_set_sortorder() {
577        $category = new grade_category($this->grade_categories[0]);
578        $this->assertTrue(method_exists($category, 'set_sortorder'));
579        $category->load_grade_item();
580        $this->assertEqual($category->set_sortorder(10), $category->grade_item->set_sortorder(10));
581    }
582
583    function sub_test_grade_category_move_after_sortorder() {
584        $category = new grade_category($this->grade_categories[0]);
585        $this->assertTrue(method_exists($category, 'move_after_sortorder'));
586        $category->load_grade_item();
587        $this->assertEqual($category->move_after_sortorder(10), $category->grade_item->move_after_sortorder(10));
588    }
589
590    function sub_test_grade_category_is_course_category() {
591        $category = grade_category::fetch_course_category($this->courseid);
592        $this->assertTrue(method_exists($category, 'is_course_category'));
593        $this->assertTrue($category->is_course_category());
594    }
595
596    function sub_test_grade_category_fetch_course_category() {
597        $category = new grade_category();
598        $this->assertTrue(method_exists($category, 'fetch_course_category'));
599        $category = grade_category::fetch_course_category($this->courseid);
600        $this->assertTrue(empty($category->parent));
601    }
602    /**
603     * TODO implement
604     */
605    function sub_test_grade_category_is_editable() {
606
607    }
608
609    function sub_test_grade_category_is_locked() {
610        $category = new grade_category($this->grade_categories[0]);
611        $this->assertTrue(method_exists($category, 'is_locked'));
612        $category->load_grade_item();
613        $this->assertEqual($category->is_locked(), $category->grade_item->is_locked());
614    }
615
616    function sub_test_grade_category_set_locked() {
617        $category = new grade_category($this->grade_categories[0]);
618        $this->assertTrue(method_exists($category, 'set_locked'));
619
620        //will return false as cannot lock a grade that needs updating
621        $this->assertFalse($category->set_locked(1));
622        grade_regrade_final_grades($this->courseid);
623
624        //get the category from the db again
625        $category = new grade_category($this->grade_categories[0]);
626        $this->assertTrue($category->set_locked(1));
627    }
628
629    function sub_test_grade_category_is_hidden() {
630        $category = new grade_category($this->grade_categories[0]);
631        $this->assertTrue(method_exists($category, 'is_hidden'));
632        $category->load_grade_item();
633        $this->assertEqual($category->is_hidden(), $category->grade_item->is_hidden());
634    }
635
636    function sub_test_grade_category_set_hidden() {
637        $category = new grade_category($this->grade_categories[0]);
638        $this->assertTrue(method_exists($category, 'set_hidden'));
639        $category->set_hidden(1);
640        $category->load_grade_item();
641        $this->assertEqual(true, $category->grade_item->is_hidden());
642    }
643
644    //beware: adding a duplicate course category messes up the data in a way that's hard to recover from
645    function sub_test_grade_category_insert_course_category() {
646        $grade_category = new grade_category();
647        $this->assertTrue(method_exists($grade_category, 'insert_course_category'));
648
649        $id = $grade_category->insert_course_category($this->courseid);
650        $this->assertNotNull($id);
651        $this->assertEqual('?', $grade_category->fullname);
652        $this->assertEqual(GRADE_AGGREGATE_WEIGHTED_MEAN2, $grade_category->aggregation);
653        $this->assertEqual("/$id/", $grade_category->path);
654        $this->assertEqual(1, $grade_category->depth);
655        $this->assertNull($grade_category->parent);
656    }
657
658    function generate_random_raw_grade($item, $userid) {
659        $grade = new grade_grade();
660        $grade->itemid = $item->id;
661        $grade->userid = $userid;
662        $grade->grademin = 0;
663        $grade->grademax = 1;
664        $valuetype = "grade$item->gradetype";
665        $grade->rawgrade = rand(0, 1000) / 1000;
666        $grade->insert();
667        return $grade->rawgrade;
668    }
669}