Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 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
namespace mod_assign;
18
 
19
use core_component;
20
use core_grades\penalty_manager;
21
use grade_item;
22
use mod_assign_test_generator;
23
use mod_assign_testable_assign;
24
use ReflectionClass;
25
 
26
defined('MOODLE_INTERNAL') || die();
27
 
28
global $CFG;
29
require_once($CFG->dirroot . '/mod/assign/locallib.php');
30
require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
31
 
32
/**
33
 * Penalty test.
34
 *
35
 * @package    mod_assign
36
 * @copyright  2024 Catalyst IT Australia Pty Ltd
37
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38
 */
39
final class penalty_test extends \advanced_testcase {
40
    // Use the generator helper.
41
    use mod_assign_test_generator;
42
 
43
    /**
44
     * Set up test
45
     *
46
     * @return array The course and student.
47
     */
48
    protected function set_up_test(): array {
49
        global $CFG;
50
        $this->setAdminUser();
51
 
52
        penalty_manager::enable_module('assign');
53
 
54
        // Load a mocked grade penalty plugin.
55
        $mockedcomponent = new ReflectionClass(core_component::class);
56
        $mockedplugins = $mockedcomponent->getProperty('plugins');
57
        $plugins = $mockedplugins->getValue();
58
        $plugins['gradepenalty'] = ["fake_deduction" => "{$CFG->dirroot}/mod/assign/tests/fixtures/fakeplugins/fake_deduction"];
59
        // Load the penalty_calculator class.
60
        require_once($CFG->dirroot . '/mod/assign/tests/fixtures/fakeplugins/fake_deduction/classes/penalty_calculator.php');
61
        $mockedplugins->setValue(null, $plugins);
62
 
63
        \core\plugininfo\gradepenalty::enable_plugin('fake_deduction', true);
64
 
65
        // Create a course with user.
66
        $generator = $this->getDataGenerator();
67
        $course = $generator->create_course();
68
        $student = $this->getDataGenerator()->create_and_enrol($course);
69
 
70
        return [$course, $student];
71
    }
72
 
73
    /**
74
     * Test penalty support.
75
     *
76
     * @covers ::assign_supports
77
     */
78
    public function test_penalty_support(): void {
79
        $this->resetAfterTest();
80
        $this->setAdminUser();
81
 
82
        // Assign should be in the supported list.
83
        $this->assertTrue(in_array('assign', penalty_manager::get_supported_modules()));
84
 
85
        // Penalty is not enabled for any modules by default.
86
        $this->assertFalse(penalty_manager::is_penalty_enabled_for_module('assign'));
87
 
88
        // Enable penalty for assign.
89
        penalty_manager::enable_module('assign');
90
 
91
        // Assign should be enabled by now.
92
        $this->assertTrue(penalty_manager::is_penalty_enabled_for_module('assign'));
93
    }
94
 
95
    /**
96
     * Data provider for test_hook_callback.
97
     *
98
     * @return array
99
     */
100
    public static function apply_penalty_provider(): array {
101
        return [
102
            // Submission date, Due date, User override, Group override, Extension due date, Expected messages, Expected grade.
103
            // No overrides.
104
            [50, DAYSECS, DAYSECS, null, null, null, ['Submission date: 86400', 'Due date: 86400'], 50],
105
            [50, DAYSECS + 1, DAYSECS, null, null, null, ['Submission date: 86401', 'Due date: 86400'], 30],
106
            // User override.
107
            [50, DAYSECS + 1, DAYSECS, DAYSECS + 1, null, null, ['Submission date: 86401', 'Due date: 86401'], 50],
108
            [50, DAYSECS + 2, DAYSECS, DAYSECS + 1, null, null, ['Submission date: 86402', 'Due date: 86401'], 30],
109
            // Group override.
110
            [50, DAYSECS + 1, DAYSECS, null, DAYSECS + 1, null, ['Submission date: 86401', 'Due date: 86401'], 50],
111
            [50, DAYSECS + 2, DAYSECS, null, DAYSECS + 1, null, ['Submission date: 86402', 'Due date: 86401'], 30],
112
            // User and group override.
113
            [50, DAYSECS + 1, DAYSECS, DAYSECS + 1, DAYSECS + 2, null, ['Submission date: 86401', 'Due date: 86401'], 50],
114
            [50, DAYSECS + 2, DAYSECS, DAYSECS + 1, DAYSECS + 2, null, ['Submission date: 86402', 'Due date: 86401'], 30],
115
            // User, group override and extension.
116
            [50, DAYSECS + 3, DAYSECS, DAYSECS + 1, DAYSECS + 2, DAYSECS + 3, ['Submission date: 86403', 'Due date: 86403'], 50],
117
            [50, DAYSECS + 4, DAYSECS, DAYSECS + 1, DAYSECS + 2, DAYSECS + 3, ['Submission date: 86404', 'Due date: 86403'], 30],
118
            // Zero grade.
119
            [0, DAYSECS, DAYSECS, null, null, null, [], 0],
120
            [0, DAYSECS + 1, DAYSECS, null, null, null, [], 0],
121
        ];
122
    }
123
 
124
    /**
125
     * Test for hook_listener class.
126
     *
127
     * @dataProvider apply_penalty_provider
128
     *
129
     * @covers \mod_assign\penalty\helper::apply_penalty_to_submission
130
     *
131
     * @param float $usergrade the grade given to user.
132
     * @param int $submissiondate The submission date.
133
     * @param int $duedate The due date.
134
     * @param int $useroverrideduedate The user override due date.
135
     * @param int $groupoverrideduedate The group override due date.
136
     * @param int $extensionduedate The extension due date.
137
     * @param array $expectedmessages The expected debug messages.
138
     * @param float $expectedgrade The expected final grade.
139
     *
140
     */
141
    public function test_apply_penalty(
142
        $usergrade,
143
        $submissiondate,
144
        $duedate,
145
        $useroverrideduedate,
146
        $groupoverrideduedate,
147
        $extensionduedate,
148
        $expectedmessages,
149
        $expectedgrade,
150
    ): void {
151
        global $DB;
152
 
153
        $this->resetAfterTest();
154
        [$course, $student] = $this->set_up_test();
155
 
156
        // Assignment.
157
        $generator = $this->getDataGenerator();
158
        $assignmentgenerator = $generator->get_plugin_generator('mod_assign');
159
        $instance = $assignmentgenerator->create_instance([
160
            'course' => $course->id,
161
            'duedate' => $duedate,
162
            'assignsubmission_onlinetext_enabled' => 1,
163
            'gradepenalty' => 1,
164
            'grade' => 200,
165
        ]);
166
        $cm = get_coursemodule_from_instance('assign', $instance->id);
167
        $context = \context_module::instance($cm->id);
168
        $assign = new mod_assign_testable_assign($context, $cm, $course);
169
 
170
        // If there is user override.
171
        if ($useroverrideduedate) {
172
            $assignmentgenerator->create_override([
173
                'assignid' => $instance->id,
174
                'userid' => $student->id,
175
                'duedate' => $useroverrideduedate,
176
            ]);
177
        }
178
 
179
        // If there is extension.
180
        if ($extensionduedate) {
181
            $flags = $assign->get_user_flags($student->id, true);
182
            $flags->extensionduedate = $extensionduedate;
183
            $assign->update_user_flags($flags);
184
        }
185
 
186
        // If there is group override.
187
        if ($groupoverrideduedate) {
188
            $group = $generator->create_group(['courseid' => $course->id]);
189
            $generator->create_group_member(['groupid' => $group->id, 'userid' => $student->id]);
190
            $assignmentgenerator->create_override([
191
                'assignid' => $instance->id,
192
                'groupid' => $group->id,
193
                'duedate' => $groupoverrideduedate,
194
            ]);
195
        }
196
 
197
        // Add submission and grade.
198
        $this->add_submission($student, $assign, 'Sample text');
199
        $this->submit_for_grading($student, $assign);
200
        // Submission date.
201
        $DB->set_field('assign_submission', 'timemodified', $submissiondate, ['userid' => $student->id]);
202
        $assign->testable_apply_grade_to_user((object)['grade' => $usergrade], $student->id, 0);
203
 
204
        // Expect debug messages.
205
        $this->assertdebuggingcalledcount(count($expectedmessages), $expectedmessages);
206
 
207
        // The expected final grade.
208
        $gradeitem = grade_item::fetch([
209
            'courseid' => $course->id,
210
            'itemtype' => 'mod',
211
            'itemmodule' => 'assign',
212
            'iteminstance' => $instance->id,
213
            'itemnumber' => 0,
214
        ]);
215
        $this->assertEquals($expectedgrade, $gradeitem->get_final($student->id)->finalgrade);
216
    }
217
 
218
    /**
219
     * Test recalculation.
220
     *
221
     * @covers \mod_assign\penalty\helper::apply_penalty_to_submission
222
     *
223
     */
224
    public function test_recalculate_penalty(): void {
225
        global $DB;
226
 
227
        $this->resetAfterTest();
228
 
229
        [$course, $student] = $this->set_up_test();
230
 
231
        // Assignment.
232
        $duedate = time() + DAYSECS;
233
        $generator = $this->getDataGenerator();
234
        $assignmentgenerator = $generator->get_plugin_generator('mod_assign');
235
        $instance = $assignmentgenerator->create_instance([
236
            'course' => $course->id,
237
            'duedate' => $duedate,
238
            'assignsubmission_onlinetext_enabled' => 1,
239
            'gradepenalty' => 1,
240
            'grade' => 200,
241
        ]);
242
        $cm = get_coursemodule_from_instance('assign', $instance->id);
243
        $context = \context_module::instance($cm->id);
244
        $assign = new mod_assign_testable_assign($context, $cm, $course);
245
 
246
        // Add submission and grade.
247
        $submissiondate = $duedate + HOURSECS;
248
        $this->add_submission($student, $assign, 'Sample text');
249
        $this->submit_for_grading($student, $assign);
250
        // Submission date.
251
        $DB->set_field('assign_submission', 'timemodified', $submissiondate, ['userid' => $student->id]);
252
        $assign->testable_apply_grade_to_user((object)['grade' => 50.0], $student->id, 0);
253
 
254
        $this->assertdebuggingcalledcount(2);
255
 
256
        // Check the grade.
257
        $gradeitem = grade_item::fetch([
258
            'courseid' => $course->id,
259
            'itemtype' => 'mod',
260
            'itemmodule' => 'assign',
261
            'iteminstance' => $instance->id,
262
            'itemnumber' => 0,
263
        ]);
264
        $this->assertEquals(30, $gradeitem->get_final($student->id)->finalgrade);
265
 
266
        // Change the due date.
267
        $duedate = time() + DAYSECS * 2;
268
        $DB->set_field('assign', 'duedate', $duedate, ['id' => $instance->id]);
269
 
270
        // Recalculate the penalty.
271
        $clonedassign = clone $assign->get_instance();
272
        $clonedassign->cmidnumber = $assign->get_course_module()->idnumber;
273
        assign_update_grades($clonedassign);
274
        $this->assertdebuggingcalledcount(2);
275
 
276
        // Check the grade.
277
        $this->assertEquals(50, $gradeitem->get_final($student->id)->finalgrade);
278
    }
279
}