Merge branch 'master_MDL-47431' of https://github.com/danmarsden/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';
69         $data->grade = array();
70         $data->grade[$student->id] = array();
71         $data->grade[$student->id][$forum1->id] = $testgrade;
73         $warnings = $report->process_data($data);
74         $this->assertEquals(count($warnings), 0);
76         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
77         $this->assertEquals($studentgrade->finalgrade, $testgrade);
79         // Grade above max. Should be pulled down to max.
80         $toobig = 200.00;
81         $data->grade[$student->id][$forum1->id] = $toobig;
82         $warnings = $report->process_data($data);
83         $this->assertEquals(count($warnings), 1);
85         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
86         $this->assertEquals($studentgrade->finalgrade, $forummax);
88         // Grade below min. Should be pulled up to min.
89         $toosmall = -10.00;
90         $data->grade[$student->id][$forum1->id] = $toosmall;
91         $warnings = $report->process_data($data);
92         $this->assertEquals(count($warnings), 1);
94         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
95         $this->assertEquals($studentgrade->finalgrade, 0);
97         // Test unlimited grades so we can give a student a grade about max.
98         $CFG->unlimitedgrades = 1;
100         $data->grade[$student->id][$forum1->id] = $toobig;
101         $warnings = $report->process_data($data);
102         $this->assertEquals(count($warnings), 0);
104         $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id));
105         $this->assertEquals($studentgrade->finalgrade, $toobig);
106     }
108     public function test_collapsed_preferences() {
109         $this->resetAfterTest(true);
111         $emptypreferences = array('aggregatesonly' => array(), 'gradesonly' => array());
113         $user1 = $this->getDataGenerator()->create_user();
114         $course1 = $this->getDataGenerator()->create_course();
115         $course2 = $this->getDataGenerator()->create_course();
116         $course3 = $this->getDataGenerator()->create_course();
118         $this->setUser($user1);
120         $report = $this->create_report($course1);
121         $this->assertEquals($emptypreferences, $report->collapsed);
123         // Validating preferences set/get for one course.
124         $report->process_action('cg13', 'switch_minus');
125         $report = $this->create_report($course1);
126         $this->assertEquals(array(13), $report->collapsed['aggregatesonly']);
127         $this->assertEmpty($report->collapsed['gradesonly']);
129         $report->process_action('cg13', 'switch_plus');
130         $report = $this->create_report($course1);
131         $this->assertEmpty($report->collapsed['aggregatesonly']);
132         $this->assertEquals(array(13), $report->collapsed['gradesonly']);
134         $report->process_action('cg13', 'switch_whole');
135         $report = $this->create_report($course1);
136         $this->assertEquals($emptypreferences, $report->collapsed);
138         // Validating preferences set/get for several courses.
140         $course1cats = $course2cats = $course3cats = array();
141         for ($i=0;$i<10;$i++) {
142             $course1cats[] = $this->create_grade_category($course1)->id;
143             $course2cats[] = $this->create_grade_category($course2)->id;
144             $course3cats[] = $this->create_grade_category($course3)->id;
145         }
147         $report1 = $this->create_report($course1);
148         foreach ($course1cats as $catid) {
149             $report1->process_action('cg'.$catid, 'switch_minus');
150         }
151         $report2 = $this->create_report($course2);
152         foreach ($course2cats as $catid) {
153             $report2->process_action('cg'.$catid, 'switch_minus');
154             $report2->process_action('cg'.$catid, 'switch_plus');
155         }
156         $report3 = $this->create_report($course3);
157         foreach ($course3cats as $catid) {
158             $report3->process_action('cg'.$catid, 'switch_minus');
159             if (($i++)%2) {
160                 $report3->process_action('cg'.$catid, 'switch_plus');
161             }
162         }
164         $report1 = $this->create_report($course1);
165         $this->assertEquals(10, count($report1->collapsed['aggregatesonly']));
166         $this->assertEquals(0, count($report1->collapsed['gradesonly']));
167         $report2 = $this->create_report($course2);
168         $this->assertEquals(0, count($report2->collapsed['aggregatesonly']));
169         $this->assertEquals(10, count($report2->collapsed['gradesonly']));
170         $report3 = $this->create_report($course3);
171         $this->assertEquals(5, count($report3->collapsed['aggregatesonly']));
172         $this->assertEquals(5, count($report3->collapsed['gradesonly']));
174         // Test upgrade script.
175         // Combine data generated for user1 and set it in the old format for user2, Try to retrieve it and make sure it is converted.
177         $user2 = $this->getDataGenerator()->create_user();
178         $alldata = array(
179             'aggregatesonly' => array_merge($report1->collapsed['aggregatesonly'], $report2->collapsed['aggregatesonly'], $report3->collapsed['aggregatesonly']),
180             'gradesonly' => array_merge($report1->collapsed['gradesonly'], $report2->collapsed['gradesonly'], $report3->collapsed['gradesonly']),
181         );
182         set_user_preference('grade_report_grader_collapsed_categories', serialize($alldata), $user2);
184         $this->setUser($user2);
185         $convertedreport1 = $this->create_report($course1);
186         $this->assertEquals($report1->collapsed, $convertedreport1->collapsed);
187         $convertedreport2 = $this->create_report($course2);
188         $this->assertEquals($report2->collapsed, $convertedreport2->collapsed);
189         $convertedreport3 = $this->create_report($course3);
190         $this->assertEquals($report3->collapsed, $convertedreport3->collapsed);
191         // Make sure the old style user preference is removed now.
192         $this->assertEmpty(get_user_preferences('grade_report_grader_collapsed_categories'));
194         // Test overflowing the setting with non-existing categories (only validated if new setting size exceeds 1333 chars).
196         $toobigvalue = $expectedvalue = $report1->collapsed;
197         for ($i = 0; strlen(json_encode($toobigvalue)) < 1333; $i++) {
198             $toobigvalue[($i < 7) ? 'gradesonly' : 'aggregatesonly'][] = $course1cats[9] + 1 + $i;
199         }
200         $lastvalue = array_pop($toobigvalue['gradesonly']);
201         set_user_preference('grade_report_grader_collapsed_categories'.$course1->id, json_encode($toobigvalue));
203         $report1 = $this->create_report($course1);
204         $report1->process_action('cg'.$lastvalue, 'switch_minus');
206         $report1 = $this->create_report($course1);
207         $this->assertEquals($expectedvalue, $report1->collapsed);
209         // Test overflowing the setting with existing categories.
211         $toobigvalue = $report1->collapsed;
212         for ($i = 0; strlen(json_encode($toobigvalue)) < 1333; $i++) {
213             $catid = $this->create_grade_category($course1)->id;
214             $toobigvalue[($i < 7) ? 'gradesonly' : 'aggregatesonly'][] = $catid;
215         }
216         $lastcatid = array_pop($toobigvalue['gradesonly']);
217         set_user_preference('grade_report_grader_collapsed_categories'.$course1->id, json_encode($toobigvalue));
218         $toobigvalue['aggregatesonly'][] = $lastcatid;
220         $report1 = $this->create_report($course1);
221         $report1->process_action('cg'.$lastcatid, 'switch_minus');
223         // One last value should be removed from both arrays.
224         $report1 = $this->create_report($course1);
225         $this->assertEquals(count($toobigvalue['aggregatesonly']) - 1, count($report1->collapsed['aggregatesonly']));
226         $this->assertEquals(count($toobigvalue['gradesonly']) - 1, count($report1->collapsed['gradesonly']));
227     }
229     private function create_grade_category($course) {
230         static $cnt = 0;
231         $cnt++;
232         $grade_category = new grade_category(array('courseid' => $course->id, 'fullname' => 'Cat '.$cnt), false);
233         $grade_category->apply_default_settings();
234         $grade_category->apply_forced_settings();
235         $grade_category->insert();
236         return $grade_category;
237     }
239     private function create_report($course) {
241         $coursecontext = context_course::instance($course->id);
242         $gpr = new grade_plugin_return(array('type' => 'report', 'plugin'=>'grader', 'courseid' => $course->id));
243         $report = new grade_report_grader($course->id, $gpr, $coursecontext);
245         return $report;
246     }