MDL-49294 logging: Improve cleanup tests
[moodle.git] / lib / tests / accesslib_test.php
blobbb1f1e87386f25895320361a0bf9615030f591fb
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 * Full functional accesslib test.
20 * @package core
21 * @category phpunit
22 * @copyright 2011 Petr Skoda {@link http://skodak.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
29 /**
30 * Functional test for accesslib.php
32 * Note: execution may take many minutes especially on slower servers.
34 class core_accesslib_testcase extends advanced_testcase {
35 /**
36 * Verify comparison of context instances in phpunit asserts.
38 public function test_context_comparisons() {
39 $frontpagecontext1 = context_course::instance(SITEID);
40 context_helper::reset_caches();
41 $frontpagecontext2 = context_course::instance(SITEID);
42 $this->assertEquals($frontpagecontext1, $frontpagecontext2);
44 $user1 = context_user::instance(1);
45 $user2 = context_user::instance(2);
46 $this->assertNotEquals($user1, $user2);
49 /**
50 * Test resetting works.
52 public function test_accesslib_clear_all_caches() {
53 global $ACCESSLIB_PRIVATE;
55 $this->resetAfterTest();
57 $this->setAdminUser();
58 load_all_capabilities();
60 $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
61 $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
62 $this->assertNotEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
63 accesslib_clear_all_caches_for_unit_testing();
64 $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
65 $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
66 $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts);
67 $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
70 /**
71 * Test getting of role access
73 public function test_get_role_access() {
74 global $DB;
76 $roles = $DB->get_records('role');
77 foreach ($roles as $role) {
78 $access = get_role_access($role->id);
80 $this->assertTrue(is_array($access));
81 $this->assertTrue(is_array($access['ra']));
82 $this->assertTrue(is_array($access['rdef']));
83 $this->assertTrue(isset($access['rdef_count']));
84 $this->assertTrue(is_array($access['loaded']));
85 $this->assertTrue(isset($access['time']));
86 $this->assertTrue(is_array($access['rsw']));
89 // Note: the data is validated in the functional permission evaluation test at the end of this testcase.
92 /**
93 * Test getting of guest role.
95 public function test_get_guest_role() {
96 global $CFG;
98 $guest = get_guest_role();
99 $this->assertEquals('guest', $guest->archetype);
100 $this->assertEquals('guest', $guest->shortname);
102 $this->assertEquals($CFG->guestroleid, $guest->id);
106 * Test if user is admin.
108 public function test_is_siteadmin() {
109 global $DB, $CFG;
111 $this->resetAfterTest();
113 $users = $DB->get_records('user');
115 foreach ($users as $user) {
116 $this->setUser(0);
117 if ($user->username === 'admin') {
118 $this->assertTrue(is_siteadmin($user));
119 $this->assertTrue(is_siteadmin($user->id));
120 $this->setUser($user);
121 $this->assertTrue(is_siteadmin());
122 $this->assertTrue(is_siteadmin(null));
123 } else {
124 $this->assertFalse(is_siteadmin($user));
125 $this->assertFalse(is_siteadmin($user->id));
126 $this->setUser($user);
127 $this->assertFalse(is_siteadmin());
128 $this->assertFalse(is_siteadmin(null));
132 // Change the site admin list and check that it still works with
133 // multiple admins. We do this with userids only (not real user
134 // accounts) because it makes the test simpler.
135 $before = $CFG->siteadmins;
136 set_config('siteadmins', '666,667,668');
137 $this->assertTrue(is_siteadmin(666));
138 $this->assertTrue(is_siteadmin(667));
139 $this->assertTrue(is_siteadmin(668));
140 $this->assertFalse(is_siteadmin(669));
141 set_config('siteadmins', '13');
142 $this->assertTrue(is_siteadmin(13));
143 $this->assertFalse(is_siteadmin(666));
144 set_config('siteadmins', $before);
148 * Test if user is enrolled in a course
150 public function test_is_enrolled() {
151 global $DB;
153 $this->resetAfterTest();
155 // Generate data.
156 $user = $this->getDataGenerator()->create_user();
157 $course = $this->getDataGenerator()->create_course();
158 $coursecontext = context_course::instance($course->id);
159 $role = $DB->get_record('role', array('shortname'=>'student'));
161 // There should be a manual enrolment as part of the default install.
162 $plugin = enrol_get_plugin('manual');
163 $instance = $DB->get_record('enrol', array(
164 'courseid' => $course->id,
165 'enrol' => 'manual',
167 $this->assertNotSame(false, $instance);
169 // Enrol the user in the course.
170 $plugin->enrol_user($instance, $user->id, $role->id);
172 // We'll test with the mod/assign:submit capability.
173 $capability= 'mod/assign:submit';
174 $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
176 // Switch to our user.
177 $this->setUser($user);
179 // Ensure that the user has the capability first.
180 $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
182 // We first test whether the user is enrolled on the course as this
183 // seeds the cache, then we test for the capability.
184 $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
185 $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
187 // Prevent the capability for this user role.
188 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
189 $coursecontext->mark_dirty();
190 $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
192 // Again, we seed the cache first by checking initial enrolment,
193 // and then we test the actual capability.
194 $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
195 $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
199 * Test logged in test.
201 public function test_isloggedin() {
202 global $USER;
204 $this->resetAfterTest();
206 $USER->id = 0;
207 $this->assertFalse(isloggedin());
208 $USER->id = 1;
209 $this->assertTrue(isloggedin());
213 * Test guest user test.
215 public function test_isguestuser() {
216 global $DB;
218 $this->resetAfterTest();
220 $guest = $DB->get_record('user', array('username'=>'guest'));
221 $this->setUser(0);
222 $this->assertFalse(isguestuser());
223 $this->setAdminUser();
224 $this->assertFalse(isguestuser());
225 $this->assertTrue(isguestuser($guest));
226 $this->assertTrue(isguestuser($guest->id));
227 $this->setUser($guest);
228 $this->assertTrue(isguestuser());
230 $users = $DB->get_records('user');
231 foreach ($users as $user) {
232 if ($user->username === 'guest') {
233 continue;
235 $this->assertFalse(isguestuser($user));
240 * Test capability riskiness.
242 public function test_is_safe_capability() {
243 global $DB;
244 // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap.
245 $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST);
246 $this->assertFalse(is_safe_capability($capability));
250 * Test context fetching.
252 public function test_get_context_info_array() {
253 $this->resetAfterTest();
255 $syscontext = context_system::instance();
256 $user = $this->getDataGenerator()->create_user();
257 $usercontext = context_user::instance($user->id);
258 $course = $this->getDataGenerator()->create_course();
259 $catcontext = context_coursecat::instance($course->category);
260 $coursecontext = context_course::instance($course->id);
261 $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
262 $modcontext = context_module::instance($page->cmid);
263 $cm = get_coursemodule_from_instance('page', $page->id);
264 $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
265 $block1context = context_block::instance($block1->id);
266 $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id));
267 $block2context = context_block::instance($block2->id);
269 $result = get_context_info_array($syscontext->id);
270 $this->assertCount(3, $result);
271 $this->assertEquals($syscontext, $result[0]);
272 $this->assertNull($result[1]);
273 $this->assertNull($result[2]);
275 $result = get_context_info_array($usercontext->id);
276 $this->assertCount(3, $result);
277 $this->assertEquals($usercontext, $result[0]);
278 $this->assertNull($result[1]);
279 $this->assertNull($result[2]);
281 $result = get_context_info_array($catcontext->id);
282 $this->assertCount(3, $result);
283 $this->assertEquals($catcontext, $result[0]);
284 $this->assertNull($result[1]);
285 $this->assertNull($result[2]);
287 $result = get_context_info_array($coursecontext->id);
288 $this->assertCount(3, $result);
289 $this->assertEquals($coursecontext, $result[0]);
290 $this->assertEquals($course->id, $result[1]->id);
291 $this->assertSame($course->shortname, $result[1]->shortname);
292 $this->assertNull($result[2]);
294 $result = get_context_info_array($block1context->id);
295 $this->assertCount(3, $result);
296 $this->assertEquals($block1context, $result[0]);
297 $this->assertEquals($course->id, $result[1]->id);
298 $this->assertEquals($course->shortname, $result[1]->shortname);
299 $this->assertNull($result[2]);
301 $result = get_context_info_array($modcontext->id);
302 $this->assertCount(3, $result);
303 $this->assertEquals($modcontext, $result[0]);
304 $this->assertEquals($course->id, $result[1]->id);
305 $this->assertSame($course->shortname, $result[1]->shortname);
306 $this->assertEquals($cm->id, $result[2]->id);
307 $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
309 $result = get_context_info_array($block2context->id);
310 $this->assertCount(3, $result);
311 $this->assertEquals($block2context, $result[0]);
312 $this->assertEquals($course->id, $result[1]->id);
313 $this->assertSame($course->shortname, $result[1]->shortname);
314 $this->assertEquals($cm->id, $result[2]->id);
315 $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
319 * Test looking for course contacts.
321 public function test_has_coursecontact_role() {
322 global $DB, $CFG;
324 $this->resetAfterTest();
326 $users = $DB->get_records('user');
328 // Nobody is expected to have any course level roles.
329 $this->assertNotEmpty($CFG->coursecontact);
330 foreach ($users as $user) {
331 $this->assertFalse(has_coursecontact_role($user->id));
334 $user = $this->getDataGenerator()->create_user();
335 $course = $this->getDataGenerator()->create_course();
336 role_assign($CFG->coursecontact, $user->id, context_course::instance($course->id));
337 $this->assertTrue(has_coursecontact_role($user->id));
341 * Test creation of roles.
343 public function test_create_role() {
344 global $DB;
346 $this->resetAfterTest();
348 $id = create_role('New student role', 'student2', 'New student description', 'student');
349 $role = $DB->get_record('role', array('id'=>$id));
351 $this->assertNotEmpty($role);
352 $this->assertSame('New student role', $role->name);
353 $this->assertSame('student2', $role->shortname);
354 $this->assertSame('New student description', $role->description);
355 $this->assertSame('student', $role->archetype);
359 * Test adding of capabilities to roles.
361 public function test_assign_capability() {
362 global $DB;
364 $this->resetAfterTest();
366 $user = $this->getDataGenerator()->create_user();
367 $syscontext = context_system::instance();
368 $frontcontext = context_course::instance(SITEID);
369 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
370 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to student by default.
371 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
372 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
374 $this->setUser($user);
375 $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id);
376 $this->assertTrue($result);
377 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
378 $this->assertNotEmpty($permission);
379 $this->assertEquals(CAP_ALLOW, $permission->permission);
380 $this->assertEquals($user->id, $permission->modifierid);
382 $this->setUser(0);
383 $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false);
384 $this->assertTrue($result);
385 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
386 $this->assertNotEmpty($permission);
387 $this->assertEquals(CAP_ALLOW, $permission->permission);
388 $this->assertEquals(3, $permission->modifierid);
390 $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true);
391 $this->assertTrue($result);
392 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
393 $this->assertNotEmpty($permission);
394 $this->assertEquals(CAP_PROHIBIT, $permission->permission);
395 $this->assertEquals(0, $permission->modifierid);
397 $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id);
398 $this->assertTrue($result);
399 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
400 $this->assertEmpty($permission);
402 // Test event trigger.
403 $rolecapabilityevent = \core\event\role_capabilities_updated::create(array('context' => $syscontext,
404 'objectid' => $student->id,
405 'other' => array('name' => $student->shortname)
407 $expectedlegacylog = array(SITEID, 'role', 'view', 'admin/roles/define.php?action=view&roleid=' . $student->id,
408 $student->shortname, '', $user->id);
409 $rolecapabilityevent->set_legacy_logdata($expectedlegacylog);
410 $rolecapabilityevent->add_record_snapshot('role', $student);
412 $sink = $this->redirectEvents();
413 $rolecapabilityevent->trigger();
414 $events = $sink->get_events();
415 $sink->close();
416 $event = array_pop($events);
418 $this->assertInstanceOf('\core\event\role_capabilities_updated', $event);
419 $expectedurl = new moodle_url('/admin/roles/define.php', array('action' => 'view', 'roleid' => $student->id));
420 $this->assertEquals($expectedurl, $event->get_url());
421 $this->assertEventLegacyLogData($expectedlegacylog, $event);
422 $this->assertEventContextNotUsed($event);
426 * Test removing of capabilities from roles.
428 public function test_unassign_capability() {
429 global $DB;
431 $this->resetAfterTest();
433 $syscontext = context_system::instance();
434 $frontcontext = context_course::instance(SITEID);
435 $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
436 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to manager by default.
437 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
439 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
440 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
442 $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id);
443 $this->assertTrue($result);
444 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
445 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
446 unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext);
447 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
449 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
450 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
451 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
453 $result = unassign_capability('moodle/backup:backupcourse', $manager->id);
454 $this->assertTrue($result);
455 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
456 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
460 * Test role assigning.
462 public function test_role_assign() {
463 global $DB, $USER;
465 $this->resetAfterTest();
467 $user = $this->getDataGenerator()->create_user();
468 $course = $this->getDataGenerator()->create_course();
469 $role = $DB->get_record('role', array('shortname'=>'student'));
471 $this->setUser(0);
472 $context = context_system::instance();
473 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
474 role_assign($role->id, $user->id, $context->id);
475 $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
476 $this->assertNotEmpty($ras);
477 $this->assertSame('', $ras->component);
478 $this->assertSame('0', $ras->itemid);
479 $this->assertEquals($USER->id, $ras->modifierid);
481 $this->setAdminUser();
482 $context = context_course::instance($course->id);
483 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
484 role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666);
485 $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
486 $this->assertNotEmpty($ras);
487 $this->assertSame('enrol_self', $ras->component);
488 $this->assertSame('1', $ras->itemid);
489 $this->assertEquals($USER->id, $ras->modifierid);
490 $this->assertEquals(666, $ras->timemodified);
492 // Test event triggered.
494 $user2 = $this->getDataGenerator()->create_user();
495 $sink = $this->redirectEvents();
496 $raid = role_assign($role->id, $user2->id, $context->id);
497 $events = $sink->get_events();
498 $sink->close();
499 $this->assertCount(1, $events);
500 $event = $events[0];
501 $this->assertInstanceOf('\core\event\role_assigned', $event);
502 $this->assertSame('role', $event->target);
503 $this->assertSame('role', $event->objecttable);
504 $this->assertEquals($role->id, $event->objectid);
505 $this->assertEquals($context->id, $event->contextid);
506 $this->assertEquals($user2->id, $event->relateduserid);
507 $this->assertCount(3, $event->other);
508 $this->assertEquals($raid, $event->other['id']);
509 $this->assertSame('', $event->other['component']);
510 $this->assertEquals(0, $event->other['itemid']);
511 $this->assertInstanceOf('moodle_url', $event->get_url());
512 $this->assertSame('role_assigned', $event::get_legacy_eventname());
513 $roles = get_all_roles();
514 $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
515 $expectedlegacylog = array($course->id, 'role', 'assign',
516 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
517 $this->assertEventLegacyLogData($expectedlegacylog, $event);
521 * Test role unassigning.
523 public function test_role_unassign() {
524 global $DB, $USER;
526 $this->resetAfterTest();
528 $user = $this->getDataGenerator()->create_user();
529 $course = $this->getDataGenerator()->create_course();
530 $role = $DB->get_record('role', array('shortname'=>'student'));
532 $context = context_course::instance($course->id);
533 role_assign($role->id, $user->id, $context->id);
534 $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
535 role_unassign($role->id, $user->id, $context->id);
536 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
538 role_assign($role->id, $user->id, $context->id, 'enrol_self', 1);
539 $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
540 role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1);
541 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
543 // Test event triggered.
545 role_assign($role->id, $user->id, $context->id);
546 $sink = $this->redirectEvents();
547 role_unassign($role->id, $user->id, $context->id);
548 $events = $sink->get_events();
549 $sink->close();
550 $this->assertCount(1, $events);
551 $event = $events[0];
552 $this->assertInstanceOf('\core\event\role_unassigned', $event);
553 $this->assertSame('role', $event->target);
554 $this->assertSame('role', $event->objecttable);
555 $this->assertEquals($role->id, $event->objectid);
556 $this->assertEquals($context->id, $event->contextid);
557 $this->assertEquals($user->id, $event->relateduserid);
558 $this->assertCount(3, $event->other);
559 $this->assertSame('', $event->other['component']);
560 $this->assertEquals(0, $event->other['itemid']);
561 $this->assertInstanceOf('moodle_url', $event->get_url());
562 $roles = get_all_roles();
563 $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
564 $expectedlegacylog = array($course->id, 'role', 'unassign',
565 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
566 $this->assertEventLegacyLogData($expectedlegacylog, $event);
570 * Test role unassigning.
572 public function test_role_unassign_all() {
573 global $DB;
575 $this->resetAfterTest();
577 $user = $this->getDataGenerator()->create_user();
578 $course = $this->getDataGenerator()->create_course();
579 $role = $DB->get_record('role', array('shortname'=>'student'));
580 $role2 = $DB->get_record('role', array('shortname'=>'teacher'));
581 $syscontext = context_system::instance();
582 $coursecontext = context_course::instance($course->id);
583 $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
584 $modcontext = context_module::instance($page->cmid);
586 role_assign($role->id, $user->id, $syscontext->id);
587 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
588 $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
589 role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id));
590 $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
592 role_assign($role->id, $user->id, $syscontext->id);
593 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
594 role_assign($role->id, $user->id, $modcontext->id);
595 $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id)));
596 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false);
597 $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
598 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true);
599 $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
600 role_unassign_all(array('userid'=>$user->id));
601 $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
603 role_assign($role->id, $user->id, $syscontext->id);
604 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
605 role_assign($role->id, $user->id, $coursecontext->id);
606 role_assign($role->id, $user->id, $modcontext->id);
607 $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id)));
608 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true);
609 $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
611 // Test events triggered.
613 role_assign($role2->id, $user->id, $coursecontext->id);
614 role_assign($role2->id, $user->id, $modcontext->id);
615 $sink = $this->redirectEvents();
616 role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role2->id));
617 $events = $sink->get_events();
618 $sink->close();
619 $this->assertCount(2, $events);
620 $this->assertInstanceOf('\core\event\role_unassigned', $events[0]);
621 $this->assertInstanceOf('\core\event\role_unassigned', $events[1]);
625 * Test role queries.
627 public function test_get_roles_with_capability() {
628 global $DB;
630 $this->resetAfterTest();
632 $syscontext = context_system::instance();
633 $frontcontext = context_course::instance(SITEID);
634 $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
635 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
637 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
638 $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse'));
640 $roles = get_roles_with_capability('moodle/backup:backupcourse');
641 $this->assertEquals(array(), $roles);
643 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
644 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id);
645 assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id);
647 $roles = get_roles_with_capability('moodle/backup:backupcourse');
648 $this->assertEquals(array($teacher->id, $manager->id), array_keys($roles), '', 0, 10, true);
650 $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW);
651 $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
653 $roles = get_roles_with_capability('moodle/backup:backupcourse', null, $syscontext);
654 $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
658 * Test deleting of roles.
660 public function test_delete_role() {
661 global $DB;
663 $this->resetAfterTest();
665 $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
666 $user = $this->getDataGenerator()->create_user();
667 role_assign($role->id, $user->id, context_system::instance());
668 $course = $this->getDataGenerator()->create_course();
669 $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id);
670 $DB->insert_record('role_names', $rolename);
672 $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
673 $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
674 $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id)));
675 $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
676 $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
677 $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
678 $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
679 $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
681 // Delete role and get event.
682 $sink = $this->redirectEvents();
683 $result = delete_role($role->id);
684 $events = $sink->get_events();
685 $sink->close();
686 $event = array_pop($events);
688 $this->assertTrue($result);
689 $this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
690 $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
691 $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
692 $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id)));
693 $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
694 $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
695 $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
696 $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
697 $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
699 // Test triggered event.
700 $this->assertInstanceOf('\core\event\role_deleted', $event);
701 $this->assertSame('role', $event->target);
702 $this->assertSame('role', $event->objecttable);
703 $this->assertSame($role->id, $event->objectid);
704 $this->assertEquals(context_system::instance(), $event->get_context());
705 $this->assertSame($role->shortname, $event->other['shortname']);
706 $this->assertSame($role->description, $event->other['description']);
707 $this->assertSame($role->archetype, $event->other['archetype']);
709 $expectedlegacylog = array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$role->id,
710 $role->shortname, '');
711 $this->assertEventLegacyLogData($expectedlegacylog, $event);
715 * Test fetching of all roles.
717 public function test_get_all_roles() {
718 global $DB;
720 $this->resetAfterTest();
722 $allroles = get_all_roles();
723 $this->assertInternalType('array', $allroles);
724 $this->assertCount(8, $allroles); // There are 8 roles is standard install.
726 $role = reset($allroles);
727 $role = (array)$role;
729 $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), array_keys($role), '', 0, 10, true);
731 foreach ($allroles as $roleid => $role) {
732 $this->assertEquals($role->id, $roleid);
735 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
736 $course = $this->getDataGenerator()->create_course();
737 $coursecontext = context_course::instance($course->id);
738 $otherid = create_role('Other role', 'other', 'Some other role', '');
739 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
740 $DB->insert_record('role_names', $teacherename);
741 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
742 $DB->insert_record('role_names', $otherrename);
743 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
745 $allroles = get_all_roles($coursecontext);
746 $this->assertInternalType('array', $allroles);
747 $this->assertCount(9, $allroles);
748 $role = reset($allroles);
749 $role = (array)$role;
751 $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role), '', 0, 10, true);
753 foreach ($allroles as $roleid => $role) {
754 $this->assertEquals($role->id, $roleid);
755 if (isset($renames[$roleid])) {
756 $this->assertSame($renames[$roleid], $role->coursealias);
757 } else {
758 $this->assertNull($role->coursealias);
764 * Test getting of all archetypes.
766 public function test_get_role_archetypes() {
767 $archetypes = get_role_archetypes();
768 $this->assertCount(8, $archetypes); // There are 8 archetypes in standard install.
769 foreach ($archetypes as $k => $v) {
770 $this->assertSame($k, $v);
775 * Test getting of roles with given archetype.
777 public function test_get_archetype_roles() {
778 $this->resetAfterTest();
780 // New install should have 1 role for each archetype.
781 $archetypes = get_role_archetypes();
782 foreach ($archetypes as $archetype) {
783 $roles = get_archetype_roles($archetype);
784 $this->assertCount(1, $roles);
785 $role = reset($roles);
786 $this->assertSame($archetype, $role->archetype);
789 create_role('New student role', 'student2', 'New student description', 'student');
790 $roles = get_archetype_roles('student');
791 $this->assertCount(2, $roles);
795 * Test aliased role names.
797 public function test_role_get_name() {
798 global $DB;
800 $this->resetAfterTest();
802 $allroles = $DB->get_records('role');
803 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
804 $course = $this->getDataGenerator()->create_course();
805 $coursecontext = context_course::instance($course->id);
806 $otherid = create_role('Other role', 'other', 'Some other role', '');
807 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
808 $DB->insert_record('role_names', $teacherename);
809 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
810 $DB->insert_record('role_names', $otherrename);
811 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
813 foreach ($allroles as $role) {
814 // Get localised name from lang pack.
815 $this->assertSame('', $role->name);
816 $name = role_get_name($role, null, ROLENAME_ORIGINAL);
817 $this->assertNotEmpty($name);
818 $this->assertNotEquals($role->shortname, $name);
820 if (isset($renames[$role->id])) {
821 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext));
822 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS));
823 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
824 $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH));
825 } else {
826 $this->assertSame($name, role_get_name($role, $coursecontext));
827 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS));
828 $this->assertNull(role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
829 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH));
831 $this->assertSame($name, role_get_name($role));
832 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL));
833 $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL));
834 $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT));
835 $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT));
836 $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT));
837 $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT));
838 $this->assertNull(role_get_name($role, null, ROLENAME_ALIAS_RAW));
843 * Test tweaking of role name arrays.
845 public function test_role_fix_names() {
846 global $DB;
848 $this->resetAfterTest();
850 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
851 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
852 $otherid = create_role('Other role', 'other', 'Some other role', '');
853 $anotherid = create_role('Another role', 'another', 'Yet another other role', '');
854 $allroles = $DB->get_records('role');
856 $syscontext = context_system::instance();
857 $frontcontext = context_course::instance(SITEID);
858 $course = $this->getDataGenerator()->create_course();
859 $coursecontext = context_course::instance($course->id);
860 $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST);
861 $categorycontext = context_coursecat::instance($category->id);
863 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
864 $DB->insert_record('role_names', $teacherename);
865 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
866 $DB->insert_record('role_names', $otherrename);
867 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
869 // Make sure all localname contain proper values for each ROLENAME_ constant,
870 // note role_get_name() on frontpage is used to get the original name for future compatibility.
871 $roles = $allroles;
872 unset($roles[$student->id]); // Remove one role to make sure no role is added or removed.
873 $rolenames = array();
874 foreach ($roles as $role) {
875 $rolenames[$role->id] = $role->name;
878 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
879 foreach ($alltypes as $type) {
880 $fixed = role_fix_names($roles, $coursecontext, $type);
881 $this->assertCount(count($roles), $fixed);
882 foreach ($fixed as $roleid => $rolename) {
883 $this->assertInstanceOf('stdClass', $rolename);
884 $role = $allroles[$roleid];
885 $name = role_get_name($role, $coursecontext, $type);
886 $this->assertSame($name, $rolename->localname);
888 $fixed = role_fix_names($rolenames, $coursecontext, $type);
889 $this->assertCount(count($rolenames), $fixed);
890 foreach ($fixed as $roleid => $rolename) {
891 $role = $allroles[$roleid];
892 $name = role_get_name($role, $coursecontext, $type);
893 $this->assertSame($name, $rolename);
899 * Test role default allows.
901 public function test_get_default_role_archetype_allows() {
902 $archetypes = get_role_archetypes();
903 foreach ($archetypes as $archetype) {
905 $result = get_default_role_archetype_allows('assign', $archetype);
906 $this->assertInternalType('array', $result);
908 $result = get_default_role_archetype_allows('override', $archetype);
909 $this->assertInternalType('array', $result);
911 $result = get_default_role_archetype_allows('switch', $archetype);
912 $this->assertInternalType('array', $result);
915 $result = get_default_role_archetype_allows('assign', '');
916 $this->assertSame(array(), $result);
918 $result = get_default_role_archetype_allows('override', '');
919 $this->assertSame(array(), $result);
921 $result = get_default_role_archetype_allows('switch', '');
922 $this->assertSame(array(), $result);
924 $result = get_default_role_archetype_allows('assign', 'wrongarchetype');
925 $this->assertSame(array(), $result);
926 $this->assertDebuggingCalled();
928 $result = get_default_role_archetype_allows('override', 'wrongarchetype');
929 $this->assertSame(array(), $result);
930 $this->assertDebuggingCalled();
932 $result = get_default_role_archetype_allows('switch', 'wrongarchetype');
933 $this->assertSame(array(), $result);
934 $this->assertDebuggingCalled();
938 * Test allowing of role assignments.
940 public function test_allow_assign() {
941 global $DB, $CFG;
943 $this->resetAfterTest();
945 $otherid = create_role('Other role', 'other', 'Some other role', '');
946 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
948 $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
949 allow_assign($otherid, $student->id);
950 $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
952 // Test event trigger.
953 $allowroleassignevent = \core\event\role_allow_assign_updated::create(array('context' => context_system::instance()));
954 $sink = $this->redirectEvents();
955 $allowroleassignevent->trigger();
956 $events = $sink->get_events();
957 $sink->close();
958 $event = array_pop($events);
959 $this->assertInstanceOf('\core\event\role_allow_assign_updated', $event);
960 $mode = 'assign';
961 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
962 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
963 $this->assertEventLegacyLogData($expectedlegacylog, $event);
967 * Test allowing of role overrides.
969 public function test_allow_override() {
970 global $DB, $CFG;
972 $this->resetAfterTest();
974 $otherid = create_role('Other role', 'other', 'Some other role', '');
975 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
977 $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
978 allow_override($otherid, $student->id);
979 $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
981 // Test event trigger.
982 $allowroleassignevent = \core\event\role_allow_override_updated::create(array('context' => context_system::instance()));
983 $sink = $this->redirectEvents();
984 $allowroleassignevent->trigger();
985 $events = $sink->get_events();
986 $sink->close();
987 $event = array_pop($events);
988 $this->assertInstanceOf('\core\event\role_allow_override_updated', $event);
989 $mode = 'override';
990 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
991 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
992 $this->assertEventLegacyLogData($expectedlegacylog, $event);
996 * Test allowing of role switching.
998 public function test_allow_switch() {
999 global $DB, $CFG;
1001 $this->resetAfterTest();
1003 $otherid = create_role('Other role', 'other', 'Some other role', '');
1004 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1006 $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
1007 allow_switch($otherid, $student->id);
1008 $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
1010 // Test event trigger.
1011 $allowroleassignevent = \core\event\role_allow_switch_updated::create(array('context' => context_system::instance()));
1012 $sink = $this->redirectEvents();
1013 $allowroleassignevent->trigger();
1014 $events = $sink->get_events();
1015 $sink->close();
1016 $event = array_pop($events);
1017 $this->assertInstanceOf('\core\event\role_allow_switch_updated', $event);
1018 $mode = 'switch';
1019 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
1020 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
1021 $this->assertEventLegacyLogData($expectedlegacylog, $event);
1025 * Test returning of assignable roles in context.
1027 public function test_get_assignable_roles() {
1028 global $DB;
1030 $this->resetAfterTest();
1032 $course = $this->getDataGenerator()->create_course();
1033 $coursecontext = context_course::instance($course->id);
1035 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1036 $teacher = $this->getDataGenerator()->create_user();
1037 role_assign($teacherrole->id, $teacher->id, $coursecontext);
1038 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1039 $DB->insert_record('role_names', $teacherename);
1041 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1042 $student = $this->getDataGenerator()->create_user();
1043 role_assign($studentrole->id, $student->id, $coursecontext);
1045 $contexts = $DB->get_records('context');
1046 $users = $DB->get_records('user');
1047 $allroles = $DB->get_records('role');
1049 // Evaluate all results for all users in all contexts.
1050 foreach ($users as $user) {
1051 $this->setUser($user);
1052 foreach ($contexts as $contextid => $unused) {
1053 $context = context_helper::instance_by_id($contextid);
1054 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1055 foreach ($allroles as $roleid => $role) {
1056 if (isset($roles[$roleid])) {
1057 if (is_siteadmin()) {
1058 $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)));
1059 } else {
1060 $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid");
1062 $this->assertEquals($role->shortname, $roles[$roleid]);
1063 } else {
1064 $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid));
1065 if (is_siteadmin()) {
1066 $this->assertFalse($allowed);
1067 } else {
1068 $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel");
1075 // Not-logged-in user.
1076 $this->setUser(0);
1077 foreach ($contexts as $contextid => $unused) {
1078 $context = context_helper::instance_by_id($contextid);
1079 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1080 $this->assertSame(array(), $roles);
1083 // Test current user.
1084 $this->setUser(0);
1085 $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST);
1086 $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin);
1087 $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id);
1088 $this->setAdminUser();
1089 $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT);
1090 $this->assertSame($roles1, $roles3);
1091 $this->assertSame($roles2, $roles3);
1093 // Test parameter defaults.
1094 $this->setAdminUser();
1095 $roles1 = get_assignable_roles($coursecontext);
1096 $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
1097 $this->assertEquals($roles2, $roles1);
1099 // Verify returned names - let's allow all roles everywhere to simplify this a bit.
1100 $alllevels = context_helper::get_all_levels();
1101 $alllevels = array_keys($alllevels);
1102 foreach ($allroles as $roleid => $role) {
1103 set_role_contextlevels($roleid, $alllevels);
1105 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1106 foreach ($alltypes as $type) {
1107 $rolenames = role_fix_names($allroles, $coursecontext, $type);
1108 $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1109 foreach ($roles as $roleid => $rolename) {
1110 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1114 // Verify counts.
1115 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1116 foreach ($alltypes as $type) {
1117 $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1118 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin);
1119 $this->assertEquals($roles, $rolenames);
1120 foreach ($rolenames as $roleid => $name) {
1121 if ($roleid == $teacherrole->id or $roleid == $studentrole->id) {
1122 $this->assertEquals(1, $rolecounts[$roleid]);
1123 } else {
1124 $this->assertEquals(0, $rolecounts[$roleid]);
1126 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1132 * Test getting of all switchable roles.
1134 public function test_get_switchable_roles() {
1135 global $DB;
1137 $this->resetAfterTest();
1139 $course = $this->getDataGenerator()->create_course();
1140 $coursecontext = context_course::instance($course->id);
1142 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1143 $teacher = $this->getDataGenerator()->create_user();
1144 role_assign($teacherrole->id, $teacher->id, $coursecontext);
1145 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1146 $DB->insert_record('role_names', $teacherename);
1148 $contexts = $DB->get_records('context');
1149 $users = $DB->get_records('user');
1150 $allroles = $DB->get_records('role');
1152 // Evaluate all results for all users in all contexts.
1153 foreach ($users as $user) {
1154 $this->setUser($user);
1155 foreach ($contexts as $contextid => $unused) {
1156 $context = context_helper::instance_by_id($contextid);
1157 $roles = get_switchable_roles($context);
1158 foreach ($allroles as $roleid => $role) {
1159 if (is_siteadmin()) {
1160 $this->assertTrue(isset($roles[$roleid]));
1161 } else {
1162 $parents = $context->get_parent_context_ids(true);
1163 $pcontexts = implode(',' , $parents);
1164 $allowed = $DB->record_exists_sql(
1165 "SELECT r.id
1166 FROM {role} r
1167 JOIN {role_allow_switch} ras ON ras.allowswitch = r.id
1168 JOIN {role_assignments} ra ON ra.roleid = ras.roleid
1169 WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1171 array('userid'=>$user->id, 'roleid'=>$roleid)
1173 if (isset($roles[$roleid])) {
1174 $this->assertTrue($allowed);
1175 } else {
1176 $this->assertFalse($allowed);
1180 if (isset($roles[$roleid])) {
1181 $coursecontext = $context->get_course_context(false);
1182 $this->assertSame(role_get_name($role, $coursecontext), $roles[$roleid]);
1190 * Test getting of all overridable roles.
1192 public function test_get_overridable_roles() {
1193 global $DB;
1195 $this->resetAfterTest();
1197 $course = $this->getDataGenerator()->create_course();
1198 $coursecontext = context_course::instance($course->id);
1200 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1201 $teacher = $this->getDataGenerator()->create_user();
1202 role_assign($teacherrole->id, $teacher->id, $coursecontext);
1203 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1204 $DB->insert_record('role_names', $teacherename);
1205 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
1206 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
1208 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1209 $student = $this->getDataGenerator()->create_user();
1210 role_assign($studentrole->id, $student->id, $coursecontext);
1212 $contexts = $DB->get_records('context');
1213 $users = $DB->get_records('user');
1214 $allroles = $DB->get_records('role');
1216 // Evaluate all results for all users in all contexts.
1217 foreach ($users as $user) {
1218 $this->setUser($user);
1219 foreach ($contexts as $contextid => $unused) {
1220 $context = context_helper::instance_by_id($contextid);
1221 $roles = get_overridable_roles($context, ROLENAME_SHORT);
1222 foreach ($allroles as $roleid => $role) {
1223 $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context);
1224 if (is_siteadmin()) {
1225 $this->assertTrue(isset($roles[$roleid]));
1226 } else {
1227 $parents = $context->get_parent_context_ids(true);
1228 $pcontexts = implode(',' , $parents);
1229 $allowed = $DB->record_exists_sql(
1230 "SELECT r.id
1231 FROM {role} r
1232 JOIN {role_allow_override} rao ON r.id = rao.allowoverride
1233 JOIN {role_assignments} ra ON rao.roleid = ra.roleid
1234 WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1236 array('userid'=>$user->id, 'roleid'=>$roleid)
1238 if (isset($roles[$roleid])) {
1239 $this->assertTrue($hascap);
1240 $this->assertTrue($allowed);
1241 } else {
1242 $this->assertFalse($hascap and $allowed);
1246 if (isset($roles[$roleid])) {
1247 $this->assertEquals($role->shortname, $roles[$roleid]);
1253 // Test parameter defaults.
1254 $this->setAdminUser();
1255 $roles1 = get_overridable_roles($coursecontext);
1256 $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1257 $this->assertEquals($roles2, $roles1);
1259 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1260 foreach ($alltypes as $type) {
1261 $rolenames = role_fix_names($allroles, $coursecontext, $type);
1262 $roles = get_overridable_roles($coursecontext, $type, false);
1263 foreach ($roles as $roleid => $rolename) {
1264 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1268 // Verify counts.
1269 $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1270 list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true);
1271 $this->assertEquals($roles, $rolenames);
1272 foreach ($rolenames as $roleid => $name) {
1273 if ($roleid == $teacherrole->id) {
1274 $this->assertEquals(1, $rolecounts[$roleid]);
1275 } else {
1276 $this->assertEquals(0, $rolecounts[$roleid]);
1278 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1283 * Test we have context level defaults.
1285 public function test_get_default_contextlevels() {
1286 $archetypes = get_role_archetypes();
1287 $alllevels = context_helper::get_all_levels();
1288 foreach ($archetypes as $archetype) {
1289 $defaults = get_default_contextlevels($archetype);
1290 $this->assertInternalType('array', $defaults);
1291 foreach ($defaults as $level) {
1292 $this->assertTrue(isset($alllevels[$level]));
1298 * Test role context level setup.
1300 public function test_set_role_contextlevels() {
1301 global $DB;
1303 $this->resetAfterTest();
1305 $roleid = create_role('New student role', 'student2', 'New student description', 'student');
1307 $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid)));
1309 set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE));
1310 $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1311 $this->assertCount(2, $levels);
1312 $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1313 $this->assertTrue(isset($levels[CONTEXT_MODULE]));
1315 set_role_contextlevels($roleid, array(CONTEXT_COURSE));
1316 $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1317 $this->assertCount(1, $levels);
1318 $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1322 * Test getting of role context levels
1324 public function test_get_roles_for_contextlevels() {
1325 global $DB;
1327 $allroles = get_all_roles();
1328 foreach (context_helper::get_all_levels() as $level => $unused) {
1329 $roles = get_roles_for_contextlevels($level);
1330 foreach ($allroles as $roleid => $unused) {
1331 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid));
1332 if (in_array($roleid, $roles)) {
1333 $this->assertTrue($exists);
1334 } else {
1335 $this->assertFalse($exists);
1342 * Test default enrol roles.
1344 public function test_get_default_enrol_roles() {
1345 $this->resetAfterTest();
1347 $course = $this->getDataGenerator()->create_course();
1348 $coursecontext = context_course::instance($course->id);
1350 $id2 = create_role('New student role', 'student2', 'New student description', 'student');
1351 set_role_contextlevels($id2, array(CONTEXT_COURSE));
1353 $allroles = get_all_roles();
1354 $expected = array($id2=>$allroles[$id2]);
1356 foreach (get_role_archetypes() as $archetype) {
1357 $defaults = get_default_contextlevels($archetype);
1358 if (in_array(CONTEXT_COURSE, $defaults)) {
1359 $roles = get_archetype_roles($archetype);
1360 foreach ($roles as $role) {
1361 $expected[$role->id] = $role;
1366 $roles = get_default_enrol_roles($coursecontext);
1367 foreach ($allroles as $role) {
1368 $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id]));
1369 if (isset($roles[$role->id])) {
1370 $this->assertSame(role_get_name($role, $coursecontext), $roles[$role->id]);
1376 * Test getting of role users.
1378 public function test_get_role_users() {
1379 global $DB;
1381 $this->resetAfterTest();
1383 $systemcontext = context_system::instance();
1384 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1385 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1386 $course = $this->getDataGenerator()->create_course();
1387 $coursecontext = context_course::instance($course->id);
1388 $otherid = create_role('Other role', 'other', 'Some other role', '');
1389 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1390 $DB->insert_record('role_names', $teacherrename);
1391 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1392 $DB->insert_record('role_names', $otherrename);
1394 $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith'));
1395 role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1396 $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar'));
1397 role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1398 $user3 = $this->getDataGenerator()->create_user();
1399 $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id);
1400 $user4 = $this->getDataGenerator()->create_user();
1401 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id);
1403 $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id));
1404 groups_add_member($group, $user3);
1406 $users = get_role_users($teacherrole->id, $coursecontext);
1407 $this->assertCount(2, $users);
1408 $this->assertArrayHasKey($user1->id, $users);
1409 $this->assertEquals($users[$user1->id]->id, $user1->id);
1410 $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id);
1411 $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name);
1412 $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname);
1413 $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name);
1414 $this->assertArrayHasKey($user3->id, $users);
1415 $this->assertEquals($users[$user3->id]->id, $user3->id);
1416 $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id);
1417 $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name);
1418 $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname);
1419 $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name);
1421 $users = get_role_users($teacherrole->id, $coursecontext, true);
1422 $this->assertCount(3, $users);
1424 $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1);
1425 $this->assertCount(1, $users);
1427 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber');
1428 $this->assertCount(2, $users);
1429 $this->assertArrayHasKey($user1->id, $users);
1430 $this->assertArrayHasKey($user3->id, $users);
1432 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id);
1433 $this->assertCount(1, $users);
1434 $this->assertArrayHasKey($user3->id, $users);
1436 $users = get_role_users($teacherrole->id, $coursecontext, true, 'u.id, u.email, u.idnumber, u.firstname', 'u.idnumber', null, '', '', '', 'u.firstname = :xfirstname', array('xfirstname'=>'John'));
1437 $this->assertCount(1, $users);
1438 $this->assertArrayHasKey($user1->id, $users);
1442 * Test used role query.
1444 public function test_get_roles_used_in_context() {
1445 global $DB;
1447 $this->resetAfterTest();
1449 $systemcontext = context_system::instance();
1450 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1451 $course = $this->getDataGenerator()->create_course();
1452 $coursecontext = context_course::instance($course->id);
1453 $otherid = create_role('Other role', 'other', 'Some other role', '');
1454 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1455 $DB->insert_record('role_names', $teacherrename);
1456 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1457 $DB->insert_record('role_names', $otherrename);
1459 $user1 = $this->getDataGenerator()->create_user();
1460 role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1462 $roles = get_roles_used_in_context($coursecontext);
1463 $this->assertCount(1, $roles);
1464 $role = reset($roles);
1465 $roleid = key($roles);
1466 $this->assertEquals($roleid, $role->id);
1467 $this->assertEquals($teacherrole->id, $role->id);
1468 $this->assertSame($teacherrole->name, $role->name);
1469 $this->assertSame($teacherrole->shortname, $role->shortname);
1470 $this->assertEquals($teacherrole->sortorder, $role->sortorder);
1471 $this->assertSame($teacherrename->name, $role->coursealias);
1473 $user2 = $this->getDataGenerator()->create_user();
1474 role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1475 role_assign($otherid, $user2->id, $systemcontext->id);
1477 $roles = get_roles_used_in_context($systemcontext);
1478 $this->assertCount(2, $roles);
1482 * Test roles used in course.
1484 public function test_get_user_roles_in_course() {
1485 global $DB, $CFG;
1487 $this->resetAfterTest();
1489 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1490 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1491 $course = $this->getDataGenerator()->create_course();
1492 $coursecontext = context_course::instance($course->id);
1493 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1494 $DB->insert_record('role_names', $teacherrename);
1496 $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
1497 $this->assertTrue(in_array($teacherrole->id, $roleids));
1498 $this->assertTrue(in_array($studentrole->id, $roleids));
1500 $user1 = $this->getDataGenerator()->create_user();
1501 role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1502 role_assign($studentrole->id, $user1->id, $coursecontext->id);
1503 $user2 = $this->getDataGenerator()->create_user();
1504 role_assign($studentrole->id, $user2->id, $coursecontext->id);
1505 $user3 = $this->getDataGenerator()->create_user();
1507 $roles = get_user_roles_in_course($user1->id, $course->id);
1508 $this->assertEquals(1, preg_match_all('/,/', $roles, $matches));
1509 $this->assertTrue(strpos($roles, role_get_name($teacherrole, $coursecontext)) !== false);
1511 $roles = get_user_roles_in_course($user2->id, $course->id);
1512 $this->assertEquals(0, preg_match_all('/,/', $roles, $matches));
1513 $this->assertTrue(strpos($roles, role_get_name($studentrole, $coursecontext)) !== false);
1515 $roles = get_user_roles_in_course($user3->id, $course->id);
1516 $this->assertSame('', $roles);
1520 * Test has_capability(), has_any_capability() and has_all_capabilities().
1522 public function test_has_capability_and_friends() {
1523 global $DB;
1525 $this->resetAfterTest();
1527 $course = $this->getDataGenerator()->create_course();
1528 $coursecontext = context_course::instance($course->id);
1529 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1530 $teacher = $this->getDataGenerator()->create_user();
1531 role_assign($teacherrole->id, $teacher->id, $coursecontext);
1532 $admin = $DB->get_record('user', array('username'=>'admin'));
1534 // Note: Here are used default capabilities, the full test is in permission evaluation bellow,
1535 // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user.
1537 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection')));
1538 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse')));
1539 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse')));
1541 $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse');
1542 $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse');
1544 $this->setUser(0);
1545 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext));
1546 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext));
1547 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1548 $this->assertFalse(has_any_capability($sca, $coursecontext));
1549 $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1551 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher));
1552 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher));
1553 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher));
1554 $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher));
1555 $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher));
1556 $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher));
1558 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin));
1559 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin));
1560 $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin));
1561 $this->assertTrue(has_any_capability($sca, $coursecontext, $admin));
1562 $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin));
1563 $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin));
1565 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false));
1566 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false));
1567 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false));
1568 $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false));
1569 $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false));
1570 $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false));
1572 $this->setUser($teacher);
1573 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1574 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1575 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1576 $this->assertTrue(has_any_capability($sca, $coursecontext));
1577 $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1578 $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1580 $this->setAdminUser();
1581 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1582 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1583 $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext));
1584 $this->assertTrue(has_any_capability($sca, $coursecontext));
1585 $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1586 $this->assertTrue(has_all_capabilities($sca, $coursecontext));
1588 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0));
1589 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0));
1590 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0));
1591 $this->assertFalse(has_any_capability($sca, $coursecontext, 0));
1592 $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0));
1596 * Test if course creator future capability lookup works.
1598 public function test_guess_if_creator_will_have_course_capability() {
1599 global $DB, $CFG, $USER;
1601 $this->resetAfterTest();
1603 $category = $this->getDataGenerator()->create_category();
1604 $course = $this->getDataGenerator()->create_course(array('category'=>$category->id));
1606 $syscontext = context_system::instance();
1607 $categorycontext = context_coursecat::instance($category->id);
1608 $coursecontext = context_course::instance($course->id);
1609 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1610 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1611 $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST);
1612 $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
1614 $this->assertEquals($teacherrole->id, $CFG->creatornewroleid);
1616 $creator = $this->getDataGenerator()->create_user();
1617 $manager = $this->getDataGenerator()->create_user();
1618 role_assign($managerrole->id, $manager->id, $categorycontext);
1620 $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator));
1621 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
1622 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
1623 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
1624 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
1625 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
1627 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1628 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager));
1629 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager));
1630 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id));
1631 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id));
1633 $this->assertEquals(0, $USER->id);
1634 $this->assertFalse(has_capability('moodle/course:view', $categorycontext));
1635 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext));
1636 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext));
1637 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext));
1638 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
1639 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
1641 $this->setUser($manager);
1642 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
1643 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
1644 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
1645 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
1646 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
1648 $this->setAdminUser();
1649 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
1650 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
1651 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
1652 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
1653 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
1654 $this->setUser(0);
1656 role_assign($creatorrole->id, $creator->id, $categorycontext);
1658 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
1659 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
1660 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
1661 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
1662 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
1664 $this->setUser($creator);
1665 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, null));
1666 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, null));
1667 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, null));
1668 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, null));
1669 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, null));
1670 $this->setUser(0);
1672 set_config('creatornewroleid', $studentrole->id);
1674 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
1675 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
1676 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
1677 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
1679 set_config('creatornewroleid', $teacherrole->id);
1681 role_change_permission($managerrole->id, $categorycontext, 'moodle/course:visibility', CAP_PREVENT);
1682 role_assign($creatorrole->id, $manager->id, $categorycontext);
1684 $this->assertTrue(has_capability('moodle/course:view', $categorycontext, $manager));
1685 $this->assertTrue(has_capability('moodle/course:view', $coursecontext, $manager));
1686 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1687 $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager));
1688 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
1689 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
1690 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
1691 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
1693 role_change_permission($managerrole->id, $categorycontext, 'moodle/course:view', CAP_PREVENT);
1694 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1695 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
1696 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
1697 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
1698 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
1700 $this->getDataGenerator()->enrol_user($manager->id, $course->id, 0);
1702 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1703 $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager));
1704 $this->assertTrue(is_enrolled($coursecontext, $manager));
1705 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
1706 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
1707 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
1708 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
1710 // Test problems.
1712 try {
1713 guess_if_creator_will_have_course_capability('moodle/course:visibility', $syscontext, $creator);
1714 $this->fail('Exception expected when non course/category context passed to guess_if_creator_will_have_course_capability()');
1715 } catch (moodle_exception $e) {
1716 $this->assertInstanceOf('coding_exception', $e);
1721 * Test require_capability() exceptions.
1723 public function test_require_capability() {
1724 $this->resetAfterTest();
1726 $syscontext = context_system::instance();
1728 $this->setUser(0);
1729 $this->assertFalse(has_capability('moodle/site:config', $syscontext));
1730 try {
1731 require_capability('moodle/site:config', $syscontext);
1732 $this->fail('Exception expected from require_capability()');
1733 } catch (moodle_exception $e) {
1734 $this->assertInstanceOf('required_capability_exception', $e);
1736 $this->setAdminUser();
1737 $this->assertFalse(has_capability('moodle/site:config', $syscontext, 0));
1738 try {
1739 require_capability('moodle/site:config', $syscontext, 0);
1740 $this->fail('Exception expected from require_capability()');
1741 } catch (moodle_exception $e) {
1742 $this->assertInstanceOf('required_capability_exception', $e);
1744 $this->assertFalse(has_capability('moodle/site:config', $syscontext, null, false));
1745 try {
1746 require_capability('moodle/site:config', $syscontext, null, false);
1747 $this->fail('Exception expected from require_capability()');
1748 } catch (moodle_exception $e) {
1749 $this->assertInstanceOf('required_capability_exception', $e);
1754 * A small functional test of permission evaluations.
1756 public function test_permission_evaluation() {
1757 global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE;
1759 $this->resetAfterTest();
1761 $generator = $this->getDataGenerator();
1763 // Fill the site with some real data.
1764 $testcategories = array();
1765 $testcourses = array();
1766 $testpages = array();
1767 $testblocks = array();
1768 $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
1770 $systemcontext = context_system::instance();
1771 $frontpagecontext = context_course::instance(SITEID);
1773 // Add block to system context.
1774 $bi = $generator->create_block('online_users');
1775 context_block::instance($bi->id);
1776 $testblocks[] = $bi->id;
1778 // Some users.
1779 $testusers = array();
1780 for ($i=0; $i<20; $i++) {
1781 $user = $generator->create_user();
1782 $testusers[$i] = $user->id;
1783 $usercontext = context_user::instance($user->id);
1785 // Add block to user profile.
1786 $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id));
1787 $testblocks[] = $bi->id;
1789 // Deleted user - should be ignored everywhere, can not have context.
1790 $generator->create_user(array('deleted'=>1));
1792 // Add block to frontpage.
1793 $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id));
1794 $frontpageblockcontext = context_block::instance($bi->id);
1795 $testblocks[] = $bi->id;
1797 // Add a resource to frontpage.
1798 $page = $generator->create_module('page', array('course'=>$SITE->id));
1799 $testpages[] = $page->id;
1800 $frontpagepagecontext = context_module::instance($page->cmid);
1802 // Add block to frontpage resource.
1803 $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id));
1804 $frontpagepageblockcontext = context_block::instance($bi->id);
1805 $testblocks[] = $bi->id;
1807 // Some nested course categories with courses.
1808 $manualenrol = enrol_get_plugin('manual');
1809 $parentcat = 0;
1810 for ($i=0; $i<5; $i++) {
1811 $cat = $generator->create_category(array('parent'=>$parentcat));
1812 $testcategories[] = $cat->id;
1813 $catcontext = context_coursecat::instance($cat->id);
1814 $parentcat = $cat->id;
1816 if ($i >= 4) {
1817 continue;
1820 // Add resource to each category.
1821 $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id));
1822 context_block::instance($bi->id);
1824 // Add a few courses to each category.
1825 for ($j=0; $j<6; $j++) {
1826 $course = $generator->create_course(array('category'=>$cat->id));
1827 $testcourses[] = $course->id;
1828 $coursecontext = context_course::instance($course->id);
1830 if ($j >= 5) {
1831 continue;
1833 // Add manual enrol instance.
1834 $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id)));
1836 // Add block to each course.
1837 $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
1838 $testblocks[] = $bi->id;
1840 // Add a resource to each course.
1841 $page = $generator->create_module('page', array('course'=>$course->id));
1842 $testpages[] = $page->id;
1843 $modcontext = context_module::instance($page->cmid);
1845 // Add block to each module.
1846 $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id));
1847 $testblocks[] = $bi->id;
1851 // Make sure all contexts were created properly.
1852 $count = 1; // System.
1853 $count += $DB->count_records('user', array('deleted'=>0));
1854 $count += $DB->count_records('course_categories');
1855 $count += $DB->count_records('course');
1856 $count += $DB->count_records('course_modules');
1857 $count += $DB->count_records('block_instances');
1858 $this->assertEquals($count, $DB->count_records('context'));
1859 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
1860 $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
1863 // Test context_helper::get_level_name() method.
1865 $levels = context_helper::get_all_levels();
1866 foreach ($levels as $level => $classname) {
1867 $name = context_helper::get_level_name($level);
1868 $this->assertNotEmpty($name);
1872 // Test context::instance_by_id(), context_xxx::instance() methods.
1874 $context = context::instance_by_id($frontpagecontext->id);
1875 $this->assertSame(CONTEXT_COURSE, $context->contextlevel);
1876 $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING));
1877 try {
1878 context::instance_by_id(-1);
1879 $this->fail('exception expected');
1880 } catch (moodle_exception $e) {
1881 $this->assertTrue(true);
1883 $this->assertInstanceOf('context_system', context_system::instance());
1884 $this->assertInstanceOf('context_coursecat', context_coursecat::instance($testcategories[0]));
1885 $this->assertInstanceOf('context_course', context_course::instance($testcourses[0]));
1886 $this->assertInstanceOf('context_module', context_module::instance($testpages[0]));
1887 $this->assertInstanceOf('context_block', context_block::instance($testblocks[0]));
1889 $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING));
1890 $this->assertFalse(context_course::instance(-1, IGNORE_MISSING));
1891 $this->assertFalse(context_module::instance(-1, IGNORE_MISSING));
1892 $this->assertFalse(context_block::instance(-1, IGNORE_MISSING));
1893 try {
1894 context_coursecat::instance(-1);
1895 $this->fail('exception expected');
1896 } catch (moodle_exception $e) {
1897 $this->assertTrue(true);
1899 try {
1900 context_course::instance(-1);
1901 $this->fail('exception expected');
1902 } catch (moodle_exception $e) {
1903 $this->assertTrue(true);
1905 try {
1906 context_module::instance(-1);
1907 $this->fail('exception expected');
1908 } catch (moodle_exception $e) {
1909 $this->assertTrue(true);
1911 try {
1912 context_block::instance(-1);
1913 $this->fail('exception expected');
1914 } catch (moodle_exception $e) {
1915 $this->assertTrue(true);
1919 // Test $context->get_url(), $context->get_context_name(), $context->get_capabilities() methods.
1921 $testcontexts = array();
1922 $testcontexts[CONTEXT_SYSTEM] = context_system::instance();
1923 $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]);
1924 $testcontexts[CONTEXT_COURSE] = context_course::instance($testcourses[0]);
1925 $testcontexts[CONTEXT_MODULE] = context_module::instance($testpages[0]);
1926 $testcontexts[CONTEXT_BLOCK] = context_block::instance($testblocks[0]);
1928 foreach ($testcontexts as $context) {
1929 $name = $context->get_context_name(true, true);
1930 $this->assertNotEmpty($name);
1932 $this->assertInstanceOf('moodle_url', $context->get_url());
1934 $caps = $context->get_capabilities();
1935 $this->assertTrue(is_array($caps));
1936 foreach ($caps as $cap) {
1937 $cap = (array)$cap;
1938 $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask'));
1941 unset($testcontexts);
1943 // Test $context->get_course_context() method.
1945 $this->assertFalse($systemcontext->get_course_context(false));
1946 try {
1947 $systemcontext->get_course_context();
1948 $this->fail('exception expected');
1949 } catch (moodle_exception $e) {
1950 $this->assertInstanceOf('coding_exception', $e);
1952 $context = context_coursecat::instance($testcategories[0]);
1953 $this->assertFalse($context->get_course_context(false));
1954 try {
1955 $context->get_course_context();
1956 $this->fail('exception expected');
1957 } catch (moodle_exception $e) {
1958 $this->assertInstanceOf('coding_exception', $e);
1960 $this->assertEquals($frontpagecontext, $frontpagecontext->get_course_context(true));
1961 $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_course_context(true));
1962 $this->assertEquals($frontpagecontext, $frontpagepageblockcontext->get_course_context(true));
1965 // Test $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() methods.
1967 $userid = reset($testusers);
1968 $usercontext = context_user::instance($userid);
1969 $this->assertEquals($systemcontext, $usercontext->get_parent_context());
1970 $this->assertEquals(array($systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts());
1971 $this->assertEquals(array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts(true));
1973 $this->assertEquals(array(), $systemcontext->get_parent_contexts());
1974 $this->assertEquals(array($systemcontext->id=>$systemcontext), $systemcontext->get_parent_contexts(true));
1975 $this->assertEquals(array(), $systemcontext->get_parent_context_ids());
1976 $this->assertEquals(array($systemcontext->id), $systemcontext->get_parent_context_ids(true));
1978 $this->assertEquals($systemcontext, $frontpagecontext->get_parent_context());
1979 $this->assertEquals(array($systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts());
1980 $this->assertEquals(array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts(true));
1981 $this->assertEquals(array($systemcontext->id), $frontpagecontext->get_parent_context_ids());
1982 $this->assertEquals(array($frontpagecontext->id, $systemcontext->id), $frontpagecontext->get_parent_context_ids(true));
1984 $this->assertFalse($systemcontext->get_parent_context());
1985 $frontpagecontext = context_course::instance($SITE->id);
1986 $parent = $systemcontext;
1987 foreach ($testcategories as $catid) {
1988 $catcontext = context_coursecat::instance($catid);
1989 $this->assertEquals($parent, $catcontext->get_parent_context());
1990 $parent = $catcontext;
1992 $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_parent_context());
1993 $this->assertEquals($frontpagecontext, $frontpageblockcontext->get_parent_context());
1994 $this->assertEquals($frontpagepagecontext, $frontpagepageblockcontext->get_parent_context());
1997 // Test $context->get_child_contexts() method.
1999 $children = $systemcontext->get_child_contexts();
2000 $this->resetDebugging();
2001 $this->assertEquals(count($children)+1, $DB->count_records('context'));
2003 $context = context_coursecat::instance($testcategories[3]);
2004 $children = $context->get_child_contexts();
2005 $countcats = 0;
2006 $countcourses = 0;
2007 $countblocks = 0;
2008 foreach ($children as $child) {
2009 if ($child->contextlevel == CONTEXT_COURSECAT) {
2010 $countcats++;
2012 if ($child->contextlevel == CONTEXT_COURSE) {
2013 $countcourses++;
2015 if ($child->contextlevel == CONTEXT_BLOCK) {
2016 $countblocks++;
2019 $this->assertCount(8, $children);
2020 $this->assertEquals(1, $countcats);
2021 $this->assertEquals(6, $countcourses);
2022 $this->assertEquals(1, $countblocks);
2024 $context = context_course::instance($testcourses[2]);
2025 $children = $context->get_child_contexts();
2026 $this->assertCount(7, $children); // Depends on number of default blocks.
2028 $context = context_module::instance($testpages[3]);
2029 $children = $context->get_child_contexts();
2030 $this->assertCount(1, $children);
2032 $context = context_block::instance($testblocks[1]);
2033 $children = $context->get_child_contexts();
2034 $this->assertCount(0, $children);
2036 unset($children);
2037 unset($countcats);
2038 unset($countcourses);
2039 unset($countblocks);
2042 // Test context_helper::reset_caches() method.
2044 context_helper::reset_caches();
2045 $this->assertEquals(0, context_inspection::test_context_cache_size());
2046 context_course::instance($SITE->id);
2047 $this->assertEquals(1, context_inspection::test_context_cache_size());
2050 // Test context preloading.
2052 context_helper::reset_caches();
2053 $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')."
2054 FROM {context} c
2055 WHERE c.contextlevel <> ".CONTEXT_SYSTEM;
2056 $records = $DB->get_records_sql($sql);
2057 $firstrecord = reset($records);
2058 $columns = context_helper::get_preload_record_columns('c');
2059 $firstrecord = (array)$firstrecord;
2060 $this->assertSame(array_keys($firstrecord), array_values($columns));
2061 context_helper::reset_caches();
2062 foreach ($records as $record) {
2063 context_helper::preload_from_record($record);
2064 $this->assertEquals(new stdClass(), $record);
2066 $this->assertEquals(count($records), context_inspection::test_context_cache_size());
2067 unset($records);
2068 unset($columns);
2070 context_helper::reset_caches();
2071 context_helper::preload_course($SITE->id);
2072 $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id));
2073 $this->assertEquals(6 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // Depends on number of default blocks.
2075 // Test assign_capability(), unassign_capability() functions.
2077 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2078 $this->assertFalse($rc);
2079 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id);
2080 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2081 $this->assertEquals(CAP_ALLOW, $rc->permission);
2082 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id);
2083 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2084 $this->assertEquals(CAP_ALLOW, $rc->permission);
2085 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true);
2086 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2087 $this->assertEquals(CAP_PREVENT, $rc->permission);
2089 assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext);
2090 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2091 $this->assertFalse($rc);
2092 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext);
2093 unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true);
2094 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2095 $this->assertFalse($rc);
2096 unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true);
2097 unset($rc);
2099 accesslib_clear_all_caches_for_unit_testing(); // Must be done after assign_capability().
2102 // Test role_assign(), role_unassign(), role_unassign_all() functions.
2104 $context = context_course::instance($testcourses[1]);
2105 $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2106 role_assign($allroles['teacher'], $testusers[1], $context->id);
2107 role_assign($allroles['teacher'], $testusers[2], $context->id);
2108 role_assign($allroles['manager'], $testusers[1], $context->id);
2109 $this->assertEquals(3, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2110 role_unassign($allroles['teacher'], $testusers[1], $context->id);
2111 $this->assertEquals(2, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2112 role_unassign_all(array('contextid'=>$context->id));
2113 $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2114 unset($context);
2116 accesslib_clear_all_caches_for_unit_testing(); // Just in case.
2119 // Test has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends functions.
2121 $adminid = get_admin()->id;
2122 $guestid = $CFG->siteguest;
2124 // Enrol some users into some courses.
2125 $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST);
2126 $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST);
2127 $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id');
2128 $cm1 = reset($cms);
2129 $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id');
2130 $block1 = reset($blocks);
2131 $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id));
2132 $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id));
2133 for ($i=0; $i<9; $i++) {
2134 $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']);
2136 $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']);
2137 $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']);
2139 for ($i=10; $i<15; $i++) {
2140 $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']);
2142 $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']);
2144 // Add tons of role assignments - the more the better.
2145 role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2]));
2146 role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1]));
2147 role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id));
2148 role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id));
2149 role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id));
2150 role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id));
2151 role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id));
2152 role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id));
2154 role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id));
2155 role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id));
2157 // Add tons of overrides - the more the better.
2158 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true);
2159 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true);
2160 assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true);
2161 assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true);
2162 assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true);
2164 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true);
2165 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true);
2166 assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true);
2167 assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true);
2168 assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true);
2170 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true);
2171 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true);
2172 assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true);
2173 assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true);
2175 assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true);
2177 accesslib_clear_all_caches_for_unit_testing(); /// Must be done after assign_capability().
2179 // Extra tests for guests and not-logged-in users because they can not be verified by cross checking
2180 // with get_users_by_capability() where they are ignored.
2181 $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid));
2182 $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid));
2183 $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid));
2184 $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid));
2186 $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0));
2187 $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0));
2188 $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0));
2189 $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0));
2191 $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11]));
2192 $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11]));
2193 $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11]));
2194 $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11]));
2196 $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9]));
2197 $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9]));
2198 $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9]));
2200 // Test the list of enrolled users.
2201 $coursecontext = context_course::instance($course1->id);
2202 $enrolled = get_enrolled_users($coursecontext);
2203 $this->assertCount(10, $enrolled);
2204 for ($i=0; $i<10; $i++) {
2205 $this->assertTrue(isset($enrolled[$testusers[$i]]));
2207 $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update');
2208 $this->assertCount(1, $enrolled);
2209 $this->assertTrue(isset($enrolled[$testusers[9]]));
2210 unset($enrolled);
2212 // Role switching.
2213 $userid = $testusers[9];
2214 $USER = $DB->get_record('user', array('id'=>$userid));
2215 load_all_capabilities();
2216 $coursecontext = context_course::instance($course1->id);
2217 $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2218 $this->assertFalse(is_role_switched($course1->id));
2219 role_switch($allroles['student'], $coursecontext);
2220 $this->assertTrue(is_role_switched($course1->id));
2221 $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]);
2222 $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2223 reload_all_capabilities();
2224 $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2225 role_switch(0, $coursecontext);
2226 $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2227 $userid = $adminid;
2228 $USER = $DB->get_record('user', array('id'=>$userid));
2229 load_all_capabilities();
2230 $coursecontext = context_course::instance($course1->id);
2231 $blockcontext = context_block::instance($block1->id);
2232 $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
2233 role_switch($allroles['student'], $coursecontext);
2234 $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]);
2235 $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
2236 reload_all_capabilities();
2237 $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
2238 load_all_capabilities();
2239 $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
2241 // Temp course role for enrol.
2242 $DB->delete_records('cache_flags', array()); // This prevents problem with dirty contexts immediately resetting the temp role - this is a known problem...
2243 $userid = $testusers[5];
2244 $roleid = $allroles['editingteacher'];
2245 $USER = $DB->get_record('user', array('id'=>$userid));
2246 load_all_capabilities();
2247 $coursecontext = context_course::instance($course1->id);
2248 $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2249 $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid]));
2250 load_temp_course_role($coursecontext, $roleid);
2251 $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid);
2252 $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2253 remove_temp_course_roles($coursecontext);
2254 $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
2255 load_temp_course_role($coursecontext, $roleid);
2256 reload_all_capabilities();
2257 $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
2258 $USER = new stdClass();
2259 $USER->id = 0;
2261 // Now cross check has_capability() with get_users_by_capability(), each using different code paths,
2262 // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong,
2263 // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users).
2264 $contexts = $DB->get_records('context', array(), 'id');
2265 $contexts = array_values($contexts);
2266 $capabilities = $DB->get_records('capabilities', array(), 'id');
2267 $capabilities = array_values($capabilities);
2268 $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']);
2269 $userids = array_values($testusers);
2270 $userids[] = get_admin()->id;
2272 if (!PHPUNIT_LONGTEST) {
2273 $contexts = array_slice($contexts, 0, 10);
2274 $capabilities = array_slice($capabilities, 0, 5);
2275 $userids = array_slice($userids, 0, 5);
2278 foreach ($userids as $userid) { // No guest or deleted.
2279 // Each user gets 0-10 random roles.
2280 $rcount = rand(0, 10);
2281 for ($j=0; $j<$rcount; $j++) {
2282 $roleid = $roles[rand(0, count($roles)-1)];
2283 $contextid = $contexts[rand(0, count($contexts)-1)]->id;
2284 role_assign($roleid, $userid, $contextid);
2288 $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT);
2289 $maxoverrides = count($contexts)*10;
2290 for ($j=0; $j<$maxoverrides; $j++) {
2291 $roleid = $roles[rand(0, count($roles)-1)];
2292 $contextid = $contexts[rand(0, count($contexts)-1)]->id;
2293 $permission = $permissions[rand(0, count($permissions)-1)];
2294 $capname = $capabilities[rand(0, count($capabilities)-1)]->name;
2295 assign_capability($capname, $permission, $roleid, $contextid, true);
2297 unset($permissions);
2298 unset($roles);
2300 accesslib_clear_all_caches_for_unit_testing(); // must be done after assign_capability().
2302 // Test time - let's set up some real user, just in case the logic for USER affects the others...
2303 $USER = $DB->get_record('user', array('id'=>$testusers[3]));
2304 load_all_capabilities();
2306 $userids[] = $CFG->siteguest;
2307 $userids[] = 0; // Not-logged-in user.
2308 $userids[] = -1; // Non-existent user.
2310 foreach ($contexts as $crecord) {
2311 $context = context::instance_by_id($crecord->id);
2312 if ($coursecontext = $context->get_course_context(false)) {
2313 $enrolled = get_enrolled_users($context);
2314 } else {
2315 $enrolled = array();
2317 foreach ($capabilities as $cap) {
2318 $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username');
2319 if ($enrolled) {
2320 $enrolledwithcap = get_enrolled_users($context, $cap->name);
2321 } else {
2322 $enrolledwithcap = array();
2324 foreach ($userids as $userid) {
2325 if ($userid == 0 or isguestuser($userid)) {
2326 if ($userid == 0) {
2327 $CFG->forcelogin = true;
2328 $this->assertFalse(has_capability($cap->name, $context, $userid));
2329 unset($CFG->forcelogin);
2331 if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) {
2332 $this->assertFalse(has_capability($cap->name, $context, $userid));
2334 $this->assertFalse(isset($allowed[$userid]));
2335 } else {
2336 if (is_siteadmin($userid)) {
2337 $this->assertTrue(has_capability($cap->name, $context, $userid, true));
2339 $hascap = has_capability($cap->name, $context, $userid, false);
2340 $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
2341 if (isset($enrolled[$userid])) {
2342 $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
2348 // Back to nobody.
2349 $USER = new stdClass();
2350 $USER->id = 0;
2351 unset($contexts);
2352 unset($userids);
2353 unset($capabilities);
2355 // Now let's do all the remaining tests that break our carefully prepared fake site.
2358 // Test $context->mark_dirty() method.
2360 $DB->delete_records('cache_flags', array());
2361 accesslib_clear_all_caches(false);
2362 $systemcontext->mark_dirty();
2363 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2364 $this->assertTrue(isset($dirty[$systemcontext->path]));
2365 $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path]));
2368 // Test $context->reload_if_dirty() method.
2370 $DB->delete_records('cache_flags', array());
2371 accesslib_clear_all_caches(false);
2372 load_all_capabilities();
2373 $context = context_course::instance($testcourses[2]);
2374 $page = $DB->get_record('page', array('course'=>$testcourses[2]));
2375 $pagecm = get_coursemodule_from_instance('page', $page->id);
2376 $pagecontext = context_module::instance($pagecm->id);
2378 $context->mark_dirty();
2379 $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2380 $USER->access['test'] = true;
2381 $context->reload_if_dirty();
2382 $this->assertFalse(isset($USER->access['test']));
2384 $context->mark_dirty();
2385 $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2386 $USER->access['test'] = true;
2387 $pagecontext->reload_if_dirty();
2388 $this->assertFalse(isset($USER->access['test']));
2391 // Test context_helper::build_all_paths() method.
2393 $oldcontexts = $DB->get_records('context', array(), 'id');
2394 $DB->set_field_select('context', 'path', null, "contextlevel <> ".CONTEXT_SYSTEM);
2395 $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM);
2396 context_helper::build_all_paths();
2397 $newcontexts = $DB->get_records('context', array(), 'id');
2398 $this->assertEquals($oldcontexts, $newcontexts);
2399 unset($oldcontexts);
2400 unset($newcontexts);
2403 // Test $context->reset_paths() method.
2405 $context = context_course::instance($testcourses[2]);
2406 $children = $context->get_child_contexts();
2407 $context->reset_paths(false);
2408 $this->assertNull($DB->get_field('context', 'path', array('id'=>$context->id)));
2409 $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$context->id)));
2410 foreach ($children as $child) {
2411 $this->assertNull($DB->get_field('context', 'path', array('id'=>$child->id)));
2412 $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$child->id)));
2414 $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0)));
2415 $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>null)));
2417 $context = context_course::instance($testcourses[2]);
2418 $context->reset_paths(true);
2419 $context = context_course::instance($testcourses[2]);
2420 $this->assertSame($context->path, $DB->get_field('context', 'path', array('id'=>$context->id)));
2421 $this->assertSame($context->depth, $DB->get_field('context', 'depth', array('id'=>$context->id)));
2422 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2423 $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2426 // Test $context->update_moved() method.
2428 accesslib_clear_all_caches(false);
2429 $DB->delete_records('cache_flags', array());
2430 $course = $DB->get_record('course', array('id'=>$testcourses[0]));
2431 $context = context_course::instance($course->id);
2432 $oldpath = $context->path;
2433 $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2434 $categorycontext = context_coursecat::instance($miscid);
2435 $course->category = $miscid;
2436 $DB->update_record('course', $course);
2437 $context->update_moved($categorycontext);
2439 $context = context_course::instance($course->id);
2440 $this->assertEquals($categorycontext, $context->get_parent_context());
2441 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2442 $this->assertTrue(isset($dirty[$oldpath]));
2443 $this->assertTrue(isset($dirty[$context->path]));
2446 // Test $context->delete_content() method.
2448 context_helper::reset_caches();
2449 $context = context_module::instance($testpages[3]);
2450 $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2451 $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2452 $context->delete_content();
2453 $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2454 $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2457 // Test $context->delete() method.
2459 context_helper::reset_caches();
2460 $context = context_module::instance($testpages[4]);
2461 $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2462 $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2463 $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id));
2464 $bicontext = context_block::instance($bi->id);
2465 $DB->delete_records('cache_flags', array());
2466 $context->delete(); // Should delete also linked blocks.
2467 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2468 $this->assertTrue(isset($dirty[$context->path]));
2469 $this->assertFalse($DB->record_exists('context', array('id'=>$context->id)));
2470 $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id)));
2471 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4])));
2472 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id)));
2473 $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2474 context_module::instance($testpages[4]);
2477 // Test context_helper::delete_instance() method.
2479 context_helper::reset_caches();
2480 $lastcourse = array_pop($testcourses);
2481 $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2482 $coursecontext = context_course::instance($lastcourse);
2483 $this->assertEquals(1, context_inspection::test_context_cache_size());
2484 $this->assertNotEquals(CONTEXT_COURSE, $coursecontext->instanceid);
2485 $DB->delete_records('cache_flags', array());
2486 context_helper::delete_instance(CONTEXT_COURSE, $lastcourse);
2487 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2488 $this->assertTrue(isset($dirty[$coursecontext->path]));
2489 $this->assertEquals(0, context_inspection::test_context_cache_size());
2490 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2491 context_course::instance($lastcourse);
2494 // Test context_helper::create_instances() method.
2496 $prevcount = $DB->count_records('context');
2497 $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2498 context_helper::create_instances(null, true);
2499 $this->assertSame($DB->count_records('context'), $prevcount);
2500 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2501 $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2503 $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2504 $DB->delete_records('block_instances', array());
2505 $prevcount = $DB->count_records('context');
2506 $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM);
2507 context_helper::create_instances(null, true);
2508 $this->assertSame($prevcount, $DB->count_records('context'));
2509 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2510 $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2512 // Test context_helper::cleanup_instances() method.
2514 $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2515 $DB->delete_records('course', array('id'=>$lastcourse));
2516 $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2517 $DB->delete_records('course_categories', array('id'=>$lastcategory));
2518 $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2519 $DB->delete_records('user', array('id'=>$lastuser));
2520 $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2521 $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2522 context_helper::cleanup_instances();
2523 $count = 1; // System.
2524 $count += $DB->count_records('user', array('deleted'=>0));
2525 $count += $DB->count_records('course_categories');
2526 $count += $DB->count_records('course');
2527 $count += $DB->count_records('course_modules');
2528 $count += $DB->count_records('block_instances');
2529 $this->assertEquals($count, $DB->count_records('context'));
2532 // Test context cache size restrictions.
2534 $testusers= array();
2535 for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2536 $user = $generator->create_user();
2537 $testusers[$i] = $user->id;
2539 context_helper::create_instances(null, true);
2540 context_helper::reset_caches();
2541 for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2542 context_user::instance($testusers[$i]);
2543 if ($i == CONTEXT_CACHE_MAX_SIZE - 1) {
2544 $this->assertEquals(CONTEXT_CACHE_MAX_SIZE, context_inspection::test_context_cache_size());
2545 } else if ($i == CONTEXT_CACHE_MAX_SIZE) {
2546 // Once the limit is reached roughly 1/3 of records should be removed from cache.
2547 $this->assertEquals((int)ceil(CONTEXT_CACHE_MAX_SIZE * (2/3) + 101), context_inspection::test_context_cache_size());
2550 // We keep the first 100 cached.
2551 $prevsize = context_inspection::test_context_cache_size();
2552 for ($i=0; $i<100; $i++) {
2553 context_user::instance($testusers[$i]);
2554 $this->assertEquals($prevsize, context_inspection::test_context_cache_size());
2556 context_user::instance($testusers[102]);
2557 $this->assertEquals($prevsize+1, context_inspection::test_context_cache_size());
2558 unset($testusers);
2562 // Test basic test of legacy functions.
2563 // Note: watch out, the fake site might be pretty borked already.
2565 $this->assertEquals(get_system_context(), context_system::instance());
2567 foreach ($DB->get_records('context') as $contextid => $record) {
2568 $context = context::instance_by_id($contextid);
2569 $this->assertEquals($context, get_context_instance_by_id($contextid, IGNORE_MISSING));
2570 $this->assertEquals($context, get_context_instance($record->contextlevel, $record->instanceid));
2571 $this->assertEquals($context->get_parent_context_ids(), get_parent_contexts($context));
2572 if ($context->id == SYSCONTEXTID) {
2573 $this->assertFalse(get_parent_contextid($context));
2574 } else {
2575 $this->assertSame($context->get_parent_context()->id, get_parent_contextid($context));
2579 $children = get_child_contexts($systemcontext);
2580 // Using assertEquals here as assertSame fails for some reason...
2581 $this->assertEquals($children, $systemcontext->get_child_contexts());
2582 $this->assertEquals(count($children), $DB->count_records('context')-1);
2583 $this->resetDebugging();
2584 unset($children);
2586 // Make sure a debugging is thrown.
2587 get_context_instance($record->contextlevel, $record->instanceid);
2588 $this->assertDebuggingCalled('get_context_instance() is deprecated, please use context_xxxx::instance() instead.', DEBUG_DEVELOPER);
2589 get_context_instance_by_id($record->id);
2590 $this->assertDebuggingCalled('get_context_instance_by_id() is deprecated, please use context::instance_by_id($id) instead.', DEBUG_DEVELOPER);
2591 get_system_context();
2592 $this->assertDebuggingCalled('get_system_context() is deprecated, please use context_system::instance() instead.', DEBUG_DEVELOPER);
2593 get_parent_contexts($context);
2594 $this->assertDebuggingCalled('get_parent_contexts() is deprecated, please use $context->get_parent_context_ids() instead.', DEBUG_DEVELOPER);
2595 get_parent_contextid($context);
2596 $this->assertDebuggingCalled('get_parent_contextid() is deprecated, please use $context->get_parent_context() instead.', DEBUG_DEVELOPER);
2597 get_child_contexts($frontpagecontext);
2598 $this->assertDebuggingCalled('get_child_contexts() is deprecated, please use $context->get_child_contexts() instead.', DEBUG_DEVELOPER);
2600 $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2601 create_contexts();
2602 $this->assertDebuggingCalled('create_contexts() is deprecated, please use context_helper::create_instances() instead.', DEBUG_DEVELOPER);
2603 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK)));
2605 $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK));
2606 build_context_path();
2607 $this->assertDebuggingCalled('build_context_path() is deprecated, please use context_helper::build_all_paths() instead.', DEBUG_DEVELOPER);
2608 $this->assertFalse($DB->record_exists('context', array('depth'=>0)));
2610 $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2611 $DB->delete_records('course', array('id'=>$lastcourse));
2612 $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2613 $DB->delete_records('course_categories', array('id'=>$lastcategory));
2614 $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2615 $DB->delete_records('user', array('id'=>$lastuser));
2616 $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2617 $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2618 cleanup_contexts();
2619 $this->assertDebuggingCalled('cleanup_contexts() is deprecated, please use context_helper::cleanup_instances() instead.', DEBUG_DEVELOPER);
2620 $count = 1; // System.
2621 $count += $DB->count_records('user', array('deleted'=>0));
2622 $count += $DB->count_records('course_categories');
2623 $count += $DB->count_records('course');
2624 $count += $DB->count_records('course_modules');
2625 $count += $DB->count_records('block_instances');
2626 $this->assertEquals($count, $DB->count_records('context'));
2628 // Test legacy rebuild_contexts().
2629 $context = context_course::instance($testcourses[2]);
2630 rebuild_contexts(array($context));
2631 $this->assertDebuggingCalled('rebuild_contexts() is deprecated, please use $context->reset_paths(true) instead.', DEBUG_DEVELOPER);
2632 $context = context_course::instance($testcourses[2]);
2633 $this->assertSame($context->path, $DB->get_field('context', 'path', array('id' => $context->id)));
2634 $this->assertSame($context->depth, $DB->get_field('context', 'depth', array('id' => $context->id)));
2635 $this->assertEquals(0, $DB->count_records('context', array('depth' => 0)));
2636 $this->assertEquals(0, $DB->count_records('context', array('path' => null)));
2638 context_helper::reset_caches();
2639 preload_course_contexts($SITE->id);
2640 $this->assertDebuggingCalled('preload_course_contexts() is deprecated, please use context_helper::preload_course() instead.', DEBUG_DEVELOPER);
2641 $this->assertEquals(1 + $DB->count_records('course_modules', array('course' => $SITE->id)),
2642 context_inspection::test_context_cache_size());
2644 context_helper::reset_caches();
2645 list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx');
2646 $this->assertDebuggingCalled('context_instance_preload_sql() is deprecated, please use context_helper::get_preload_record_columns_sql() instead.', DEBUG_DEVELOPER);
2647 $this->assertEquals(', ' . context_helper::get_preload_record_columns_sql('ctx'), $select);
2648 $this->assertEquals('LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = ' . CONTEXT_COURSECAT . ')', $join);
2649 $sql = "SELECT c.id $select FROM {course_categories} c $join";
2650 $records = $DB->get_records_sql($sql);
2651 foreach ($records as $record) {
2652 context_instance_preload($record);
2653 $this->assertDebuggingCalled('context_instance_preload() is deprecated, please use context_helper::preload_from_record() instead.',
2654 DEBUG_DEVELOPER);
2655 $record = (array)$record;
2656 $this->assertEquals(1, count($record)); // Only id left.
2658 $this->assertEquals(count($records), context_inspection::test_context_cache_size());
2660 accesslib_clear_all_caches(true);
2661 $DB->delete_records('cache_flags', array());
2662 mark_context_dirty($systemcontext->path);
2663 $this->assertDebuggingCalled('mark_context_dirty() is deprecated, please use $context->mark_dirty() instead.', DEBUG_DEVELOPER);
2664 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2665 $this->assertTrue(isset($dirty[$systemcontext->path]));
2667 accesslib_clear_all_caches(false);
2668 $DB->delete_records('cache_flags', array());
2669 $course = $DB->get_record('course', array('id'=>$testcourses[2]));
2670 $context = context_course::instance($course->id);
2671 $oldpath = $context->path;
2672 $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2673 $categorycontext = context_coursecat::instance($miscid);
2674 $course->category = $miscid;
2675 $DB->update_record('course', $course);
2676 context_moved($context, $categorycontext);
2677 $this->assertDebuggingCalled('context_moved() is deprecated, please use context::update_moved() instead.', DEBUG_DEVELOPER);
2678 $context = context_course::instance($course->id);
2679 $this->assertEquals($categorycontext, $context->get_parent_context());
2681 $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2682 delete_context(CONTEXT_COURSE, $testcourses[2]);
2683 $this->assertDebuggingCalled('delete_context() is deprecated, please use context_helper::delete_instance() instead.', DEBUG_DEVELOPER);
2684 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2685 delete_context(CONTEXT_COURSE, $testcourses[2], false);
2686 $this->assertDebuggingCalled('delete_context() is deprecated, please use $context->delete_content() instead.', DEBUG_DEVELOPER);
2688 $name = get_contextlevel_name(CONTEXT_COURSE);
2689 $this->assertDebuggingCalled('get_contextlevel_name() is deprecated, please use context_helper::get_level_name() instead.', DEBUG_DEVELOPER);
2690 $this->assertFalse(empty($name));
2692 $context = context_course::instance($testcourses[2]);
2693 $name = print_context_name($context);
2694 $this->assertDebuggingCalled('print_context_name() is deprecated, please use $context->get_context_name() instead.', DEBUG_DEVELOPER);
2695 $this->assertFalse(empty($name));
2697 $url1 = get_context_url($coursecontext);
2698 $this->assertDebuggingCalled('get_context_url() is deprecated, please use $context->get_url() instead.', DEBUG_DEVELOPER);
2699 $url2 = $coursecontext->get_url();
2700 $this->assertEquals($url1, $url2);
2701 $this->assertInstanceOf('moodle_url', $url2);
2703 $pagecm = get_coursemodule_from_instance('page', $testpages[7]);
2704 $context = context_module::instance($pagecm->id);
2705 $coursecontext1 = get_course_context($context);
2706 $this->assertDebuggingCalled('get_course_context() is deprecated, please use $context->get_course_context(true) instead.', DEBUG_DEVELOPER);
2707 $coursecontext2 = $context->get_course_context(true);
2708 $this->assertEquals($coursecontext1, $coursecontext2);
2709 $this->assertEquals(CONTEXT_COURSE, $coursecontext2->contextlevel);
2710 $this->assertEquals($pagecm->course, get_courseid_from_context($context));
2711 $this->assertDebuggingCalled('get_courseid_from_context() is deprecated, please use $context->get_course_context(false) instead.', DEBUG_DEVELOPER);
2713 $caps = fetch_context_capabilities($systemcontext);
2714 $this->assertDebuggingCalled('fetch_context_capabilities() is deprecated, please use $context->get_capabilities() instead.', DEBUG_DEVELOPER);
2715 $this->assertEquals($caps, $systemcontext->get_capabilities());
2716 unset($caps);
2720 * Test updating of role capabilities during upgrade
2722 public function test_update_capabilities() {
2723 global $DB, $SITE;
2725 $this->resetAfterTest(true);
2727 $froncontext = context_course::instance($SITE->id);
2728 $student = $DB->get_record('role', array('archetype'=>'student'));
2729 $teacher = $DB->get_record('role', array('archetype'=>'teacher'));
2731 $existingcaps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2733 $this->assertFalse(isset($existingcaps['moodle/site:restore'])); // Moved to new 'moodle/restore:restorecourse'.
2734 $this->assertTrue(isset($existingcaps['moodle/restore:restorecourse'])); // New cap from 'moodle/site:restore'.
2735 $this->assertTrue(isset($existingcaps['moodle/site:sendmessage'])); // New capability.
2736 $this->assertTrue(isset($existingcaps['moodle/backup:backupcourse']));
2737 $this->assertTrue(isset($existingcaps['moodle/backup:backupsection'])); // Cloned from 'moodle/backup:backupcourse'.
2738 $this->assertTrue(isset($existingcaps['moodle/site:approvecourse'])); // Updated bitmask.
2739 $this->assertTrue(isset($existingcaps['moodle/course:manageactivities']));
2740 $this->assertTrue(isset($existingcaps['mod/page:addinstance'])); // Cloned from core 'moodle/course:manageactivities'.
2742 // Fake state before upgrade.
2743 $DB->set_field('capabilities', 'name', 'moodle/site:restore', array('name'=>'moodle/restore:restorecourse'));
2744 $DB->set_field('role_capabilities', 'capability', 'moodle/site:restore', array('capability'=>'moodle/restore:restorecourse'));
2745 assign_capability('moodle/site:restore', CAP_PROHIBIT, $teacher->id, $froncontext->id, true);
2746 $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/site:restore', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2748 $DB->delete_records('role_capabilities', array('capability'=>'moodle/site:sendmessage'));
2749 $DB->delete_records('capabilities', array('name'=>'moodle/site:sendmessage'));
2751 $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupsection'));
2752 $DB->delete_records('capabilities', array('name'=>'moodle/backup:backupsection'));
2753 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2754 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2756 $DB->set_field('capabilities', 'riskbitmask', 0, array('name'=>'moodle/site:approvecourse'));
2758 $DB->delete_records('role_capabilities', array('capability'=>'mod/page:addinstance'));
2759 $DB->delete_records('capabilities', array('name'=>'mod/page:addinstance'));
2760 assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2761 assign_capability('moodle/course:manageactivities', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2763 // Execute core.
2764 update_capabilities('moodle');
2766 // Only core should be upgraded.
2767 $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2769 $this->assertFalse(isset($existingcaps['moodle/site:restore']));
2770 $this->assertTrue(isset($caps['moodle/restore:restorecourse']));
2771 $this->assertEquals($existingcaps['moodle/restore:restorecourse'], $caps['moodle/restore:restorecourse']);
2772 $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/restore:restorecourse', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2773 $this->assertEquals($perms1, $perms2);
2775 $this->assertTrue(isset($caps['moodle/site:sendmessage']));
2776 $this->assertEquals($existingcaps['moodle/site:sendmessage'], $caps['moodle/site:sendmessage']);
2778 $this->assertTrue(isset($caps['moodle/backup:backupsection']));
2779 $this->assertEquals($existingcaps['moodle/backup:backupsection'], $caps['moodle/backup:backupsection']);
2780 $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/backup:backupcourse', 'moodle/backup:backupsection'));
2781 foreach ($roles as $role) {
2782 $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2783 $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupsection', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2784 $this->assertEquals($perms1, $perms2);
2787 $this->assertTrue(isset($caps['moodle/site:approvecourse']));
2788 $this->assertEquals($existingcaps['moodle/site:approvecourse'], $caps['moodle/site:approvecourse']);
2790 $this->assertFalse(isset($caps['mod/page:addinstance']));
2792 // Execute plugin.
2793 update_capabilities('mod_page');
2794 $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2795 $this->assertTrue(isset($caps['mod/page:addinstance']));
2796 $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/course:manageactivities', 'mod/page:addinstance'));
2797 foreach ($roles as $role) {
2798 $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/course:manageactivities', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2799 $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'mod/page:addinstance', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2801 $this->assertEquals($perms1, $perms2);
2805 * Tests reset_role_capabilities function.
2807 public function test_reset_role_capabilities() {
2808 global $DB;
2809 $this->resetAfterTest(true);
2810 $generator = $this->getDataGenerator();
2812 // Create test course and user, enrol one in the other.
2813 $course = $generator->create_course();
2814 $user = $generator->create_user();
2815 $roleid = $DB->get_field('role', 'id', array('shortname' => 'student'), MUST_EXIST);
2816 $generator->enrol_user($user->id, $course->id, $roleid);
2818 // Change student role so it DOES have 'mod/forum:addinstance'.
2819 $systemcontext = context_system::instance();
2820 assign_capability('mod/forum:addinstance', CAP_ALLOW, $roleid, $systemcontext->id);
2822 // Override course so it does NOT allow students 'mod/forum:viewdiscussion'.
2823 $coursecontext = context_course::instance($course->id);
2824 assign_capability('mod/forum:viewdiscussion', CAP_PREVENT, $roleid, $coursecontext->id);
2826 // Check expected capabilities so far.
2827 $this->assertTrue(has_capability('mod/forum:addinstance', $coursecontext, $user));
2828 $this->assertFalse(has_capability('mod/forum:viewdiscussion', $coursecontext, $user));
2830 // Oops, allowing student to add forums was a mistake, let's reset the role.
2831 reset_role_capabilities($roleid);
2833 // Check new expected capabilities - role capabilities should have been reset,
2834 // while the override at course level should remain.
2835 $this->assertFalse(has_capability('mod/forum:addinstance', $coursecontext, $user));
2836 $this->assertFalse(has_capability('mod/forum:viewdiscussion', $coursecontext, $user));
2841 * Context caching fixture
2843 class context_inspection extends context_helper {
2844 public static function test_context_cache_size() {
2845 return self::$cache_count;