Merge branch 'MDL-38732-master-2nd' of git://github.com/FMCorz/moodle
[moodle.git] / grade / tests / report_graderlib_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  * Unit tests for grade/report/user/lib.php.
19  *
20  * @package  core_grade
21  * @category phpunit
22  * @copyright 2012 Andrew Davis
23  * @license  http://www.gnu.org/copyleft/gpl.html GNU Public License
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot.'/grade/lib.php');
30 require_once($CFG->dirroot.'/grade/report/grader/lib.php');
32 /**
33  * Tests grade_report_grader (the grader report)
34  */
35 class core_grade_report_graderlib_testcase extends advanced_testcase {
37     /**
38      * Tests grade_report_grader::process_data()
39      *
40      * process_data() processes submitted grade and feedback data
41      */
42     public function test_process_data() {
43         global $DB, $CFG;
45         $this->resetAfterTest(true);
47         $course = $this->getDataGenerator()->create_course();
49         // Create and enrol a student.
50         $student = $this->getDataGenerator()->create_user(array('username' => 'Student Sam'));
51         $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
52         $this->getDataGenerator()->enrol_user($student->id, $course->id, $role->id);
54         // Test with limited grades.
55         $CFG->unlimitedgrades = 0;
57         $forummax = 80;
58         $forum1 = $this->getDataGenerator()->create_module('forum', array('assessed' => 1, 'scale' => $forummax, 'course' => $course->id));
59         // Switch the stdClass instance for a grade item instance.
60         $forum1 = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum1->id, 'courseid' => $course->id));
62         $report = $this->create_report($course);
63         $testgrade = 60.00;
65         $data = new stdClass();
66         $data->id = $course->id;
67         $data->report = 'grader';
68         $data->timepageload = time();
70         $data->grade = array();
71         $data->grade[$student->id] = array();
72         $data->grade[$student->id][$forum1->id] = $testgrade;
74         $warnings = $report->process_data($data);
75         $this->assertEquals(count($warnings), 0);
77         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
78         $this->assertEquals($studentgrade->finalgrade, $testgrade);
80         // Grade above max. Should be pulled down to max.
81         $toobig = 200.00;
82         $data->grade[$student->id][$forum1->id] = $toobig;
83         $warnings = $report->process_data($data);
84         $this->assertEquals(count($warnings), 1);
86         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
87         $this->assertEquals($studentgrade->finalgrade, $forummax);
89         // Grade below min. Should be pulled up to min.
90         $toosmall = -10.00;
91         $data->grade[$student->id][$forum1->id] = $toosmall;
92         $warnings = $report->process_data($data);
93         $this->assertEquals(count($warnings), 1);
95         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
96         $this->assertEquals($studentgrade->finalgrade, 0);
98         // Test unlimited grades so we can give a student a grade about max.
99         $CFG->unlimitedgrades = 1;
101         $data->grade[$student->id][$forum1->id] = $toobig;
102         $warnings = $report->process_data($data);
103         $this->assertEquals(count($warnings), 0);
105         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
106         $this->assertEquals($studentgrade->finalgrade, $toobig);
107     }
109     public function test_collapsed_preferences() {
110         $this->resetAfterTest(true);
112         $emptypreferences = array('aggregatesonly' => array(), 'gradesonly' => array());
114         $user1 = $this->getDataGenerator()->create_user();
115         $course1 = $this->getDataGenerator()->create_course();
116         $course2 = $this->getDataGenerator()->create_course();
117         $course3 = $this->getDataGenerator()->create_course();
119         $this->setUser($user1);
121         $report = $this->create_report($course1);
122         $this->assertEquals($emptypreferences, $report->collapsed);
124         // Validating preferences set/get for one course.
125         $report->process_action('cg13', 'switch_minus');
126         $report = $this->create_report($course1);
127         $this->assertEquals(array(13), $report->collapsed['aggregatesonly']);
128         $this->assertEmpty($report->collapsed['gradesonly']);
130         $report->process_action('cg13', 'switch_plus');
131         $report = $this->create_report($course1);
132         $this->assertEmpty($report->collapsed['aggregatesonly']);
133         $this->assertEquals(array(13), $report->collapsed['gradesonly']);
135         $report->process_action('cg13', 'switch_whole');
136         $report = $this->create_report($course1);
137         $this->assertEquals($emptypreferences, $report->collapsed);
139         // Validating preferences set/get for several courses.
141         $course1cats = $course2cats = $course3cats = array();
142         for ($i=0;$i<10;$i++) {
143             $course1cats[] = $this->create_grade_category($course1)->id;
144             $course2cats[] = $this->create_grade_category($course2)->id;
145             $course3cats[] = $this->create_grade_category($course3)->id;
146         }
148         $report1 = $this->create_report($course1);
149         foreach ($course1cats as $catid) {
150             $report1->process_action('cg'.$catid, 'switch_minus');
151         }
152         $report2 = $this->create_report($course2);
153         foreach ($course2cats as $catid) {
154             $report2->process_action('cg'.$catid, 'switch_minus');
155             $report2->process_action('cg'.$catid, 'switch_plus');
156         }
157         $report3 = $this->create_report($course3);
158         foreach ($course3cats as $catid) {
159             $report3->process_action('cg'.$catid, 'switch_minus');
160             if (($i++)%2) {
161                 $report3->process_action('cg'.$catid, 'switch_plus');
162             }
163         }
165         $report1 = $this->create_report($course1);
166         $this->assertEquals(10, count($report1->collapsed['aggregatesonly']));
167         $this->assertEquals(0, count($report1->collapsed['gradesonly']));
168         $report2 = $this->create_report($course2);
169         $this->assertEquals(0, count($report2->collapsed['aggregatesonly']));
170         $this->assertEquals(10, count($report2->collapsed['gradesonly']));
171         $report3 = $this->create_report($course3);
172         $this->assertEquals(5, count($report3->collapsed['aggregatesonly']));
173         $this->assertEquals(5, count($report3->collapsed['gradesonly']));
175         // Test upgrade script.
176         // Combine data generated for user1 and set it in the old format for user2, Try to retrieve it and make sure it is converted.
178         $user2 = $this->getDataGenerator()->create_user();
179         $alldata = array(
180             'aggregatesonly' => array_merge($report1->collapsed['aggregatesonly'], $report2->collapsed['aggregatesonly'], $report3->collapsed['aggregatesonly']),
181             'gradesonly' => array_merge($report1->collapsed['gradesonly'], $report2->collapsed['gradesonly'], $report3->collapsed['gradesonly']),
182         );
183         set_user_preference('grade_report_grader_collapsed_categories', serialize($alldata), $user2);
185         $this->setUser($user2);
186         $convertedreport1 = $this->create_report($course1);
187         $this->assertEquals($report1->collapsed, $convertedreport1->collapsed);
188         $convertedreport2 = $this->create_report($course2);
189         $this->assertEquals($report2->collapsed, $convertedreport2->collapsed);
190         $convertedreport3 = $this->create_report($course3);
191         $this->assertEquals($report3->collapsed, $convertedreport3->collapsed);
192         // Make sure the old style user preference is removed now.
193         $this->assertEmpty(get_user_preferences('grade_report_grader_collapsed_categories'));
195         // Test overflowing the setting with non-existing categories (only validated if new setting size exceeds 1333 chars).
197         $toobigvalue = $expectedvalue = $report1->collapsed;
198         for ($i = 0; strlen(json_encode($toobigvalue)) < 1333; $i++) {
199             $toobigvalue[($i < 7) ? 'gradesonly' : 'aggregatesonly'][] = $course1cats[9] + 1 + $i;
200         }
201         $lastvalue = array_pop($toobigvalue['gradesonly']);
202         set_user_preference('grade_report_grader_collapsed_categories'.$course1->id, json_encode($toobigvalue));
204         $report1 = $this->create_report($course1);
205         $report1->process_action('cg'.$lastvalue, 'switch_minus');
207         $report1 = $this->create_report($course1);
208         $this->assertEquals($expectedvalue, $report1->collapsed);
210         // Test overflowing the setting with existing categories.
212         $toobigvalue = $report1->collapsed;
213         for ($i = 0; strlen(json_encode($toobigvalue)) < 1333; $i++) {
214             $catid = $this->create_grade_category($course1)->id;
215             $toobigvalue[($i < 7) ? 'gradesonly' : 'aggregatesonly'][] = $catid;
216         }
217         $lastcatid = array_pop($toobigvalue['gradesonly']);
218         set_user_preference('grade_report_grader_collapsed_categories'.$course1->id, json_encode($toobigvalue));
219         $toobigvalue['aggregatesonly'][] = $lastcatid;
221         $report1 = $this->create_report($course1);
222         $report1->process_action('cg'.$lastcatid, 'switch_minus');
224         // One last value should be removed from both arrays.
225         $report1 = $this->create_report($course1);
226         $this->assertEquals(count($toobigvalue['aggregatesonly']) - 1, count($report1->collapsed['aggregatesonly']));
227         $this->assertEquals(count($toobigvalue['gradesonly']) - 1, count($report1->collapsed['gradesonly']));
228     }
230     private function create_grade_category($course) {
231         static $cnt = 0;
232         $cnt++;
233         $grade_category = new grade_category(array('courseid' => $course->id, 'fullname' => 'Cat '.$cnt), false);
234         $grade_category->apply_default_settings();
235         $grade_category->apply_forced_settings();
236         $grade_category->insert();
237         return $grade_category;
238     }
240     private function create_report($course) {
242         $coursecontext = context_course::instance($course->id);
243         $gpr = new grade_plugin_return(array('type' => 'report', 'plugin'=>'grader', 'courseid' => $course->id));
244         $report = new grade_report_grader($course->id, $gpr, $coursecontext);
246         return $report;
247     }