2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
19 use advanced_testcase
;
31 * Unit tests for lib/modinfolib.php.
35 * @copyright 2012 Andrew Davis
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 class modinfolib_test
extends advanced_testcase
{
39 public function test_section_info_properties() {
42 $this->resetAfterTest();
43 $oldcfgenableavailability = $CFG->enableavailability
;
44 $oldcfgenablecompletion = $CFG->enablecompletion
;
45 set_config('enableavailability', 1);
46 set_config('enablecompletion', 1);
47 $this->setAdminUser();
49 // Generate the course and pre-requisite module.
50 $course = $this->getDataGenerator()->create_course(
51 array('format' => 'topics',
53 'enablecompletion' => 1,
54 'groupmode' => SEPARATEGROUPS
,
55 'forcegroupmode' => 0),
56 array('createsections' => true));
57 $coursecontext = context_course
::instance($course->id
);
58 $prereqforum = $this->getDataGenerator()->create_module('forum',
59 array('course' => $course->id
),
60 array('completion' => 1));
62 // Add availability conditions.
63 $availability = '{"op":"&","showc":[true,true,true],"c":[' .
64 '{"type":"completion","cm":' . $prereqforum->cmid
. ',"e":"' .
65 COMPLETION_COMPLETE
. '"},' .
66 '{"type":"grade","id":666,"min":0.4},' .
67 '{"type":"profile","op":"contains","sf":"email","v":"test"}' .
69 $DB->set_field('course_sections', 'availability', $availability,
70 array('course' => $course->id
, 'section' => 2));
71 rebuild_course_cache($course->id
, true);
72 $sectiondb = $DB->get_record('course_sections', array('course' => $course->id
, 'section' => 2));
74 // Create and enrol a student.
75 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST
);
76 $student = $this->getDataGenerator()->create_user();
77 role_assign($studentrole->id
, $student->id
, $coursecontext);
78 $enrolplugin = enrol_get_plugin('manual');
79 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id
, 'enrol' => 'manual'));
80 $enrolplugin->enrol_user($enrolinstance, $student->id
);
81 $this->setUser($student);
84 $modinfo = get_fast_modinfo($course->id
);
85 $si = $modinfo->get_section_info(2);
87 $this->assertEquals($sectiondb->id
, $si->id
);
88 $this->assertEquals($sectiondb->course
, $si->course
);
89 $this->assertEquals($sectiondb->section
, $si->section
);
90 $this->assertEquals($sectiondb->name
, $si->name
);
91 $this->assertEquals($sectiondb->visible
, $si->visible
);
92 $this->assertEquals($sectiondb->summary
, $si->summary
);
93 $this->assertEquals($sectiondb->summaryformat
, $si->summaryformat
);
94 $this->assertEquals($sectiondb->sequence
, $si->sequence
); // Since this section does not contain invalid modules.
95 $this->assertEquals($availability, $si->availability
);
97 // Dynamic fields, just test that they can be retrieved (must be carefully tested in each activity type).
98 $this->assertEquals(0, $si->available
);
99 $this->assertNotEmpty($si->availableinfo
); // Lists all unmet availability conditions.
100 $this->assertEquals(0, $si->uservisible
);
103 set_config('enableavailability', $oldcfgenableavailability);
104 set_config('enablecompletion', $oldcfgenablecompletion);
107 public function test_cm_info_properties() {
110 $this->resetAfterTest();
111 $oldcfgenableavailability = $CFG->enableavailability
;
112 $oldcfgenablecompletion = $CFG->enablecompletion
;
113 set_config('enableavailability', 1);
114 set_config('enablecompletion', 1);
115 $this->setAdminUser();
117 // Generate the course and pre-requisite module.
118 $course = $this->getDataGenerator()->create_course(
119 array('format' => 'topics',
121 'enablecompletion' => 1,
122 'groupmode' => SEPARATEGROUPS
,
123 'forcegroupmode' => 0),
124 array('createsections' => true));
125 $coursecontext = context_course
::instance($course->id
);
126 $prereqforum = $this->getDataGenerator()->create_module('forum',
127 array('course' => $course->id
),
128 array('completion' => 1));
130 // Generate module and add availability conditions.
131 $availability = '{"op":"&","showc":[true,true,true],"c":[' .
132 '{"type":"completion","cm":' . $prereqforum->cmid
. ',"e":"' .
133 COMPLETION_COMPLETE
. '"},' .
134 '{"type":"grade","id":666,"min":0.4},' .
135 '{"type":"profile","op":"contains","sf":"email","v":"test"}' .
137 $assign = $this->getDataGenerator()->create_module('assign',
138 array('course' => $course->id
),
139 array('idnumber' => 123,
140 'groupmode' => VISIBLEGROUPS
,
141 'availability' => $availability));
142 rebuild_course_cache($course->id
, true);
144 // Retrieve all related records from DB.
145 $assigndb = $DB->get_record('assign', array('id' => $assign->id
));
146 $moduletypedb = $DB->get_record('modules', array('name' => 'assign'));
147 $moduledb = $DB->get_record('course_modules', array('module' => $moduletypedb->id
, 'instance' => $assign->id
));
148 $sectiondb = $DB->get_record('course_sections', array('id' => $moduledb->section
));
149 $modnamessingular = get_module_types_names(false);
150 $modnamesplural = get_module_types_names(true);
152 // Create and enrol a student.
153 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST
);
154 $student = $this->getDataGenerator()->create_user();
155 role_assign($studentrole->id
, $student->id
, $coursecontext);
156 $enrolplugin = enrol_get_plugin('manual');
157 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id
, 'enrol' => 'manual'));
158 $enrolplugin->enrol_user($enrolinstance, $student->id
);
159 $this->setUser($student);
161 // Emulate data used in building course cache to receive the same instance of cached_cm_info as was used in building modinfo.
162 $rawmods = get_course_mods($course->id
);
163 $cachedcminfo = assign_get_coursemodule_info($rawmods[$moduledb->id
]);
166 $modinfo = get_fast_modinfo($course->id
);
167 $cm = $modinfo->instances
['assign'][$assign->id
];
169 $this->assertEquals($moduledb->id
, $cm->id
);
170 $this->assertEquals($assigndb->id
, $cm->instance
);
171 $this->assertEquals($moduledb->course
, $cm->course
);
172 $this->assertEquals($moduledb->idnumber
, $cm->idnumber
);
173 $this->assertEquals($moduledb->added
, $cm->added
);
174 $this->assertEquals($moduledb->visible
, $cm->visible
);
175 $this->assertEquals($moduledb->visibleold
, $cm->visibleold
);
176 $this->assertEquals($moduledb->groupmode
, $cm->groupmode
);
177 $this->assertEquals(VISIBLEGROUPS
, $cm->groupmode
);
178 $this->assertEquals($moduledb->groupingid
, $cm->groupingid
);
179 $this->assertEquals($course->groupmodeforce
, $cm->coursegroupmodeforce
);
180 $this->assertEquals($course->groupmode
, $cm->coursegroupmode
);
181 $this->assertEquals(SEPARATEGROUPS
, $cm->coursegroupmode
);
182 $this->assertEquals($course->groupmodeforce ?
$course->groupmode
: $moduledb->groupmode
,
183 $cm->effectivegroupmode
); // (since mod_assign supports groups).
184 $this->assertEquals(VISIBLEGROUPS
, $cm->effectivegroupmode
);
185 $this->assertEquals($moduledb->indent
, $cm->indent
);
186 $this->assertEquals($moduledb->completion
, $cm->completion
);
187 $this->assertEquals($moduledb->completiongradeitemnumber
, $cm->completiongradeitemnumber
);
188 $this->assertEquals($moduledb->completionpassgrade
, $cm->completionpassgrade
);
189 $this->assertEquals($moduledb->completionview
, $cm->completionview
);
190 $this->assertEquals($moduledb->completionexpected
, $cm->completionexpected
);
191 $this->assertEquals($moduledb->showdescription
, $cm->showdescription
);
192 $this->assertEquals(null, $cm->extra
); // Deprecated field. Used in module types that don't return cached_cm_info.
193 $this->assertEquals($cachedcminfo->icon
, $cm->icon
);
194 $this->assertEquals($cachedcminfo->iconcomponent
, $cm->iconcomponent
);
195 $this->assertEquals('assign', $cm->modname
);
196 $this->assertEquals($moduledb->module
, $cm->module
);
197 $this->assertEquals($cachedcminfo->name
, $cm->name
);
198 $this->assertEquals($sectiondb->section
, $cm->sectionnum
);
199 $this->assertEquals($moduledb->section
, $cm->section
);
200 $this->assertEquals($availability, $cm->availability
);
201 $this->assertEquals(context_module
::instance($moduledb->id
), $cm->context
);
202 $this->assertEquals($modnamessingular['assign'], $cm->modfullname
);
203 $this->assertEquals($modnamesplural['assign'], $cm->modplural
);
204 $this->assertEquals(new moodle_url('/mod/assign/view.php', array('id' => $moduledb->id
)), $cm->url
);
205 $this->assertEquals($cachedcminfo->customdata
, $cm->customdata
);
207 // Dynamic fields, just test that they can be retrieved (must be carefully tested in each activity type).
208 $this->assertNotEmpty($cm->availableinfo
); // Lists all unmet availability conditions.
209 $this->assertEquals(0, $cm->uservisible
);
210 $this->assertEquals('', $cm->extraclasses
);
211 $this->assertEquals('', $cm->onclick
);
212 $this->assertEquals(null, $cm->afterlink
);
213 $this->assertEquals(null, $cm->afterediticons
);
214 $this->assertEquals('', $cm->content
);
216 // Attempt to access and set non-existing field.
217 $this->assertTrue(empty($modinfo->somefield
));
218 $this->assertFalse(isset($modinfo->somefield
));
220 $this->assertDebuggingCalled();
221 $cm->somefield
= 'Some value';
222 $this->assertDebuggingCalled();
223 $this->assertEmpty($cm->somefield
);
224 $this->assertDebuggingCalled();
226 // Attempt to overwrite an existing field.
227 $prevvalue = $cm->name
;
228 $this->assertNotEmpty($cm->name
);
229 $this->assertFalse(empty($cm->name
));
230 $this->assertTrue(isset($cm->name
));
231 $cm->name
= 'Illegal overwriting';
232 $this->assertDebuggingCalled();
233 $this->assertEquals($prevvalue, $cm->name
);
234 $this->assertDebuggingNotCalled();
237 set_config('enableavailability', $oldcfgenableavailability);
238 set_config('enablecompletion', $oldcfgenablecompletion);
241 public function test_matching_cacherev() {
244 $this->resetAfterTest();
245 $this->setAdminUser();
246 $cache = cache
::make('core', 'coursemodinfo');
248 // Generate the course and pre-requisite module.
249 $course = $this->getDataGenerator()->create_course(
250 array('format' => 'topics',
252 array('createsections' => true));
254 // Make sure the cacherev is set.
255 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
256 $this->assertGreaterThan(0, $cacherev);
257 $prevcacherev = $cacherev;
259 // Reset course cache and make sure cacherev is bumped up but cache is empty.
260 rebuild_course_cache($course->id
, true);
261 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
262 $this->assertGreaterThan($prevcacherev, $cacherev);
263 $this->assertEmpty($cache->get_versioned($course->id
, $prevcacherev));
264 $prevcacherev = $cacherev;
266 // Build course cache. Cacherev should not change but cache is now not empty. Make sure cacherev is the same everywhere.
267 $modinfo = get_fast_modinfo($course->id
);
268 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
269 $this->assertEquals($prevcacherev, $cacherev);
270 $cachedvalue = $cache->get_versioned($course->id
, $cacherev);
271 $this->assertNotEmpty($cachedvalue);
272 $this->assertEquals($cacherev, $cachedvalue->cacherev
);
273 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev
);
274 $prevcacherev = $cacherev;
276 // 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.
277 $cache->set_versioned($course->id
, $cacherev, (object)array_merge((array)$cachedvalue, array('secretfield' => 1)));
279 // Clear static cache and call get_fast_modinfo() again (pretend we are in another request). Cache should not be rebuilt.
280 course_modinfo
::clear_instance_cache();
281 $modinfo = get_fast_modinfo($course->id
);
282 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
283 $this->assertEquals($prevcacherev, $cacherev);
284 $cachedvalue = $cache->get_versioned($course->id
, $cacherev);
285 $this->assertNotEmpty($cachedvalue);
286 $this->assertEquals($cacherev, $cachedvalue->cacherev
);
287 $this->assertNotEmpty($cachedvalue->secretfield
);
288 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev
);
289 $prevcacherev = $cacherev;
291 // Rebuild course cache. Cacherev must be incremented everywhere.
292 rebuild_course_cache($course->id
);
293 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
294 $this->assertGreaterThan($prevcacherev, $cacherev);
295 $cachedvalue = $cache->get_versioned($course->id
, $cacherev);
296 $this->assertNotEmpty($cachedvalue);
297 $this->assertEquals($cacherev, $cachedvalue->cacherev
);
298 $modinfo = get_fast_modinfo($course->id
);
299 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev
);
300 $prevcacherev = $cacherev;
302 // Update cacherev in DB and make sure the cache will be rebuilt on the next call to get_fast_modinfo().
303 increment_revision_number('course', 'cacherev', 'id = ?', array($course->id
));
304 // We need to clear static cache for course_modinfo instances too.
305 course_modinfo
::clear_instance_cache();
306 $modinfo = get_fast_modinfo($course->id
);
307 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
308 $this->assertGreaterThan($prevcacherev, $cacherev);
309 $cachedvalue = $cache->get_versioned($course->id
, $cacherev);
310 $this->assertNotEmpty($cachedvalue);
311 $this->assertEquals($cacherev, $cachedvalue->cacherev
);
312 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev
);
313 $prevcacherev = $cacherev;
315 // Reset cache for all courses and make sure this course cache is reset.
316 rebuild_course_cache(0, true);
317 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
318 $this->assertGreaterThan($prevcacherev, $cacherev);
319 $this->assertEmpty($cache->get_versioned($course->id
, $cacherev));
321 $modinfo = get_fast_modinfo($course->id
);
322 $cachedvalue = $cache->get_versioned($course->id
, $cacherev);
323 $this->assertNotEmpty($cachedvalue);
324 $this->assertEquals($cacherev, $cachedvalue->cacherev
);
325 $this->assertEquals($cacherev, $modinfo->get_course()->cacherev
);
326 $prevcacherev = $cacherev;
328 // Purge all caches and make sure cacherev is increased and data from MUC erased.
330 $cacherev = $DB->get_field('course', 'cacherev', array('id' => $course->id
));
331 $this->assertGreaterThan($prevcacherev, $cacherev);
332 $this->assertEmpty($cache->get($course->id
));
335 public function test_course_modinfo_properties() {
338 $this->resetAfterTest();
339 $this->setAdminUser();
341 // Generate the course and some modules. Make one section hidden.
342 $course = $this->getDataGenerator()->create_course(
343 array('format' => 'topics',
345 array('createsections' => true));
346 $DB->execute('UPDATE {course_sections} SET visible = 0 WHERE course = ? and section = ?',
347 array($course->id
, 3));
348 $coursecontext = context_course
::instance($course->id
);
349 $forum0 = $this->getDataGenerator()->create_module('forum',
350 array('course' => $course->id
), array('section' => 0));
351 $assign0 = $this->getDataGenerator()->create_module('assign',
352 array('course' => $course->id
), array('section' => 0, 'visible' => 0));
353 $forum1 = $this->getDataGenerator()->create_module('forum',
354 array('course' => $course->id
), array('section' => 1));
355 $assign1 = $this->getDataGenerator()->create_module('assign',
356 array('course' => $course->id
), array('section' => 1));
357 $page1 = $this->getDataGenerator()->create_module('page',
358 array('course' => $course->id
), array('section' => 1));
359 $page3 = $this->getDataGenerator()->create_module('page',
360 array('course' => $course->id
), array('section' => 3));
362 $modinfo = get_fast_modinfo($course->id
);
364 $this->assertEquals(array($forum0->cmid
, $assign0->cmid
, $forum1->cmid
, $assign1->cmid
, $page1->cmid
, $page3->cmid
),
365 array_keys($modinfo->cms
));
366 $this->assertEquals($course->id
, $modinfo->courseid
);
367 $this->assertEquals($USER->id
, $modinfo->userid
);
368 $this->assertEquals(array(0 => array($forum0->cmid
, $assign0->cmid
),
369 1 => array($forum1->cmid
, $assign1->cmid
, $page1->cmid
), 3 => array($page3->cmid
)), $modinfo->sections
);
370 $this->assertEquals(array('forum', 'assign', 'page'), array_keys($modinfo->instances
));
371 $this->assertEquals(array($assign0->id
, $assign1->id
), array_keys($modinfo->instances
['assign']));
372 $this->assertEquals(array($forum0->id
, $forum1->id
), array_keys($modinfo->instances
['forum']));
373 $this->assertEquals(array($page1->id
, $page3->id
), array_keys($modinfo->instances
['page']));
374 $this->assertEquals(groups_get_user_groups($course->id
), $modinfo->groups
);
375 $this->assertEquals(array(0 => array($forum0->cmid
, $assign0->cmid
),
376 1 => array($forum1->cmid
, $assign1->cmid
, $page1->cmid
),
377 3 => array($page3->cmid
)), $modinfo->get_sections());
378 $this->assertEquals(array(0, 1, 2, 3), array_keys($modinfo->get_section_info_all()));
379 $this->assertEquals($forum0->cmid
. ',' . $assign0->cmid
, $modinfo->get_section_info(0)->sequence
);
380 $this->assertEquals($forum1->cmid
. ',' . $assign1->cmid
. ',' . $page1->cmid
, $modinfo->get_section_info(1)->sequence
);
381 $this->assertEquals('', $modinfo->get_section_info(2)->sequence
);
382 $this->assertEquals($page3->cmid
, $modinfo->get_section_info(3)->sequence
);
383 $this->assertEquals($course->id
, $modinfo->get_course()->id
);
384 $names = array_keys($modinfo->get_used_module_names());
386 $this->assertEquals(array('assign', 'forum', 'page'), $names);
387 $names = array_keys($modinfo->get_used_module_names(true));
389 $this->assertEquals(array('assign', 'forum', 'page'), $names);
390 // Admin can see hidden modules/sections.
391 $this->assertTrue($modinfo->cms
[$assign0->cmid
]->uservisible
);
392 $this->assertTrue($modinfo->get_section_info(3)->uservisible
);
394 // Get modinfo for non-current user (without capability to view hidden activities/sections).
395 $user = $this->getDataGenerator()->create_user();
396 $modinfo = get_fast_modinfo($course->id
, $user->id
);
397 $this->assertEquals($user->id
, $modinfo->userid
);
398 $this->assertFalse($modinfo->cms
[$assign0->cmid
]->uservisible
);
399 $this->assertFalse($modinfo->get_section_info(3)->uservisible
);
401 // Attempt to access and set non-existing field.
402 $this->assertTrue(empty($modinfo->somefield
));
403 $this->assertFalse(isset($modinfo->somefield
));
405 $this->assertDebuggingCalled();
406 $modinfo->somefield
= 'Some value';
407 $this->assertDebuggingCalled();
408 $this->assertEmpty($modinfo->somefield
);
409 $this->assertDebuggingCalled();
411 // Attempt to overwrite existing field.
412 $this->assertFalse(empty($modinfo->cms
));
413 $this->assertTrue(isset($modinfo->cms
));
414 $modinfo->cms
= 'Illegal overwriting';
415 $this->assertDebuggingCalled();
416 $this->assertNotEquals('Illegal overwriting', $modinfo->cms
);
419 public function test_is_user_access_restricted_by_capability() {
422 $this->resetAfterTest();
424 // Create a course and a mod_assign instance.
425 $course = $this->getDataGenerator()->create_course();
426 $assign = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id
));
428 // Create and enrol a student.
429 $coursecontext = context_course
::instance($course->id
);
430 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST
);
431 $student = $this->getDataGenerator()->create_user();
432 role_assign($studentrole->id
, $student->id
, $coursecontext);
433 $enrolplugin = enrol_get_plugin('manual');
434 $enrolinstance = $DB->get_record('enrol', array('courseid' => $course->id
, 'enrol' => 'manual'));
435 $enrolplugin->enrol_user($enrolinstance, $student->id
);
436 $this->setUser($student);
438 // Make sure student can see the module.
439 $cm = get_fast_modinfo($course->id
)->instances
['assign'][$assign->id
];
440 $this->assertTrue($cm->uservisible
);
441 $this->assertFalse($cm->is_user_access_restricted_by_capability());
443 // Prohibit student to view mod_assign for the course.
444 role_change_permission($studentrole->id
, $coursecontext, 'mod/assign:view', CAP_PROHIBIT
);
445 get_fast_modinfo($course->id
, 0, true);
446 $cm = get_fast_modinfo($course->id
)->instances
['assign'][$assign->id
];
447 $this->assertFalse($cm->uservisible
);
448 $this->assertTrue($cm->is_user_access_restricted_by_capability());
450 // Restore permission to student to view mod_assign for the course.
451 role_change_permission($studentrole->id
, $coursecontext, 'mod/assign:view', CAP_INHERIT
);
452 get_fast_modinfo($course->id
, 0, true);
453 $cm = get_fast_modinfo($course->id
)->instances
['assign'][$assign->id
];
454 $this->assertTrue($cm->uservisible
);
455 $this->assertFalse($cm->is_user_access_restricted_by_capability());
457 // Prohibit student to view mod_assign for the particular module.
458 role_change_permission($studentrole->id
, context_module
::instance($cm->id
), 'mod/assign:view', CAP_PROHIBIT
);
459 get_fast_modinfo($course->id
, 0, true);
460 $cm = get_fast_modinfo($course->id
)->instances
['assign'][$assign->id
];
461 $this->assertFalse($cm->uservisible
);
462 $this->assertTrue($cm->is_user_access_restricted_by_capability());
464 // Check calling get_fast_modinfo() for different user:
465 $this->setAdminUser();
466 $cm = get_fast_modinfo($course->id
)->instances
['assign'][$assign->id
];
467 $this->assertTrue($cm->uservisible
);
468 $this->assertFalse($cm->is_user_access_restricted_by_capability());
469 $cm = get_fast_modinfo($course->id
, $student->id
)->instances
['assign'][$assign->id
];
470 $this->assertFalse($cm->uservisible
);
471 $this->assertTrue($cm->is_user_access_restricted_by_capability());
475 * Tests for function cm_info::get_course_module_record()
477 public function test_cm_info_get_course_module_record() {
480 $this->resetAfterTest();
481 $this->setAdminUser();
483 set_config('enableavailability', 1);
484 set_config('enablecompletion', 1);
486 $course = $this->getDataGenerator()->create_course(
487 array('format' => 'topics', 'numsections' => 3, 'enablecompletion' => 1),
488 array('createsections' => true));
490 $mods[0] = $this->getDataGenerator()->create_module('forum', array('course' => $course->id
));
491 $mods[1] = $this->getDataGenerator()->create_module('assign',
492 array('course' => $course->id
,
494 'idnumber' => '12345',
495 'showdescription' => true
497 // Pick a small valid availability value to use.
498 $availabilityvalue = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":4}]}';
499 $mods[2] = $this->getDataGenerator()->create_module('book',
500 array('course' => $course->id
,
502 'availability' => $availabilityvalue,
503 'showdescription' => false,
504 'completion' => true,
505 'completionview' => true,
506 'completionexpected' => time() +
5000,
508 $mods[3] = $this->getDataGenerator()->create_module('forum',
509 array('course' => $course->id
,
512 'availability' => null));
513 $mods[4] = $this->getDataGenerator()->create_module('forum',
514 array('course' => $course->id
,
517 $modinfo = get_fast_modinfo($course->id
);
519 // Make sure that object returned by get_course_module_record(false) has exactly the same fields as DB table 'course_modules'.
520 $dbfields = array_keys($DB->get_columns('course_modules'));
522 $cmrecord = $modinfo->get_cm($mods[0]->cmid
)->get_course_module_record();
523 $cmrecordfields = array_keys((array)$cmrecord);
524 sort($cmrecordfields);
525 $this->assertEquals($dbfields, $cmrecordfields);
527 // Make sure that object returned by get_course_module_record(true) has exactly the same fields
528 // as object returned by get_coursemodule_from_id(,,,true,);
529 $cmrecordfull = $modinfo->get_cm($mods[0]->cmid
)->get_course_module_record(true);
530 $cmrecordfullfields = array_keys((array)$cmrecordfull);
531 $cm = get_coursemodule_from_id(null, $mods[0]->cmid
, 0, true, MUST_EXIST
);
532 $cmfields = array_keys((array)$cm);
533 $this->assertEquals($cmfields, $cmrecordfullfields);
535 // Make sure that object returned by get_course_module_record(true) has exactly the same fields
536 // as object returned by get_coursemodule_from_instance(,,,true,);
537 $cm = get_coursemodule_from_instance('forum', $mods[0]->id
, null, true, MUST_EXIST
);
538 $cmfields = array_keys((array)$cm);
539 $this->assertEquals($cmfields, $cmrecordfullfields);
541 // Make sure the objects have the same properties.
542 $cm1 = get_coursemodule_from_id(null, $mods[0]->cmid
, 0, true, MUST_EXIST
);
543 $cm2 = get_coursemodule_from_instance('forum', $mods[0]->id
, 0, true, MUST_EXIST
);
544 $cminfo = $modinfo->get_cm($mods[0]->cmid
);
545 $record = $DB->get_record('course_modules', array('id' => $mods[0]->cmid
));
546 $this->assertEquals($record, $cminfo->get_course_module_record());
547 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
548 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
550 $cm1 = get_coursemodule_from_id(null, $mods[1]->cmid
, 0, true, MUST_EXIST
);
551 $cm2 = get_coursemodule_from_instance('assign', $mods[1]->id
, 0, true, MUST_EXIST
);
552 $cminfo = $modinfo->get_cm($mods[1]->cmid
);
553 $record = $DB->get_record('course_modules', array('id' => $mods[1]->cmid
));
554 $this->assertEquals($record, $cminfo->get_course_module_record());
555 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
556 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
558 $cm1 = get_coursemodule_from_id(null, $mods[2]->cmid
, 0, true, MUST_EXIST
);
559 $cm2 = get_coursemodule_from_instance('book', $mods[2]->id
, 0, true, MUST_EXIST
);
560 $cminfo = $modinfo->get_cm($mods[2]->cmid
);
561 $record = $DB->get_record('course_modules', array('id' => $mods[2]->cmid
));
562 $this->assertEquals($record, $cminfo->get_course_module_record());
563 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
564 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
566 $cm1 = get_coursemodule_from_id(null, $mods[3]->cmid
, 0, true, MUST_EXIST
);
567 $cm2 = get_coursemodule_from_instance('forum', $mods[3]->id
, 0, true, MUST_EXIST
);
568 $cminfo = $modinfo->get_cm($mods[3]->cmid
);
569 $record = $DB->get_record('course_modules', array('id' => $mods[3]->cmid
));
570 $this->assertEquals($record, $cminfo->get_course_module_record());
571 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
572 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
574 $cm1 = get_coursemodule_from_id(null, $mods[4]->cmid
, 0, true, MUST_EXIST
);
575 $cm2 = get_coursemodule_from_instance('forum', $mods[4]->id
, 0, true, MUST_EXIST
);
576 $cminfo = $modinfo->get_cm($mods[4]->cmid
);
577 $record = $DB->get_record('course_modules', array('id' => $mods[4]->cmid
));
578 $this->assertEquals($record, $cminfo->get_course_module_record());
579 $this->assertEquals($cm1, $cminfo->get_course_module_record(true));
580 $this->assertEquals($cm2, $cminfo->get_course_module_record(true));
585 * Tests the availability property that has been added to course modules
586 * and sections (just to see that it is correctly saved and accessed).
588 public function test_availability_property() {
591 $this->resetAfterTest();
593 // Create a course with two modules and three sections.
594 $course = $this->getDataGenerator()->create_course(
595 array('format' => 'topics', 'numsections' => 3),
596 array('createsections' => true));
597 $forum = $this->getDataGenerator()->create_module('forum',
598 array('course' => $course->id
));
599 $forum2 = $this->getDataGenerator()->create_module('forum',
600 array('course' => $course->id
));
602 // Get modinfo. Check that availability is null for both cm and sections.
603 $modinfo = get_fast_modinfo($course->id
);
604 $cm = $modinfo->get_cm($forum->cmid
);
605 $this->assertNull($cm->availability
);
606 $section = $modinfo->get_section_info(1, MUST_EXIST
);
607 $this->assertNull($section->availability
);
609 // Update availability for cm and section in database.
610 $DB->set_field('course_modules', 'availability', '{}', array('id' => $cm->id
));
611 $DB->set_field('course_sections', 'availability', '{}', array('id' => $section->id
));
613 // Clear cache and get modinfo again.
614 rebuild_course_cache($course->id
, true);
615 get_fast_modinfo(0, 0, true);
616 $modinfo = get_fast_modinfo($course->id
);
618 // Check values that were changed.
619 $cm = $modinfo->get_cm($forum->cmid
);
620 $this->assertEquals('{}', $cm->availability
);
621 $section = $modinfo->get_section_info(1, MUST_EXIST
);
622 $this->assertEquals('{}', $section->availability
);
624 // Check other values are still null.
625 $cm = $modinfo->get_cm($forum2->cmid
);
626 $this->assertNull($cm->availability
);
627 $section = $modinfo->get_section_info(2, MUST_EXIST
);
628 $this->assertNull($section->availability
);
632 * Tests for get_groups() method.
634 public function test_get_groups() {
635 $this->resetAfterTest();
636 $generator = $this->getDataGenerator();
639 $course1 = $generator->create_course();
640 $course2 = $generator->create_course();
641 $course3 = $generator->create_course();
644 $user1 = $generator->create_user();
645 $user2 = $generator->create_user();
646 $user3 = $generator->create_user();
648 // Enrol users on courses.
649 $generator->enrol_user($user1->id
, $course1->id
);
650 $generator->enrol_user($user2->id
, $course2->id
);
651 $generator->enrol_user($user3->id
, $course2->id
);
652 $generator->enrol_user($user3->id
, $course3->id
);
655 $group1 = $generator->create_group(array('courseid' => $course1->id
));
656 $group2 = $generator->create_group(array('courseid' => $course2->id
));
657 $group3 = $generator->create_group(array('courseid' => $course2->id
));
659 // Assign users to groups and assert the result.
660 $this->assertTrue($generator->create_group_member(array('groupid' => $group1->id
, 'userid' => $user1->id
)));
661 $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id
, 'userid' => $user2->id
)));
662 $this->assertTrue($generator->create_group_member(array('groupid' => $group3->id
, 'userid' => $user2->id
)));
663 $this->assertTrue($generator->create_group_member(array('groupid' => $group2->id
, 'userid' => $user3->id
)));
666 $grouping1 = $generator->create_grouping(array('courseid' => $course1->id
));
667 $grouping2 = $generator->create_grouping(array('courseid' => $course2->id
));
669 // Assign and assert group to groupings.
670 groups_assign_grouping($grouping1->id
, $group1->id
);
671 groups_assign_grouping($grouping2->id
, $group2->id
);
672 groups_assign_grouping($grouping2->id
, $group3->id
);
674 // Test with one single group.
675 $modinfo = get_fast_modinfo($course1, $user1->id
);
676 $groups = $modinfo->get_groups($grouping1->id
);
677 $this->assertCount(1, $groups);
678 $this->assertArrayHasKey($group1->id
, $groups);
680 // Test with two groups.
681 $modinfo = get_fast_modinfo($course2, $user2->id
);
682 $groups = $modinfo->get_groups();
683 $this->assertCount(2, $groups);
684 $this->assertTrue(in_array($group2->id
, $groups));
685 $this->assertTrue(in_array($group3->id
, $groups));
687 // Test with no groups.
688 $modinfo = get_fast_modinfo($course3, $user3->id
);
689 $groups = $modinfo->get_groups();
690 $this->assertCount(0, $groups);
691 $this->assertArrayNotHasKey($group1->id
, $groups);
695 * Tests the function for constructing a cm_info from mixed data.
697 public function test_create() {
699 $this->resetAfterTest();
701 // Create a course and an activity.
702 $generator = $this->getDataGenerator();
703 $course = $generator->create_course();
704 $page = $generator->create_module('page', array('course' => $course->id
,
707 // Null is passed through.
708 $this->assertNull(cm_info
::create(null));
710 // Stdclass object turns into cm_info.
711 $cm = cm_info
::create(
712 (object)array('id' => $page->cmid
, 'course' => $course->id
));
713 $this->assertInstanceOf('cm_info', $cm);
714 $this->assertEquals('Annie', $cm->name
);
716 // A cm_info object stays as cm_info.
717 $this->assertSame($cm, cm_info
::create($cm));
719 // Invalid object (missing fields) causes error.
721 cm_info
::create((object)array('id' => $page->cmid
));
723 } catch (Exception
$e) {
724 $this->assertInstanceOf('coding_exception', $e);
727 // Create a second hidden activity.
728 $hiddenpage = $generator->create_module('page', array('course' => $course->id
,
729 'name' => 'Annie', 'visible' => 0));
731 // Create 2 user accounts, one is a manager who can see everything.
732 $user = $generator->create_user();
733 $generator->enrol_user($user->id
, $course->id
);
734 $manager = $generator->create_user();
735 $generator->enrol_user($manager->id
, $course->id
,
736 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST
));
738 // User can see the normal page but not the hidden one.
739 $cm = cm_info
::create((object)array('id' => $page->cmid
, 'course' => $course->id
),
741 $this->assertTrue($cm->uservisible
);
742 $cm = cm_info
::create((object)array('id' => $hiddenpage->cmid
, 'course' => $course->id
),
744 $this->assertFalse($cm->uservisible
);
746 // Manager can see the hidden one too.
747 $cm = cm_info
::create((object)array('id' => $hiddenpage->cmid
, 'course' => $course->id
),
749 $this->assertTrue($cm->uservisible
);
753 * Tests function for getting $course and $cm at once quickly from modinfo
754 * based on cmid or cm record.
756 public function test_get_course_and_cm_from_cmid() {
758 $this->resetAfterTest();
760 // Create a course and an activity.
761 $generator = $this->getDataGenerator();
762 $course = $generator->create_course(array('shortname' => 'Halls'));
763 $page = $generator->create_module('page', array('course' => $course->id
,
767 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid
);
768 $this->assertEquals('Halls', $course->shortname
);
769 $this->assertInstanceOf('cm_info', $cm);
770 $this->assertEquals('Annie', $cm->name
);
772 // Specified module type.
773 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid
, 'page');
774 $this->assertEquals('Annie', $cm->name
);
776 // With id in object.
777 $fakecm = (object)array('id' => $page->cmid
);
778 list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
779 $this->assertEquals('Halls', $course->shortname
);
780 $this->assertEquals('Annie', $cm->name
);
782 // With both id and course in object.
783 $fakecm->course
= $course->id
;
784 list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
785 $this->assertEquals('Halls', $course->shortname
);
786 $this->assertEquals('Annie', $cm->name
);
788 // With supplied course id.
789 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid
, 'page', $course->id
);
790 $this->assertEquals('Annie', $cm->name
);
792 // With supplied course object (modified just so we can check it is
793 // indeed reusing the supplied object).
794 $course->silly
= true;
795 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid
, 'page', $course);
796 $this->assertEquals('Annie', $cm->name
);
797 $this->assertTrue($course->silly
);
799 // Incorrect module type.
801 get_course_and_cm_from_cmid($page->cmid
, 'forum');
803 } catch (moodle_exception
$e) {
804 $this->assertEquals('invalidcoursemodule', $e->errorcode
);
807 // Invalid module name.
809 get_course_and_cm_from_cmid($page->cmid
, 'pigs can fly');
811 } catch (coding_exception
$e) {
812 $this->assertStringContainsString('Invalid modulename parameter', $e->getMessage());
817 get_course_and_cm_from_cmid($page->cmid +
1);
819 } catch (moodle_exception
$e) {
820 $this->assertInstanceOf('dml_exception', $e);
823 // Create a second hidden activity.
824 $hiddenpage = $generator->create_module('page', array('course' => $course->id
,
825 'name' => 'Annie', 'visible' => 0));
827 // Create 2 user accounts, one is a manager who can see everything.
828 $user = $generator->create_user();
829 $generator->enrol_user($user->id
, $course->id
);
830 $manager = $generator->create_user();
831 $generator->enrol_user($manager->id
, $course->id
,
832 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST
));
834 // User can see the normal page but not the hidden one.
835 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid
, 'page', 0, $user->id
);
836 $this->assertTrue($cm->uservisible
);
837 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid
, 'page', 0, $user->id
);
838 $this->assertFalse($cm->uservisible
);
840 // Manager can see the hidden one too.
841 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid
, 'page', 0, $manager->id
);
842 $this->assertTrue($cm->uservisible
);
846 * Tests function for getting $course and $cm at once quickly from modinfo
847 * based on instance id or record.
849 public function test_get_course_and_cm_from_instance() {
851 $this->resetAfterTest();
853 // Create a course and an activity.
854 $generator = $this->getDataGenerator();
855 $course = $generator->create_course(array('shortname' => 'Halls'));
856 $page = $generator->create_module('page', array('course' => $course->id
,
860 list($course, $cm) = get_course_and_cm_from_instance($page->id
, 'page');
861 $this->assertEquals('Halls', $course->shortname
);
862 $this->assertInstanceOf('cm_info', $cm);
863 $this->assertEquals('Annie', $cm->name
);
865 // With id in object.
866 $fakeinstance = (object)array('id' => $page->id
);
867 list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
868 $this->assertEquals('Halls', $course->shortname
);
869 $this->assertEquals('Annie', $cm->name
);
871 // With both id and course in object.
872 $fakeinstance->course
= $course->id
;
873 list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
874 $this->assertEquals('Halls', $course->shortname
);
875 $this->assertEquals('Annie', $cm->name
);
877 // With supplied course id.
878 list($course, $cm) = get_course_and_cm_from_instance($page->id
, 'page', $course->id
);
879 $this->assertEquals('Annie', $cm->name
);
881 // With supplied course object (modified just so we can check it is
882 // indeed reusing the supplied object).
883 $course->silly
= true;
884 list($course, $cm) = get_course_and_cm_from_instance($page->id
, 'page', $course);
885 $this->assertEquals('Annie', $cm->name
);
886 $this->assertTrue($course->silly
);
888 // Doesn't exist (or is wrong type).
890 get_course_and_cm_from_instance($page->id
, 'forum');
892 } catch (moodle_exception
$e) {
893 $this->assertInstanceOf('dml_exception', $e);
896 // Invalid module name.
898 get_course_and_cm_from_cmid($page->cmid
, '1337 h4x0ring');
900 } catch (coding_exception
$e) {
901 $this->assertStringContainsString('Invalid modulename parameter', $e->getMessage());
904 // Create a second hidden activity.
905 $hiddenpage = $generator->create_module('page', array('course' => $course->id
,
906 'name' => 'Annie', 'visible' => 0));
908 // Create 2 user accounts, one is a manager who can see everything.
909 $user = $generator->create_user();
910 $generator->enrol_user($user->id
, $course->id
);
911 $manager = $generator->create_user();
912 $generator->enrol_user($manager->id
, $course->id
,
913 $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST
));
915 // User can see the normal page but not the hidden one.
916 list($course, $cm) = get_course_and_cm_from_cmid($page->cmid
, 'page', 0, $user->id
);
917 $this->assertTrue($cm->uservisible
);
918 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid
, 'page', 0, $user->id
);
919 $this->assertFalse($cm->uservisible
);
921 // Manager can see the hidden one too.
922 list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid
, 'page', 0, $manager->id
);
923 $this->assertTrue($cm->uservisible
);
927 * Test test_get_section_info_by_id method
929 * @dataProvider get_section_info_by_id_provider
930 * @covers \course_modinfo::get_section_info_by_id
932 * @param int $sectionnum the section number
933 * @param int $strictness the search strict mode
934 * @param bool $expectnull if the function will return a null
935 * @param bool $expectexception if the function will throw an exception
937 public function test_get_section_info_by_id(
939 int $strictness = IGNORE_MISSING
,
940 bool $expectnull = false,
941 bool $expectexception = false
945 $this->resetAfterTest();
947 // Create a course with 4 sections.
948 $course = $this->getDataGenerator()->create_course(['numsections' => 4]);
952 $modinfo = get_fast_modinfo($course);
953 $allsections = $modinfo->get_section_info_all();
954 foreach ($allsections as $section) {
955 $sectionindex[$section->section
] = $section->id
;
958 if ($expectexception) {
959 $this->expectException(moodle_exception
::class);
962 $sectionid = $sectionindex[$sectionnum] ??
-1;
964 $section = $modinfo->get_section_info_by_id($sectionid, $strictness);
967 $this->assertNull($section);
969 $this->assertEquals($sectionid, $section->id
);
970 $this->assertEquals($sectionnum, $section->section
);
975 * Data provider for test_get_section_info_by_id().
979 public function get_section_info_by_id_provider() {
981 'Valid section id' => [
983 'strictness' => IGNORE_MISSING
,
984 'expectnull' => false,
985 'expectexception' => false,
989 'strictness' => IGNORE_MISSING
,
990 'expectnull' => false,
991 'expectexception' => false,
993 'invalid section ignore missing' => [
995 'strictness' => IGNORE_MISSING
,
996 'expectnull' => true,
997 'expectexception' => false,
999 'invalid section must exists' => [
1001 'strictness' => MUST_EXIST
,
1002 'expectnull' => false,
1003 'expectexception' => true,
1009 * Test purge_section_cache_by_id method
1011 * @covers \course_modinfo::purge_course_section_cache_by_id
1014 public function test_purge_section_cache_by_id(): void
{
1015 $this->resetAfterTest();
1016 $this->setAdminUser();
1017 $cache = cache
::make('core', 'coursemodinfo');
1019 // Generate the course and pre-requisite section.
1020 $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 3], ['createsections' => true]);
1021 // Reset course cache.
1022 rebuild_course_cache($course->id
, true);
1023 // Build course cache.
1024 get_fast_modinfo($course->id
);
1025 // Get the course modinfo cache.
1026 $coursemodinfo = $cache->get_versioned($course->id
, $course->cacherev
);
1027 // Get the section cache.
1028 $sectioncaches = $coursemodinfo->sectioncache
;
1030 // Make sure that we will have 4 section caches here.
1031 $this->assertCount(4, $sectioncaches);
1032 $this->assertArrayHasKey(0, $sectioncaches);
1033 $this->assertArrayHasKey(1, $sectioncaches);
1034 $this->assertArrayHasKey(2, $sectioncaches);
1035 $this->assertArrayHasKey(3, $sectioncaches);
1037 // Purge cache for the section by id.
1038 course_modinfo
::purge_course_section_cache_by_id($course->id
, $sectioncaches[1]->id
);
1039 // Get the course modinfo cache.
1040 $coursemodinfo = $cache->get_versioned($course->id
, $course->cacherev
);
1041 // Get the section cache.
1042 $sectioncaches = $coursemodinfo->sectioncache
;
1044 // Make sure that we will have 3 section caches left.
1045 $this->assertCount(3, $sectioncaches);
1046 $this->assertArrayNotHasKey(1, $sectioncaches);
1047 $this->assertArrayHasKey(0, $sectioncaches);
1048 $this->assertArrayHasKey(2, $sectioncaches);
1049 $this->assertArrayHasKey(3, $sectioncaches);
1050 // Make sure that the cacherev will be reset.
1051 $this->assertEquals(-1, $coursemodinfo->cacherev
);
1055 * Test purge_section_cache_by_number method
1057 * @covers \course_modinfo::purge_course_section_cache_by_number
1060 public function test_section_cache_by_number(): void
{
1061 $this->resetAfterTest();
1062 $this->setAdminUser();
1063 $cache = cache
::make('core', 'coursemodinfo');
1065 // Generate the course and pre-requisite section.
1066 $course = $this->getDataGenerator()->create_course(['format' => 'topics', 'numsections' => 3], ['createsections' => true]);
1067 // Reset course cache.
1068 rebuild_course_cache($course->id
, true);
1069 // Build course cache.
1070 get_fast_modinfo($course->id
);
1071 // Get the course modinfo cache.
1072 $coursemodinfo = $cache->get_versioned($course->id
, $course->cacherev
);
1073 // Get the section cache.
1074 $sectioncaches = $coursemodinfo->sectioncache
;
1076 // Make sure that we will have 4 section caches here.
1077 $this->assertCount(4, $sectioncaches);
1078 $this->assertArrayHasKey(0, $sectioncaches);
1079 $this->assertArrayHasKey(1, $sectioncaches);
1080 $this->assertArrayHasKey(2, $sectioncaches);
1081 $this->assertArrayHasKey(3, $sectioncaches);
1083 // Purge cache for the section with section number is 1.
1084 course_modinfo
::purge_course_section_cache_by_number($course->id
, 1);
1085 // Get the course modinfo cache.
1086 $coursemodinfo = $cache->get_versioned($course->id
, $course->cacherev
);
1087 // Get the section cache.
1088 $sectioncaches = $coursemodinfo->sectioncache
;
1090 // Make sure that we will have 3 section caches left.
1091 $this->assertCount(3, $sectioncaches);
1092 $this->assertArrayNotHasKey(1, $sectioncaches);
1093 $this->assertArrayHasKey(0, $sectioncaches);
1094 $this->assertArrayHasKey(2, $sectioncaches);
1095 $this->assertArrayHasKey(3, $sectioncaches);
1096 // Make sure that the cacherev will be reset.
1097 $this->assertEquals(-1, $coursemodinfo->cacherev
);