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 gradingform_rubric\grades\grader\gradingpanel\external;
20
 
21
use advanced_testcase;
22
use coding_exception;
23
use core_grades\component_gradeitem;
24
use core_grades\component_gradeitems;
25
use core_external\external_api;
26
use mod_forum\local\entities\forum as forum_entity;
27
use moodle_exception;
28
 
29
/**
30
 * Unit tests for core_grades\component_gradeitems;
31
 *
32
 * @package   gradingform_rubric
33
 * @category  test
34
 * @copyright 2019 Mathew May <mathew.solutions>
35
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
37
class fetch_test extends advanced_testcase {
38
    /**
39
     * Ensure that an execute with an invalid component is rejected.
40
     */
41
    public function test_execute_invalid_component(): void {
42
        $this->resetAfterTest();
43
        $user = $this->getDataGenerator()->create_user();
44
        $this->setUser($user);
45
 
46
        $this->expectException(coding_exception::class);
47
        $this->expectExceptionMessage("The 'foo' item is not valid for the 'mod_invalid' component");
48
        fetch::execute('mod_invalid', 1, 'foo', 2);
49
    }
50
 
51
    /**
52
     * Ensure that an execute with an invalid itemname on a valid component is rejected.
53
     */
54
    public function test_execute_invalid_itemname(): void {
55
        $this->resetAfterTest();
56
        $user = $this->getDataGenerator()->create_user();
57
        $this->setUser($user);
58
 
59
        $this->expectException(coding_exception::class);
60
        $this->expectExceptionMessage("The 'foo' item is not valid for the 'mod_forum' component");
61
        fetch::execute('mod_forum', 1, 'foo', 2);
62
    }
63
 
64
    /**
65
     * Ensure that an execute against a different grading method is rejected.
66
     */
67
    public function test_execute_incorrect_type(): void {
68
        $this->resetAfterTest();
69
 
70
        $forum = $this->get_forum_instance([
71
            // Negative numbers mean a scale.
72
            'grade_forum' => 5,
73
        ]);
74
        $course = $forum->get_course_record();
75
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
76
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
77
        $this->setUser($teacher);
78
 
79
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
80
 
81
        $this->expectException(moodle_exception::class);
82
        $this->expectExceptionMessage("not configured for advanced grading with a rubric");
83
        fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
84
    }
85
 
86
    /**
87
     * Ensure that an execute against the correct grading method returns the current state of the user.
88
     */
89
    public function test_execute_fetch_empty(): void {
90
        $this->resetAfterTest();
91
 
92
        [
93
            'forum' => $forum,
94
            'controller' => $controller,
95
            'definition' => $definition,
96
            'student' => $student,
97
            'teacher' => $teacher,
98
        ] = $this->get_test_data();
99
 
100
        $this->setUser($teacher);
101
 
102
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
103
 
104
        $result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
105
        $result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
106
 
107
        $this->assertIsArray($result);
108
        $this->assertArrayHasKey('templatename', $result);
109
 
110
        $this->assertEquals('gradingform_rubric/grades/grader/gradingpanel', $result['templatename']);
111
 
112
        $this->assertArrayHasKey('warnings', $result);
113
        $this->assertIsArray($result['warnings']);
114
        $this->assertEmpty($result['warnings']);
115
 
116
        // Test the grade array items.
117
        $this->assertArrayHasKey('grade', $result);
118
        $this->assertIsArray($result['grade']);
119
        $this->assertIsInt($result['grade']['timecreated']);
120
 
121
        $this->assertArrayHasKey('timemodified', $result['grade']);
122
        $this->assertIsInt($result['grade']['timemodified']);
123
 
124
        $this->assertArrayHasKey('usergrade', $result['grade']);
125
        $this->assertEquals('- / 100.00', $result['grade']['usergrade']);
126
 
127
        $this->assertArrayHasKey('maxgrade', $result['grade']);
128
        $this->assertIsInt($result['grade']['maxgrade']);
129
        $this->assertEquals(100, $result['grade']['maxgrade']);
130
 
131
        $this->assertArrayHasKey('gradedby', $result['grade']);
132
        $this->assertEquals(null, $result['grade']['gradedby']);
133
 
134
        $this->assertArrayHasKey('criteria', $result['grade']);
135
        $criteria = $result['grade']['criteria'];
136
        $this->assertCount(count($definition->rubric_criteria), $criteria);
137
        foreach ($criteria as $criterion) {
138
            $this->assertArrayHasKey('id', $criterion);
139
            $criterionid = $criterion['id'];
140
            $sourcecriterion = $definition->rubric_criteria[$criterionid];
141
 
142
            $this->assertArrayHasKey('description', $criterion);
143
            $this->assertEquals($sourcecriterion['description'], $criterion['description']);
144
 
145
            $this->assertArrayHasKey('levels', $criterion);
146
 
147
            $levels = $criterion['levels'];
148
            foreach ($levels as $level) {
149
                $levelid = $level['id'];
150
                if (!isset($levelid)) {
151
                    continue;
152
                }
153
                $sourcelevel = $sourcecriterion['levels'][$levelid];
154
 
155
                $this->assertArrayHasKey('criterionid', $level);
156
                $this->assertEquals($criterionid, $level['criterionid']);
157
 
158
                $this->assertArrayHasKey('checked', $level);
159
 
160
                $this->assertArrayHasKey('definition', $level);
161
                $this->assertEquals($sourcelevel['definition'], $level['definition']);
162
 
163
                $this->assertArrayHasKey('score', $level);
164
                $this->assertEquals($sourcelevel['score'], $level['score']);
165
            }
166
        }
167
    }
168
 
169
    /**
170
     * Ensure that an execute against the correct grading method returns the current state of the user.
171
     */
172
    public function test_execute_fetch_graded(): void {
173
        $this->resetAfterTest();
174
 
175
        [
176
            'forum' => $forum,
177
            'controller' => $controller,
178
            'definition' => $definition,
179
            'student' => $student,
180
            'teacher' => $teacher,
181
        ] = $this->get_test_data();
182
 
183
        $this->execute_and_assert_fetch($forum, $controller, $definition, $teacher, $teacher, $student);
184
    }
185
 
186
    /**
187
     * Class mates should not get other's grades.
188
     */
189
    public function test_execute_fetch_does_not_return_data_to_other_students(): void {
190
        $this->resetAfterTest();
191
 
192
        [
193
            'forum' => $forum,
194
            'controller' => $controller,
195
            'definition' => $definition,
196
            'student' => $student,
197
            'teacher' => $teacher,
198
            'course' => $course,
199
        ] = $this->get_test_data();
200
 
201
        $evilstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
202
 
203
        $this->expectException(\required_capability_exception::class);
204
        $this->execute_and_assert_fetch($forum, $controller, $definition, $evilstudent, $teacher, $student);
205
    }
206
 
207
    /**
208
     * Grades can be returned to graded user.
209
     */
210
    public function test_execute_fetch_return_data_to_graded_user(): void {
211
        $this->resetAfterTest();
212
 
213
        [
214
            'forum' => $forum,
215
            'controller' => $controller,
216
            'definition' => $definition,
217
            'student' => $student,
218
            'teacher' => $teacher,
219
        ] = $this->get_test_data();
220
 
221
        $this->execute_and_assert_fetch($forum, $controller, $definition, $student, $teacher, $student);
222
    }
223
 
224
    /**
225
     * Executes and performs all the assertions of the fetch method with the given parameters.
226
     */
227
    private function execute_and_assert_fetch($forum, $controller, $definition, $fetcheruser, $grader, $gradeduser) {
228
        $generator = \testing_util::get_data_generator();
229
        $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric');
230
 
231
        $this->setUser($grader);
232
 
233
        $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
234
        $grade = $gradeitem->get_grade_for_user($gradeduser, $grader);
235
        $instance = $gradeitem->get_advanced_grading_instance($grader, $grade);
236
 
237
        $submissiondata = $rubricgenerator->get_test_form_data($controller, (int) $gradeduser->id,
238
            0, 'Too many mistakes. Please try again.',
239
            2, 'Great number of pictures. Well done.'
240
        );
241
 
242
        $gradeitem->store_grade_from_formdata($gradeduser, $grader, (object) [
243
            'instanceid' => $instance->get_id(),
244
            'advancedgrading' => $submissiondata,
245
        ]);
246
 
247
        $this->setUser($fetcheruser);
248
 
249
        $result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id);
250
        $result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
251
 
252
        $this->assertIsArray($result);
253
        $this->assertArrayHasKey('templatename', $result);
254
 
255
        $this->assertEquals('gradingform_rubric/grades/grader/gradingpanel', $result['templatename']);
256
 
257
        $this->assertArrayHasKey('warnings', $result);
258
        $this->assertIsArray($result['warnings']);
259
        $this->assertEmpty($result['warnings']);
260
 
261
        // Test the grade array items.
262
        $this->assertArrayHasKey('grade', $result);
263
        $this->assertIsArray($result['grade']);
264
        $this->assertIsInt($result['grade']['timecreated']);
265
 
266
        $this->assertArrayHasKey('timemodified', $result['grade']);
267
        $this->assertIsInt($result['grade']['timemodified']);
268
 
269
        $this->assertArrayHasKey('usergrade', $result['grade']);
270
        $this->assertEquals('50.00 / 100.00', $result['grade']['usergrade']);
271
 
272
        $this->assertArrayHasKey('maxgrade', $result['grade']);
273
        $this->assertIsInt($result['grade']['maxgrade']);
274
        $this->assertEquals(100, $result['grade']['maxgrade']);
275
 
276
        $this->assertArrayHasKey('gradedby', $result['grade']);
277
        $this->assertEquals(fullname($grader), $result['grade']['gradedby']);
278
 
279
        $this->assertArrayHasKey('criteria', $result['grade']);
280
        $criteria = $result['grade']['criteria'];
281
        $this->assertCount(count($definition->rubric_criteria), $criteria);
282
        foreach ($criteria as $criterion) {
283
            $this->assertArrayHasKey('id', $criterion);
284
            $criterionid = $criterion['id'];
285
            $sourcecriterion = $definition->rubric_criteria[$criterionid];
286
 
287
            $this->assertArrayHasKey('description', $criterion);
288
            $this->assertEquals($sourcecriterion['description'], $criterion['description']);
289
 
290
            $this->assertArrayHasKey('remark', $criterion);
291
 
292
            $this->assertArrayHasKey('levels', $criterion);
293
 
294
            $levels = $criterion['levels'];
295
            foreach ($levels as $level) {
296
                $levelid = $level['id'];
297
                if (!isset($levelid)) {
298
                    continue;
299
                }
300
                $sourcelevel = $sourcecriterion['levels'][$levelid];
301
 
302
                $this->assertArrayHasKey('criterionid', $level);
303
                $this->assertEquals($criterionid, $level['criterionid']);
304
 
305
                $this->assertArrayHasKey('checked', $level);
306
 
307
                $this->assertArrayHasKey('definition', $level);
308
                $this->assertEquals($sourcelevel['definition'], $level['definition']);
309
 
310
                $this->assertArrayHasKey('score', $level);
311
                $this->assertEquals($sourcelevel['score'], $level['score']);
312
            }
313
 
314
        }
315
 
316
        $this->assertEquals(1, $criteria[0]['levels'][1]['checked']);
317
        $this->assertEquals('Too many mistakes. Please try again.', $criteria[0]['remark']);
318
        $this->assertEquals(1, $criteria[1]['levels'][3]['checked']);
319
        $this->assertEquals('Great number of pictures. Well done.', $criteria[1]['remark']);
320
    }
321
 
322
    /**
323
     * Get a forum instance.
324
     *
325
     * @param array $config
326
     * @return forum_entity
327
     */
328
    protected function get_forum_instance(array $config = []): forum_entity {
329
        $this->resetAfterTest();
330
 
331
        $datagenerator = $this->getDataGenerator();
332
        $course = $datagenerator->create_course();
333
        $forum = $datagenerator->create_module('forum', array_merge($config, ['course' => $course->id, 'grade_forum' => 100]));
334
 
335
        $vaultfactory = \mod_forum\local\container::get_vault_factory();
336
        $vault = $vaultfactory->get_forum_vault();
337
 
338
        return $vault->get_from_id((int) $forum->id);
339
    }
340
 
341
    /**
342
     * Get test data for forums graded using a rubric.
343
     *
344
     * @return array
345
     */
346
    protected function get_test_data(): array {
347
        global $DB;
348
 
349
        $this->resetAfterTest();
350
 
351
        $generator = \testing_util::get_data_generator();
352
        $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric');
353
 
354
        $forum = $this->get_forum_instance();
355
        $course = $forum->get_course_record();
356
        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
357
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
358
 
359
        $this->setUser($teacher);
360
 
361
        $controller = $rubricgenerator->get_test_rubric($forum->get_context(), 'forum', 'forum');
362
        $definition = $controller->get_definition();
363
 
364
        // In the situation of mod_forum this would be the id from forum_grades.
365
        $itemid = 1;
366
        $instance = $controller->create_instance($student->id, $itemid);
367
 
368
        $data = $this->get_test_form_data(
369
            $controller,
370
            $itemid,
371
            1, 'This user made several mistakes.',
372
            0, 'Please add more pictures.'
373
        );
374
 
375
        // Update this instance with data.
376
        $instance->update($data);
377
 
378
        return [
379
            'forum' => $forum,
380
            'controller' => $controller,
381
            'definition' => $definition,
382
            'student' => $student,
383
            'teacher' => $teacher,
384
            'course' => $course,
385
        ];
386
    }
387
    /**
388
     * Fetch a set of sample data.
389
     *
390
     * @param \gradingform_rubric_controller $controller
391
     * @param int $itemid
392
     * @param float $spellingscore
393
     * @param string $spellingremark
394
     * @param float $picturescore
395
     * @param string $pictureremark
396
     * @return array
397
     */
398
    protected function get_test_form_data(
399
        \gradingform_rubric_controller $controller,
400
        int $itemid,
401
        float $spellingscore,
402
        string $spellingremark,
403
        float $picturescore,
404
        string $pictureremark
405
    ): array {
406
        $generator = \testing_util::get_data_generator();
407
        $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric');
408
 
409
        return $rubricgenerator->get_test_form_data(
410
            $controller,
411
            $itemid,
412
            $spellingscore,
413
            $spellingremark,
414
            $picturescore,
415
            $pictureremark
416
        );
417
    }
418
}