Merge branch 'MDL-51434-master' of git://github.com/jleyva/moodle
[moodle.git] / lib / tests / modinfolib_test.php
blob938366db6eace68ce0655b4da4ef7362f9d2ca7b
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.
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 lib/modinfolib.php.
20 * @package core
21 * @category phpunit
22 * @copyright 2012 Andrew Davis
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
28 require_once($CFG->libdir . '/modinfolib.php');
30 /**
31 * Unit tests for modinfolib.php
33 * @copyright 2012 Andrew Davis
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class core_modinfolib_testcase extends advanced_testcase {
37 public function test_section_info_properties() {
38 global $DB, $CFG;
40 $this->resetAfterTest();
41 $oldcfgenableavailability = $CFG->enableavailability;
42 $oldcfgenablecompletion = $CFG->enablecompletion;
43 set_config('enableavailability', 1);
44 set_config('enablecompletion', 1);
45 $this->setAdminUser();
47 // Generate the course and pre-requisite module.
48 $course = $this->getDataGenerator()->create_course(
49 array('format' => 'topics',
50 'numsections' => 3,
51 'enablecompletion' => 1,
52 'groupmode' => SEPARATEGROUPS,
53 'forcegroupmode' => 0),
54 array('createsections' => true));
55 $coursecontext = context_course::instance($course->id);
56 $prereqforum = $this->getDataGenerator()->create_module('forum',
57 array('course' => $course->id),
58 array('completion' => 1));
60 // Add availability conditions.
61 $availability = '{"op":"&","showc":[true,true,true],"c":[' .
62 '{"type":"completion","cm":' . $prereqforum->cmid . ',"e":"' .
63 COMPLETION_COMPLETE . '"},' .
64 '{"type":"grade","id":666,"min":0.4},' .
65 '{"type":"profile","op":"contains","sf":"email","v":"test"}' .
66 ']}';
67 $DB->set_field('course_sections', 'availability', $availability,
68 array('course' => $course->id, 'section' => 2));
69 rebuild_course_cache($course->id, true);
70 $sectiondb = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
72 // Create and enrol a student.
73 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
74 $student = $this->getDataGenerator()->create_user();
75 role_assign($studentrole->id, $student->id, $coursecontext);
76 $enrolplugin = enrol_get_plugin('manual');
77 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'));
78 $enrolplugin->enrol_user($enrolinstance, $student->id);
79 $this->setUser($student);
81 // Get modinfo.
82 $modinfo = get_fast_modinfo($course->id);
83 $si = $modinfo->get_section_info(2);
85 $this->assertEquals($sectiondb->id, $si->id);
86 $this->assertEquals($sectiondb->course, $si->course);
87 $this->assertEquals($sectiondb->section, $si->section);
88 $this->assertEquals($sectiondb->name, $si->name);
89 $this->assertEquals($sectiondb->visible, $si->visible);
90 $this->assertEquals($sectiondb->summary, $si->summary);
91 $this->assertEquals($sectiondb->summaryformat, $si->summaryformat);
92 $this->assertEquals($sectiondb->sequence, $si->sequence); // Since this section does not contain invalid modules.
93 $this->assertEquals($availability, $si->availability);
95 // Dynamic fields, just test that they can be retrieved (must be carefully tested in each activity type).
96 $this->assertEquals(0, $si->available);
97 $this->assertNotEmpty($si->availableinfo); // Lists all unmet availability conditions.
98 $this->assertEquals(0, $si->uservisible);
100 // Restore settings.
101 set_config('enableavailability', $oldcfgenableavailability);
102 set_config('enablecompletion', $oldcfgenablecompletion);
105 public function test_cm_info_properties() {
106 global $DB, $CFG;
108 $this->resetAfterTest();
109 $oldcfgenableavailability = $CFG->enableavailability;
110 $oldcfgenablecompletion = $CFG->enablecompletion;
111 set_config('enableavailability', 1);
112 set_config('enablecompletion', 1);
113 $this->setAdminUser();
115 // Generate the course and pre-requisite module.
116 $course = $this->getDataGenerator()->create_course(
117 array('format' => 'topics',
118 'numsections' => 3,
119 'enablecompletion' => 1,
120 'groupmode' => SEPARATEGROUPS,
121 'forcegroupmode' => 0),
122 array('createsections' => true));
123 $coursecontext = context_course::instance($course->id);
124 $prereqforum = $this->getDataGenerator()->create_module('forum',
125 array('course' => $course->id),
126 array('completion' => 1));
128 // Generate module and add availability conditions.
129 $availability = '{"op":"&","showc":[true,true,true],"c":[' .
130 '{"type":"completion","cm":' . $prereqforum->cmid . ',"e":"' .
131 COMPLETION_COMPLETE . '"},' .
132 '{"type":"grade","id":666,"min":0.4},' .
133 '{"type":"profile","op":"contains","sf":"email","v":"test"}' .
134 ']}';
135 $assign = $this->getDataGenerator()->create_module('assign',
136 array('course' => $course->id),
137 array('idnumber' => 123,
138 'groupmode' => VISIBLEGROUPS,
139 'availability' => $availability));
140 rebuild_course_cache($course->id, true);
142 // Retrieve all related records from DB.
143 $assigndb = $DB->get_record('assign', array('id' => $assign->id));
144 $moduletypedb = $DB->get_record('modules', array('name' => 'assign'));
145 $moduledb = $DB->get_record('course_modules', array('module' => $moduletypedb->id, 'instance' => $assign->id));
146 $sectiondb = $DB->get_record('course_sections', array('id' => $moduledb->section));
147 $modnamessingular = get_module_types_names(false);
148 $modnamesplural = get_module_types_names(true);
150 // Create and enrol a student.
151 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
152 $student = $this->getDataGenerator()->create_user();
153 role_assign($studentrole->id, $student->id, $coursecontext);
154 $enrolplugin = enrol_get_plugin('manual');
155 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'));
156 $enrolplugin->enrol_user($enrolinstance, $student->id);
157 $this->setUser($student);
159 // Emulate data used in building course cache to receive the same instance of cached_cm_info as was used in building modinfo.
160 $rawmods = get_course_mods($course->id);
161 $cachedcminfo = assign_get_coursemodule_info($rawmods[$moduledb->id]);
163 // Get modinfo.
164 $modinfo = get_fast_modinfo($course->id);
165 $cm = $modinfo->instances['assign'][$assign->id];
167 $this->assertEquals($moduledb->id, $cm->id);
168 $this->assertEquals($assigndb->id, $cm->instance);
169 $this->assertEquals($moduledb->course, $cm->course);
170 $this->assertEquals($moduledb->idnumber, $cm->idnumber);
171 $this->assertEquals($moduledb->added, $cm->added);
172 $this->assertEquals($moduledb->visible, $cm->visible);
173 $this->assertEquals($moduledb->visibleold, $cm->visibleold);
174 $this->assertEquals($moduledb->groupmode, $cm->groupmode);
175 $this->assertEquals(VISIBLEGROUPS, $cm->groupmode);
176 $this->assertEquals($moduledb->groupingid, $cm->groupingid);
177 $this->assertEquals($course->groupmodeforce, $cm->coursegroupmodeforce);
178 $this->assertEquals($course->groupmode, $cm->coursegroupmode);
179 $this->assertEquals(SEPARATEGROUPS, $cm->coursegroupmode);
180 $this->assertEquals($course->groupmodeforce ? $course->groupmode : $moduledb->groupmode,
181 $cm->effectivegroupmode); // (since mod_assign supports groups).
182 $this->assertEquals(VISIBLEGROUPS, $cm->effectivegroupmode);
183 $this->assertEquals($moduledb->indent, $cm->indent);
184 $this->assertEquals($moduledb->completion, $cm->completion);
185 $this->assertEquals($moduledb->completiongradeitemnumber, $cm->completiongradeitemnumber);
186 $this->assertEquals($moduledb->completionview, $cm->completionview);
187 $this->assertEquals($moduledb->completionexpected, $cm->completionexpected);
188 $this->assertEquals($moduledb->showdescription, $cm->showdescription);
189 $this->assertEquals(null, $cm->extra); // Deprecated field. Used in module types that don't return cached_cm_info.
190 $this->assertEquals($cachedcminfo->icon, $cm->icon);
191 $this->assertEquals($cachedcminfo->iconcomponent, $cm->iconcomponent);
192 $this->assertEquals('assign', $cm->modname);
193 $this->assertEquals($moduledb->module, $cm->module);
194 $this->assertEquals($cachedcminfo->name, $cm->name);
195 $this->assertEquals($sectiondb->section, $cm->sectionnum);
196 $this->assertEquals($moduledb->section, $cm->section);
197 $this->assertEquals($availability, $cm->availability);
198 $this->assertEquals(context_module::instance($moduledb->id), $cm->context);
199 $this->assertEquals($modnamessingular['assign'], $cm->modfullname);
200 $this->assertEquals($modnamesplural['assign'], $cm->modplural);
201 $this->assertEquals(new moodle_url('/mod/assign/view.php', array('id' => $moduledb->id)), $cm->url);
202 $this->assertEquals($cachedcminfo->customdata, $cm->customdata);
204 // Deprecated field.
205 $this->assertEquals(0, $cm->groupmembersonly);
206 $this->assertDebuggingCalled();
208 // Dynamic fields, just test that they can be retrieved (must be carefully tested in each activity type).
209 $this->assertNotEmpty($cm->availableinfo); // Lists all unmet availability conditions.
210 $this->assertEquals(0, $cm->uservisible);
211 $this->assertEquals('', $cm->extraclasses);
212 $this->assertEquals('', $cm->onclick);
213 $this->assertEquals(null, $cm->afterlink);
214 $this->assertEquals(null, $cm->afterediticons);
215 $this->assertEquals('', $cm->content);
217 // Attempt to access and set non-existing field.
218 $this->assertTrue(empty($modinfo->somefield));
219 $this->assertFalse(isset($modinfo->somefield));
220 $cm->somefield;
221 $this->assertDebuggingCalled();
222 $cm->somefield = 'Some value';
223 $this->assertDebuggingCalled();
224 $this->assertEmpty($cm->somefield);
225 $this->assertDebuggingCalled();
227 // Attempt to overwrite an existing field.
228 $prevvalue = $cm->name;
229 $this->assertNotEmpty($cm->name);
230 $this->assertFalse(empty($cm->name));
231 $this->assertTrue(isset($cm->name));
232 $cm->name = 'Illegal overwriting';
233 $this->assertDebuggingCalled();
234 $this->assertEquals($prevvalue, $cm->name);
235 $this->assertDebuggingNotCalled();
237 // Restore settings.
238 set_config('enableavailability', $oldcfgenableavailability);
239 set_config('enablecompletion', $oldcfgenablecompletion);
242 public function test_matching_cacherev() {
243 global $DB, $CFG;
245 $this->resetAfterTest();
246 $this->setAdminUser();
247 $cache = cache::make('core', 'coursemodinfo');
249 // Generate the course and pre-requisite module.
250 $course = $this->getDataGenerator()->create_course(
251 array('format' => 'topics',
252 'numsections' => 3),
253 array('createsections' => true));
255 // Make sure the cacherev is set.
256 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
257 $this->assertGreaterThan(0, $cacherev);
258 $prevcacherev = $cacherev;
260 // Reset course cache and make sure cacherev is bumped up but cache is empty.
261 rebuild_course_cache($course->id, true);
262 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
263 $this->assertGreaterThan($prevcacherev, $cacherev);
264 $this->assertEmpty($cache->get($course->id));
265 $prevcacherev = $cacherev;
267 // Build course cache. Cacherev should not change but cache is now not empty. Make sure cacherev is the same everywhere.
268 $modinfo = get_fast_modinfo($course->id);
269 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
270 $this->assertEquals($prevcacherev, $cacherev);
271 $cachedvalue = $cache->get($course->id);
272 $this->assertNotEmpty($cachedvalue);
273 $this->assertEquals($cacherev, $cachedvalue->cacherev);
274 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
275 $prevcacherev = $cacherev;
277 // Little trick to check that cache is not rebuilt druing the next step - substitute the value in MUC and later check that it is still there.
278 $cache->set($course->id, (object)array_merge((array)$cachedvalue, array('secretfield' => 1)));
280 // Clear static cache and call get_fast_modinfo() again (pretend we are in another request). Cache should not be rebuilt.
281 course_modinfo::clear_instance_cache();
282 $modinfo = get_fast_modinfo($course->id);
283 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
284 $this->assertEquals($prevcacherev, $cacherev);
285 $cachedvalue = $cache->get($course->id);
286 $this->assertNotEmpty($cachedvalue);
287 $this->assertEquals($cacherev, $cachedvalue->cacherev);
288 $this->assertNotEmpty($cachedvalue->secretfield);
289 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
290 $prevcacherev = $cacherev;
292 // Rebuild course cache. Cacherev must be incremented everywhere.
293 rebuild_course_cache($course->id);
294 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
295 $this->assertGreaterThan($prevcacherev, $cacherev);
296 $cachedvalue = $cache->get($course->id);
297 $this->assertNotEmpty($cachedvalue);
298 $this->assertEquals($cacherev, $cachedvalue->cacherev);
299 $modinfo = get_fast_modinfo($course->id);
300 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
301 $prevcacherev = $cacherev;
303 // Update cacherev in DB and make sure the cache will be rebuilt on the next call to get_fast_modinfo().
304 increment_revision_number('course', 'cacherev', 'id = ?', array($course->id));
305 // We need to clear static cache for course_modinfo instances too.
306 course_modinfo::clear_instance_cache();
307 $modinfo = get_fast_modinfo($course->id);
308 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
309 $this->assertGreaterThan($prevcacherev, $cacherev);
310 $cachedvalue = $cache->get($course->id);
311 $this->assertNotEmpty($cachedvalue);
312 $this->assertEquals($cacherev, $cachedvalue->cacherev);
313 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
314 $prevcacherev = $cacherev;
316 // Reset cache for all courses and make sure this course cache is reset.
317 rebuild_course_cache(0, true);
318 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
319 $this->assertGreaterThan($prevcacherev, $cacherev);
320 $this->assertEmpty($cache->get($course->id));
321 // Rebuild again.
322 $modinfo = get_fast_modinfo($course->id);
323 $cachedvalue = $cache->get($course->id);
324 $this->assertNotEmpty($cachedvalue);
325 $this->assertEquals($cacherev, $cachedvalue->cacherev);
326 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
327 $prevcacherev = $cacherev;
329 // Purge all caches and make sure cacherev is increased and data from MUC erased.
330 purge_all_caches();
331 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
332 $this->assertGreaterThan($prevcacherev, $cacherev);
333 $this->assertEmpty($cache->get($course->id));
336 public function test_course_modinfo_properties() {
337 global $USER, $DB;
339 $this->resetAfterTest();
340 $this->setAdminUser();
342 // Generate the course and some modules. Make one section hidden.
343 $course = $this->getDataGenerator()->create_course(
344 array('format' => 'topics',
345 'numsections' => 3),
346 array('createsections' => true));
347 $DB->execute('UPDATE {course_sections} SET visible = 0 WHERE course = ? and section = ?',
348 array($course->id, 3));
349 $coursecontext = context_course::instance($course->id);
350 $forum0 = $this->getDataGenerator()->create_module('forum',
351 array('course' => $course->id), array('section' => 0));
352 $assign0 = $this->getDataGenerator()->create_module('assign',
353 array('course' => $course->id), array('section' => 0, 'visible' => 0));
354 $forum1 = $this->getDataGenerator()->create_module('forum',
355 array('course' => $course->id), array('section' => 1));
356 $assign1 = $this->getDataGenerator()->create_module('assign',
357 array('course' => $course->id), array('section' => 1));
358 $page1 = $this->getDataGenerator()->create_module('page',
359 array('course' => $course->id), array('section' => 1));
360 $page3 = $this->getDataGenerator()->create_module('page',
361 array('course' => $course->id), array('section' => 3));
363 $modinfo = get_fast_modinfo($course->id);
365 $this->assertEquals(array($forum0->cmid, $assign0->cmid, $forum1->cmid, $assign1->cmid, $page1->cmid, $page3->cmid),
366 array_keys($modinfo->cms));
367 $this->assertEquals($course->id, $modinfo->courseid);
368 $this->assertEquals($USER->id, $modinfo->userid);
369 $this->assertEquals(array(0 => array($forum0->cmid, $assign0->cmid),
370 1 => array($forum1->cmid, $assign1->cmid, $page1->cmid), 3 => array($page3->cmid)), $modinfo->sections);
371 $this->assertEquals(array('forum', 'assign', 'page'), array_keys($modinfo->instances));
372 $this->assertEquals(array($assign0->id, $assign1->id), array_keys($modinfo->instances['assign']));
373 $this->assertEquals(array($forum0->id, $forum1->id), array_keys($modinfo->instances['forum']));
374 $this->assertEquals(array($page1->id, $page3->id), array_keys($modinfo->instances['page']));
375 $this->assertEquals(groups_get_user_groups($course->id), $modinfo->groups);
376 $this->assertEquals(array(0 => array($forum0->cmid, $assign0->cmid),
377 1 => array($forum1->cmid, $assign1->cmid, $page1->cmid),
378 3 => array($page3->cmid)), $modinfo->get_sections());
379 $this->assertEquals(array(0, 1, 2, 3), array_keys($modinfo->get_section_info_all()));
380 $this->assertEquals($forum0->cmid . ',' . $assign0->cmid, $modinfo->get_section_info(0)->sequence);
381 $this->assertEquals($forum1->cmid . ',' . $assign1->cmid . ',' . $page1->cmid, $modinfo->get_section_info(1)->sequence);
382 $this->assertEquals('', $modinfo->get_section_info(2)->sequence);
383 $this->assertEquals($page3->cmid, $modinfo->get_section_info(3)->sequence);
384 $this->assertEquals($course->id, $modinfo->get_course()->id);
385 $this->assertEquals(array('assign', 'forum', 'page'),
386 array_keys($modinfo->get_used_module_names()));
387 $this->assertEquals(array('assign', 'forum', 'page'),
388 array_keys($modinfo->get_used_module_names(true)));
389 // Admin can see hidden modules/sections.
390 $this->assertTrue($modinfo->cms[$assign0->cmid]->uservisible);
391 $this->assertTrue($modinfo->get_section_info(3)->uservisible);
393 // Get modinfo for non-current user (without capability to view hidden activities/sections).
394 $user = $this->getDataGenerator()->create_user();
395 $modinfo = get_fast_modinfo($course->id, $user->id);
396 $this->assertEquals($user->id, $modinfo->userid);
397 $this->assertFalse($modinfo->cms[$assign0->cmid]->uservisible);
398 $this->assertFalse($modinfo->get_section_info(3)->uservisible);
400 // Attempt to access and set non-existing field.
401 $this->assertTrue(empty($modinfo->somefield));
402 $this->assertFalse(isset($modinfo->somefield));
403 $modinfo->somefield;
404 $this->assertDebuggingCalled();
405 $modinfo->somefield = 'Some value';
406 $this->assertDebuggingCalled();
407 $this->assertEmpty($modinfo->somefield);
408 $this->assertDebuggingCalled();
410 // Attempt to overwrite existing field.
411 $this->assertFalse(empty($modinfo->cms));
412 $this->assertTrue(isset($modinfo->cms));
413 $modinfo->cms = 'Illegal overwriting';
414 $this->assertDebuggingCalled();
415 $this->assertNotEquals('Illegal overwriting', $modinfo->cms);
418 public function test_is_user_access_restricted_by_capability() {
419 global $DB;
421 $this->resetAfterTest();
423 // Create a course and a mod_assign instance.
424 $course = $this->getDataGenerator()->create_course();
425 $assign = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id));
427 // Create and enrol a student.
428 $coursecontext = context_course::instance($course->id);
429 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
430 $student = $this->getDataGenerator()->create_user();
431 role_assign($studentrole->id, $student->id, $coursecontext);
432 $enrolplugin = enrol_get_plugin('manual');
433 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'));
434 $enrolplugin->enrol_user($enrolinstance, $student->id);
435 $this->setUser($student);
437 // Make sure student can see the module.
438 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
439 $this->assertTrue($cm->uservisible);
440 $this->assertFalse($cm->is_user_access_restricted_by_capability());
442 // Prohibit student to view mod_assign for the course.
443 role_change_permission($studentrole->id, $coursecontext, 'mod/assign:view', CAP_PROHIBIT);
444 get_fast_modinfo($course->id, 0, true);
445 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
446 $this->assertFalse($cm->uservisible);
447 $this->assertTrue($cm->is_user_access_restricted_by_capability());
449 // Restore permission to student to view mod_assign for the course.
450 role_change_permission($studentrole->id, $coursecontext, 'mod/assign:view', CAP_INHERIT);
451 get_fast_modinfo($course->id, 0, true);
452 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
453 $this->assertTrue($cm->uservisible);
454 $this->assertFalse($cm->is_user_access_restricted_by_capability());
456 // Prohibit student to view mod_assign for the particular module.
457 role_change_permission($studentrole->id, context_module::instance($cm->id), 'mod/assign:view', CAP_PROHIBIT);
458 get_fast_modinfo($course->id, 0, true);
459 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
460 $this->assertFalse($cm->uservisible);
461 $this->assertTrue($cm->is_user_access_restricted_by_capability());
463 // Check calling get_fast_modinfo() for different user:
464 $this->setAdminUser();
465 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
466 $this->assertTrue($cm->uservisible);
467 $this->assertFalse($cm->is_user_access_restricted_by_capability());
468 $cm = get_fast_modinfo($course->id, $student->id)->instances['assign'][$assign->id];
469 $this->assertFalse($cm->uservisible);
470 $this->assertTrue($cm->is_user_access_restricted_by_capability());
474 * Tests that various deprecated cm_info methods are throwing debuggign messages
476 public function test_cm_info_property_deprecations() {
477 global $DB, $CFG;
479 $this->resetAfterTest();
481 $course = $this->getDataGenerator()->create_course( array('format' => 'topics', 'numsections' => 3),
482 array('createsections' => true));
483 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
484 $cm = get_fast_modinfo($course->id)->instances['forum'][$forum->id];
486 $cm->get_url();
487 $this->assertDebuggingCalled('cm_info::get_url() is deprecated, please use the property cm_info->url instead.');
489 $cm->get_content();
490 $this->assertDebuggingCalled('cm_info::get_content() is deprecated, please use the property cm_info->content instead.');
492 $cm->get_extra_classes();
493 $this->assertDebuggingCalled('cm_info::get_extra_classes() is deprecated, please use the property cm_info->extraclasses instead.');
495 $cm->get_on_click();
496 $this->assertDebuggingCalled('cm_info::get_on_click() is deprecated, please use the property cm_info->onclick instead.');
498 $cm->get_custom_data();
499 $this->assertDebuggingCalled('cm_info::get_custom_data() is deprecated, please use the property cm_info->customdata instead.');
501 $cm->get_after_link();
502 $this->assertDebuggingCalled('cm_info::get_after_link() is deprecated, please use the property cm_info->afterlink instead.');
504 $cm->get_after_edit_icons();
505 $this->assertDebuggingCalled('cm_info::get_after_edit_icons() is deprecated, please use the property cm_info->afterediticons instead.');
507 $cm->obtain_dynamic_data();
508 $this->assertDebuggingCalled('cm_info::obtain_dynamic_data() is deprecated and should not be used.');
512 * Tests for function cm_info::get_course_module_record()
514 public function test_cm_info_get_course_module_record() {
515 global $DB, $CFG;
517 $this->resetAfterTest();
519 set_config('enableavailability', 1);
520 set_config('enablecompletion', 1);
522 $course = $this->getDataGenerator()->create_course(
523 array('format' => 'topics', 'numsections' => 3, 'enablecompletion' => 1),
524 array('createsections' => true));
525 $mods = array();
526 $mods[0] = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
527 $mods[1] = $this->getDataGenerator()->create_module('assign',
528 array('course' => $course->id,
529 'section' => 3,
530 'idnumber' => '12345',
531 'showdescription' => true
533 // Pick a small valid availability value to use.
534 $availabilityvalue = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":4}]}';
535 $mods[2] = $this->getDataGenerator()->create_module('book',
536 array('course' => $course->id,
537 'indent' => 5,
538 'availability' => $availabilityvalue,
539 'showdescription' => false,
540 'completion' => true,
541 'completionview' => true,
542 'completionexpected' => time() + 5000,
544 $mods[3] = $this->getDataGenerator()->create_module('forum',
545 array('course' => $course->id,
546 'visible' => 0,
547 'groupmode' => 1,
548 'availability' => null));
549 $mods[4] = $this->getDataGenerator()->create_module('forum',
550 array('course' => $course->id,
551 'grouping' => 12));
553 $modinfo = get_fast_modinfo($course->id);
555 // Make sure that object returned by get_course_module_record(false) has exactly the same fields as DB table 'course_modules'.
556 $dbfields = array_keys($DB->get_columns('course_modules'));
557 sort($dbfields);
558 $cmrecord = $modinfo->get_cm($mods[0]->cmid)->get_course_module_record();
559 $cmrecordfields = array_keys((array)$cmrecord);
560 sort($cmrecordfields);
561 $this->assertEquals($dbfields, $cmrecordfields);
563 // Make sure that object returned by get_course_module_record(true) has exactly the same fields
564 // as object returned by get_coursemodule_from_id(,,,true,);
565 $cmrecordfull = $modinfo->get_cm($mods[0]->cmid)->get_course_module_record(true);
566 $cmrecordfullfields = array_keys((array)$cmrecordfull);
567 $cm = get_coursemodule_from_id(null, $mods[0]->cmid, 0, true, MUST_EXIST);
568 $cmfields = array_keys((array)$cm);
569 $this->assertEquals($cmfields, $cmrecordfullfields);
571 // Make sure that object returned by get_course_module_record(true) has exactly the same fields
572 // as object returned by get_coursemodule_from_instance(,,,true,);
573 $cm = get_coursemodule_from_instance('forum', $mods[0]->id, null, true, MUST_EXIST);
574 $cmfields = array_keys((array)$cm);
575 $this->assertEquals($cmfields, $cmrecordfullfields);
577 // Make sure the objects have the same properties.
578 $cm1 = get_coursemodule_from_id(null, $mods[0]->cmid, 0, true, MUST_EXIST);
579 $cm2 = get_coursemodule_from_instance('forum', $mods[0]->id, 0, true, MUST_EXIST);
580 $cminfo = $modinfo->get_cm($mods[0]->cmid);
581 $record = $DB->get_record('course_modules', array('id' => $mods[0]->cmid));
582 $this->assertEquals($record, $cminfo->get_course_module_record());
583 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
584 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
586 $cm1 = get_coursemodule_from_id(null, $mods[1]->cmid, 0, true, MUST_EXIST);
587 $cm2 = get_coursemodule_from_instance('assign', $mods[1]->id, 0, true, MUST_EXIST);
588 $cminfo = $modinfo->get_cm($mods[1]->cmid);
589 $record = $DB->get_record('course_modules', array('id' => $mods[1]->cmid));
590 $this->assertEquals($record, $cminfo->get_course_module_record());
591 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
592 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
594 $cm1 = get_coursemodule_from_id(null, $mods[2]->cmid, 0, true, MUST_EXIST);
595 $cm2 = get_coursemodule_from_instance('book', $mods[2]->id, 0, true, MUST_EXIST);
596 $cminfo = $modinfo->get_cm($mods[2]->cmid);
597 $record = $DB->get_record('course_modules', array('id' => $mods[2]->cmid));
598 $this->assertEquals($record, $cminfo->get_course_module_record());
599 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
600 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
602 $cm1 = get_coursemodule_from_id(null, $mods[3]->cmid, 0, true, MUST_EXIST);
603 $cm2 = get_coursemodule_from_instance('forum', $mods[3]->id, 0, true, MUST_EXIST);
604 $cminfo = $modinfo->get_cm($mods[3]->cmid);
605 $record = $DB->get_record('course_modules', array('id' => $mods[3]->cmid));
606 $this->assertEquals($record, $cminfo->get_course_module_record());
607 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
608 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
610 $cm1 = get_coursemodule_from_id(null, $mods[4]->cmid, 0, true, MUST_EXIST);
611 $cm2 = get_coursemodule_from_instance('forum', $mods[4]->id, 0, true, MUST_EXIST);
612 $cminfo = $modinfo->get_cm($mods[4]->cmid);
613 $record = $DB->get_record('course_modules', array('id' => $mods[4]->cmid));
614 $this->assertEquals($record, $cminfo->get_course_module_record());
615 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
616 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
621 * Tests the availability property that has been added to course modules
622 * and sections (just to see that it is correctly saved and accessed).
624 public function test_availability_property() {
625 global $DB, $CFG;
627 $this->resetAfterTest();
629 // Create a course with two modules and three sections.
630 $course = $this->getDataGenerator()->create_course(
631 array('format' => 'topics', 'numsections' => 3),
632 array('createsections' => true));
633 $forum = $this->getDataGenerator()->create_module('forum',
634 array('course' => $course->id));
635 $forum2 = $this->getDataGenerator()->create_module('forum',
636 array('course' => $course->id));
638 // Get modinfo. Check that availability is null for both cm and sections.
639 $modinfo = get_fast_modinfo($course->id);
640 $cm = $modinfo->get_cm($forum->cmid);
641 $this->assertNull($cm->availability);
642 $section = $modinfo->get_section_info(1, MUST_EXIST);
643 $this->assertNull($section->availability);
645 // Update availability for cm and section in database.
646 $DB->set_field('course_modules', 'availability', '{}', array('id' => $cm->id));
647 $DB->set_field('course_sections', 'availability', '{}', array('id' => $section->id));
649 // Clear cache and get modinfo again.
650 rebuild_course_cache($course->id, true);
651 get_fast_modinfo(0, 0, true);
652 $modinfo = get_fast_modinfo($course->id);
654 // Check values that were changed.
655 $cm = $modinfo->get_cm($forum->cmid);
656 $this->assertEquals('{}', $cm->availability);
657 $section = $modinfo->get_section_info(1, MUST_EXIST);
658 $this->assertEquals('{}', $section->availability);
660 // Check other values are still null.
661 $cm = $modinfo->get_cm($forum2->cmid);
662 $this->assertNull($cm->availability);
663 $section = $modinfo->get_section_info(2, MUST_EXIST);
664 $this->assertNull($section->availability);
668 * Tests for get_groups() method.
670 public function test_get_groups() {
671 $this->resetAfterTest();
672 $generator = $this->getDataGenerator();
674 // Create courses.
675 $course1 = $generator->create_course();
676 $course2 = $generator->create_course();
677 $course3 = $generator->create_course();
679 // Create users.
680 $user1 = $generator->create_user();
681 $user2 = $generator->create_user();
682 $user3 = $generator->create_user();
684 // Enrol users on courses.
685 $generator->enrol_user($user1->id, $course1->id);
686 $generator->enrol_user($user2->id, $course2->id);
687 $generator->enrol_user($user3->id, $course2->id);
688 $generator->enrol_user($user3->id, $course3->id);
690 // Create groups.
691 $group1 = $generator->create_group(array('courseid' => $course1->id));
692 $group2 = $generator->create_group(array('courseid' => $course2->id));
693 $group3 = $generator->create_group(array('courseid' => $course2->id));
695 // Assign users to groups and assert the result.
696 $this->assertTrue($generator->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id)));
697 $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id)));
698 $this->assertTrue($generator->create_group_member(array('groupid' => $group3->id, 'userid' => $user2->id)));
699 $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user3->id)));
701 // Create groupings.
702 $grouping1 = $generator->create_grouping(array('courseid' => $course1->id));
703 $grouping2 = $generator->create_grouping(array('courseid' => $course2->id));
705 // Assign and assert group to groupings.
706 groups_assign_grouping($grouping1->id, $group1->id);
707 groups_assign_grouping($grouping2->id, $group2->id);
708 groups_assign_grouping($grouping2->id, $group3->id);
710 // Test with one single group.
711 $modinfo = get_fast_modinfo($course1, $user1->id);
712 $groups = $modinfo->get_groups($grouping1->id);
713 $this->assertCount(1, $groups);
714 $this->assertArrayHasKey($group1->id, $groups);
716 // Test with two groups.
717 $modinfo = get_fast_modinfo($course2, $user2->id);
718 $groups = $modinfo->get_groups();
719 $this->assertCount(2, $groups);
720 $this->assertTrue(in_array($group2->id, $groups));
721 $this->assertTrue(in_array($group3->id, $groups));
723 // Test with no groups.
724 $modinfo = get_fast_modinfo($course3, $user3->id);
725 $groups = $modinfo->get_groups();
726 $this->assertCount(0, $groups);
727 $this->assertArrayNotHasKey($group1->id, $groups);
731 * Tests the function for constructing a cm_info from mixed data.
733 public function test_create() {
734 global $CFG, $DB;
735 $this->resetAfterTest();
737 // Create a course and an activity.
738 $generator = $this->getDataGenerator();
739 $course = $generator->create_course();
740 $page = $generator->create_module('page', array('course' => $course->id,
741 'name' => 'Annie'));
743 // Null is passed through.
744 $this->assertNull(cm_info::create(null));
746 // Stdclass object turns into cm_info.
747 $cm = cm_info::create(
748 (object)array('id' => $page->cmid, 'course' => $course->id));
749 $this->assertInstanceOf('cm_info', $cm);
750 $this->assertEquals('Annie', $cm->name);
752 // A cm_info object stays as cm_info.
753 $this->assertSame($cm, cm_info::create($cm));
755 // Invalid object (missing fields) causes error.
756 try {
757 cm_info::create((object)array('id' => $page->cmid));
758 $this->fail();
759 } catch (Exception $e) {
760 $this->assertInstanceOf('coding_exception', $e);
763 // Create a second hidden activity.
764 $hiddenpage = $generator->create_module('page', array('course' => $course->id,
765 'name' => 'Annie', 'visible' => 0));
767 // Create 2 user accounts, one is a manager who can see everything.
768 $user = $generator->create_user();
769 $generator->enrol_user($user->id, $course->id);
770 $manager = $generator->create_user();
771 $generator->enrol_user($manager->id, $course->id,
772 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
774 // User can see the normal page but not the hidden one.
775 $cm = cm_info::create((object)array('id' => $page->cmid, 'course' => $course->id),
776 $user->id);
777 $this->assertTrue($cm->uservisible);
778 $cm = cm_info::create((object)array('id' => $hiddenpage->cmid, 'course' => $course->id),
779 $user->id);
780 $this->assertFalse($cm->uservisible);
782 // Manager can see the hidden one too.
783 $cm = cm_info::create((object)array('id' => $hiddenpage->cmid, 'course' => $course->id),
784 $manager->id);
785 $this->assertTrue($cm->uservisible);
789 * Tests function for getting $course and $cm at once quickly from modinfo
790 * based on cmid or cm record.
792 public function test_get_course_and_cm_from_cmid() {
793 global $CFG, $DB;
794 $this->resetAfterTest();
796 // Create a course and an activity.
797 $generator = $this->getDataGenerator();
798 $course = $generator->create_course(array('shortname' => 'Halls'));
799 $page = $generator->create_module('page', array('course' => $course->id,
800 'name' => 'Annie'));
802 // Successful usage.
803 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid);
804 $this->assertEquals('Halls', $course->shortname);
805 $this->assertInstanceOf('cm_info', $cm);
806 $this->assertEquals('Annie', $cm->name);
808 // Specified module type.
809 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page');
810 $this->assertEquals('Annie', $cm->name);
812 // With id in object.
813 $fakecm = (object)array('id' => $page->cmid);
814 list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
815 $this->assertEquals('Halls', $course->shortname);
816 $this->assertEquals('Annie', $cm->name);
818 // With both id and course in object.
819 $fakecm->course = $course->id;
820 list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
821 $this->assertEquals('Halls', $course->shortname);
822 $this->assertEquals('Annie', $cm->name);
824 // With supplied course id.
825 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', $course->id);
826 $this->assertEquals('Annie', $cm->name);
828 // With supplied course object (modified just so we can check it is
829 // indeed reusing the supplied object).
830 $course->silly = true;
831 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', $course);
832 $this->assertEquals('Annie', $cm->name);
833 $this->assertTrue($course->silly);
835 // Incorrect module type.
836 try {
837 get_course_and_cm_from_cmid($page->cmid, 'forum');
838 $this->fail();
839 } catch (moodle_exception $e) {
840 $this->assertEquals('invalidcoursemodule', $e->errorcode);
843 // Invalid module name.
844 try {
845 get_course_and_cm_from_cmid($page->cmid, 'pigs can fly');
846 $this->fail();
847 } catch (coding_exception $e) {
848 $this->assertContains('Invalid modulename parameter', $e->getMessage());
851 // Doesn't exist.
852 try {
853 get_course_and_cm_from_cmid($page->cmid + 1);
854 $this->fail();
855 } catch (moodle_exception $e) {
856 $this->assertInstanceOf('dml_exception', $e);
859 // Create a second hidden activity.
860 $hiddenpage = $generator->create_module('page', array('course' => $course->id,
861 'name' => 'Annie', 'visible' => 0));
863 // Create 2 user accounts, one is a manager who can see everything.
864 $user = $generator->create_user();
865 $generator->enrol_user($user->id, $course->id);
866 $manager = $generator->create_user();
867 $generator->enrol_user($manager->id, $course->id,
868 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
870 // User can see the normal page but not the hidden one.
871 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', 0, $user->id);
872 $this->assertTrue($cm->uservisible);
873 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $user->id);
874 $this->assertFalse($cm->uservisible);
876 // Manager can see the hidden one too.
877 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $manager->id);
878 $this->assertTrue($cm->uservisible);
882 * Tests function for getting $course and $cm at once quickly from modinfo
883 * based on instance id or record.
885 public function test_get_course_and_cm_from_instance() {
886 global $CFG, $DB;
887 $this->resetAfterTest();
889 // Create a course and an activity.
890 $generator = $this->getDataGenerator();
891 $course = $generator->create_course(array('shortname' => 'Halls'));
892 $page = $generator->create_module('page', array('course' => $course->id,
893 'name' => 'Annie'));
895 // Successful usage.
896 list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page');
897 $this->assertEquals('Halls', $course->shortname);
898 $this->assertInstanceOf('cm_info', $cm);
899 $this->assertEquals('Annie', $cm->name);
901 // With id in object.
902 $fakeinstance = (object)array('id' => $page->id);
903 list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
904 $this->assertEquals('Halls', $course->shortname);
905 $this->assertEquals('Annie', $cm->name);
907 // With both id and course in object.
908 $fakeinstance->course = $course->id;
909 list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
910 $this->assertEquals('Halls', $course->shortname);
911 $this->assertEquals('Annie', $cm->name);
913 // With supplied course id.
914 list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page', $course->id);
915 $this->assertEquals('Annie', $cm->name);
917 // With supplied course object (modified just so we can check it is
918 // indeed reusing the supplied object).
919 $course->silly = true;
920 list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page', $course);
921 $this->assertEquals('Annie', $cm->name);
922 $this->assertTrue($course->silly);
924 // Doesn't exist (or is wrong type).
925 try {
926 get_course_and_cm_from_instance($page->id, 'forum');
927 $this->fail();
928 } catch (moodle_exception $e) {
929 $this->assertInstanceOf('dml_exception', $e);
932 // Invalid module name.
933 try {
934 get_course_and_cm_from_cmid($page->cmid, '1337 h4x0ring');
935 $this->fail();
936 } catch (coding_exception $e) {
937 $this->assertContains('Invalid modulename parameter', $e->getMessage());
940 // Create a second hidden activity.
941 $hiddenpage = $generator->create_module('page', array('course' => $course->id,
942 'name' => 'Annie', 'visible' => 0));
944 // Create 2 user accounts, one is a manager who can see everything.
945 $user = $generator->create_user();
946 $generator->enrol_user($user->id, $course->id);
947 $manager = $generator->create_user();
948 $generator->enrol_user($manager->id, $course->id,
949 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
951 // User can see the normal page but not the hidden one.
952 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', 0, $user->id);
953 $this->assertTrue($cm->uservisible);
954 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $user->id);
955 $this->assertFalse($cm->uservisible);
957 // Manager can see the hidden one too.
958 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $manager->id);
959 $this->assertTrue($cm->uservisible);