Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
declare(strict_types = 1);
18
 
19
namespace core_grades\grades\grader\gradingpanel\point\external;
20
 
21
use advanced_testcase;
22
use coding_exception;
23
use core_grades\component_gradeitem;
24
use core_external\external_api;
25
use mod_forum\local\entities\forum as forum_entity;
26
use moodle_exception;
27
use grade_grade;
28
use grade_item;
29
 
30
/**
31
 * Unit tests for core_grades\component_gradeitems;
32
 *
33
 * @package   core_grades
34
 * @category  test
35
 * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
36
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 */
38
class store_test extends advanced_testcase {
39
 
40
    /**
41
     * Ensure that an execute with an invalid component is rejected.
42
     */
43
    public function test_execute_invalid_component(): void {
44
        $this->resetAfterTest();
45
        $user = $this->getDataGenerator()->create_user();
46
        $this->setUser($user);
47
 
48
        $this->expectException(coding_exception::class);
49
        $this->expectExceptionMessage("The 'foo' item is not valid for the 'mod_invalid' component");
50
        store::execute('mod_invalid', 1, 'foo', 2, false, 'formdata');
51
    }
52
 
53
    /**
54
     * Ensure that an execute with an invalid itemname on a valid component is rejected.
55
     */
56
    public function test_execute_invalid_itemname(): void {
57
        $this->resetAfterTest();
58
        $user = $this->getDataGenerator()->create_user();
59
        $this->setUser($user);
60
 
61
        $this->expectException(coding_exception::class);
62
        $this->expectExceptionMessage("The 'foo' item is not valid for the 'mod_forum' component");
63
        store::execute('mod_forum', 1, 'foo', 2, false, 'formdata');
64
    }
65
 
66
    /**
67
     * Ensure that an execute against a different grading method is rejected.
68
     */
69
    public function test_execute_incorrect_type(): void {
70
        $this->resetAfterTest();
71
 
72
        $forum = $this->get_forum_instance([
73
            // Negative numbers mean a scale.
74
            'grade_forum' => -1,
75
        ]);
76
        $course = $forum->get_course_record();
77
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
78
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
79
        $this->setUser($teacher);
80
 
81
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
82
 
83
        $this->expectException(moodle_exception::class);
84
        $this->expectExceptionMessage("not configured for direct grading");
85
        store::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id, false, 'formdata');
86
    }
87
 
88
    /**
89
     * Ensure that an execute against a different grading method is rejected.
90
     */
91
    public function test_execute_disabled(): void {
92
        $this->resetAfterTest();
93
 
94
        $forum = $this->get_forum_instance();
95
        $course = $forum->get_course_record();
96
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
97
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
98
        $this->setUser($teacher);
99
 
100
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
101
 
102
        $this->expectException(moodle_exception::class);
103
        $this->expectExceptionMessage("Grading is not enabled");
104
        store::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id, false, 'formdata');
105
    }
106
 
107
    /**
108
     * Ensure that an execute against the correct grading method returns the current state of the user.
109
     */
110
    public function test_execute_store_empty(): void {
111
        $this->resetAfterTest();
112
 
113
        $forum = $this->get_forum_instance([
114
            // Negative numbers mean a scale.
115
            'grade_forum' => 5,
116
        ]);
117
        $course = $forum->get_course_record();
118
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
119
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
120
        $this->setUser($teacher);
121
 
122
        $formdata = [
123
            'grade' => null,
124
        ];
125
 
126
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
127
 
128
        $result = store::execute('mod_forum', (int) $forum->get_context()->id, 'forum',
129
                (int) $student->id, false, http_build_query($formdata));
130
        $result = external_api::clean_returnvalue(store::execute_returns(), $result);
131
 
132
        // The result should still be empty.
133
        $this->assertIsArray($result);
134
        $this->assertArrayHasKey('templatename', $result);
135
 
136
        $this->assertEquals('core_grades/grades/grader/gradingpanel/point', $result['templatename']);
137
 
138
        $this->assertArrayHasKey('grade', $result);
139
        $this->assertIsArray($result['grade']);
140
        $this->assertArrayHasKey('grade', $result['grade']);
141
        $this->assertEmpty($result['grade']['grade']);
142
        $this->assertArrayHasKey('timecreated', $result['grade']);
143
        $this->assertIsInt($result['grade']['timecreated']);
144
        $this->assertArrayHasKey('timemodified', $result['grade']);
145
        $this->assertIsInt($result['grade']['timemodified']);
146
 
147
        $this->assertArrayHasKey('warnings', $result);
148
        $this->assertIsArray($result['warnings']);
149
        $this->assertEmpty($result['warnings']);
150
 
151
        // Test the grade array items.
152
        $this->assertArrayHasKey('grade', $result);
153
        $this->assertIsArray($result['grade']);
154
 
155
        $this->assertArrayHasKey('grade', $result['grade']);
156
        $this->assertEquals(null, $result['grade']['grade']);
157
 
158
        $this->assertIsInt($result['grade']['timecreated']);
159
        $this->assertArrayHasKey('timemodified', $result['grade']);
160
        $this->assertIsInt($result['grade']['timemodified']);
161
 
162
        $this->assertArrayHasKey('usergrade', $result['grade']);
163
        $this->assertEquals('- / 5.00', $result['grade']['usergrade']);
164
 
165
        $this->assertArrayHasKey('maxgrade', $result['grade']);
166
        $this->assertIsInt($result['grade']['maxgrade']);
167
        $this->assertEquals(5, $result['grade']['maxgrade']);
168
 
169
        $this->assertArrayHasKey('gradedby', $result['grade']);
170
        $this->assertEquals(fullname($teacher), $result['grade']['gradedby']);
171
 
172
        // Compare against the grade stored in the database.
173
        $storedgradeitem = grade_item::fetch([
174
            'courseid' => $forum->get_course_id(),
175
            'itemtype' => 'mod',
176
            'itemmodule' => 'forum',
177
            'iteminstance' => $forum->get_id(),
178
            'itemnumber' => $gradeitem->get_grade_itemid(),
179
        ]);
180
        $storedgrade = grade_grade::fetch([
181
            'userid' => $student->id,
182
            'itemid' => $storedgradeitem->id,
183
        ]);
184
 
185
        $this->assertEmpty($storedgrade->rawgrade);
186
    }
187
 
188
    /**
189
     * Ensure that an execute against the correct grading method returns the current state of the user.
190
     */
191
    public function test_execute_store_graded(): void {
192
        $this->resetAfterTest();
193
 
194
        $forum = $this->get_forum_instance([
195
            // Negative numbers mean a scale.
196
            'grade_forum' => 5,
197
        ]);
198
        $course = $forum->get_course_record();
199
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
200
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
201
        $this->setUser($teacher);
202
 
203
        $formdata = [
204
            'grade' => 4,
205
        ];
206
 
207
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
208
 
209
        $result = store::execute('mod_forum', (int) $forum->get_context()->id, 'forum',
210
                (int) $student->id, false, http_build_query($formdata));
211
        $result = external_api::clean_returnvalue(store::execute_returns(), $result);
212
 
213
        // The result should still be empty.
214
        $this->assertIsArray($result);
215
        $this->assertArrayHasKey('templatename', $result);
216
 
217
        $this->assertEquals('core_grades/grades/grader/gradingpanel/point', $result['templatename']);
218
 
219
        $this->assertArrayHasKey('warnings', $result);
220
        $this->assertIsArray($result['warnings']);
221
        $this->assertEmpty($result['warnings']);
222
 
223
        // Test the grade array items.
224
        $this->assertArrayHasKey('grade', $result);
225
        $this->assertIsArray($result['grade']);
226
 
227
        $this->assertArrayHasKey('grade', $result['grade']);
228
        $this->assertEquals(grade_floatval(unformat_float(4)), $result['grade']['grade']);
229
 
230
        $this->assertIsInt($result['grade']['timecreated']);
231
        $this->assertArrayHasKey('timemodified', $result['grade']);
232
        $this->assertIsInt($result['grade']['timemodified']);
233
 
234
        $this->assertArrayHasKey('usergrade', $result['grade']);
235
        $this->assertEquals('4.00 / 5.00', $result['grade']['usergrade']);
236
 
237
        $this->assertArrayHasKey('maxgrade', $result['grade']);
238
        $this->assertIsInt($result['grade']['maxgrade']);
239
        $this->assertEquals(5, $result['grade']['maxgrade']);
240
 
241
        $this->assertArrayHasKey('gradedby', $result['grade']);
242
        $this->assertEquals(fullname($teacher), $result['grade']['gradedby']);
243
 
244
        // Compare against the grade stored in the database.
245
        $storedgradeitem = grade_item::fetch([
246
            'courseid' => $forum->get_course_id(),
247
            'itemtype' => 'mod',
248
            'itemmodule' => 'forum',
249
            'iteminstance' => $forum->get_id(),
250
            'itemnumber' => $gradeitem->get_grade_itemid(),
251
        ]);
252
        $storedgrade = grade_grade::fetch([
253
            'userid' => $student->id,
254
            'itemid' => $storedgradeitem->id,
255
        ]);
256
 
257
        $this->assertEquals(grade_floatval(unformat_float(4)), $storedgrade->rawgrade);
258
    }
259
 
260
    /**
261
     * Ensure that an out-of-range value is rejected.
262
     *
263
     * @dataProvider execute_out_of_range_provider
264
     * @param int $maxvalue The max value of the forum
265
     * @param int $suppliedvalue The value that was submitted
266
     */
267
    public function test_execute_store_out_of__range(int $maxvalue, float $suppliedvalue): void {
268
        $this->resetAfterTest();
269
 
270
        $forum = $this->get_forum_instance([
271
            // Negative numbers mean a scale.
272
            'grade_forum' => $maxvalue,
273
        ]);
274
        $course = $forum->get_course_record();
275
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
276
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
277
        $this->setUser($teacher);
278
 
279
        $formdata = [
280
            'grade' => $suppliedvalue,
281
        ];
282
 
283
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
284
 
285
        $this->expectException(moodle_exception::class);
286
        $this->expectExceptionMessage("Invalid grade '{$suppliedvalue}' provided. Grades must be between 0 and {$maxvalue}.");
287
        store::execute('mod_forum', (int) $forum->get_context()->id, 'forum',
288
                (int) $student->id, false, http_build_query($formdata));
289
    }
290
 
291
    /**
292
     * Data provider for out of range tests.
293
     *
294
     * @return array
295
     */
296
    public function execute_out_of_range_provider(): array {
297
        return [
298
            'above' => [
299
                'max' => 100,
300
                'supplied' => 101,
301
            ],
302
            'above just' => [
303
                'max' => 100,
304
                'supplied' => 101.001,
305
            ],
306
            'below' => [
307
                'max' => 100,
308
                'supplied' => -100,
309
            ],
310
            '-1' => [
311
                'max' => 100,
312
                'supplied' => -1,
313
            ],
314
        ];
315
    }
316
 
317
 
318
    /**
319
     * Get a forum instance.
320
     *
321
     * @param array $config
322
     * @return forum_entity
323
     */
324
    protected function get_forum_instance(array $config = []): forum_entity {
325
        $this->resetAfterTest();
326
 
327
        $datagenerator = $this->getDataGenerator();
328
        $course = $datagenerator->create_course();
329
        $forum = $datagenerator->create_module('forum', array_merge($config, ['course' => $course->id]));
330
 
331
        $vaultfactory = \mod_forum\local\container::get_vault_factory();
332
        $vault = $vaultfactory->get_forum_vault();
333
 
334
        return $vault->get_from_id((int) $forum->id);
335
    }
336
}