MDL-60425 blog: Remove empty line
[moodle.git] / lib / tests / modinfolib_test.php
blobe1ea0251ca28f398f5053c906bbb23c9b7b3f0b2
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 // Dynamic fields, just test that they can be retrieved (must be carefully tested in each activity type).
205 $this->assertNotEmpty($cm->availableinfo); // Lists all unmet availability conditions.
206 $this->assertEquals(0, $cm->uservisible);
207 $this->assertEquals('', $cm->extraclasses);
208 $this->assertEquals('', $cm->onclick);
209 $this->assertEquals(null, $cm->afterlink);
210 $this->assertEquals(null, $cm->afterediticons);
211 $this->assertEquals('', $cm->content);
213 // Attempt to access and set non-existing field.
214 $this->assertTrue(empty($modinfo->somefield));
215 $this->assertFalse(isset($modinfo->somefield));
216 $cm->somefield;
217 $this->assertDebuggingCalled();
218 $cm->somefield = 'Some value';
219 $this->assertDebuggingCalled();
220 $this->assertEmpty($cm->somefield);
221 $this->assertDebuggingCalled();
223 // Attempt to overwrite an existing field.
224 $prevvalue = $cm->name;
225 $this->assertNotEmpty($cm->name);
226 $this->assertFalse(empty($cm->name));
227 $this->assertTrue(isset($cm->name));
228 $cm->name = 'Illegal overwriting';
229 $this->assertDebuggingCalled();
230 $this->assertEquals($prevvalue, $cm->name);
231 $this->assertDebuggingNotCalled();
233 // Restore settings.
234 set_config('enableavailability', $oldcfgenableavailability);
235 set_config('enablecompletion', $oldcfgenablecompletion);
238 public function test_matching_cacherev() {
239 global $DB, $CFG;
241 $this->resetAfterTest();
242 $this->setAdminUser();
243 $cache = cache::make('core', 'coursemodinfo');
245 // Generate the course and pre-requisite module.
246 $course = $this->getDataGenerator()->create_course(
247 array('format' => 'topics',
248 'numsections' => 3),
249 array('createsections' => true));
251 // Make sure the cacherev is set.
252 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
253 $this->assertGreaterThan(0, $cacherev);
254 $prevcacherev = $cacherev;
256 // Reset course cache and make sure cacherev is bumped up but cache is empty.
257 rebuild_course_cache($course->id, true);
258 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
259 $this->assertGreaterThan($prevcacherev, $cacherev);
260 $this->assertEmpty($cache->get($course->id));
261 $prevcacherev = $cacherev;
263 // Build course cache. Cacherev should not change but cache is now not empty. Make sure cacherev is the same everywhere.
264 $modinfo = get_fast_modinfo($course->id);
265 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
266 $this->assertEquals($prevcacherev, $cacherev);
267 $cachedvalue = $cache->get($course->id);
268 $this->assertNotEmpty($cachedvalue);
269 $this->assertEquals($cacherev, $cachedvalue->cacherev);
270 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
271 $prevcacherev = $cacherev;
273 // 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.
274 $cache->set($course->id, (object)array_merge((array)$cachedvalue, array('secretfield' => 1)));
276 // Clear static cache and call get_fast_modinfo() again (pretend we are in another request). Cache should not be rebuilt.
277 course_modinfo::clear_instance_cache();
278 $modinfo = get_fast_modinfo($course->id);
279 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
280 $this->assertEquals($prevcacherev, $cacherev);
281 $cachedvalue = $cache->get($course->id);
282 $this->assertNotEmpty($cachedvalue);
283 $this->assertEquals($cacherev, $cachedvalue->cacherev);
284 $this->assertNotEmpty($cachedvalue->secretfield);
285 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
286 $prevcacherev = $cacherev;
288 // Rebuild course cache. Cacherev must be incremented everywhere.
289 rebuild_course_cache($course->id);
290 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
291 $this->assertGreaterThan($prevcacherev, $cacherev);
292 $cachedvalue = $cache->get($course->id);
293 $this->assertNotEmpty($cachedvalue);
294 $this->assertEquals($cacherev, $cachedvalue->cacherev);
295 $modinfo = get_fast_modinfo($course->id);
296 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
297 $prevcacherev = $cacherev;
299 // Update cacherev in DB and make sure the cache will be rebuilt on the next call to get_fast_modinfo().
300 increment_revision_number('course', 'cacherev', 'id = ?', array($course->id));
301 // We need to clear static cache for course_modinfo instances too.
302 course_modinfo::clear_instance_cache();
303 $modinfo = get_fast_modinfo($course->id);
304 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
305 $this->assertGreaterThan($prevcacherev, $cacherev);
306 $cachedvalue = $cache->get($course->id);
307 $this->assertNotEmpty($cachedvalue);
308 $this->assertEquals($cacherev, $cachedvalue->cacherev);
309 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
310 $prevcacherev = $cacherev;
312 // Reset cache for all courses and make sure this course cache is reset.
313 rebuild_course_cache(0, true);
314 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
315 $this->assertGreaterThan($prevcacherev, $cacherev);
316 $this->assertEmpty($cache->get($course->id));
317 // Rebuild again.
318 $modinfo = get_fast_modinfo($course->id);
319 $cachedvalue = $cache->get($course->id);
320 $this->assertNotEmpty($cachedvalue);
321 $this->assertEquals($cacherev, $cachedvalue->cacherev);
322 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev);
323 $prevcacherev = $cacherev;
325 // Purge all caches and make sure cacherev is increased and data from MUC erased.
326 purge_all_caches();
327 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id));
328 $this->assertGreaterThan($prevcacherev, $cacherev);
329 $this->assertEmpty($cache->get($course->id));
332 public function test_course_modinfo_properties() {
333 global $USER, $DB;
335 $this->resetAfterTest();
336 $this->setAdminUser();
338 // Generate the course and some modules. Make one section hidden.
339 $course = $this->getDataGenerator()->create_course(
340 array('format' => 'topics',
341 'numsections' => 3),
342 array('createsections' => true));
343 $DB->execute('UPDATE {course_sections} SET visible = 0 WHERE course = ? and section = ?',
344 array($course->id, 3));
345 $coursecontext = context_course::instance($course->id);
346 $forum0 = $this->getDataGenerator()->create_module('forum',
347 array('course' => $course->id), array('section' => 0));
348 $assign0 = $this->getDataGenerator()->create_module('assign',
349 array('course' => $course->id), array('section' => 0, 'visible' => 0));
350 $forum1 = $this->getDataGenerator()->create_module('forum',
351 array('course' => $course->id), array('section' => 1));
352 $assign1 = $this->getDataGenerator()->create_module('assign',
353 array('course' => $course->id), array('section' => 1));
354 $page1 = $this->getDataGenerator()->create_module('page',
355 array('course' => $course->id), array('section' => 1));
356 $page3 = $this->getDataGenerator()->create_module('page',
357 array('course' => $course->id), array('section' => 3));
359 $modinfo = get_fast_modinfo($course->id);
361 $this->assertEquals(array($forum0->cmid, $assign0->cmid, $forum1->cmid, $assign1->cmid, $page1->cmid, $page3->cmid),
362 array_keys($modinfo->cms));
363 $this->assertEquals($course->id, $modinfo->courseid);
364 $this->assertEquals($USER->id, $modinfo->userid);
365 $this->assertEquals(array(0 => array($forum0->cmid, $assign0->cmid),
366 1 => array($forum1->cmid, $assign1->cmid, $page1->cmid), 3 => array($page3->cmid)), $modinfo->sections);
367 $this->assertEquals(array('forum', 'assign', 'page'), array_keys($modinfo->instances));
368 $this->assertEquals(array($assign0->id, $assign1->id), array_keys($modinfo->instances['assign']));
369 $this->assertEquals(array($forum0->id, $forum1->id), array_keys($modinfo->instances['forum']));
370 $this->assertEquals(array($page1->id, $page3->id), array_keys($modinfo->instances['page']));
371 $this->assertEquals(groups_get_user_groups($course->id), $modinfo->groups);
372 $this->assertEquals(array(0 => array($forum0->cmid, $assign0->cmid),
373 1 => array($forum1->cmid, $assign1->cmid, $page1->cmid),
374 3 => array($page3->cmid)), $modinfo->get_sections());
375 $this->assertEquals(array(0, 1, 2, 3), array_keys($modinfo->get_section_info_all()));
376 $this->assertEquals($forum0->cmid . ',' . $assign0->cmid, $modinfo->get_section_info(0)->sequence);
377 $this->assertEquals($forum1->cmid . ',' . $assign1->cmid . ',' . $page1->cmid, $modinfo->get_section_info(1)->sequence);
378 $this->assertEquals('', $modinfo->get_section_info(2)->sequence);
379 $this->assertEquals($page3->cmid, $modinfo->get_section_info(3)->sequence);
380 $this->assertEquals($course->id, $modinfo->get_course()->id);
381 $this->assertEquals(array('assign', 'forum', 'page'),
382 array_keys($modinfo->get_used_module_names()));
383 $this->assertEquals(array('assign', 'forum', 'page'),
384 array_keys($modinfo->get_used_module_names(true)));
385 // Admin can see hidden modules/sections.
386 $this->assertTrue($modinfo->cms[$assign0->cmid]->uservisible);
387 $this->assertTrue($modinfo->get_section_info(3)->uservisible);
389 // Get modinfo for non-current user (without capability to view hidden activities/sections).
390 $user = $this->getDataGenerator()->create_user();
391 $modinfo = get_fast_modinfo($course->id, $user->id);
392 $this->assertEquals($user->id, $modinfo->userid);
393 $this->assertFalse($modinfo->cms[$assign0->cmid]->uservisible);
394 $this->assertFalse($modinfo->get_section_info(3)->uservisible);
396 // Attempt to access and set non-existing field.
397 $this->assertTrue(empty($modinfo->somefield));
398 $this->assertFalse(isset($modinfo->somefield));
399 $modinfo->somefield;
400 $this->assertDebuggingCalled();
401 $modinfo->somefield = 'Some value';
402 $this->assertDebuggingCalled();
403 $this->assertEmpty($modinfo->somefield);
404 $this->assertDebuggingCalled();
406 // Attempt to overwrite existing field.
407 $this->assertFalse(empty($modinfo->cms));
408 $this->assertTrue(isset($modinfo->cms));
409 $modinfo->cms = 'Illegal overwriting';
410 $this->assertDebuggingCalled();
411 $this->assertNotEquals('Illegal overwriting', $modinfo->cms);
414 public function test_is_user_access_restricted_by_capability() {
415 global $DB;
417 $this->resetAfterTest();
419 // Create a course and a mod_assign instance.
420 $course = $this->getDataGenerator()->create_course();
421 $assign = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id));
423 // Create and enrol a student.
424 $coursecontext = context_course::instance($course->id);
425 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
426 $student = $this->getDataGenerator()->create_user();
427 role_assign($studentrole->id, $student->id, $coursecontext);
428 $enrolplugin = enrol_get_plugin('manual');
429 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'));
430 $enrolplugin->enrol_user($enrolinstance, $student->id);
431 $this->setUser($student);
433 // Make sure student can see the module.
434 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
435 $this->assertTrue($cm->uservisible);
436 $this->assertFalse($cm->is_user_access_restricted_by_capability());
438 // Prohibit student to view mod_assign for the course.
439 role_change_permission($studentrole->id, $coursecontext, 'mod/assign:view', CAP_PROHIBIT);
440 get_fast_modinfo($course->id, 0, true);
441 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
442 $this->assertFalse($cm->uservisible);
443 $this->assertTrue($cm->is_user_access_restricted_by_capability());
445 // Restore permission to student to view mod_assign for the course.
446 role_change_permission($studentrole->id, $coursecontext, 'mod/assign:view', CAP_INHERIT);
447 get_fast_modinfo($course->id, 0, true);
448 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
449 $this->assertTrue($cm->uservisible);
450 $this->assertFalse($cm->is_user_access_restricted_by_capability());
452 // Prohibit student to view mod_assign for the particular module.
453 role_change_permission($studentrole->id, context_module::instance($cm->id), 'mod/assign:view', CAP_PROHIBIT);
454 get_fast_modinfo($course->id, 0, true);
455 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
456 $this->assertFalse($cm->uservisible);
457 $this->assertTrue($cm->is_user_access_restricted_by_capability());
459 // Check calling get_fast_modinfo() for different user:
460 $this->setAdminUser();
461 $cm = get_fast_modinfo($course->id)->instances['assign'][$assign->id];
462 $this->assertTrue($cm->uservisible);
463 $this->assertFalse($cm->is_user_access_restricted_by_capability());
464 $cm = get_fast_modinfo($course->id, $student->id)->instances['assign'][$assign->id];
465 $this->assertFalse($cm->uservisible);
466 $this->assertTrue($cm->is_user_access_restricted_by_capability());
470 * Tests for function cm_info::get_course_module_record()
472 public function test_cm_info_get_course_module_record() {
473 global $DB;
475 $this->resetAfterTest();
476 $this->setAdminUser();
478 set_config('enableavailability', 1);
479 set_config('enablecompletion', 1);
481 $course = $this->getDataGenerator()->create_course(
482 array('format' => 'topics', 'numsections' => 3, 'enablecompletion' => 1),
483 array('createsections' => true));
484 $mods = array();
485 $mods[0] = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
486 $mods[1] = $this->getDataGenerator()->create_module('assign',
487 array('course' => $course->id,
488 'section' => 3,
489 'idnumber' => '12345',
490 'showdescription' => true
492 // Pick a small valid availability value to use.
493 $availabilityvalue = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":4}]}';
494 $mods[2] = $this->getDataGenerator()->create_module('book',
495 array('course' => $course->id,
496 'indent' => 5,
497 'availability' => $availabilityvalue,
498 'showdescription' => false,
499 'completion' => true,
500 'completionview' => true,
501 'completionexpected' => time() + 5000,
503 $mods[3] = $this->getDataGenerator()->create_module('forum',
504 array('course' => $course->id,
505 'visible' => 0,
506 'groupmode' => 1,
507 'availability' => null));
508 $mods[4] = $this->getDataGenerator()->create_module('forum',
509 array('course' => $course->id,
510 'grouping' => 12));
512 $modinfo = get_fast_modinfo($course->id);
514 // Make sure that object returned by get_course_module_record(false) has exactly the same fields as DB table 'course_modules'.
515 $dbfields = array_keys($DB->get_columns('course_modules'));
516 sort($dbfields);
517 $cmrecord = $modinfo->get_cm($mods[0]->cmid)->get_course_module_record();
518 $cmrecordfields = array_keys((array)$cmrecord);
519 sort($cmrecordfields);
520 $this->assertEquals($dbfields, $cmrecordfields);
522 // Make sure that object returned by get_course_module_record(true) has exactly the same fields
523 // as object returned by get_coursemodule_from_id(,,,true,);
524 $cmrecordfull = $modinfo->get_cm($mods[0]->cmid)->get_course_module_record(true);
525 $cmrecordfullfields = array_keys((array)$cmrecordfull);
526 $cm = get_coursemodule_from_id(null, $mods[0]->cmid, 0, true, MUST_EXIST);
527 $cmfields = array_keys((array)$cm);
528 $this->assertEquals($cmfields, $cmrecordfullfields);
530 // Make sure that object returned by get_course_module_record(true) has exactly the same fields
531 // as object returned by get_coursemodule_from_instance(,,,true,);
532 $cm = get_coursemodule_from_instance('forum', $mods[0]->id, null, true, MUST_EXIST);
533 $cmfields = array_keys((array)$cm);
534 $this->assertEquals($cmfields, $cmrecordfullfields);
536 // Make sure the objects have the same properties.
537 $cm1 = get_coursemodule_from_id(null, $mods[0]->cmid, 0, true, MUST_EXIST);
538 $cm2 = get_coursemodule_from_instance('forum', $mods[0]->id, 0, true, MUST_EXIST);
539 $cminfo = $modinfo->get_cm($mods[0]->cmid);
540 $record = $DB->get_record('course_modules', array('id' => $mods[0]->cmid));
541 $this->assertEquals($record, $cminfo->get_course_module_record());
542 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
543 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
545 $cm1 = get_coursemodule_from_id(null, $mods[1]->cmid, 0, true, MUST_EXIST);
546 $cm2 = get_coursemodule_from_instance('assign', $mods[1]->id, 0, true, MUST_EXIST);
547 $cminfo = $modinfo->get_cm($mods[1]->cmid);
548 $record = $DB->get_record('course_modules', array('id' => $mods[1]->cmid));
549 $this->assertEquals($record, $cminfo->get_course_module_record());
550 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
551 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
553 $cm1 = get_coursemodule_from_id(null, $mods[2]->cmid, 0, true, MUST_EXIST);
554 $cm2 = get_coursemodule_from_instance('book', $mods[2]->id, 0, true, MUST_EXIST);
555 $cminfo = $modinfo->get_cm($mods[2]->cmid);
556 $record = $DB->get_record('course_modules', array('id' => $mods[2]->cmid));
557 $this->assertEquals($record, $cminfo->get_course_module_record());
558 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
559 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
561 $cm1 = get_coursemodule_from_id(null, $mods[3]->cmid, 0, true, MUST_EXIST);
562 $cm2 = get_coursemodule_from_instance('forum', $mods[3]->id, 0, true, MUST_EXIST);
563 $cminfo = $modinfo->get_cm($mods[3]->cmid);
564 $record = $DB->get_record('course_modules', array('id' => $mods[3]->cmid));
565 $this->assertEquals($record, $cminfo->get_course_module_record());
566 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
567 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
569 $cm1 = get_coursemodule_from_id(null, $mods[4]->cmid, 0, true, MUST_EXIST);
570 $cm2 = get_coursemodule_from_instance('forum', $mods[4]->id, 0, true, MUST_EXIST);
571 $cminfo = $modinfo->get_cm($mods[4]->cmid);
572 $record = $DB->get_record('course_modules', array('id' => $mods[4]->cmid));
573 $this->assertEquals($record, $cminfo->get_course_module_record());
574 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
575 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
580 * Tests the availability property that has been added to course modules
581 * and sections (just to see that it is correctly saved and accessed).
583 public function test_availability_property() {
584 global $DB, $CFG;
586 $this->resetAfterTest();
588 // Create a course with two modules and three sections.
589 $course = $this->getDataGenerator()->create_course(
590 array('format' => 'topics', 'numsections' => 3),
591 array('createsections' => true));
592 $forum = $this->getDataGenerator()->create_module('forum',
593 array('course' => $course->id));
594 $forum2 = $this->getDataGenerator()->create_module('forum',
595 array('course' => $course->id));
597 // Get modinfo. Check that availability is null for both cm and sections.
598 $modinfo = get_fast_modinfo($course->id);
599 $cm = $modinfo->get_cm($forum->cmid);
600 $this->assertNull($cm->availability);
601 $section = $modinfo->get_section_info(1, MUST_EXIST);
602 $this->assertNull($section->availability);
604 // Update availability for cm and section in database.
605 $DB->set_field('course_modules', 'availability', '{}', array('id' => $cm->id));
606 $DB->set_field('course_sections', 'availability', '{}', array('id' => $section->id));
608 // Clear cache and get modinfo again.
609 rebuild_course_cache($course->id, true);
610 get_fast_modinfo(0, 0, true);
611 $modinfo = get_fast_modinfo($course->id);
613 // Check values that were changed.
614 $cm = $modinfo->get_cm($forum->cmid);
615 $this->assertEquals('{}', $cm->availability);
616 $section = $modinfo->get_section_info(1, MUST_EXIST);
617 $this->assertEquals('{}', $section->availability);
619 // Check other values are still null.
620 $cm = $modinfo->get_cm($forum2->cmid);
621 $this->assertNull($cm->availability);
622 $section = $modinfo->get_section_info(2, MUST_EXIST);
623 $this->assertNull($section->availability);
627 * Tests for get_groups() method.
629 public function test_get_groups() {
630 $this->resetAfterTest();
631 $generator = $this->getDataGenerator();
633 // Create courses.
634 $course1 = $generator->create_course();
635 $course2 = $generator->create_course();
636 $course3 = $generator->create_course();
638 // Create users.
639 $user1 = $generator->create_user();
640 $user2 = $generator->create_user();
641 $user3 = $generator->create_user();
643 // Enrol users on courses.
644 $generator->enrol_user($user1->id, $course1->id);
645 $generator->enrol_user($user2->id, $course2->id);
646 $generator->enrol_user($user3->id, $course2->id);
647 $generator->enrol_user($user3->id, $course3->id);
649 // Create groups.
650 $group1 = $generator->create_group(array('courseid' => $course1->id));
651 $group2 = $generator->create_group(array('courseid' => $course2->id));
652 $group3 = $generator->create_group(array('courseid' => $course2->id));
654 // Assign users to groups and assert the result.
655 $this->assertTrue($generator->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id)));
656 $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id)));
657 $this->assertTrue($generator->create_group_member(array('groupid' => $group3->id, 'userid' => $user2->id)));
658 $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user3->id)));
660 // Create groupings.
661 $grouping1 = $generator->create_grouping(array('courseid' => $course1->id));
662 $grouping2 = $generator->create_grouping(array('courseid' => $course2->id));
664 // Assign and assert group to groupings.
665 groups_assign_grouping($grouping1->id, $group1->id);
666 groups_assign_grouping($grouping2->id, $group2->id);
667 groups_assign_grouping($grouping2->id, $group3->id);
669 // Test with one single group.
670 $modinfo = get_fast_modinfo($course1, $user1->id);
671 $groups = $modinfo->get_groups($grouping1->id);
672 $this->assertCount(1, $groups);
673 $this->assertArrayHasKey($group1->id, $groups);
675 // Test with two groups.
676 $modinfo = get_fast_modinfo($course2, $user2->id);
677 $groups = $modinfo->get_groups();
678 $this->assertCount(2, $groups);
679 $this->assertTrue(in_array($group2->id, $groups));
680 $this->assertTrue(in_array($group3->id, $groups));
682 // Test with no groups.
683 $modinfo = get_fast_modinfo($course3, $user3->id);
684 $groups = $modinfo->get_groups();
685 $this->assertCount(0, $groups);
686 $this->assertArrayNotHasKey($group1->id, $groups);
690 * Tests the function for constructing a cm_info from mixed data.
692 public function test_create() {
693 global $CFG, $DB;
694 $this->resetAfterTest();
696 // Create a course and an activity.
697 $generator = $this->getDataGenerator();
698 $course = $generator->create_course();
699 $page = $generator->create_module('page', array('course' => $course->id,
700 'name' => 'Annie'));
702 // Null is passed through.
703 $this->assertNull(cm_info::create(null));
705 // Stdclass object turns into cm_info.
706 $cm = cm_info::create(
707 (object)array('id' => $page->cmid, 'course' => $course->id));
708 $this->assertInstanceOf('cm_info', $cm);
709 $this->assertEquals('Annie', $cm->name);
711 // A cm_info object stays as cm_info.
712 $this->assertSame($cm, cm_info::create($cm));
714 // Invalid object (missing fields) causes error.
715 try {
716 cm_info::create((object)array('id' => $page->cmid));
717 $this->fail();
718 } catch (Exception $e) {
719 $this->assertInstanceOf('coding_exception', $e);
722 // Create a second hidden activity.
723 $hiddenpage = $generator->create_module('page', array('course' => $course->id,
724 'name' => 'Annie', 'visible' => 0));
726 // Create 2 user accounts, one is a manager who can see everything.
727 $user = $generator->create_user();
728 $generator->enrol_user($user->id, $course->id);
729 $manager = $generator->create_user();
730 $generator->enrol_user($manager->id, $course->id,
731 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
733 // User can see the normal page but not the hidden one.
734 $cm = cm_info::create((object)array('id' => $page->cmid, 'course' => $course->id),
735 $user->id);
736 $this->assertTrue($cm->uservisible);
737 $cm = cm_info::create((object)array('id' => $hiddenpage->cmid, 'course' => $course->id),
738 $user->id);
739 $this->assertFalse($cm->uservisible);
741 // Manager can see the hidden one too.
742 $cm = cm_info::create((object)array('id' => $hiddenpage->cmid, 'course' => $course->id),
743 $manager->id);
744 $this->assertTrue($cm->uservisible);
748 * Tests function for getting $course and $cm at once quickly from modinfo
749 * based on cmid or cm record.
751 public function test_get_course_and_cm_from_cmid() {
752 global $CFG, $DB;
753 $this->resetAfterTest();
755 // Create a course and an activity.
756 $generator = $this->getDataGenerator();
757 $course = $generator->create_course(array('shortname' => 'Halls'));
758 $page = $generator->create_module('page', array('course' => $course->id,
759 'name' => 'Annie'));
761 // Successful usage.
762 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid);
763 $this->assertEquals('Halls', $course->shortname);
764 $this->assertInstanceOf('cm_info', $cm);
765 $this->assertEquals('Annie', $cm->name);
767 // Specified module type.
768 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page');
769 $this->assertEquals('Annie', $cm->name);
771 // With id in object.
772 $fakecm = (object)array('id' => $page->cmid);
773 list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
774 $this->assertEquals('Halls', $course->shortname);
775 $this->assertEquals('Annie', $cm->name);
777 // With both id and course in object.
778 $fakecm->course = $course->id;
779 list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
780 $this->assertEquals('Halls', $course->shortname);
781 $this->assertEquals('Annie', $cm->name);
783 // With supplied course id.
784 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', $course->id);
785 $this->assertEquals('Annie', $cm->name);
787 // With supplied course object (modified just so we can check it is
788 // indeed reusing the supplied object).
789 $course->silly = true;
790 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', $course);
791 $this->assertEquals('Annie', $cm->name);
792 $this->assertTrue($course->silly);
794 // Incorrect module type.
795 try {
796 get_course_and_cm_from_cmid($page->cmid, 'forum');
797 $this->fail();
798 } catch (moodle_exception $e) {
799 $this->assertEquals('invalidcoursemodule', $e->errorcode);
802 // Invalid module name.
803 try {
804 get_course_and_cm_from_cmid($page->cmid, 'pigs can fly');
805 $this->fail();
806 } catch (coding_exception $e) {
807 $this->assertContains('Invalid modulename parameter', $e->getMessage());
810 // Doesn't exist.
811 try {
812 get_course_and_cm_from_cmid($page->cmid + 1);
813 $this->fail();
814 } catch (moodle_exception $e) {
815 $this->assertInstanceOf('dml_exception', $e);
818 // Create a second hidden activity.
819 $hiddenpage = $generator->create_module('page', array('course' => $course->id,
820 'name' => 'Annie', 'visible' => 0));
822 // Create 2 user accounts, one is a manager who can see everything.
823 $user = $generator->create_user();
824 $generator->enrol_user($user->id, $course->id);
825 $manager = $generator->create_user();
826 $generator->enrol_user($manager->id, $course->id,
827 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
829 // User can see the normal page but not the hidden one.
830 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', 0, $user->id);
831 $this->assertTrue($cm->uservisible);
832 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $user->id);
833 $this->assertFalse($cm->uservisible);
835 // Manager can see the hidden one too.
836 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $manager->id);
837 $this->assertTrue($cm->uservisible);
841 * Tests function for getting $course and $cm at once quickly from modinfo
842 * based on instance id or record.
844 public function test_get_course_and_cm_from_instance() {
845 global $CFG, $DB;
846 $this->resetAfterTest();
848 // Create a course and an activity.
849 $generator = $this->getDataGenerator();
850 $course = $generator->create_course(array('shortname' => 'Halls'));
851 $page = $generator->create_module('page', array('course' => $course->id,
852 'name' => 'Annie'));
854 // Successful usage.
855 list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page');
856 $this->assertEquals('Halls', $course->shortname);
857 $this->assertInstanceOf('cm_info', $cm);
858 $this->assertEquals('Annie', $cm->name);
860 // With id in object.
861 $fakeinstance = (object)array('id' => $page->id);
862 list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
863 $this->assertEquals('Halls', $course->shortname);
864 $this->assertEquals('Annie', $cm->name);
866 // With both id and course in object.
867 $fakeinstance->course = $course->id;
868 list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
869 $this->assertEquals('Halls', $course->shortname);
870 $this->assertEquals('Annie', $cm->name);
872 // With supplied course id.
873 list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page', $course->id);
874 $this->assertEquals('Annie', $cm->name);
876 // With supplied course object (modified just so we can check it is
877 // indeed reusing the supplied object).
878 $course->silly = true;
879 list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page', $course);
880 $this->assertEquals('Annie', $cm->name);
881 $this->assertTrue($course->silly);
883 // Doesn't exist (or is wrong type).
884 try {
885 get_course_and_cm_from_instance($page->id, 'forum');
886 $this->fail();
887 } catch (moodle_exception $e) {
888 $this->assertInstanceOf('dml_exception', $e);
891 // Invalid module name.
892 try {
893 get_course_and_cm_from_cmid($page->cmid, '1337 h4x0ring');
894 $this->fail();
895 } catch (coding_exception $e) {
896 $this->assertContains('Invalid modulename parameter', $e->getMessage());
899 // Create a second hidden activity.
900 $hiddenpage = $generator->create_module('page', array('course' => $course->id,
901 'name' => 'Annie', 'visible' => 0));
903 // Create 2 user accounts, one is a manager who can see everything.
904 $user = $generator->create_user();
905 $generator->enrol_user($user->id, $course->id);
906 $manager = $generator->create_user();
907 $generator->enrol_user($manager->id, $course->id,
908 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
910 // User can see the normal page but not the hidden one.
911 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', 0, $user->id);
912 $this->assertTrue($cm->uservisible);
913 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $user->id);
914 $this->assertFalse($cm->uservisible);
916 // Manager can see the hidden one too.
917 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $manager->id);
918 $this->assertTrue($cm->uservisible);