Merge branch 'MDL-24951-master' of git://github.com/Chocolate-lightning/moodle
[moodle.git] / lib / tests / accesslib_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Full functional accesslib test.
19  *
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
24  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Functional test for accesslib.php
31  *
32  * Note: execution may take many minutes especially on slower servers.
33  */
34 class core_accesslib_testcase extends advanced_testcase {
35     /**
36      * Verify comparison of context instances in phpunit asserts.
37      */
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);
47     }
49     /**
50      * Test resetting works.
51      */
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->accessdatabyuser);
61         accesslib_clear_all_caches_for_unit_testing();
62         $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts);
63         $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
64     }
66     /**
67      * Check modifying capability record is not exposed to other code.
68      */
69     public function test_capabilities_mutation() {
70         $oldcap = get_capability_info('moodle/site:config');
71         $cap = get_capability_info('moodle/site:config');
72         unset($cap->name);
73         $newcap = get_capability_info('moodle/site:config');
75         $this->assertFalse(isset($cap->name));
76         $this->assertTrue(isset($newcap->name));
77         $this->assertTrue(isset($oldcap->name));
78     }
80     /**
81      * Test getting of role access
82      */
83     public function test_get_role_access() {
84         global $DB;
86         $roles = $DB->get_records('role');
87         foreach ($roles as $role) {
88             $access = get_role_access($role->id);
90             $this->assertTrue(is_array($access));
91             $this->assertTrue(is_array($access['ra']));
92             $this->assertFalse(isset($access['rdef']));
93             $this->assertFalse(isset($access['rdef_count']));
94             $this->assertFalse(isset($access['loaded']));
95             $this->assertTrue(isset($access['time']));
96             $this->assertTrue(is_array($access['rsw']));
97         }
99         // Note: the data is validated in the functional permission evaluation test at the end of this testcase.
100     }
102     /**
103      * Test getting of guest role.
104      */
105     public function test_get_guest_role() {
106         global $CFG;
108         $guest = get_guest_role();
109         $this->assertEquals('guest', $guest->archetype);
110         $this->assertEquals('guest', $guest->shortname);
112         $this->assertEquals($CFG->guestroleid, $guest->id);
113     }
115     /**
116      * Test if user is admin.
117      */
118     public function test_is_siteadmin() {
119         global $DB, $CFG;
121         $this->resetAfterTest();
123         $users = $DB->get_records('user');
125         foreach ($users as $user) {
126             $this->setUser(0);
127             if ($user->username === 'admin') {
128                 $this->assertTrue(is_siteadmin($user));
129                 $this->assertTrue(is_siteadmin($user->id));
130                 $this->setUser($user);
131                 $this->assertTrue(is_siteadmin());
132                 $this->assertTrue(is_siteadmin(null));
133             } else {
134                 $this->assertFalse(is_siteadmin($user));
135                 $this->assertFalse(is_siteadmin($user->id));
136                 $this->setUser($user);
137                 $this->assertFalse(is_siteadmin());
138                 $this->assertFalse(is_siteadmin(null));
139             }
140         }
142         // Change the site admin list and check that it still works with
143         // multiple admins. We do this with userids only (not real user
144         // accounts) because it makes the test simpler.
145         $before = $CFG->siteadmins;
146         set_config('siteadmins', '666,667,668');
147         $this->assertTrue(is_siteadmin(666));
148         $this->assertTrue(is_siteadmin(667));
149         $this->assertTrue(is_siteadmin(668));
150         $this->assertFalse(is_siteadmin(669));
151         set_config('siteadmins', '13');
152         $this->assertTrue(is_siteadmin(13));
153         $this->assertFalse(is_siteadmin(666));
154         set_config('siteadmins', $before);
155     }
157     /**
158      * Test if user is enrolled in a course
159      */
160     public function test_is_enrolled() {
161         global $DB;
163         $this->resetAfterTest();
165         // Generate data.
166         $user = $this->getDataGenerator()->create_user();
167         $course = $this->getDataGenerator()->create_course();
168         $coursecontext = context_course::instance($course->id);
169         $role = $DB->get_record('role', array('shortname'=>'student'));
171         // There should be a manual enrolment as part of the default install.
172         $plugin = enrol_get_plugin('manual');
173         $instance = $DB->get_record('enrol', array(
174             'courseid' => $course->id,
175             'enrol' => 'manual',
176         ));
177         $this->assertNotSame(false, $instance);
179         // Enrol the user in the course.
180         $plugin->enrol_user($instance, $user->id, $role->id);
182         // We'll test with the mod/assign:submit capability.
183         $capability= 'mod/assign:submit';
184         $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
186         // Switch to our user.
187         $this->setUser($user);
189         // Ensure that the user has the capability first.
190         $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
192         // We first test whether the user is enrolled on the course as this
193         // seeds the cache, then we test for the capability.
194         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
195         $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
197         // Prevent the capability for this user role.
198         assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
199         $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
201         // Again, we seed the cache first by checking initial enrolment,
202         // and then we test the actual capability.
203         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
204         $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
205     }
207     /**
208      * Test logged in test.
209      */
210     public function test_isloggedin() {
211         global $USER;
213         $this->resetAfterTest();
215         $USER->id = 0;
216         $this->assertFalse(isloggedin());
217         $USER->id = 1;
218         $this->assertTrue(isloggedin());
219     }
221     /**
222      * Test guest user test.
223      */
224     public function test_isguestuser() {
225         global $DB;
227         $this->resetAfterTest();
229         $guest = $DB->get_record('user', array('username'=>'guest'));
230         $this->setUser(0);
231         $this->assertFalse(isguestuser());
232         $this->setAdminUser();
233         $this->assertFalse(isguestuser());
234         $this->assertTrue(isguestuser($guest));
235         $this->assertTrue(isguestuser($guest->id));
236         $this->setUser($guest);
237         $this->assertTrue(isguestuser());
239         $users = $DB->get_records('user');
240         foreach ($users as $user) {
241             if ($user->username === 'guest') {
242                 continue;
243             }
244             $this->assertFalse(isguestuser($user));
245         }
246     }
248     /**
249      * Test capability riskiness.
250      */
251     public function test_is_safe_capability() {
252         global $DB;
253         // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap.
254         $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST);
255         $this->assertFalse(is_safe_capability($capability));
256     }
258     /**
259      * Test context fetching.
260      */
261     public function test_get_context_info_array() {
262         $this->resetAfterTest();
264         $syscontext = context_system::instance();
265         $user = $this->getDataGenerator()->create_user();
266         $usercontext = context_user::instance($user->id);
267         $course = $this->getDataGenerator()->create_course();
268         $catcontext = context_coursecat::instance($course->category);
269         $coursecontext = context_course::instance($course->id);
270         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
271         $modcontext = context_module::instance($page->cmid);
272         $cm = get_coursemodule_from_instance('page', $page->id);
273         $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
274         $block1context = context_block::instance($block1->id);
275         $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id));
276         $block2context = context_block::instance($block2->id);
278         $result = get_context_info_array($syscontext->id);
279         $this->assertCount(3, $result);
280         $this->assertEquals($syscontext, $result[0]);
281         $this->assertNull($result[1]);
282         $this->assertNull($result[2]);
284         $result = get_context_info_array($usercontext->id);
285         $this->assertCount(3, $result);
286         $this->assertEquals($usercontext, $result[0]);
287         $this->assertNull($result[1]);
288         $this->assertNull($result[2]);
290         $result = get_context_info_array($catcontext->id);
291         $this->assertCount(3, $result);
292         $this->assertEquals($catcontext, $result[0]);
293         $this->assertNull($result[1]);
294         $this->assertNull($result[2]);
296         $result = get_context_info_array($coursecontext->id);
297         $this->assertCount(3, $result);
298         $this->assertEquals($coursecontext, $result[0]);
299         $this->assertEquals($course->id, $result[1]->id);
300         $this->assertSame($course->shortname, $result[1]->shortname);
301         $this->assertNull($result[2]);
303         $result = get_context_info_array($block1context->id);
304         $this->assertCount(3, $result);
305         $this->assertEquals($block1context, $result[0]);
306         $this->assertEquals($course->id, $result[1]->id);
307         $this->assertEquals($course->shortname, $result[1]->shortname);
308         $this->assertNull($result[2]);
310         $result = get_context_info_array($modcontext->id);
311         $this->assertCount(3, $result);
312         $this->assertEquals($modcontext, $result[0]);
313         $this->assertEquals($course->id, $result[1]->id);
314         $this->assertSame($course->shortname, $result[1]->shortname);
315         $this->assertEquals($cm->id, $result[2]->id);
317         $result = get_context_info_array($block2context->id);
318         $this->assertCount(3, $result);
319         $this->assertEquals($block2context, $result[0]);
320         $this->assertEquals($course->id, $result[1]->id);
321         $this->assertSame($course->shortname, $result[1]->shortname);
322         $this->assertEquals($cm->id, $result[2]->id);
323     }
325     /**
326      * Test looking for course contacts.
327      */
328     public function test_has_coursecontact_role() {
329         global $DB, $CFG;
331         $this->resetAfterTest();
333         $users = $DB->get_records('user');
335         // Nobody is expected to have any course level roles.
336         $this->assertNotEmpty($CFG->coursecontact);
337         foreach ($users as $user) {
338             $this->assertFalse(has_coursecontact_role($user->id));
339         }
341         $user = $this->getDataGenerator()->create_user();
342         $course = $this->getDataGenerator()->create_course();
343         role_assign($CFG->coursecontact, $user->id, context_course::instance($course->id));
344         $this->assertTrue(has_coursecontact_role($user->id));
345     }
347     /**
348      * Test creation of roles.
349      */
350     public function test_create_role() {
351         global $DB;
353         $this->resetAfterTest();
355         $id = create_role('New student role', 'student2', 'New student description', 'student');
356         $role = $DB->get_record('role', array('id'=>$id));
358         $this->assertNotEmpty($role);
359         $this->assertSame('New student role', $role->name);
360         $this->assertSame('student2', $role->shortname);
361         $this->assertSame('New student description', $role->description);
362         $this->assertSame('student', $role->archetype);
363     }
365     /**
366      * Test adding of capabilities to roles.
367      */
368     public function test_assign_capability() {
369         global $DB;
371         $this->resetAfterTest();
373         $user = $this->getDataGenerator()->create_user();
374         $syscontext = context_system::instance();
375         $frontcontext = context_course::instance(SITEID);
376         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
377         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to student by default.
378         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
379         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
381         $this->setUser($user);
382         $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id);
383         $this->assertTrue($result);
384         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
385         $this->assertNotEmpty($permission);
386         $this->assertEquals(CAP_ALLOW, $permission->permission);
387         $this->assertEquals($user->id, $permission->modifierid);
389         $this->setUser(0);
390         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false);
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_ALLOW, $permission->permission);
395         $this->assertEquals($user->id, $permission->modifierid);
397         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true);
398         $this->assertTrue($result);
399         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
400         $this->assertNotEmpty($permission);
401         $this->assertEquals(CAP_PROHIBIT, $permission->permission);
402         $this->assertEquals(0, $permission->modifierid);
404         $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id);
405         $this->assertTrue($result);
406         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
407         $this->assertEmpty($permission);
409         // Test event trigger.
410         $rolecapabilityevent = \core\event\role_capabilities_updated::create(array('context' => $syscontext,
411                                                                                   'objectid' => $student->id,
412                                                                                   'other' => array('name' => $student->shortname)
413                                                                                  ));
414         $expectedlegacylog = array(SITEID, 'role', 'view', 'admin/roles/define.php?action=view&roleid=' . $student->id,
415                             $student->shortname, '', $user->id);
416         $rolecapabilityevent->set_legacy_logdata($expectedlegacylog);
417         $rolecapabilityevent->add_record_snapshot('role', $student);
419         $sink = $this->redirectEvents();
420         $rolecapabilityevent->trigger();
421         $events = $sink->get_events();
422         $sink->close();
423         $event = array_pop($events);
425         $this->assertInstanceOf('\core\event\role_capabilities_updated', $event);
426         $expectedurl = new moodle_url('/admin/roles/define.php', array('action' => 'view', 'roleid' => $student->id));
427         $this->assertEquals($expectedurl, $event->get_url());
428         $this->assertEventLegacyLogData($expectedlegacylog, $event);
429         $this->assertEventContextNotUsed($event);
430     }
432     /**
433      * Test removing of capabilities from roles.
434      */
435     public function test_unassign_capability() {
436         global $DB;
438         $this->resetAfterTest();
440         $syscontext = context_system::instance();
441         $frontcontext = context_course::instance(SITEID);
442         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
443         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to manager by default.
444         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
446         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
447         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
449         $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id);
450         $this->assertTrue($result);
451         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
452         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
453         unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext);
454         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
456         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
457         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
458         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
460         $result = unassign_capability('moodle/backup:backupcourse', $manager->id);
461         $this->assertTrue($result);
462         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
463         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
464     }
466     /**
467      * Test role assigning.
468      */
469     public function test_role_assign() {
470         global $DB, $USER;
472         $this->resetAfterTest();
474         $user = $this->getDataGenerator()->create_user();
475         $course = $this->getDataGenerator()->create_course();
476         $role = $DB->get_record('role', array('shortname'=>'student'));
478         $this->setUser(0);
479         $context = context_system::instance();
480         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
481         role_assign($role->id, $user->id, $context->id);
482         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
483         $this->assertNotEmpty($ras);
484         $this->assertSame('', $ras->component);
485         $this->assertSame('0', $ras->itemid);
486         $this->assertEquals($USER->id, $ras->modifierid);
488         $this->setAdminUser();
489         $context = context_course::instance($course->id);
490         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
491         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666);
492         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
493         $this->assertNotEmpty($ras);
494         $this->assertSame('enrol_self', $ras->component);
495         $this->assertSame('1', $ras->itemid);
496         $this->assertEquals($USER->id, $ras->modifierid);
497         $this->assertEquals(666, $ras->timemodified);
499         // Test event triggered.
501         $user2 = $this->getDataGenerator()->create_user();
502         $sink = $this->redirectEvents();
503         $raid = role_assign($role->id, $user2->id, $context->id);
504         $events = $sink->get_events();
505         $sink->close();
506         $this->assertCount(1, $events);
507         $event = $events[0];
508         $this->assertInstanceOf('\core\event\role_assigned', $event);
509         $this->assertSame('role', $event->target);
510         $this->assertSame('role', $event->objecttable);
511         $this->assertEquals($role->id, $event->objectid);
512         $this->assertEquals($context->id, $event->contextid);
513         $this->assertEquals($user2->id, $event->relateduserid);
514         $this->assertCount(3, $event->other);
515         $this->assertEquals($raid, $event->other['id']);
516         $this->assertSame('', $event->other['component']);
517         $this->assertEquals(0, $event->other['itemid']);
518         $this->assertInstanceOf('moodle_url', $event->get_url());
519         $this->assertSame('role_assigned', $event::get_legacy_eventname());
520         $roles = get_all_roles();
521         $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
522         $expectedlegacylog = array($course->id, 'role', 'assign',
523             'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
524         $this->assertEventLegacyLogData($expectedlegacylog, $event);
525     }
527     /**
528      * Test role unassigning.
529      */
530     public function test_role_unassign() {
531         global $DB, $USER;
533         $this->resetAfterTest();
535         $user = $this->getDataGenerator()->create_user();
536         $course = $this->getDataGenerator()->create_course();
537         $role = $DB->get_record('role', array('shortname'=>'student'));
539         $context = context_course::instance($course->id);
540         role_assign($role->id, $user->id, $context->id);
541         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
542         role_unassign($role->id, $user->id, $context->id);
543         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
545         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1);
546         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
547         role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1);
548         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
550         // Test event triggered.
552         role_assign($role->id, $user->id, $context->id);
553         $sink = $this->redirectEvents();
554         role_unassign($role->id, $user->id, $context->id);
555         $events = $sink->get_events();
556         $sink->close();
557         $this->assertCount(1, $events);
558         $event = $events[0];
559         $this->assertInstanceOf('\core\event\role_unassigned', $event);
560         $this->assertSame('role', $event->target);
561         $this->assertSame('role', $event->objecttable);
562         $this->assertEquals($role->id, $event->objectid);
563         $this->assertEquals($context->id, $event->contextid);
564         $this->assertEquals($user->id, $event->relateduserid);
565         $this->assertCount(3, $event->other);
566         $this->assertSame('', $event->other['component']);
567         $this->assertEquals(0, $event->other['itemid']);
568         $this->assertInstanceOf('moodle_url', $event->get_url());
569         $roles = get_all_roles();
570         $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
571         $expectedlegacylog = array($course->id, 'role', 'unassign',
572             'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
573         $this->assertEventLegacyLogData($expectedlegacylog, $event);
574     }
576     /**
577      * Test role unassigning.
578      */
579     public function test_role_unassign_all() {
580         global $DB;
582         $this->resetAfterTest();
584         $user = $this->getDataGenerator()->create_user();
585         $course = $this->getDataGenerator()->create_course();
586         $role = $DB->get_record('role', array('shortname'=>'student'));
587         $role2 = $DB->get_record('role', array('shortname'=>'teacher'));
588         $syscontext = context_system::instance();
589         $coursecontext = context_course::instance($course->id);
590         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
591         $modcontext = context_module::instance($page->cmid);
593         role_assign($role->id, $user->id, $syscontext->id);
594         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
595         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
596         role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id));
597         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
599         role_assign($role->id, $user->id, $syscontext->id);
600         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
601         role_assign($role->id, $user->id, $modcontext->id);
602         $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id)));
603         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false);
604         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
605         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true);
606         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
607         role_unassign_all(array('userid'=>$user->id));
608         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
610         role_assign($role->id, $user->id, $syscontext->id);
611         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
612         role_assign($role->id, $user->id, $coursecontext->id);
613         role_assign($role->id, $user->id, $modcontext->id);
614         $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id)));
615         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true);
616         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
618         // Test events triggered.
620         role_assign($role2->id, $user->id, $coursecontext->id);
621         role_assign($role2->id, $user->id, $modcontext->id);
622         $sink = $this->redirectEvents();
623         role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role2->id));
624         $events = $sink->get_events();
625         $sink->close();
626         $this->assertCount(2, $events);
627         $this->assertInstanceOf('\core\event\role_unassigned', $events[0]);
628         $this->assertInstanceOf('\core\event\role_unassigned', $events[1]);
629     }
631     /**
632      * Test role queries.
633      */
634     public function test_get_roles_with_capability() {
635         global $DB;
637         $this->resetAfterTest();
639         $syscontext = context_system::instance();
640         $frontcontext = context_course::instance(SITEID);
641         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
642         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
644         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
645         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse'));
647         $roles = get_roles_with_capability('moodle/backup:backupcourse');
648         $this->assertEquals(array(), $roles);
650         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
651         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id);
652         assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id);
654         $roles = get_roles_with_capability('moodle/backup:backupcourse');
655         $this->assertEquals(array($teacher->id, $manager->id), array_keys($roles), '', 0, 10, true);
657         $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW);
658         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
660         $roles = get_roles_with_capability('moodle/backup:backupcourse', null, $syscontext);
661         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
662     }
664     /**
665      * Test deleting of roles.
666      */
667     public function test_delete_role() {
668         global $DB;
670         $this->resetAfterTest();
672         $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
673         $user = $this->getDataGenerator()->create_user();
674         role_assign($role->id, $user->id, context_system::instance());
675         $course = $this->getDataGenerator()->create_course();
676         $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id);
677         $DB->insert_record('role_names', $rolename);
679         $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
680         $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
681         $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id)));
682         $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
683         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
684         $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
685         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
686         $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
688         // Delete role and get event.
689         $sink = $this->redirectEvents();
690         $result = delete_role($role->id);
691         $events = $sink->get_events();
692         $sink->close();
693         $event = array_pop($events);
695         $this->assertTrue($result);
696         $this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
697         $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
698         $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
699         $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id)));
700         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
701         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
702         $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
703         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
704         $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
706         // Test triggered event.
707         $this->assertInstanceOf('\core\event\role_deleted', $event);
708         $this->assertSame('role', $event->target);
709         $this->assertSame('role', $event->objecttable);
710         $this->assertSame($role->id, $event->objectid);
711         $this->assertEquals(context_system::instance(), $event->get_context());
712         $this->assertSame($role->shortname, $event->other['shortname']);
713         $this->assertSame($role->description, $event->other['description']);
714         $this->assertSame($role->archetype, $event->other['archetype']);
716         $expectedlegacylog = array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$role->id,
717                                    $role->shortname, '');
718         $this->assertEventLegacyLogData($expectedlegacylog, $event);
719     }
721     /**
722      * Test fetching of all roles.
723      */
724     public function test_get_all_roles() {
725         global $DB;
727         $this->resetAfterTest();
729         $allroles = get_all_roles();
730         $this->assertInternalType('array', $allroles);
731         $this->assertCount(8, $allroles); // There are 8 roles is standard install.
733         $role = reset($allroles);
734         $role = (array)$role;
736         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), array_keys($role), '', 0, 10, true);
738         foreach ($allroles as $roleid => $role) {
739             $this->assertEquals($role->id, $roleid);
740         }
742         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
743         $course = $this->getDataGenerator()->create_course();
744         $coursecontext = context_course::instance($course->id);
745         $otherid = create_role('Other role', 'other', 'Some other role', '');
746         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
747         $DB->insert_record('role_names', $teacherename);
748         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
749         $DB->insert_record('role_names', $otherrename);
750         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
752         $allroles = get_all_roles($coursecontext);
753         $this->assertInternalType('array', $allroles);
754         $this->assertCount(9, $allroles);
755         $role = reset($allroles);
756         $role = (array)$role;
758         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role), '', 0, 10, true);
760         foreach ($allroles as $roleid => $role) {
761             $this->assertEquals($role->id, $roleid);
762             if (isset($renames[$roleid])) {
763                 $this->assertSame($renames[$roleid], $role->coursealias);
764             } else {
765                 $this->assertNull($role->coursealias);
766             }
767         }
768     }
770     /**
771      * Test getting of all archetypes.
772      */
773     public function test_get_role_archetypes() {
774         $archetypes = get_role_archetypes();
775         $this->assertCount(8, $archetypes); // There are 8 archetypes in standard install.
776         foreach ($archetypes as $k => $v) {
777             $this->assertSame($k, $v);
778         }
779     }
781     /**
782      * Test getting of roles with given archetype.
783      */
784     public function test_get_archetype_roles() {
785         $this->resetAfterTest();
787         // New install should have 1 role for each archetype.
788         $archetypes = get_role_archetypes();
789         foreach ($archetypes as $archetype) {
790             $roles = get_archetype_roles($archetype);
791             $this->assertCount(1, $roles);
792             $role = reset($roles);
793             $this->assertSame($archetype, $role->archetype);
794         }
796         create_role('New student role', 'student2', 'New student description', 'student');
797         $roles = get_archetype_roles('student');
798         $this->assertCount(2, $roles);
799     }
801     /**
802      * Test aliased role names.
803      */
804     public function test_role_get_name() {
805         global $DB;
807         $this->resetAfterTest();
809         $allroles = $DB->get_records('role');
810         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
811         $course = $this->getDataGenerator()->create_course();
812         $coursecontext = context_course::instance($course->id);
813         $otherid = create_role('Other role', 'other', 'Some other role', '');
814         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
815         $DB->insert_record('role_names', $teacherename);
816         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
817         $DB->insert_record('role_names', $otherrename);
818         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
820         foreach ($allroles as $role) {
821             // Get localised name from lang pack.
822             $this->assertSame('', $role->name);
823             $name = role_get_name($role, null, ROLENAME_ORIGINAL);
824             $this->assertNotEmpty($name);
825             $this->assertNotEquals($role->shortname, $name);
827             if (isset($renames[$role->id])) {
828                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext));
829                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS));
830                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
831                 $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH));
832             } else {
833                 $this->assertSame($name, role_get_name($role, $coursecontext));
834                 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS));
835                 $this->assertNull(role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
836                 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH));
837             }
838             $this->assertSame($name, role_get_name($role));
839             $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL));
840             $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL));
841             $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT));
842             $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT));
843             $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT));
844             $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT));
845             $this->assertNull(role_get_name($role, null, ROLENAME_ALIAS_RAW));
846         }
847     }
849     /**
850      * Test tweaking of role name arrays.
851      */
852     public function test_role_fix_names() {
853         global $DB;
855         $this->resetAfterTest();
857         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
858         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
859         $otherid = create_role('Other role', 'other', 'Some other role', '');
860         $anotherid = create_role('Another role', 'another', 'Yet another other role', '');
861         $allroles = $DB->get_records('role');
863         $syscontext = context_system::instance();
864         $frontcontext = context_course::instance(SITEID);
865         $course = $this->getDataGenerator()->create_course();
866         $coursecontext = context_course::instance($course->id);
867         $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST);
868         $categorycontext = context_coursecat::instance($category->id);
870         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
871         $DB->insert_record('role_names', $teacherename);
872         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
873         $DB->insert_record('role_names', $otherrename);
874         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
876         // Make sure all localname contain proper values for each ROLENAME_ constant,
877         // note role_get_name() on frontpage is used to get the original name for future compatibility.
878         $roles = $allroles;
879         unset($roles[$student->id]); // Remove one role to make sure no role is added or removed.
880         $rolenames = array();
881         foreach ($roles as $role) {
882             $rolenames[$role->id] = $role->name;
883         }
885         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
886         foreach ($alltypes as $type) {
887             $fixed = role_fix_names($roles, $coursecontext, $type);
888             $this->assertCount(count($roles), $fixed);
889             foreach ($fixed as $roleid => $rolename) {
890                 $this->assertInstanceOf('stdClass', $rolename);
891                 $role = $allroles[$roleid];
892                 $name = role_get_name($role, $coursecontext, $type);
893                 $this->assertSame($name, $rolename->localname);
894             }
895             $fixed = role_fix_names($rolenames, $coursecontext, $type);
896             $this->assertCount(count($rolenames), $fixed);
897             foreach ($fixed as $roleid => $rolename) {
898                 $role = $allroles[$roleid];
899                 $name = role_get_name($role, $coursecontext, $type);
900                 $this->assertSame($name, $rolename);
901             }
902         }
903     }
905     /**
906      * Test role default allows.
907      */
908     public function test_get_default_role_archetype_allows() {
909         $archetypes = get_role_archetypes();
910         foreach ($archetypes as $archetype) {
912             $result = get_default_role_archetype_allows('assign', $archetype);
913             $this->assertInternalType('array', $result);
915             $result = get_default_role_archetype_allows('override', $archetype);
916             $this->assertInternalType('array', $result);
918             $result = get_default_role_archetype_allows('switch', $archetype);
919             $this->assertInternalType('array', $result);
921             $result = get_default_role_archetype_allows('view', $archetype);
922             $this->assertInternalType('array', $result);
923         }
925         $result = get_default_role_archetype_allows('assign', '');
926         $this->assertSame(array(), $result);
928         $result = get_default_role_archetype_allows('override', '');
929         $this->assertSame(array(), $result);
931         $result = get_default_role_archetype_allows('switch', '');
932         $this->assertSame(array(), $result);
934         $result = get_default_role_archetype_allows('view', '');
935         $this->assertSame(array(), $result);
937         $result = get_default_role_archetype_allows('assign', 'wrongarchetype');
938         $this->assertSame(array(), $result);
939         $this->assertDebuggingCalled();
941         $result = get_default_role_archetype_allows('override', 'wrongarchetype');
942         $this->assertSame(array(), $result);
943         $this->assertDebuggingCalled();
945         $result = get_default_role_archetype_allows('switch', 'wrongarchetype');
946         $this->assertSame(array(), $result);
947         $this->assertDebuggingCalled();
949         $result = get_default_role_archetype_allows('view', 'wrongarchetype');
950         $this->assertSame(array(), $result);
951         $this->assertDebuggingCalled();
952     }
954     /**
955      * Test allowing of role assignments.
956      */
957     public function test_core_role_set_assign_allowed() {
958         global $DB, $CFG;
960         $this->resetAfterTest();
962         $otherid = create_role('Other role', 'other', 'Some other role', '');
963         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
965         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
966         core_role_set_assign_allowed($otherid, $student->id);
967         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
969         // Test event trigger.
970         $allowroleassignevent = \core\event\role_allow_assign_updated::create(array('context' => context_system::instance()));
971         $sink = $this->redirectEvents();
972         $allowroleassignevent->trigger();
973         $events = $sink->get_events();
974         $sink->close();
975         $event = array_pop($events);
976         $this->assertInstanceOf('\core\event\role_allow_assign_updated', $event);
977         $mode = 'assign';
978         $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
979         $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
980         $this->assertEventLegacyLogData($expectedlegacylog, $event);
981     }
983     /**
984      * Test allowing of role overrides.
985      */
986     public function test_core_role_set_override_allowed() {
987         global $DB, $CFG;
989         $this->resetAfterTest();
991         $otherid = create_role('Other role', 'other', 'Some other role', '');
992         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
994         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
995         core_role_set_override_allowed($otherid, $student->id);
996         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
998         // Test event trigger.
999         $allowroleassignevent = \core\event\role_allow_override_updated::create(array('context' => context_system::instance()));
1000         $sink = $this->redirectEvents();
1001         $allowroleassignevent->trigger();
1002         $events = $sink->get_events();
1003         $sink->close();
1004         $event = array_pop($events);
1005         $this->assertInstanceOf('\core\event\role_allow_override_updated', $event);
1006         $mode = 'override';
1007         $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
1008         $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
1009         $this->assertEventLegacyLogData($expectedlegacylog, $event);
1010     }
1012     /**
1013      * Test allowing of role switching.
1014      */
1015     public function test_core_role_set_switch_allowed() {
1016         global $DB, $CFG;
1018         $this->resetAfterTest();
1020         $otherid = create_role('Other role', 'other', 'Some other role', '');
1021         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1023         $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
1024         core_role_set_switch_allowed($otherid, $student->id);
1025         $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
1027         // Test event trigger.
1028         $allowroleassignevent = \core\event\role_allow_switch_updated::create(array('context' => context_system::instance()));
1029         $sink = $this->redirectEvents();
1030         $allowroleassignevent->trigger();
1031         $events = $sink->get_events();
1032         $sink->close();
1033         $event = array_pop($events);
1034         $this->assertInstanceOf('\core\event\role_allow_switch_updated', $event);
1035         $mode = 'switch';
1036         $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
1037         $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
1038         $this->assertEventLegacyLogData($expectedlegacylog, $event);
1039     }
1041     /**
1042      * Test allowing of role switching.
1043      */
1044     public function test_core_role_set_view_allowed() {
1045         global $DB, $CFG;
1047         $this->resetAfterTest();
1049         $otherid = create_role('Other role', 'other', 'Some other role', '');
1050         $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1052         $this->assertFalse($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id)));
1053         core_role_set_view_allowed($otherid, $student->id);
1054         $this->assertTrue($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id)));
1056         // Test event trigger.
1057         $allowroleassignevent = \core\event\role_allow_view_updated::create(array('context' => context_system::instance()));
1058         $sink = $this->redirectEvents();
1059         $allowroleassignevent->trigger();
1060         $events = $sink->get_events();
1061         $sink->close();
1062         $event = array_pop($events);
1063         $this->assertInstanceOf('\core\event\role_allow_view_updated', $event);
1064         $mode = 'view';
1065         $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
1066         $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
1067         $this->assertEventLegacyLogData($expectedlegacylog, $event);
1068     }
1070     /**
1071      * Test returning of assignable roles in context.
1072      */
1073     public function test_get_assignable_roles() {
1074         global $DB;
1076         $this->resetAfterTest();
1078         $course = $this->getDataGenerator()->create_course();
1079         $coursecontext = context_course::instance($course->id);
1081         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1082         $teacher = $this->getDataGenerator()->create_user();
1083         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1084         $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1085         $DB->insert_record('role_names', $teacherename);
1087         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1088         $student = $this->getDataGenerator()->create_user();
1089         role_assign($studentrole->id, $student->id, $coursecontext);
1091         $contexts = $DB->get_records('context');
1092         $users = $DB->get_records('user');
1093         $allroles = $DB->get_records('role');
1095         // Evaluate all results for all users in all contexts.
1096         foreach ($users as $user) {
1097             $this->setUser($user);
1098             foreach ($contexts as $contextid => $unused) {
1099                 $context = context_helper::instance_by_id($contextid);
1100                 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1101                 foreach ($allroles as $roleid => $role) {
1102                     if (isset($roles[$roleid])) {
1103                         if (is_siteadmin()) {
1104                             $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)));
1105                         } else {
1106                             $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid");
1107                         }
1108                         $this->assertEquals($role->shortname, $roles[$roleid]);
1109                     } else {
1110                         $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid));
1111                         if (is_siteadmin()) {
1112                             $this->assertFalse($allowed);
1113                         } else {
1114                             $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel");
1115                         }
1116                     }
1117                 }
1118             }
1119         }
1121         // Not-logged-in user.
1122         $this->setUser(0);
1123         foreach ($contexts as $contextid => $unused) {
1124             $context = context_helper::instance_by_id($contextid);
1125             $roles = get_assignable_roles($context, ROLENAME_SHORT);
1126             $this->assertSame(array(), $roles);
1127         }
1129         // Test current user.
1130         $this->setUser(0);
1131         $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST);
1132         $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin);
1133         $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id);
1134         $this->setAdminUser();
1135         $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT);
1136         $this->assertSame($roles1, $roles3);
1137         $this->assertSame($roles2, $roles3);
1139         // Test parameter defaults.
1140         $this->setAdminUser();
1141         $roles1 = get_assignable_roles($coursecontext);
1142         $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
1143         $this->assertEquals($roles2, $roles1);
1145         // Verify returned names - let's allow all roles everywhere to simplify this a bit.
1146         $alllevels = context_helper::get_all_levels();
1147         $alllevels = array_keys($alllevels);
1148         foreach ($allroles as $roleid => $role) {
1149             set_role_contextlevels($roleid, $alllevels);
1150         }
1151         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1152         foreach ($alltypes as $type) {
1153             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1154             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1155             foreach ($roles as $roleid => $rolename) {
1156                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1157             }
1158         }
1160         // Verify counts.
1161         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1162         foreach ($alltypes as $type) {
1163             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1164             list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin);
1165             $this->assertEquals($roles, $rolenames);
1166             foreach ($rolenames as $roleid => $name) {
1167                 if ($roleid == $teacherrole->id or $roleid == $studentrole->id) {
1168                     $this->assertEquals(1, $rolecounts[$roleid]);
1169                 } else {
1170                     $this->assertEquals(0, $rolecounts[$roleid]);
1171                 }
1172                 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1173             }
1174         }
1175     }
1177     /**
1178      * Test getting of all switchable roles.
1179      */
1180     public function test_get_switchable_roles() {
1181         global $DB;
1183         $this->resetAfterTest();
1185         $course = $this->getDataGenerator()->create_course();
1186         $coursecontext = context_course::instance($course->id);
1188         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1189         $teacher = $this->getDataGenerator()->create_user();
1190         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1191         $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1192         $DB->insert_record('role_names', $teacherename);
1194         $contexts = $DB->get_records('context');
1195         $users = $DB->get_records('user');
1196         $allroles = $DB->get_records('role');
1198         // Evaluate all results for all users in all contexts.
1199         foreach ($users as $user) {
1200             $this->setUser($user);
1201             foreach ($contexts as $contextid => $unused) {
1202                 $context = context_helper::instance_by_id($contextid);
1203                 $roles = get_switchable_roles($context);
1204                 foreach ($allroles as $roleid => $role) {
1205                     if (is_siteadmin()) {
1206                         $this->assertTrue(isset($roles[$roleid]));
1207                     } else {
1208                         $parents = $context->get_parent_context_ids(true);
1209                         $pcontexts = implode(',' , $parents);
1210                         $allowed = $DB->record_exists_sql(
1211                             "SELECT r.id
1212                                FROM {role} r
1213                                JOIN {role_allow_switch} ras ON ras.allowswitch = r.id
1214                                JOIN {role_assignments} ra ON ra.roleid = ras.roleid
1215                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1216                             ",
1217                             array('userid'=>$user->id, 'roleid'=>$roleid)
1218                         );
1219                         if (isset($roles[$roleid])) {
1220                             $this->assertTrue($allowed);
1221                         } else {
1222                             $this->assertFalse($allowed);
1223                         }
1224                     }
1226                     if (isset($roles[$roleid])) {
1227                         $coursecontext = $context->get_course_context(false);
1228                         $this->assertSame(role_get_name($role, $coursecontext), $roles[$roleid]);
1229                     }
1230                 }
1231             }
1232         }
1233     }
1235     /**
1236      * Test getting of all overridable roles.
1237      */
1238     public function test_get_overridable_roles() {
1239         global $DB;
1241         $this->resetAfterTest();
1243         $course = $this->getDataGenerator()->create_course();
1244         $coursecontext = context_course::instance($course->id);
1246         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1247         $teacher = $this->getDataGenerator()->create_user();
1248         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1249         $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1250         $DB->insert_record('role_names', $teacherename);
1251         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
1252         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
1254         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1255         $student = $this->getDataGenerator()->create_user();
1256         role_assign($studentrole->id, $student->id, $coursecontext);
1258         $contexts = $DB->get_records('context');
1259         $users = $DB->get_records('user');
1260         $allroles = $DB->get_records('role');
1262         // Evaluate all results for all users in all contexts.
1263         foreach ($users as $user) {
1264             $this->setUser($user);
1265             foreach ($contexts as $contextid => $unused) {
1266                 $context = context_helper::instance_by_id($contextid);
1267                 $roles = get_overridable_roles($context, ROLENAME_SHORT);
1268                 foreach ($allroles as $roleid => $role) {
1269                     $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context);
1270                     if (is_siteadmin()) {
1271                         $this->assertTrue(isset($roles[$roleid]));
1272                     } else {
1273                         $parents = $context->get_parent_context_ids(true);
1274                         $pcontexts = implode(',' , $parents);
1275                         $allowed = $DB->record_exists_sql(
1276                             "SELECT r.id
1277                                FROM {role} r
1278                                JOIN {role_allow_override} rao ON r.id = rao.allowoverride
1279                                JOIN {role_assignments} ra ON rao.roleid = ra.roleid
1280                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1281                             ",
1282                             array('userid'=>$user->id, 'roleid'=>$roleid)
1283                         );
1284                         if (isset($roles[$roleid])) {
1285                             $this->assertTrue($hascap);
1286                             $this->assertTrue($allowed);
1287                         } else {
1288                             $this->assertFalse($hascap and $allowed);
1289                         }
1290                     }
1292                     if (isset($roles[$roleid])) {
1293                         $this->assertEquals($role->shortname, $roles[$roleid]);
1294                     }
1295                 }
1296             }
1297         }
1299         // Test parameter defaults.
1300         $this->setAdminUser();
1301         $roles1 = get_overridable_roles($coursecontext);
1302         $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1303         $this->assertEquals($roles2, $roles1);
1305         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1306         foreach ($alltypes as $type) {
1307             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1308             $roles = get_overridable_roles($coursecontext, $type, false);
1309             foreach ($roles as $roleid => $rolename) {
1310                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1311             }
1312         }
1314         // Verify counts.
1315         $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1316         list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true);
1317         $this->assertEquals($roles, $rolenames);
1318         foreach ($rolenames as $roleid => $name) {
1319             if ($roleid == $teacherrole->id) {
1320                 $this->assertEquals(1, $rolecounts[$roleid]);
1321             } else {
1322                 $this->assertEquals(0, $rolecounts[$roleid]);
1323             }
1324             $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1325         }
1326     }
1328     /**
1329      * Test getting of all overridable roles.
1330      */
1331     public function test_get_viewable_roles_course() {
1332         global $DB;
1334         $this->resetAfterTest();
1336         $course = $this->getDataGenerator()->create_course();
1337         $coursecontext = context_course::instance($course->id);
1339         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
1340         $teacher = $this->getDataGenerator()->create_user();
1341         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1343         $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1344         $studentrolerename = (object) array('roleid' => $studentrole->id, 'name' => 'Učitel', 'contextid' => $coursecontext->id);
1345         $DB->insert_record('role_names', $studentrolerename);
1347         // By default teacher can see student.
1348         $this->setUser($teacher);
1349         $viewableroles = get_viewable_roles($coursecontext);
1350         $this->assertContains($studentrolerename->name, array_values($viewableroles));
1351         // Remove view permission.
1352         $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id));
1353         $viewableroles = get_viewable_roles($coursecontext);
1354         // Teacher can no longer see student role.
1355         $this->assertNotContains($studentrolerename->name, array_values($viewableroles));
1356         // Allow again teacher to view student.
1357         core_role_set_view_allowed($teacherrole->id, $studentrole->id);
1358         // Teacher can now see student role.
1359         $viewableroles = get_viewable_roles($coursecontext);
1360         $this->assertContains($studentrolerename->name, array_values($viewableroles));
1361     }
1363     /**
1364      * Test getting of all overridable roles.
1365      */
1366     public function test_get_viewable_roles_system() {
1367         global $DB;
1369         $this->resetAfterTest();
1371         $context = context_system::instance();
1373         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
1374         $teacher = $this->getDataGenerator()->create_user();
1375         role_assign($teacherrole->id, $teacher->id, $context);
1377         $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1378         $studentrolename = role_get_name($studentrole, $context);
1380         // By default teacher can see student.
1381         $this->setUser($teacher);
1382         $viewableroles = get_viewable_roles($context);
1383         $this->assertContains($studentrolename, array_values($viewableroles));
1384         // Remove view permission.
1385         $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id));
1386         $viewableroles = get_viewable_roles($context);
1387         // Teacher can no longer see student role.
1388         $this->assertNotContains($studentrolename, array_values($viewableroles));
1389         // Allow again teacher to view student.
1390         core_role_set_view_allowed($teacherrole->id, $studentrole->id);
1391         // Teacher can now see student role.
1392         $viewableroles = get_viewable_roles($context);
1393         $this->assertContains($studentrolename, array_values($viewableroles));
1394     }
1396     /**
1397      * Test we have context level defaults.
1398      */
1399     public function test_get_default_contextlevels() {
1400         $archetypes = get_role_archetypes();
1401         $alllevels = context_helper::get_all_levels();
1402         foreach ($archetypes as $archetype) {
1403             $defaults = get_default_contextlevels($archetype);
1404             $this->assertInternalType('array', $defaults);
1405             foreach ($defaults as $level) {
1406                 $this->assertTrue(isset($alllevels[$level]));
1407             }
1408         }
1409     }
1411     /**
1412      * Test role context level setup.
1413      */
1414     public function test_set_role_contextlevels() {
1415         global $DB;
1417         $this->resetAfterTest();
1419         $roleid = create_role('New student role', 'student2', 'New student description', 'student');
1421         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid)));
1423         set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE));
1424         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1425         $this->assertCount(2, $levels);
1426         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1427         $this->assertTrue(isset($levels[CONTEXT_MODULE]));
1429         set_role_contextlevels($roleid, array(CONTEXT_COURSE));
1430         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1431         $this->assertCount(1, $levels);
1432         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1433     }
1435     /**
1436      * Test getting of role context levels
1437      */
1438     public function test_get_roles_for_contextlevels() {
1439         global $DB;
1441         $allroles = get_all_roles();
1442         foreach (context_helper::get_all_levels() as $level => $unused) {
1443             $roles = get_roles_for_contextlevels($level);
1444             foreach ($allroles as $roleid => $unused) {
1445                 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid));
1446                 if (in_array($roleid, $roles)) {
1447                     $this->assertTrue($exists);
1448                 } else {
1449                     $this->assertFalse($exists);
1450                 }
1451             }
1452         }
1453     }
1455     /**
1456      * Test default enrol roles.
1457      */
1458     public function test_get_default_enrol_roles() {
1459         $this->resetAfterTest();
1461         $course = $this->getDataGenerator()->create_course();
1462         $coursecontext = context_course::instance($course->id);
1464         $id2 = create_role('New student role', 'student2', 'New student description', 'student');
1465         set_role_contextlevels($id2, array(CONTEXT_COURSE));
1467         $allroles = get_all_roles();
1468         $expected = array($id2=>$allroles[$id2]);
1470         foreach (get_role_archetypes() as $archetype) {
1471             $defaults = get_default_contextlevels($archetype);
1472             if (in_array(CONTEXT_COURSE, $defaults)) {
1473                 $roles = get_archetype_roles($archetype);
1474                 foreach ($roles as $role) {
1475                     $expected[$role->id] = $role;
1476                 }
1477             }
1478         }
1480         $roles = get_default_enrol_roles($coursecontext);
1481         foreach ($allroles as $role) {
1482             $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id]));
1483             if (isset($roles[$role->id])) {
1484                 $this->assertSame(role_get_name($role, $coursecontext), $roles[$role->id]);
1485             }
1486         }
1487     }
1489     /**
1490      * Test getting of role users.
1491      */
1492     public function test_get_role_users() {
1493         global $DB;
1495         $this->resetAfterTest();
1497         $systemcontext = context_system::instance();
1498         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1499         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1500         $noeditteacherrole = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
1501         $course = $this->getDataGenerator()->create_course();
1502         $coursecontext = context_course::instance($course->id);
1503         $otherid = create_role('Other role', 'other', 'Some other role', '');
1504         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1505         $DB->insert_record('role_names', $teacherrename);
1506         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1507         $DB->insert_record('role_names', $otherrename);
1509         $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith'));
1510         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1511         $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar'));
1512         role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1513         $user3 = $this->getDataGenerator()->create_user();
1514         $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id);
1515         $user4 = $this->getDataGenerator()->create_user();
1516         $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id);
1517         $this->getDataGenerator()->enrol_user($user4->id, $course->id, $noeditteacherrole->id);
1519         $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id));
1520         groups_add_member($group, $user3);
1522         $users = get_role_users($teacherrole->id, $coursecontext);
1523         $this->assertCount(2, $users);
1524         $this->assertArrayHasKey($user1->id, $users);
1525         $this->assertEquals($users[$user1->id]->id, $user1->id);
1526         $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id);
1527         $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name);
1528         $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname);
1529         $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name);
1530         $this->assertArrayHasKey($user3->id, $users);
1531         $this->assertEquals($users[$user3->id]->id, $user3->id);
1532         $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id);
1533         $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name);
1534         $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname);
1535         $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name);
1537         $users = get_role_users($teacherrole->id, $coursecontext, true);
1538         $this->assertCount(3, $users);
1540         $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1);
1541         $this->assertCount(1, $users);
1543         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber');
1544         $this->assertCount(2, $users);
1545         $this->assertArrayHasKey($user1->id, $users);
1546         $this->assertArrayHasKey($user3->id, $users);
1548         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email');
1549         $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields');
1550         $this->assertCount(2, $users);
1551         $this->assertArrayHasKey($user1->id, $users);
1552         $this->assertObjectHasAttribute('lastname', $users[$user1->id]);
1553         $this->assertObjectHasAttribute('firstname', $users[$user1->id]);
1554         $this->assertArrayHasKey($user3->id, $users);
1555         $this->assertObjectHasAttribute('lastname', $users[$user3->id]);
1556         $this->assertObjectHasAttribute('firstname', $users[$user3->id]);
1558         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id AS id_alias');
1559         $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields');
1560         $this->assertCount(2, $users);
1561         $this->assertArrayHasKey($user1->id, $users);
1562         $this->assertObjectHasAttribute('id_alias', $users[$user1->id]);
1563         $this->assertObjectHasAttribute('lastname', $users[$user1->id]);
1564         $this->assertObjectHasAttribute('firstname', $users[$user1->id]);
1565         $this->assertArrayHasKey($user3->id, $users);
1566         $this->assertObjectHasAttribute('id_alias', $users[$user3->id]);
1567         $this->assertObjectHasAttribute('lastname', $users[$user3->id]);
1568         $this->assertObjectHasAttribute('firstname', $users[$user3->id]);
1570         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id);
1571         $this->assertCount(1, $users);
1572         $this->assertArrayHasKey($user3->id, $users);
1574         $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'));
1575         $this->assertCount(1, $users);
1576         $this->assertArrayHasKey($user1->id, $users);
1578         $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.id', 'ra.id');
1579         $this->assertDebuggingNotCalled();
1580         $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.userid', 'ra.userid');
1581         $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' .
1582             'role assignments id (ra.id) as unique field, you can use $fields param for it.');
1583         $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false);
1584         $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' .
1585             'role assignments id (ra.id) as unique field, you can use $fields param for it.');
1586         $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext,
1587             false, 'u.id, u.firstname', 'u.id, u.firstname');
1588         $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' .
1589             'role assignments id (ra.id) as unique field, you can use $fields param for it.');
1590     }
1592     /**
1593      * Test used role query.
1594      */
1595     public function test_get_roles_used_in_context() {
1596         global $DB;
1598         $this->resetAfterTest();
1600         $systemcontext = context_system::instance();
1601         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1602         $course = $this->getDataGenerator()->create_course();
1603         $coursecontext = context_course::instance($course->id);
1604         $otherid = create_role('Other role', 'other', 'Some other role', '');
1605         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1606         $DB->insert_record('role_names', $teacherrename);
1607         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1608         $DB->insert_record('role_names', $otherrename);
1610         $user1 = $this->getDataGenerator()->create_user();
1611         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1613         $roles = get_roles_used_in_context($coursecontext);
1614         $this->assertCount(1, $roles);
1615         $role = reset($roles);
1616         $roleid = key($roles);
1617         $this->assertEquals($roleid, $role->id);
1618         $this->assertEquals($teacherrole->id, $role->id);
1619         $this->assertSame($teacherrole->name, $role->name);
1620         $this->assertSame($teacherrole->shortname, $role->shortname);
1621         $this->assertEquals($teacherrole->sortorder, $role->sortorder);
1622         $this->assertSame($teacherrename->name, $role->coursealias);
1624         $user2 = $this->getDataGenerator()->create_user();
1625         role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1626         role_assign($otherid, $user2->id, $systemcontext->id);
1628         $roles = get_roles_used_in_context($systemcontext);
1629         $this->assertCount(2, $roles);
1630     }
1632     /**
1633      * Test roles used in course.
1634      */
1635     public function test_get_user_roles_in_course() {
1636         global $DB, $CFG;
1638         $this->resetAfterTest();
1640         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1641         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1642         $managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
1643         $course = $this->getDataGenerator()->create_course();
1644         $coursecontext = context_course::instance($course->id);
1645         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1646         $DB->insert_record('role_names', $teacherrename);
1648         $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
1649         $this->assertTrue(in_array($teacherrole->id, $roleids));
1650         $this->assertTrue(in_array($studentrole->id, $roleids));
1651         $this->assertFalse(in_array($managerrole->id, $roleids));
1653         $user1 = $this->getDataGenerator()->create_user();
1654         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1655         role_assign($studentrole->id, $user1->id, $coursecontext->id);
1656         $user2 = $this->getDataGenerator()->create_user();
1657         role_assign($studentrole->id, $user2->id, $coursecontext->id);
1658         $user3 = $this->getDataGenerator()->create_user();
1659         $user4 = $this->getDataGenerator()->create_user();
1660         role_assign($managerrole->id, $user4->id, $coursecontext->id);
1662         $this->setAdminUser();
1664         $roles = get_user_roles_in_course($user1->id, $course->id);
1665         $this->assertEquals(1, preg_match_all('/,/', $roles, $matches));
1666         $this->assertTrue(strpos($roles, role_get_name($teacherrole, $coursecontext)) !== false);
1668         $roles = get_user_roles_in_course($user2->id, $course->id);
1669         $this->assertEquals(0, preg_match_all('/,/', $roles, $matches));
1670         $this->assertTrue(strpos($roles, role_get_name($studentrole, $coursecontext)) !== false);
1672         $roles = get_user_roles_in_course($user3->id, $course->id);
1673         $this->assertSame('', $roles);
1675         // Managers should be able to see a link to their own role type, given they can assign it in the context.
1676         $this->setUser($user4);
1677         $roles = get_user_roles_in_course($user4->id, $course->id);
1678         $this->assertNotEmpty($roles);
1679         $this->assertEquals(1, count(explode(',', $roles)));
1680         $this->assertTrue(strpos($roles, role_get_name($managerrole, $coursecontext)) !== false);
1682         // Managers should see 2 roles if viewing a user who has been enrolled as a student and a teacher in the course.
1683         $roles = get_user_roles_in_course($user1->id, $course->id);
1684         $this->assertEquals(2, count(explode(',', $roles)));
1685         $this->assertTrue(strpos($roles, role_get_name($studentrole, $coursecontext)) !== false);
1686         $this->assertTrue(strpos($roles, role_get_name($teacherrole, $coursecontext)) !== false);
1688         // Students should not see the manager role if viewing a manager's profile.
1689         $this->setUser($user2);
1690         $roles = get_user_roles_in_course($user4->id, $course->id);
1691         $this->assertEmpty($roles); // Should see 0 roles on the manager's profile.
1692         $this->assertFalse(strpos($roles, role_get_name($managerrole, $coursecontext)) !== false);
1693     }
1695     /**
1696      * Test get_user_roles and get_users_roles
1697      */
1698     public function test_get_user_roles() {
1699         global $DB, $CFG;
1701         $this->resetAfterTest();
1703         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1704         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1705         $course = $this->getDataGenerator()->create_course();
1706         $coursecontext = context_course::instance($course->id);
1707         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1708         $DB->insert_record('role_names', $teacherrename);
1710         $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
1712         $user1 = $this->getDataGenerator()->create_user();
1713         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1714         role_assign($studentrole->id, $user1->id, $coursecontext->id);
1715         $user2 = $this->getDataGenerator()->create_user();
1716         role_assign($studentrole->id, $user2->id, $coursecontext->id);
1717         $user3 = $this->getDataGenerator()->create_user();
1719         $u1roles = get_user_roles($coursecontext, $user1->id);
1721         $u2roles = get_user_roles($coursecontext, $user2->id);
1723         $allroles = get_users_roles($coursecontext, [], false);
1724         $specificuserroles = get_users_roles($coursecontext, [$user1->id, $user2->id]);
1725         $this->assertEquals($u1roles, $allroles[$user1->id]);
1726         $this->assertEquals($u1roles, $specificuserroles[$user1->id]);
1727         $this->assertEquals($u2roles, $allroles[$user2->id]);
1728         $this->assertEquals($u2roles, $specificuserroles[$user2->id]);
1729     }
1731     /**
1732      * Test has_capability(), has_any_capability() and has_all_capabilities().
1733      */
1734     public function test_has_capability_and_friends() {
1735         global $DB;
1737         $this->resetAfterTest();
1739         $course = $this->getDataGenerator()->create_course();
1740         $coursecontext = context_course::instance($course->id);
1741         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1742         $teacher = $this->getDataGenerator()->create_user();
1743         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1744         $admin = $DB->get_record('user', array('username'=>'admin'));
1746         // Note: Here are used default capabilities, the full test is in permission evaluation bellow,
1747         // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user.
1749         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection')));
1750         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse')));
1751         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse')));
1753         $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse');
1754         $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse');
1756         $this->setUser(0);
1757         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext));
1758         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext));
1759         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1760         $this->assertFalse(has_any_capability($sca, $coursecontext));
1761         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1763         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher));
1764         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher));
1765         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher));
1766         $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher));
1767         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher));
1768         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher));
1770         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin));
1771         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin));
1772         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin));
1773         $this->assertTrue(has_any_capability($sca, $coursecontext, $admin));
1774         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin));
1775         $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin));
1777         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false));
1778         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false));
1779         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false));
1780         $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false));
1781         $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false));
1782         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false));
1784         $this->setUser($teacher);
1785         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1786         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1787         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1788         $this->assertTrue(has_any_capability($sca, $coursecontext));
1789         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1790         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1792         $this->setAdminUser();
1793         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1794         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1795         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext));
1796         $this->assertTrue(has_any_capability($sca, $coursecontext));
1797         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1798         $this->assertTrue(has_all_capabilities($sca, $coursecontext));
1800         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0));
1801         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0));
1802         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0));
1803         $this->assertFalse(has_any_capability($sca, $coursecontext, 0));
1804         $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0));
1805     }
1807     /**
1808      * Test that the caching in get_role_definitions() and get_role_definitions_uncached()
1809      * works as intended.
1810      */
1811     public function test_role_definition_caching() {
1812         global $DB;
1814         $this->resetAfterTest();
1816         // Get some role ids.
1817         $authenticatedrole = $DB->get_record('role', array('shortname' => 'user'), '*', MUST_EXIST);
1818         $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1819         $emptyroleid = create_role('No capabilities', 'empty', 'A role with no capabilties');
1820         $course = $this->getDataGenerator()->create_course();
1821         $coursecontext = context_course::instance($course->id);
1823         // Instantiate the cache instance, since that does DB queries (get_config)
1824         // and we don't care about those.
1825         cache::make('core', 'roledefs');
1827         // One database query is not necessarily one database read, it seems. Find out how many.
1828         $startdbreads = $DB->perf_get_reads();
1829         $rs = $DB->get_recordset('user');
1830         $rs->close();
1831         $readsperquery = $DB->perf_get_reads() - $startdbreads;
1833         // Now load some role definitions, and check when it queries the database.
1835         // Load the capabilities for two roles. Should be one query.
1836         $startdbreads = $DB->perf_get_reads();
1837         get_role_definitions([$authenticatedrole->id, $studentrole->id]);
1838         $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
1840         // Load the capabilities for same two roles. Should not query the DB.
1841         $startdbreads = $DB->perf_get_reads();
1842         get_role_definitions([$authenticatedrole->id, $studentrole->id]);
1843         $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
1845         // Include a third role. Should do one DB query.
1846         $startdbreads = $DB->perf_get_reads();
1847         get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]);
1848         $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
1850         // Repeat call. No DB queries.
1851         $startdbreads = $DB->perf_get_reads();
1852         get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]);
1853         $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
1855         // Alter a role.
1856         role_change_permission($studentrole->id, $coursecontext, 'moodle/course:tag', CAP_ALLOW);
1858         // Should now know to do one query.
1859         $startdbreads = $DB->perf_get_reads();
1860         get_role_definitions([$authenticatedrole->id, $studentrole->id]);
1861         $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
1863         // Now clear the in-memory cache, and verify that it does not query the DB.
1864         // Cannot use accesslib_clear_all_caches_for_unit_testing since that also
1865         // clears the MUC cache.
1866         global $ACCESSLIB_PRIVATE;
1867         $ACCESSLIB_PRIVATE->cacheroledefs = array();
1869         // Get all roles. Should not need the DB.
1870         $startdbreads = $DB->perf_get_reads();
1871         get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]);
1872         $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
1873     }
1875     /**
1876      * Tests get_user_capability_course() which checks a capability across all courses.
1877      */
1878     public function test_get_user_capability_course() {
1879         global $CFG, $USER;
1881         $this->resetAfterTest();
1883         $generator = $this->getDataGenerator();
1884         $cap = 'moodle/course:view';
1886         // The structure being created here is this:
1887         //
1888         // All tests work with the single capability 'moodle/course:view'.
1889         //
1890         //             ROLE DEF/OVERRIDE                        ROLE ASSIGNS
1891         //    Role:  Allow    Prohib    Empty   Def user      u1  u2  u3  u4   u5  u6  u7  u8
1892         // System    ALLOW    PROHIBIT                            A   E   A+E
1893         //   cat1                       ALLOW
1894         //     C1                               (ALLOW)                            P
1895         //     C2             ALLOW                                                    E   P
1896         //     cat2                     PREVENT
1897         //       C3                     ALLOW                                      E
1898         //       C4
1899         //   Misc.                                                             A
1900         //     C5    PREVENT                                                       A
1901         //     C6                       PROHIBIT
1902         //
1903         // Front-page and guest role stuff from the end of this test not included in the diagram.
1905         // Create a role which allows course:view and one that prohibits it, and one neither.
1906         $allowroleid = $generator->create_role();
1907         $prohibitroleid = $generator->create_role();
1908         $emptyroleid = $generator->create_role();
1909         $systemcontext = context_system::instance();
1910         assign_capability($cap, CAP_ALLOW, $allowroleid, $systemcontext->id);
1911         assign_capability($cap, CAP_PROHIBIT, $prohibitroleid, $systemcontext->id);
1913         // Create two categories (nested).
1914         $cat1 = $generator->create_category();
1915         $cat2 = $generator->create_category(['parent' => $cat1->id]);
1917         // Create six courses - two in cat1, two in cat2, and two in default category.
1918         // Shortnames are used for a sorting test. Otherwise they are not significant.
1919         $c1 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Z']);
1920         $c2 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Y']);
1921         $c3 = $generator->create_course(['category' => $cat2->id, 'shortname' => 'X']);
1922         $c4 = $generator->create_course(['category' => $cat2->id]);
1923         $c5 = $generator->create_course();
1924         $c6 = $generator->create_course();
1926         // Category overrides: in cat 1, empty role is allowed; in cat 2, empty role is prevented.
1927         assign_capability($cap, CAP_ALLOW, $emptyroleid,
1928                 context_coursecat::instance($cat1->id)->id);
1929         assign_capability($cap, CAP_PREVENT, $emptyroleid,
1930                 context_coursecat::instance($cat2->id)->id);
1932         // Course overrides: in C5, allow role is prevented; in C6, empty role is prohibited; in
1933         // C3, empty role is allowed.
1934         assign_capability($cap, CAP_PREVENT, $allowroleid,
1935                 context_course::instance($c5->id)->id);
1936         assign_capability($cap, CAP_PROHIBIT, $emptyroleid,
1937                 context_course::instance($c6->id)->id);
1938         assign_capability($cap, CAP_ALLOW, $emptyroleid,
1939                 context_course::instance($c3->id)->id);
1940         assign_capability($cap, CAP_ALLOW, $prohibitroleid,
1941                 context_course::instance($c2->id)->id);
1943         // User 1 has no roles except default user role.
1944         $u1 = $generator->create_user();
1946         // It returns false (annoyingly) if there are no courses.
1947         $this->assertFalse(get_user_capability_course($cap, $u1->id, true, '', 'id'));
1949         // Final override: in C1, default user role is allowed.
1950         assign_capability($cap, CAP_ALLOW, $CFG->defaultuserroleid,
1951                 context_course::instance($c1->id)->id);
1953         // Should now get C1 only.
1954         $courses = get_user_capability_course($cap, $u1->id, true, '', 'id');
1955         $this->assert_course_ids([$c1->id], $courses);
1957         // User 2 has allow role (system wide).
1958         $u2 = $generator->create_user();
1959         role_assign($allowroleid, $u2->id, $systemcontext->id);
1961         // Should get everything except C5.
1962         $courses = get_user_capability_course($cap, $u2->id, true, '', 'id');
1963         $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c6->id], $courses);
1965         // User 3 has empty role (system wide).
1966         $u3 = $generator->create_user();
1967         role_assign($emptyroleid, $u3->id, $systemcontext->id);
1969         // Should get cat 1 courses but not cat2, except C3.
1970         $courses = get_user_capability_course($cap, $u3->id, true, '', 'id');
1971         $this->assert_course_ids([$c1->id, $c2->id, $c3->id], $courses);
1973         // User 4 has allow and empty role (system wide).
1974         $u4 = $generator->create_user();
1975         role_assign($allowroleid, $u4->id, $systemcontext->id);
1976         role_assign($emptyroleid, $u4->id, $systemcontext->id);
1978         // Should get everything except C5 and C6.
1979         $courses = get_user_capability_course($cap, $u4->id, true, '', 'id');
1980         $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id], $courses);
1982         // User 5 has allow role in default category only.
1983         $u5 = $generator->create_user();
1984         role_assign($allowroleid, $u5->id, context_coursecat::instance($c5->category)->id);
1986         // Should get C1 and the default category courses but not C5.
1987         $courses = get_user_capability_course($cap, $u5->id, true, '', 'id');
1988         $this->assert_course_ids([$c1->id, $c6->id], $courses);
1990         // User 6 has a bunch of course roles: prohibit role in C1, empty role in C3, allow role in
1991         // C6.
1992         $u6 = $generator->create_user();
1993         role_assign($prohibitroleid, $u6->id, context_course::instance($c1->id)->id);
1994         role_assign($emptyroleid, $u6->id, context_course::instance($c3->id)->id);
1995         role_assign($allowroleid, $u6->id, context_course::instance($c5->id)->id);
1997         // Should get C3 only because the allow role is prevented in C5.
1998         $courses = get_user_capability_course($cap, $u6->id, true, '', 'id');
1999         $this->assert_course_ids([$c3->id], $courses);
2001         // User 7 has empty role in C2.
2002         $u7 = $generator->create_user();
2003         role_assign($emptyroleid, $u7->id, context_course::instance($c2->id)->id);
2005         // Should get C1 by the default user role override, and C2 by the cat1 level override.
2006         $courses = get_user_capability_course($cap, $u7->id, true, '', 'id');
2007         $this->assert_course_ids([$c1->id, $c2->id], $courses);
2009         // User 8 has prohibit role as system context, to verify that prohibits can't be overridden.
2010         $u8 = $generator->create_user();
2011         role_assign($prohibitroleid, $u8->id, context_course::instance($c2->id)->id);
2013         // Should get C1 by the default user role override, no other courses because the prohibit cannot be overridden.
2014         $courses = get_user_capability_course($cap, $u8->id, true, '', 'id');
2015         $this->assert_course_ids([$c1->id], $courses);
2017         // Admin user gets everything....
2018         $courses = get_user_capability_course($cap, get_admin()->id, true, '', 'id');
2019         $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c6->id],
2020                 $courses);
2022         // Unless you turn off doanything, when it only has the things a user with no role does.
2023         $courses = get_user_capability_course($cap, get_admin()->id, false, '', 'id');
2024         $this->assert_course_ids([$c1->id], $courses);
2026         // Using u3 as an example, test the limit feature.
2027         $courses = get_user_capability_course($cap, $u3->id, true, '', 'id', 2);
2028         $this->assert_course_ids([$c1->id, $c2->id], $courses);
2030         // Check sorting.
2031         $courses = get_user_capability_course($cap, $u3->id, true, '', 'shortname');
2032         $this->assert_course_ids([$c3->id, $c2->id, $c1->id], $courses);
2034         // Check returned fields - default.
2035         $courses = get_user_capability_course($cap, $u3->id, true, '', 'id');
2036         $this->assertEquals((object)['id' => $c1->id], $courses[0]);
2038         // Add a selection of fields, including the context ones with special handling.
2039         $courses = get_user_capability_course($cap, $u3->id, true, 'shortname, ctxlevel, ctxdepth, ctxinstance', 'id');
2040         $this->assertEquals((object)['id' => $c1->id, 'shortname' => 'Z', 'ctxlevel' => 50,
2041                 'ctxdepth' => 3, 'ctxinstance' => $c1->id], $courses[0]);
2043         // Test front page role - user 1 has no roles, but if we change the front page role
2044         // definition so that it has our capability, then they should see the front page course.
2045         // as well as C1.
2046         assign_capability($cap, CAP_ALLOW, $CFG->defaultfrontpageroleid, $systemcontext->id);
2047         $courses = get_user_capability_course($cap, $u1->id, true, '', 'id');
2048         $this->assert_course_ids([SITEID, $c1->id], $courses);
2050         // Check that temporary guest access (in this case, given on course 2 for user 1)
2051         // also is included, if it has this capability.
2052         assign_capability($cap, CAP_ALLOW, $CFG->guestroleid, $systemcontext->id);
2053         $this->setUser($u1);
2054         load_temp_course_role(context_course::instance($c2->id), $CFG->guestroleid);
2055         $courses = get_user_capability_course($cap, $USER->id, true, '', 'id');
2056         $this->assert_course_ids([SITEID, $c1->id, $c2->id], $courses);
2057     }
2059     /**
2060      * Extracts an array of course ids to make the above test script shorter.
2061      *
2062      * @param int[] $expected Array of expected course ids
2063      * @param stdClass[] $courses Array of course objects
2064      */
2065     protected function assert_course_ids(array $expected, array $courses) {
2066         $courseids = array_map(function($c) {
2067             return $c->id;
2068         }, $courses);
2069         $this->assertEquals($expected, $courseids);
2070     }
2072     /**
2073      * Test if course creator future capability lookup works.
2074      */
2075     public function test_guess_if_creator_will_have_course_capability() {
2076         global $DB, $CFG, $USER;
2078         $this->resetAfterTest();
2080         $category = $this->getDataGenerator()->create_category();
2081         $course = $this->getDataGenerator()->create_course(array('category'=>$category->id));
2083         $syscontext = context_system::instance();
2084         $categorycontext = context_coursecat::instance($category->id);
2085         $coursecontext = context_course::instance($course->id);
2086         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
2087         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
2088         $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST);
2089         $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
2091         $this->assertEquals($teacherrole->id, $CFG->creatornewroleid);
2093         $creator = $this->getDataGenerator()->create_user();
2094         $manager = $this->getDataGenerator()->create_user();
2095         role_assign($managerrole->id, $manager->id, $categorycontext);
2097         $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator));
2098         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
2099         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
2100         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
2101         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
2102         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
2104         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
2105         $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager));
2106         $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager));
2107         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id));
2108         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id));
2110         $this->assertEquals(0, $USER->id);
2111         $this->assertFalse(has_capability('moodle/course:view', $categorycontext));
2112         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext));
2113         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext));
2114         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext));
2115         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
2116         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
2118         $this->setUser($manager);
2119         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
2120         $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
2121         $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
2122         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
2123         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
2125         $this->setAdminUser();
2126         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
2127         $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
2128         $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
2129         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
2130         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
2131         $this->setUser(0);
2133         role_assign($creatorrole->id, $creator->id, $categorycontext);
2135         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
2136         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
2137         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
2138         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
2139         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
2141         $this->setUser($creator);
2142         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, null));
2143         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, null));
2144         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, null));
2145         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, null));
2146         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, null));
2147         $this->setUser(0);
2149         set_config('creatornewroleid', $studentrole->id);
2151         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
2152         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
2153         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
2154         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
2156         set_config('creatornewroleid', $teacherrole->id);
2158         role_change_permission($managerrole->id, $categorycontext, 'moodle/course:visibility', CAP_PREVENT);
2159         role_assign($creatorrole->id, $manager->id, $categorycontext);
2161         $this->assertTrue(has_capability('moodle/course:view', $categorycontext, $manager));
2162         $this->assertTrue(has_capability('moodle/course:view', $coursecontext, $manager));
2163         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
2164         $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager));
2165         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
2166         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
2167         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
2168         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
2170         role_change_permission($managerrole->id, $categorycontext, 'moodle/course:view', CAP_PREVENT);
2171         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
2172         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
2173         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
2174         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
2175         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
2177         $this->getDataGenerator()->enrol_user($manager->id, $course->id, 0);
2179         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
2180         $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager));
2181         $this->assertTrue(is_enrolled($coursecontext, $manager));
2182         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
2183         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
2184         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
2185         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
2187         // Test problems.
2189         try {
2190             guess_if_creator_will_have_course_capability('moodle/course:visibility', $syscontext, $creator);
2191             $this->fail('Exception expected when non course/category context passed to guess_if_creator_will_have_course_capability()');
2192         } catch (moodle_exception $e) {
2193             $this->assertInstanceOf('coding_exception', $e);
2194         }
2195     }
2197     /**
2198      * Test require_capability() exceptions.
2199      */
2200     public function test_require_capability() {
2201         $this->resetAfterTest();
2203         $syscontext = context_system::instance();
2205         $this->setUser(0);
2206         $this->assertFalse(has_capability('moodle/site:config', $syscontext));
2207         try {
2208             require_capability('moodle/site:config', $syscontext);
2209             $this->fail('Exception expected from require_capability()');
2210         } catch (moodle_exception $e) {
2211             $this->assertInstanceOf('required_capability_exception', $e);
2212         }
2213         $this->setAdminUser();
2214         $this->assertFalse(has_capability('moodle/site:config', $syscontext, 0));
2215         try {
2216             require_capability('moodle/site:config', $syscontext, 0);
2217             $this->fail('Exception expected from require_capability()');
2218         } catch (moodle_exception $e) {
2219             $this->assertInstanceOf('required_capability_exception', $e);
2220         }
2221         $this->assertFalse(has_capability('moodle/site:config', $syscontext, null, false));
2222         try {
2223             require_capability('moodle/site:config', $syscontext, null, false);
2224             $this->fail('Exception expected from require_capability()');
2225         } catch (moodle_exception $e) {
2226             $this->assertInstanceOf('required_capability_exception', $e);
2227         }
2228     }
2230     /**
2231      * Test that enrolled users SQL does not return any values for users in
2232      * other courses.
2233      */
2234     public function test_get_enrolled_sql_different_course() {
2235         global $DB;
2237         $this->resetAfterTest();
2239         $course = $this->getDataGenerator()->create_course();
2240         $context = context_course::instance($course->id);
2241         $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
2242         $user = $this->getDataGenerator()->create_user();
2244         // This user should not appear anywhere, we're not interested in that context.
2245         $course2 = $this->getDataGenerator()->create_course();
2246         $this->getDataGenerator()->enrol_user($user->id, $course2->id, $student->id);
2248         $enrolled   = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false);
2249         $active     = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true);
2250         $suspended  = get_suspended_userids($context);
2252         $this->assertFalse(isset($enrolled[$user->id]));
2253         $this->assertFalse(isset($active[$user->id]));
2254         $this->assertFalse(isset($suspended[$user->id]));
2255         $this->assertCount(0, $enrolled);
2256         $this->assertCount(0, $active);
2257         $this->assertCount(0, $suspended);
2258     }
2260     /**
2261      * Test that enrolled users SQL does not return any values for role
2262      * assignments without an enrolment.
2263      */
2264     public function test_get_enrolled_sql_role_only() {
2265         global $DB;
2267         $this->resetAfterTest();
2269         $course = $this->getDataGenerator()->create_course();
2270         $context = context_course::instance($course->id);
2271         $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
2272         $user = $this->getDataGenerator()->create_user();
2274         // Role assignment is not the same as course enrollment.
2275         role_assign($student->id, $user->id, $context->id);
2277         $enrolled   = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false);
2278         $active     = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true);
2279         $suspended  = get_suspended_userids($context);
2281         $this->assertFalse(isset($enrolled[$user->id]));
2282         $this->assertFalse(isset($active[$user->id]));
2283         $this->assertFalse(isset($suspended[$user->id]));
2284         $this->assertCount(0, $enrolled);
2285         $this->assertCount(0, $active);
2286         $this->assertCount(0, $suspended);
2287     }
2289     /**
2290      * Test that multiple enrolments for the same user are counted correctly.
2291      */
2292     public function test_get_enrolled_sql_multiple_enrolments() {
2293         global $DB;
2295         $this->resetAfterTest();
2297         $course = $this->getDataGenerator()->create_course();
2298         $context = context_course::instance($course->id);
2299         $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
2300         $user = $this->getDataGenerator()->create_user();
2302         // Add a suspended enrol.
2303         $selfinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'self'));
2304         $selfplugin = enrol_get_plugin('self');
2305         $selfplugin->update_status($selfinstance, ENROL_INSTANCE_ENABLED);
2306         $this->getDataGenerator()->enrol_user($user->id, $course->id, $student->id, 'self', 0, 0, ENROL_USER_SUSPENDED);
2308         // Should be enrolled, but not active - user is suspended.
2309         $enrolled   = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false);
2310         $active     = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true);
2311         $suspended  = get_suspended_userids($context);
2313         $this->assertTrue(isset($enrolled[$user->id]));
2314         $this->assertFalse(isset($active[$user->id]));
2315         $this->assertTrue(isset($suspended[$user->id]));
2316         $this->assertCount(1, $enrolled);
2317         $this->assertCount(0, $active);
2318         $this->assertCount(1, $suspended);
2320         // Add an active enrol for the user. Any active enrol makes them enrolled.
2321         $this->getDataGenerator()->enrol_user($user->id, $course->id, $student->id);
2323         // User should be active now.
2324         $enrolled   = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false);
2325         $active     = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true);
2326         $suspended  = get_suspended_userids($context);
2328         $this->assertTrue(isset($enrolled[$user->id]));
2329         $this->assertTrue(isset($active[$user->id]));
2330         $this->assertFalse(isset($suspended[$user->id]));
2331         $this->assertCount(1, $enrolled);
2332         $this->assertCount(1, $active);
2333         $this->assertCount(0, $suspended);
2335     }
2337     /**
2338      * Test that enrolled users SQL does not return any values for users
2339      * without a group when $context is not a valid course context.
2340      */
2341     public function test_get_enrolled_sql_userswithoutgroup() {
2342         global $DB;
2344         $this->resetAfterTest();
2346         $systemcontext = context_system::instance();
2347         $course = $this->getDataGenerator()->create_course();
2348         $coursecontext = context_course::instance($course->id);
2349         $user1 = $this->getDataGenerator()->create_user();
2350         $user2 = $this->getDataGenerator()->create_user();
2352         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
2353         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
2355         $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
2356         groups_add_member($group, $user1);
2358         $enrolled   = get_enrolled_users($coursecontext);
2359         $this->assertCount(2, $enrolled);
2361         // Get users without any group on the course context.
2362         $enrolledwithoutgroup = get_enrolled_users($coursecontext, '', USERSWITHOUTGROUP);
2363         $this->assertCount(1, $enrolledwithoutgroup);
2364         $this->assertFalse(isset($enrolledwithoutgroup[$user1->id]));
2366         // Get users without any group on the system context (it should throw an exception).
2367         $this->expectException('coding_exception');
2368         get_enrolled_users($systemcontext, '', USERSWITHOUTGROUP);
2369     }
2371     public function get_enrolled_sql_provider() {
2372         return array(
2373             array(
2374                 // Two users who are enrolled.
2375                 'users' => array(
2376                     array(
2377                         'enrolled'  => true,
2378                         'active'    => true,
2379                     ),
2380                     array(
2381                         'enrolled'  => true,
2382                         'active'    => true,
2383                     ),
2384                 ),
2385                 'counts' => array(
2386                     'enrolled'      => 2,
2387                     'active'        => 2,
2388                     'suspended'     => 0,
2389                 ),
2390             ),
2391             array(
2392                 // A user who is suspended.
2393                 'users' => array(
2394                     array(
2395                         'status'    => ENROL_USER_SUSPENDED,
2396                         'enrolled'  => true,
2397                         'suspended' => true,
2398                     ),
2399                 ),
2400                 'counts' => array(
2401                     'enrolled'      => 1,
2402                     'active'        => 0,
2403                     'suspended'     => 1,
2404                 ),
2405             ),
2406             array(
2407                 // One of each.
2408                 'users' => array(
2409                     array(
2410                         'enrolled'  => true,
2411                         'active'    => true,
2412                     ),
2413                     array(
2414                         'status'    => ENROL_USER_SUSPENDED,
2415                         'enrolled'  => true,
2416                         'suspended' => true,
2417                     ),
2418                 ),
2419                 'counts' => array(
2420                     'enrolled'      => 2,
2421                     'active'        => 1,
2422                     'suspended'     => 1,
2423                 ),
2424             ),
2425             array(
2426                 // One user who is not yet enrolled.
2427                 'users' => array(
2428                     array(
2429                         'timestart' => DAYSECS,
2430                         'enrolled'  => true,
2431                         'active'    => false,
2432                         'suspended' => true,
2433                     ),
2434                 ),
2435                 'counts' => array(
2436                     'enrolled'      => 1,
2437                     'active'        => 0,
2438                     'suspended'     => 1,
2439                 ),
2440             ),
2441             array(
2442                 // One user who is no longer enrolled
2443                 'users' => array(
2444                     array(
2445                         'timeend'   => -DAYSECS,
2446                         'enrolled'  => true,
2447                         'active'    => false,
2448                         'suspended' => true,
2449                     ),
2450                 ),
2451                 'counts' => array(
2452                     'enrolled'      => 1,
2453                     'active'        => 0,
2454                     'suspended'     => 1,
2455                 ),
2456             ),
2457             array(
2458                 // One user who is not yet enrolled, and one who is no longer enrolled.
2459                 'users' => array(
2460                     array(
2461                         'timeend'   => -DAYSECS,
2462                         'enrolled'  => true,
2463                         'active'    => false,
2464                         'suspended' => true,
2465                     ),
2466                     array(
2467                         'timestart' => DAYSECS,
2468                         'enrolled'  => true,
2469                         'active'    => false,
2470                         'suspended' => true,
2471                     ),
2472                 ),
2473                 'counts' => array(
2474                     'enrolled'      => 2,
2475                     'active'        => 0,
2476                     'suspended'     => 2,
2477                 ),
2478             ),
2479         );
2480     }
2482     /**
2483      * @dataProvider get_enrolled_sql_provider
2484      */
2485     public function test_get_enrolled_sql_course($users, $counts) {
2486         global $DB;
2488         $this->resetAfterTest();
2490         $course = $this->getDataGenerator()->create_course();
2491         $context = context_course::instance($course->id);
2492         $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
2493         $createdusers = array();
2495         foreach ($users as &$userdata) {
2496             $user = $this->getDataGenerator()->create_user();
2497             $userdata['id'] = $user->id;
2499             $timestart  = 0;
2500             $timeend    = 0;
2501             $status     = null;
2502             if (isset($userdata['timestart'])) {
2503                 $timestart = time() + $userdata['timestart'];
2504             }
2505             if (isset($userdata['timeend'])) {
2506                 $timeend = time() + $userdata['timeend'];
2507             }
2508             if (isset($userdata['status'])) {
2509                 $status = $userdata['status'];
2510             }
2512             // Enrol the user in the course.
2513             $this->getDataGenerator()->enrol_user($user->id, $course->id, $student->id, 'manual', $timestart, $timeend, $status);
2514         }
2516         // After all users have been enroled, check expectations.
2517         $enrolled   = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false);
2518         $active     = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true);
2519         $suspended  = get_suspended_userids($context);
2521         foreach ($users as $userdata) {
2522             if (isset($userdata['enrolled']) && $userdata['enrolled']) {
2523                 $this->assertTrue(isset($enrolled[$userdata['id']]));
2524             } else {
2525                 $this->assertFalse(isset($enrolled[$userdata['id']]));
2526             }
2528             if (isset($userdata['active']) && $userdata['active']) {
2529                 $this->assertTrue(isset($active[$userdata['id']]));
2530             } else {
2531                 $this->assertFalse(isset($active[$userdata['id']]));
2532             }
2534             if (isset($userdata['suspended']) && $userdata['suspended']) {
2535                 $this->assertTrue(isset($suspended[$userdata['id']]));
2536             } else {
2537                 $this->assertFalse(isset($suspended[$userdata['id']]));
2538             }
2539         }
2541         $this->assertCount($counts['enrolled'],     $enrolled);
2542         $this->assertCount($counts['active'],       $active);
2543         $this->assertCount($counts['suspended'],    $suspended);
2544     }
2546     /**
2547      * A small functional test of permission evaluations.
2548      */
2549     public function test_permission_evaluation() {
2550         global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE;
2552         $this->resetAfterTest();
2554         $generator = $this->getDataGenerator();
2556         // Fill the site with some real data.
2557         $testcategories = array();
2558         $testcourses = array();
2559         $testpages = array();
2560         $testblocks = array();
2561         $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
2563         $systemcontext = context_system::instance();
2564         $frontpagecontext = context_course::instance(SITEID);
2566         // Add block to system context.
2567         $bi = $generator->create_block('online_users');
2568         context_block::instance($bi->id);
2569         $testblocks[] = $bi->id;
2571         // Some users.
2572         $testusers = array();
2573         for ($i=0; $i<20; $i++) {
2574             $user = $generator->create_user();
2575             $testusers[$i] = $user->id;
2576             $usercontext = context_user::instance($user->id);
2578             // Add block to user profile.
2579             $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id));
2580             $testblocks[] = $bi->id;
2581         }
2582         // Deleted user - should be ignored everywhere, can not have context.
2583         $generator->create_user(array('deleted'=>1));
2585         // Add block to frontpage.
2586         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id));
2587         $frontpageblockcontext = context_block::instance($bi->id);
2588         $testblocks[] = $bi->id;
2590         // Add a resource to frontpage.
2591         $page = $generator->create_module('page', array('course'=>$SITE->id));
2592         $testpages[] = $page->cmid;
2593         $frontpagepagecontext = context_module::instance($page->cmid);
2595         // Add block to frontpage resource.
2596         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id));
2597         $frontpagepageblockcontext = context_block::instance($bi->id);
2598         $testblocks[] = $bi->id;
2600         // Some nested course categories with courses.
2601         $manualenrol = enrol_get_plugin('manual');
2602         $parentcat = 0;
2603         for ($i=0; $i<5; $i++) {
2604             $cat = $generator->create_category(array('parent'=>$parentcat));
2605             $testcategories[] = $cat->id;
2606             $catcontext = context_coursecat::instance($cat->id);
2607             $parentcat = $cat->id;
2609             if ($i >= 4) {
2610                 continue;
2611             }
2613             // Add resource to each category.
2614             $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id));
2615             context_block::instance($bi->id);
2617             // Add a few courses to each category.
2618             for ($j=0; $j<6; $j++) {
2619                 $course = $generator->create_course(array('category'=>$cat->id));
2620                 $testcourses[] = $course->id;
2621                 $coursecontext = context_course::instance($course->id);
2623                 if ($j >= 5) {
2624                     continue;
2625                 }
2626                 // Add manual enrol instance.
2627                 $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id)));
2629                 // Add block to each course.
2630                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
2631                 $testblocks[] = $bi->id;
2633                 // Add a resource to each course.
2634                 $page = $generator->create_module('page', array('course'=>$course->id));
2635                 $testpages[] = $page->cmid;
2636                 $modcontext = context_module::instance($page->cmid);
2638                 // Add block to each module.
2639                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id));
2640                 $testblocks[] = $bi->id;
2641             }
2642         }
2644         // Make sure all contexts were created properly.
2645         $count = 1; // System.
2646         $count += $DB->count_records('user', array('deleted'=>0));
2647         $count += $DB->count_records('course_categories');
2648         $count += $DB->count_records('course');
2649         $count += $DB->count_records('course_modules');
2650         $count += $DB->count_records('block_instances');
2651         $this->assertEquals($count, $DB->count_records('context'));
2652         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2653         $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2656         // Test context_helper::get_level_name() method.
2658         $levels = context_helper::get_all_levels();
2659         foreach ($levels as $level => $classname) {
2660             $name = context_helper::get_level_name($level);
2661             $this->assertNotEmpty($name);
2662         }
2665         // Test context::instance_by_id(), context_xxx::instance() methods.
2667         $context = context::instance_by_id($frontpagecontext->id);
2668         $this->assertSame(CONTEXT_COURSE, $context->contextlevel);
2669         $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING));
2670         try {
2671             context::instance_by_id(-1);
2672             $this->fail('exception expected');
2673         } catch (moodle_exception $e) {
2674             $this->assertTrue(true);
2675         }
2676         $this->assertInstanceOf('context_system', context_system::instance());
2677         $this->assertInstanceOf('context_coursecat', context_coursecat::instance($testcategories[0]));
2678         $this->assertInstanceOf('context_course', context_course::instance($testcourses[0]));
2679         $this->assertInstanceOf('context_module', context_module::instance($testpages[0]));
2680         $this->assertInstanceOf('context_block', context_block::instance($testblocks[0]));
2682         $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING));
2683         $this->assertFalse(context_course::instance(-1, IGNORE_MISSING));
2684         $this->assertFalse(context_module::instance(-1, IGNORE_MISSING));
2685         $this->assertFalse(context_block::instance(-1, IGNORE_MISSING));
2686         try {
2687             context_coursecat::instance(-1);
2688             $this->fail('exception expected');
2689         } catch (moodle_exception $e) {
2690             $this->assertTrue(true);
2691         }
2692         try {
2693             context_course::instance(-1);
2694             $this->fail('exception expected');
2695         } catch (moodle_exception $e) {
2696             $this->assertTrue(true);
2697         }
2698         try {
2699             context_module::instance(-1);
2700             $this->fail('exception expected');
2701         } catch (moodle_exception $e) {
2702             $this->assertTrue(true);
2703         }
2704         try {
2705             context_block::instance(-1);
2706             $this->fail('exception expected');
2707         } catch (moodle_exception $e) {
2708             $this->assertTrue(true);
2709         }
2712         // Test $context->get_url(), $context->get_context_name(), $context->get_capabilities() methods.
2714         $testcontexts = array();
2715         $testcontexts[CONTEXT_SYSTEM]    = context_system::instance();
2716         $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]);
2717         $testcontexts[CONTEXT_COURSE]    = context_course::instance($testcourses[0]);
2718         $testcontexts[CONTEXT_MODULE]    = context_module::instance($testpages[0]);
2719         $testcontexts[CONTEXT_BLOCK]     = context_block::instance($testblocks[0]);
2721         foreach ($testcontexts as $context) {
2722             $name = $context->get_context_name(true, true);
2723             $this->assertNotEmpty($name);
2725             $this->assertInstanceOf('moodle_url', $context->get_url());
2727             $caps = $context->get_capabilities();
2728             $this->assertTrue(is_array($caps));
2729             foreach ($caps as $cap) {
2730                 $cap = (array)$cap;
2731                 $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask'));
2732             }
2733         }
2734         unset($testcontexts);
2736         // Test $context->get_course_context() method.
2738         $this->assertFalse($systemcontext->get_course_context(false));
2739         try {
2740             $systemcontext->get_course_context();
2741             $this->fail('exception expected');
2742         } catch (moodle_exception $e) {
2743             $this->assertInstanceOf('coding_exception', $e);
2744         }
2745         $context = context_coursecat::instance($testcategories[0]);
2746         $this->assertFalse($context->get_course_context(false));
2747         try {
2748             $context->get_course_context();
2749             $this->fail('exception expected');
2750         } catch (moodle_exception $e) {
2751             $this->assertInstanceOf('coding_exception', $e);
2752         }
2753         $this->assertEquals($frontpagecontext, $frontpagecontext->get_course_context(true));
2754         $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_course_context(true));
2755         $this->assertEquals($frontpagecontext, $frontpagepageblockcontext->get_course_context(true));
2758         // Test $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() methods.
2760         $userid = reset($testusers);
2761         $usercontext = context_user::instance($userid);
2762         $this->assertEquals($systemcontext, $usercontext->get_parent_context());
2763         $this->assertEquals(array($systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts());
2764         $this->assertEquals(array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts(true));
2766         $this->assertEquals(array(), $systemcontext->get_parent_contexts());
2767         $this->assertEquals(array($systemcontext->id=>$systemcontext), $systemcontext->get_parent_contexts(true));
2768         $this->assertEquals(array(), $systemcontext->get_parent_context_ids());
2769         $this->assertEquals(array($systemcontext->id), $systemcontext->get_parent_context_ids(true));
2770         $this->assertEquals(array(), $systemcontext->get_parent_context_paths());
2771         $this->assertEquals(array($systemcontext->id => $systemcontext->path), $systemcontext->get_parent_context_paths(true));
2773         $this->assertEquals($systemcontext, $frontpagecontext->get_parent_context());
2774         $this->assertEquals(array($systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts());
2775         $this->assertEquals(array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts(true));
2776         $this->assertEquals(array($systemcontext->id), $frontpagecontext->get_parent_context_ids());
2777         $this->assertEquals(array($frontpagecontext->id, $systemcontext->id), $frontpagecontext->get_parent_context_ids(true));
2778         $this->assertEquals(array($systemcontext->id => $systemcontext->path), $frontpagecontext->get_parent_context_paths());
2779         $expected = array($systemcontext->id => $systemcontext->path, $frontpagecontext->id => $frontpagecontext->path);
2780         $this->assertEquals($expected, $frontpagecontext->get_parent_context_paths(true));
2782         $this->assertFalse($systemcontext->get_parent_context());
2783         $frontpagecontext = context_course::instance($SITE->id);
2784         $parent = $systemcontext;
2785         foreach ($testcategories as $catid) {
2786             $catcontext = context_coursecat::instance($catid);
2787             $this->assertEquals($parent, $catcontext->get_parent_context());
2788             $parent = $catcontext;
2789         }
2790         $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_parent_context());
2791         $this->assertEquals($frontpagecontext, $frontpageblockcontext->get_parent_context());
2792         $this->assertEquals($frontpagepagecontext, $frontpagepageblockcontext->get_parent_context());
2795         // Test $context->get_child_contexts() method.
2797         $children = $systemcontext->get_child_contexts();
2798         $this->resetDebugging();
2799         $this->assertEquals(count($children)+1, $DB->count_records('context'));
2801         $context = context_coursecat::instance($testcategories[3]);
2802         $children = $context->get_child_contexts();
2803         $countcats    = 0;
2804         $countcourses = 0;
2805         $countblocks  = 0;
2806         foreach ($children as $child) {
2807             if ($child->contextlevel == CONTEXT_COURSECAT) {
2808                 $countcats++;
2809             }
2810             if ($child->contextlevel == CONTEXT_COURSE) {
2811                 $countcourses++;
2812             }
2813             if ($child->contextlevel == CONTEXT_BLOCK) {
2814                 $countblocks++;
2815             }
2816         }
2817         $this->assertCount(8, $children);
2818         $this->assertEquals(1, $countcats);
2819         $this->assertEquals(6, $countcourses);
2820         $this->assertEquals(1, $countblocks);
2822         $context = context_course::instance($testcourses[2]);
2823         $children = $context->get_child_contexts();
2825         $context = context_module::instance($testpages[3]);
2826         $children = $context->get_child_contexts();
2827         $this->assertCount(1, $children);
2829         $context = context_block::instance($testblocks[1]);
2830         $children = $context->get_child_contexts();
2831         $this->assertCount(0, $children);
2833         unset($children);
2834         unset($countcats);
2835         unset($countcourses);
2836         unset($countblocks);
2839         // Test context_helper::reset_caches() method.
2841         context_helper::reset_caches();
2842         $this->assertEquals(0, context_inspection::test_context_cache_size());
2843         context_course::instance($SITE->id);
2844         $this->assertEquals(1, context_inspection::test_context_cache_size());
2847         // Test context preloading.
2849         context_helper::reset_caches();
2850         $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')."
2851                   FROM {context} c
2852                  WHERE c.contextlevel <> ".CONTEXT_SYSTEM;
2853         $records = $DB->get_records_sql($sql);
2854         $firstrecord = reset($records);
2855         $columns = context_helper::get_preload_record_columns('c');
2856         $firstrecord = (array)$firstrecord;
2857         $this->assertSame(array_keys($firstrecord), array_values($columns));
2858         context_helper::reset_caches();
2859         foreach ($records as $record) {
2860             context_helper::preload_from_record($record);
2861             $this->assertEquals(new stdClass(), $record);
2862         }
2863         $this->assertEquals(count($records), context_inspection::test_context_cache_size());
2864         unset($records);
2865         unset($columns);
2867         context_helper::reset_caches();
2868         context_helper::preload_course($SITE->id);
2869         $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id));
2870         $this->assertEquals(3 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // Depends on number of default blocks.
2872         // Test assign_capability(), unassign_capability() functions.
2874         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2875         $this->assertFalse($rc);
2876         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id);
2877         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2878         $this->assertEquals(CAP_ALLOW, $rc->permission);
2879         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id);
2880         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2881         $this->assertEquals(CAP_ALLOW, $rc->permission);
2882         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true);
2883         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2884         $this->assertEquals(CAP_PREVENT, $rc->permission);
2886         assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext);
2887         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2888         $this->assertFalse($rc);
2889         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext);
2890         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true);
2891         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2892         $this->assertFalse($rc);
2893         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true);
2894         unset($rc);
2896         accesslib_clear_all_caches_for_unit_testing(); // Must be done after assign_capability().
2899         // Test role_assign(), role_unassign(), role_unassign_all() functions.
2901         $context = context_course::instance($testcourses[1]);
2902         $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2903         role_assign($allroles['teacher'], $testusers[1], $context->id);
2904         role_assign($allroles['teacher'], $testusers[2], $context->id);
2905         role_assign($allroles['manager'], $testusers[1], $context->id);
2906         $this->assertEquals(3, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2907         role_unassign($allroles['teacher'], $testusers[1], $context->id);
2908         $this->assertEquals(2, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2909         role_unassign_all(array('contextid'=>$context->id));
2910         $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2911         unset($context);
2913         accesslib_clear_all_caches_for_unit_testing(); // Just in case.
2916         // Test has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends functions.
2918         $adminid = get_admin()->id;
2919         $guestid = $CFG->siteguest;
2921         // Enrol some users into some courses.
2922         $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST);
2923         $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST);
2924         $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id');
2925         $cm1 = reset($cms);
2926         $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id');
2927         $block1 = reset($blocks);
2928         $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id));
2929         $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id));
2930         for ($i=0; $i<9; $i++) {
2931             $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']);
2932         }
2933         $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']);
2934         $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']);
2936         for ($i=10; $i<15; $i++) {
2937             $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']);
2938         }
2939         $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']);
2941         // Add tons of role assignments - the more the better.
2942         role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2]));
2943         role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1]));
2944         role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id));
2945         role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id));
2946         role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id));
2947         role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id));
2948         role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id));
2949         role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id));
2951         role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id));
2952         role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id));
2954         // Add tons of overrides - the more the better.
2955         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true);
2956         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true);
2957         assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true);
2958         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true);
2959         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true);
2961         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true);
2962         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true);
2963         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true);
2964         assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true);
2965         assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true);
2967         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true);
2968         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true);
2969         assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true);
2970         assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true);
2972         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true);
2974         // Prepare for prohibit test.
2975         role_assign($allroles['editingteacher'], $testusers[19], context_system::instance());
2976         role_assign($allroles['teacher'], $testusers[19], context_course::instance($testcourses[17]));
2977         role_assign($allroles['editingteacher'], $testusers[19], context_course::instance($testcourses[17]));
2978         assign_capability('moodle/course:update', CAP_PROHIBIT, $allroles['teacher'], context_course::instance($testcourses[17]), true);
2980         accesslib_clear_all_caches_for_unit_testing(); /// Must be done after assign_capability().
2982         // Extra tests for guests and not-logged-in users because they can not be verified by cross checking
2983         // with get_users_by_capability() where they are ignored.
2984         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid));
2985         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid));
2986         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid));
2987         $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid));
2989         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0));
2990         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0));
2991         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0));
2992         $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0));
2994         $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11]));
2995         $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11]));
2996         $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11]));
2997         $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11]));
2999         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9]));
3000         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9]));
3001         $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9]));
3003         // Test prohibits.
3004         $this->assertTrue(has_capability('moodle/course:update', context_system::instance(), $testusers[19]));
3005         $ids = get_users_by_capability(context_system::instance(), 'moodle/course:update', 'u.id');
3006         $this->assertArrayHasKey($testusers[19], $ids);
3007         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[17]), $testusers[19]));
3008         $ids = get_users_by_capability(context_course::instance($testcourses[17]), 'moodle/course:update', 'u.id');
3009         $this->assertArrayNotHasKey($testusers[19], $ids);
3011         // Test the list of enrolled users.
3012         $coursecontext = context_course::instance($course1->id);
3013         $enrolled = get_enrolled_users($coursecontext);
3014         $this->assertCount(10, $enrolled);
3015         for ($i=0; $i<10; $i++) {
3016             $this->assertTrue(isset($enrolled[$testusers[$i]]));
3017         }
3018         $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update');
3019         $this->assertCount(1, $enrolled);
3020         $this->assertTrue(isset($enrolled[$testusers[9]]));
3021         unset($enrolled);
3023         // Role switching.
3024         $userid = $testusers[9];
3025         $USER = $DB->get_record('user', array('id'=>$userid));
3026         load_all_capabilities();
3027         $coursecontext = context_course::instance($course1->id);
3028         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
3029         $this->assertFalse(is_role_switched($course1->id));
3030         role_switch($allroles['student'], $coursecontext);
3031         $this->assertTrue(is_role_switched($course1->id));
3032         $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]);
3033         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
3034         reload_all_capabilities();
3035         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
3036         role_switch(0, $coursecontext);
3037         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
3038         $userid = $adminid;
3039         $USER = $DB->get_record('user', array('id'=>$userid));
3040         load_all_capabilities();
3041         $coursecontext = context_course::instance($course1->id);
3042         $blockcontext = context_block::instance($block1->id);
3043         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
3044         role_switch($allroles['student'], $coursecontext);
3045         $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]);
3046         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
3047         reload_all_capabilities();
3048         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
3049         load_all_capabilities();
3050         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
3052         // Temp course role for enrol.
3053         $DB->delete_records('cache_flags', array()); // This prevents problem with dirty contexts immediately resetting the temp role - this is a known problem...
3054         $userid = $testusers[5];
3055         $roleid = $allroles['editingteacher'];
3056         $USER = $DB->get_record('user', array('id'=>$userid));
3057         load_all_capabilities();
3058         $coursecontext = context_course::instance($course1->id);
3059         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
3060         $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid]));
3061         load_temp_course_role($coursecontext, $roleid);
3062         $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid);
3063         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
3064         remove_temp_course_roles($coursecontext);
3065         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
3066         load_temp_course_role($coursecontext, $roleid);
3067         reload_all_capabilities();
3068         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
3069         $USER = new stdClass();
3070         $USER->id = 0;
3072         // Now cross check has_capability() with get_users_by_capability(), each using different code paths,
3073         // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong,
3074         // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users).
3075         $contexts = $DB->get_records('context', array(), 'id');
3076         $contexts = array_values($contexts);
3077         $capabilities = $DB->get_records('capabilities', array(), 'id');
3078         $capabilities = array_values($capabilities);
3079         $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']);
3080         $userids = array_values($testusers);
3081         $userids[] = get_admin()->id;
3083         if (!PHPUNIT_LONGTEST) {
3084             $contexts = array_slice($contexts, 0, 10);
3085             $capabilities = array_slice($capabilities, 0, 5);
3086             $userids = array_slice($userids, 0, 5);
3087         }
3089         foreach ($userids as $userid) { // No guest or deleted.
3090             // Each user gets 0-10 random roles.
3091             $rcount = rand(0, 10);
3092             for ($j=0; $j<$rcount; $j++) {
3093                 $roleid = $roles[rand(0, count($roles)-1)];
3094                 $contextid = $contexts[rand(0, count($contexts)-1)]->id;
3095                 role_assign($roleid, $userid, $contextid);
3096             }
3097         }
3099         $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT);
3100         $maxoverrides = count($contexts)*10;
3101         for ($j=0; $j<$maxoverrides; $j++) {
3102             $roleid = $roles[rand(0, count($roles)-1)];
3103             $contextid = $contexts[rand(0, count($contexts)-1)]->id;
3104             $permission = $permissions[rand(0, count($permissions)-1)];
3105             $capname = $capabilities[rand(0, count($capabilities)-1)]->name;
3106             assign_capability($capname, $permission, $roleid, $contextid, true);
3107         }
3108         unset($permissions);
3109         unset($roles);
3111         accesslib_clear_all_caches_for_unit_testing(); // must be done after assign_capability().
3113         // Test time - let's set up some real user, just in case the logic for USER affects the others...
3114         $USER = $DB->get_record('user', array('id'=>$testusers[3]));
3115         load_all_capabilities();
3117         $userids[] = $CFG->siteguest;
3118         $userids[] = 0; // Not-logged-in user.
3119         $userids[] = -1; // Non-existent user.
3121         foreach ($contexts as $crecord) {
3122             $context = context::instance_by_id($crecord->id);
3123             if ($coursecontext = $context->get_course_context(false)) {
3124                 $enrolled = get_enrolled_users($context);
3125             } else {
3126                 $enrolled = array();
3127             }
3128             foreach ($capabilities as $cap) {
3129                 $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username');
3130                 if ($enrolled) {
3131                     $enrolledwithcap = get_enrolled_users($context, $cap->name);
3132                 } else {
3133                     $enrolledwithcap = array();
3134                 }
3135                 foreach ($userids as $userid) {
3136                     if ($userid == 0 or isguestuser($userid)) {
3137                         if ($userid == 0) {
3138                             $CFG->forcelogin = true;
3139                             $this->assertFalse(has_capability($cap->name, $context, $userid));
3140                             unset($CFG->forcelogin);
3141                         }
3142                         if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) {
3143                             $this->assertFalse(has_capability($cap->name, $context, $userid));
3144                         }
3145                         $this->assertFalse(isset($allowed[$userid]));
3146                     } else {
3147                         if (is_siteadmin($userid)) {
3148                             $this->assertTrue(has_capability($cap->name, $context, $userid, true));
3149                         }
3150                         $hascap = has_capability($cap->name, $context, $userid, false);
3151                         $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
3152                         if (isset($enrolled[$userid])) {
3153                             $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
3154                         }
3155                     }
3156                 }
3157             }
3158         }
3159         // Back to nobody.
3160         $USER = new stdClass();
3161         $USER->id = 0;
3162         unset($contexts);
3163         unset($userids);
3164         unset($capabilities);
3166         // Now let's do all the remaining tests that break our carefully prepared fake site.
3169         // Test $context->mark_dirty() method.
3171         $DB->delete_records('cache_flags', array());
3172         accesslib_clear_all_caches(false);
3173         $systemcontext->mark_dirty();
3174         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
3175         $this->assertTrue(isset($dirty[$systemcontext->path]));
3176         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path]));
3179         // Test $context->reload_if_dirty() method.
3181         $DB->delete_records('cache_flags', array());
3182         accesslib_clear_all_caches(false);
3183         load_all_capabilities();
3184         $context = context_course::instance($testcourses[2]);
3185         $page = $DB->get_record('page', array('course'=>$testcourses[2]));
3186         $pagecm = get_coursemodule_from_instance('page', $page->id);
3187         $pagecontext = context_module::instance($pagecm->id);
3189         $context->mark_dirty();
3190         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
3191         $USER->access['test'] = true;
3192         $context->reload_if_dirty();
3193         $this->assertFalse(isset($USER->access['test']));
3195         $context->mark_dirty();
3196         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
3197         $USER->access['test'] = true;
3198         $pagecontext->reload_if_dirty();
3199         $this->assertFalse(isset($USER->access['test']));
3202         // Test context_helper::build_all_paths() method.
3204         $oldcontexts = $DB->get_records('context', array(), 'id');
3205         $DB->set_field_select('context', 'path', null, "contextlevel <> ".CONTEXT_SYSTEM);
3206         $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM);
3207         context_helper::build_all_paths();
3208         $newcontexts = $DB->get_records('context', array(), 'id');
3209         $this->assertEquals($oldcontexts, $newcontexts);
3210         unset($oldcontexts);
3211         unset($newcontexts);
3214         // Test $context->reset_paths() method.
3216         $context = context_course::instance($testcourses[2]);
3217         $children = $context->get_child_contexts();
3218         $context->reset_paths(false);
3219         $this->assertNull($DB->get_field('context', 'path', array('id'=>$context->id)));
3220         $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$context->id)));
3221         foreach ($children as $child) {
3222             $this->assertNull($DB->get_field('context', 'path', array('id'=>$child->id)));
3223             $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$child->id)));
3224         }
3225         $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0)));
3226         $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>null)));
3228         $context = context_course::instance($testcourses[2]);
3229         $context->reset_paths(true);
3230         $context = context_course::instance($testcourses[2]);
3231         $this->assertSame($context->path, $DB->get_field('context', 'path', array('id'=>$context->id)));
3232         $this->assertSame($context->depth, $DB->get_field('context', 'depth', array('id'=>$context->id)));
3233         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
3234         $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
3237         // Test $context->update_moved() method.