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
/**
18
 * General unit tests for block_completion_progress.
19
 *
20
 * @package    block_completion_progress
21
 * @copyright  2017 onwards Nelson Moller  {@link http://moodle.com}
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace block_completion_progress;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
global $CFG;
30
require_once($CFG->dirroot . '/mod/assign/locallib.php');
31
require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
32
require_once($CFG->dirroot.'/blocks/completion_progress/block_completion_progress.php');
33
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
34
 
35
use block_completion_progress\completion_progress;
36
use block_completion_progress\defaults;
37
 
38
/**
39
 * General unit tests for block_completion_progress.
40
 *
41
 * @package    block_completion_progress
42
 * @copyright  2017 onwards Nelson Moller  {@link http://moodle.com}
43
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44
 */
45
class general_test extends \advanced_testcase {
46
    /**
47
     * Teacher users.
48
     * @var array
49
     */
50
    private $teachers = [];
51
 
52
    /**
53
     * Student users.
54
     * @var array
55
     */
56
    private $students = [];
57
 
58
    /**
59
     * Number of students to create.
60
     */
61
    const STUDENT_COUNT = 4;
62
 
63
    /**
64
     * Create a course and add enrol users to it.
65
     */
66
    protected function setUp(): void {
67
        $this->resetAfterTest(true);
68
 
69
        set_config('enablecompletion', 1);
70
 
71
        $generator = $this->getDataGenerator();
72
 
73
        $this->course = $generator->create_course([
74
          'enablecompletion' => 1,
75
        ]);
76
 
77
        $this->teachers[0] = $generator->create_and_enrol($this->course, 'teacher');
78
 
79
        for ($i = 0; $i < self::STUDENT_COUNT; $i++) {
80
            $status = $i >= 3 ? ENROL_USER_SUSPENDED : null;
81
            $this->students[$i] = $generator->create_and_enrol($this->course, 'student',
82
                null, 'manual', 0, 0, $status);
83
        }
84
    }
85
 
86
    /**
87
     * Convenience function to create a testable instance of an assignment.
88
     *
89
     * @param array $params Array of parameters to pass to the generator
90
     * @return assign Assign class.
91
     */
92
    protected function create_assign_instance($params) {
93
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
94
        $params['course'] = $this->course->id;
95
        $instance = $generator->create_instance($params);
96
        $cm = get_coursemodule_from_instance('assign', $instance->id);
97
        $context = \context_module::instance($cm->id);
98
        return new \assign($context, $cm, $this->course);
99
    }
100
 
101
    /**
102
     * Check that a student's excluded grade hides the activity from the student's progress bar.
103
     * @covers \block_completion_progress\completion_progress
104
     */
105
    public function test_grade_excluded() {
106
        global $DB, $PAGE;
107
 
108
        $output = $PAGE->get_renderer('block_completion_progress');
109
 
110
        // Add a block.
111
        $context = \context_course::instance($this->course->id);
112
        $blockinfo = [
113
            'parentcontextid' => $context->id,
114
            'pagetypepattern' => 'course-view-*',
115
            'showinsubcontexts' => 0,
116
            'defaultweight' => 5,
117
            'timecreated' => time(),
118
            'timemodified' => time(),
119
            'defaultregion' => 'side-post',
120
            'configdata' => base64_encode(serialize((object)[
121
                'orderby' => defaults::ORDERBY,
122
                'longbars' => defaults::LONGBARS,
123
                'progressBarIcons' => defaults::PROGRESSBARICONS,
124
                'showpercentage' => defaults::SHOWPERCENTAGE,
125
                'progressTitle' => "",
126
                'activitiesincluded' => defaults::ACTIVITIESINCLUDED,
127
            ])),
128
        ];
129
        $blockinstance = $this->getDataGenerator()->create_block('completion_progress', $blockinfo);
130
 
131
        $assign = $this->create_assign_instance([
132
          'submissiondrafts' => 0,
133
          'completionsubmit' => 1,
134
          'completion' => COMPLETION_TRACKING_AUTOMATIC
135
        ]);
136
 
137
        $gradeitem = \grade_item::fetch(['courseid' => $this->course->id,
138
            'itemtype' => 'mod', 'itemmodule' => 'assign',
139
            'iteminstance' => $assign->get_course_module()->instance]);
140
 
141
        // Set student 1's grade to be excluded.
142
        $grade = $gradeitem->get_grade($this->students[1]->id);
143
        $grade->set_excluded(1);
144
 
145
        // Student 0 ought to see the activity.
146
        $progress = (new completion_progress($this->course))
147
                    ->for_user($this->students[0])
148
                    ->for_block_instance($blockinstance);
149
        $this->assertEquals(
150
            [$assign->get_course_module()->id => COMPLETION_INCOMPLETE],
151
            $progress->get_completions()
152
        );
153
 
154
        // Student 1 ought not see the activity.
155
        $progress = (new completion_progress($this->course))
156
                    ->for_user($this->students[1])
157
                    ->for_block_instance($blockinstance);
158
        $this->assertEquals([], $progress->get_completions());
159
    }
160
 
161
    /**
162
     * Test checking of pages at site-level or not.
163
     * @covers \block_completion_progress
164
     */
165
    public function test_on_site_page() {
166
        global $PAGE;
167
 
168
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
169
        $instance = $generator->create_instance(['course' => $this->course->id]);
170
        $cm = get_coursemodule_from_instance('assign', $instance->id);
171
 
172
        // Front page.
173
        $page = new \moodle_page();
174
        $page->set_pagetype('site-index');
175
        $page->set_context(\context_course::instance(SITEID));
176
        $this->assertTrue(\block_completion_progress::on_site_page($page), 'front page');
177
 
178
        // Dashboard.
179
        $page = new \moodle_page();
180
        $page->set_pagetype('my-index');
181
        $page->set_context(\context_user::instance(get_admin()->id));
182
        $this->assertTrue(\block_completion_progress::on_site_page($page), 'dashboard');
183
 
184
        // Course.
185
        $page = new \moodle_page();
186
        $page->set_pagetype('course-view-topics');
187
        $page->set_context(\context_course::instance($this->course->id));
188
        $this->assertFalse(\block_completion_progress::on_site_page($page), 'course');
189
 
190
        // Activity, possible by making a course block viewable on all page types.
191
        $page = new \moodle_page();
192
        $page->set_pagetype('mod-assign-grader');
193
        $page->set_context(\context_module::instance($cm->id));
194
        $this->assertFalse(\block_completion_progress::on_site_page($page), 'activity');
195
 
196
        // AJAX-loaded fragment within a course module context.
197
        $page = new \moodle_page();
198
        $page->set_pagetype('site-index');
199
        $page->set_context(\context_module::instance($cm->id));
200
        $this->assertFalse(\block_completion_progress::on_site_page($page), 'ajax');
201
 
202
        // An uninitialised page. This has a default system context.
203
        $page = new \moodle_page();
204
        $this->assertTrue(\block_completion_progress::on_site_page($page), 'uninitialised');
205
 
206
        // Something very unusual.
207
        $PAGE = null;
208
        $this->assertFalse(\block_completion_progress::on_site_page(null), 'oddity');
209
    }
210
 
211
    /**
212
     * Test that asynchronous course copy preserves all expected block instances.
213
     * @covers \restore_completion_progress_block_task
214
     */
215
    public function test_course_copy() {
216
        global $DB;
217
 
218
        $this->setAdminUser();
219
 
220
        $context = \context_course::instance($this->course->id);
221
        $generator = $this->getDataGenerator();
222
        $group = $generator->create_group(['courseid' => $this->course->id, 'idnumber' => 'g1']);
223
        $block1data = [
224
            'parentcontextid' => $context->id,
225
            'pagetypepattern' => 'course-view-*',
226
            'showinsubcontexts' => 0,
227
            'defaultweight' => 5,
228
            'timecreated' => time(),
229
            'timemodified' => time(),
230
            'defaultregion' => 'side-post',
231
            'configdata' => base64_encode(serialize((object)[
232
                'orderby' => defaults::ORDERBY,
233
                'longbars' => defaults::LONGBARS,
234
                'progressBarIcons' => 0,    // Non-default.
235
                'showpercentage' => defaults::SHOWPERCENTAGE,
236
                'progressTitle' => "Instance 1",
237
                'activitiesincluded' => defaults::ACTIVITIESINCLUDED,
238
                'group' => 'group-' . $group->id,
239
            ])),
240
        ];
241
        $generator->create_block('completion_progress', $block1data);
242
        $block2data = [
243
            'parentcontextid' => $context->id,
244
            'pagetypepattern' => 'course-view-*',
245
            'showinsubcontexts' => 0,
246
            'defaultweight' => 5,
247
            'timecreated' => time(),
248
            'timemodified' => time(),
249
            'defaultregion' => 'side-post',
250
            'configdata' => base64_encode(serialize((object)[
251
                'orderby' => defaults::ORDERBY,
252
                'longbars' => defaults::LONGBARS,
253
                'progressBarIcons' => 0,    // Non-default.
254
                'showpercentage' => defaults::SHOWPERCENTAGE,
255
                'progressTitle' => "Instance 2",
256
                'activitiesincluded' => defaults::ACTIVITIESINCLUDED,
257
            ])),
258
        ];
259
        $generator->create_block('completion_progress', $block2data);
260
 
261
        $mdata = new \stdClass;
262
        $mdata->courseid = $this->course->id;
263
        $mdata->fullname = $this->course->fullname . ' Copy';
264
        $mdata->shortname = $this->course->shortname . ' Copy';
265
        $mdata->category = $this->course->category;
266
        $mdata->visible = 1;
267
        $mdata->startdate = $this->course->startdate;
268
        $mdata->enddate = $this->course->enddate;
269
        $mdata->idnumber = $this->course->idnumber . '_copy';
270
        $mdata->userdata = 0;
271
 
272
        if (method_exists('\copy_helper', 'process_formdata')) {
273
            // Moodle 3.11 or higher.
274
            $copydata = \copy_helper::process_formdata($mdata);
275
            \copy_helper::create_copy($copydata);
276
        } else {
277
            // Moodle 3.10 or older.
278
            $backupcopy = new \core_backup\copy\copy($mdata);
279
            $backupcopy->create_copy();
280
        }
281
 
282
        $now = time();
283
        $task = \core\task\manager::get_next_adhoc_task($now);
284
        $this->assertInstanceOf('\\core\\task\\asynchronous_copy_task', $task);
285
        $this->expectOutputRegex("/Course copy/");
286
        $task->execute();
287
        \core\task\manager::adhoc_task_complete($task);
288
 
289
        $copy = $DB->get_record('course', ['idnumber' => $mdata->idnumber]);
290
        $context = \context_course::instance($copy->id);
291
        $copygroup = groups_get_group_by_idnumber($copy->id, 'g1');
292
 
293
        $blocks = $DB->get_records('block_instances', ['blockname' => 'completion_progress',
294
            'parentcontextid' => $context->id]);
295
        $this->assertCount(2, $blocks);
296
 
297
        array_walk($blocks, function ($record) {
298
            $record->config = unserialize(base64_decode($record->configdata));
299
        });
300
        $copyblockmap = array_flip(array_map(function ($record) {
301
            return $record->config->progressTitle;
302
        }, $blocks));
303
 
304
        // Ensure both block instances were copied.
305
        $this->assertArrayHasKey('Instance 1', $copyblockmap);
306
        $this->assertArrayHasKey('Instance 2', $copyblockmap);
307
 
308
        // Ensure the configured group got remapped by the copy.
309
        $this->assertEquals('group-' . $copygroup->id, $blocks[$copyblockmap['Instance 1']]->config->group);
310
    }
311
 
312
    /**
313
     * Test course modules view urls.
314
     * @covers \block_completion_progress\completion_progress
315
     */
316
    public function test_view_urls() {
317
        global $DB, $PAGE;
318
 
319
        $output = $PAGE->get_renderer('block_completion_progress');
320
 
321
        // Add a block.
322
        $context = \context_course::instance($this->course->id);
323
        $blockinstance = $this->getDataGenerator()->create_block('completion_progress', [
324
            'parentcontextid' => $context->id,
325
            'pagetypepattern' => 'course-view-*',
326
            'showinsubcontexts' => 0,
327
            'defaultweight' => 5,
328
            'timecreated' => time(),
329
            'timemodified' => time(),
330
            'defaultregion' => 'side-post',
331
            'configdata' => base64_encode(serialize((object)[
332
                'orderby' => defaults::ORDERBY,
333
                'longbars' => defaults::LONGBARS,
334
                'progressBarIcons' => defaults::PROGRESSBARICONS,
335
                'showpercentage' => defaults::SHOWPERCENTAGE,
336
                'progressTitle' => "",
337
                'activitiesincluded' => defaults::ACTIVITIESINCLUDED,
338
            ])),
339
        ]);
340
 
341
        $pageinstance = $this->getDataGenerator()->create_module('page', [
342
            'course' => $this->course->id,
343
            'completion' => COMPLETION_TRACKING_MANUAL
344
        ]);
345
        $labelinstance = $this->getDataGenerator()->create_module('label', [
346
            'course' => $this->course->id,
347
            'completion' => COMPLETION_TRACKING_MANUAL
348
        ]);
349
 
350
        $modinfo = get_fast_modinfo($this->course);
351
        $pagecm = $modinfo->get_cm($pageinstance->cmid);
352
 
353
        $progress = (new completion_progress($this->course))
354
                    ->for_user($this->students[0])
355
                    ->for_block_instance($blockinstance);
356
        $activities = $progress->get_activities();
357
        $this->assertEquals($pagecm->url->out(), $activities[0]->url);
358
        $this->assertEquals('', $activities[1]->url);
359
    }
360
}