MDL-40405 libraries: Deprecate get_child_contexts()
[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  * Context caching fixture
31  */
32 class context_inspection extends context_helper {
33     public static function test_context_cache_size() {
34         return self::$cache_count;
35     }
36 }
39 /**
40  * Functional test for accesslib.php
41  *
42  * Note: execution may take many minutes especially on slower servers.
43  */
44 class accesslib_testcase extends advanced_testcase {
46     //TODO: add more tests for the remaining accesslib parts such as enrol related api
48     /**
49      * Verify comparison of context instances in phpunit asserts
50      * @return void
51      */
52     public function test_context_comparisons() {
53         $frontpagecontext1 = context_course::instance(SITEID);
54         context_helper::reset_caches();
55         $frontpagecontext2 = context_course::instance(SITEID);
56         $this->assertEquals($frontpagecontext1, $frontpagecontext2);
58         $user1 = context_user::instance(1);
59         $user2 = context_user::instance(2);
60         $this->assertNotEquals($user1, $user2);
61     }
63     /**
64      * Test resetting works.
65      */
66     public function test_accesslib_clear_all_caches() {
67         global $ACCESSLIB_PRIVATE;
69         $this->resetAfterTest();
71         $this->setAdminUser();
72         load_all_capabilities();
74         $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
75         $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
76         $this->assertNotEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
77         accesslib_clear_all_caches(true);
78         $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
79         $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
80         $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts);
81         $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
82     }
84     /**
85      * Test getting of role access
86      * @return void
87      */
88     public function test_get_role_access() {
89         global $DB;
91         $roles = $DB->get_records('role');
92         foreach ($roles as $role) {
93             $access = get_role_access($role->id);
95             $this->assertTrue(is_array($access));
96             $this->assertTrue(is_array($access['ra']));
97             $this->assertTrue(is_array($access['rdef']));
98             $this->assertTrue(isset($access['rdef_count']));
99             $this->assertTrue(is_array($access['loaded']));
100             $this->assertTrue(isset($access['time']));
101             $this->assertTrue(is_array($access['rsw']));
102         }
104         // Note: the data is validated in the functional permission evaluation test at the end of this testcase.
105     }
107     /**
108      * Test getting of guest role.
109      * @return void
110      */
111     public function test_get_guest_role() {
112         global $CFG;
114         $guest = get_guest_role();
115         $this->assertEquals('guest', $guest->archetype);
116         $this->assertEquals('guest', $guest->shortname);
118         $this->assertEquals($CFG->guestroleid, $guest->id);
119     }
121     /**
122      * Test if user is admin.
123      * @return void
124      */
125     public function test_is_siteadmin() {
126         global $DB, $CFG;
128         $this->resetAfterTest();
130         $users = $DB->get_records('user');
132         foreach ($users as $user) {
133             $this->setUser(0);
134             if ($user->username === 'admin') {
135                 $this->assertTrue(is_siteadmin($user));
136                 $this->assertTrue(is_siteadmin($user->id));
137                 $this->setUser($user);
138                 $this->assertTrue(is_siteadmin());
139                 $this->assertTrue(is_siteadmin(null));
140             } else {
141                 $this->assertFalse(is_siteadmin($user));
142                 $this->assertFalse(is_siteadmin($user->id));
143                 $this->setUser($user);
144                 $this->assertFalse(is_siteadmin());
145                 $this->assertFalse(is_siteadmin(null));
146             }
147         }
149         // Change the site admin list and check that it still works with
150         // multiple admins. We do this with userids only (not real user
151         // accounts) because it makes the test simpler.
152         $before = $CFG->siteadmins;
153         set_config('siteadmins', '666,667,668');
154         $this->assertTrue(is_siteadmin(666));
155         $this->assertTrue(is_siteadmin(667));
156         $this->assertTrue(is_siteadmin(668));
157         $this->assertFalse(is_siteadmin(669));
158         set_config('siteadmins', '13');
159         $this->assertTrue(is_siteadmin(13));
160         $this->assertFalse(is_siteadmin(666));
161         set_config('siteadmins', $before);
162     }
164     /**
165      * Test if user is enrolled in a course
166      * @return void
167      */
168     public function test_is_enrolled() {
169         global $DB;
171         // Generate data
172         $user = $this->getDataGenerator()->create_user();
173         $course = $this->getDataGenerator()->create_course();
174         $coursecontext = context_course::instance($course->id);
175         $role = $DB->get_record('role', array('shortname'=>'student'));
177         // There should be a manual enrolment as part of the default install
178         $plugin = enrol_get_plugin('manual');
179         $instance = $DB->get_record('enrol', array(
180             'courseid' => $course->id,
181             'enrol' => 'manual',
182         ));
183         $this->assertNotEquals($instance, false);
185         // Enrol the user in the course
186         $plugin->enrol_user($instance, $user->id, $role->id);
188         // We'll test with the mod/assign:submit capability
189         $capability= 'mod/assign:submit';
190         $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
192         // Switch to our user
193         $this->setUser($user);
195         // Ensure that the user has the capability first
196         $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
198         // We first test whether the user is enrolled on the course as this
199         // seeds the cache, then we test for the capability
200         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
201         $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
203         // Prevent the capability for this user role
204         assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
205         $coursecontext->mark_dirty();
206         $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
208         // Again, we seed the cache first by checking initial enrolment,
209         // and then we test the actual capability
210         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
211         $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
213         // We need variable states to be reset for the next test
214         $this->resetAfterTest(true);
215     }
217     /**
218      * Test logged in test.
219      * @return void
220      */
221     public function test_isloggedin() {
222         global $USER;
224         $this->resetAfterTest();
226         $USER->id = 0;
227         $this->assertFalse(isloggedin());
228         $USER->id = 1;
229         $this->assertTrue(isloggedin());
230     }
232     /**
233      * Test guest user test.
234      * @return void
235      */
236     public function test_isguestuser() {
237         global $DB;
239         $this->resetAfterTest();
241         $guest = $DB->get_record('user', array('username'=>'guest'));
242         $this->setUser(0);
243         $this->assertFalse(isguestuser());
244         $this->setAdminUser();
245         $this->assertFalse(isguestuser());
246         $this->assertTrue(isguestuser($guest));
247         $this->assertTrue(isguestuser($guest->id));
248         $this->setUser($guest);
249         $this->assertTrue(isguestuser());
251         $users = $DB->get_records('user');
252         foreach ($users as $user) {
253             if ($user->username === 'guest') {
254                 continue;
255             }
256             $this->assertFalse(isguestuser($user));
257         }
258     }
260     /**
261      * Test capability riskiness.
262      * @return void
263      */
264     public function test_is_safe_capability() {
265         global $DB;
266         // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap.
267         $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST);
268         $this->assertFalse(is_safe_capability($capability));
269     }
271     /**
272      * Test context fetching.
273      * @return void
274      */
275     public function test_get_context_info_array() {
276         $this->resetAfterTest();
278         $syscontext = context_system::instance();
279         $user = $this->getDataGenerator()->create_user();
280         $usercontext = context_user::instance($user->id);
281         $course = $this->getDataGenerator()->create_course();
282         $catcontext = context_coursecat::instance($course->category);
283         $coursecontext = context_course::instance($course->id);
284         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
285         $modcontext = context_module::instance($page->cmid);
286         $cm = get_coursemodule_from_instance('page', $page->id);
287         $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
288         $block1context = context_block::instance($block1->id);
289         $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id));
290         $block2context = context_block::instance($block2->id);
292         $result = get_context_info_array($syscontext->id);
293         $this->assertCount(3, $result);
294         $this->assertSame($syscontext, $result[0]);
295         $this->assertSame(null, $result[1]);
296         $this->assertSame(null, $result[2]);
298         $result = get_context_info_array($usercontext->id);
299         $this->assertCount(3, $result);
300         $this->assertSame($usercontext, $result[0]);
301         $this->assertSame(null, $result[1]);
302         $this->assertSame(null, $result[2]);
304         $result = get_context_info_array($catcontext->id);
305         $this->assertCount(3, $result);
306         $this->assertSame($catcontext, $result[0]);
307         $this->assertSame(null, $result[1]);
308         $this->assertSame(null, $result[2]);
310         $result = get_context_info_array($coursecontext->id);
311         $this->assertCount(3, $result);
312         $this->assertSame($coursecontext, $result[0]);
313         $this->assertEquals($course->id, $result[1]->id);
314         $this->assertEquals($course->shortname, $result[1]->shortname);
315         $this->assertSame(null, $result[2]);
317         $result = get_context_info_array($block1context->id);
318         $this->assertCount(3, $result);
319         $this->assertSame($block1context, $result[0]);
320         $this->assertEquals($course->id, $result[1]->id);
321         $this->assertEquals($course->shortname, $result[1]->shortname);
322         $this->assertSame(null, $result[2]);
324         $result = get_context_info_array($modcontext->id);
325         $this->assertCount(3, $result);
326         $this->assertSame($modcontext, $result[0]);
327         $this->assertEquals($course->id, $result[1]->id);
328         $this->assertEquals($course->shortname, $result[1]->shortname);
329         $this->assertEquals($cm->id, $result[2]->id);
330         $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
332         $result = get_context_info_array($block2context->id);
333         $this->assertCount(3, $result);
334         $this->assertSame($block2context, $result[0]);
335         $this->assertEquals($course->id, $result[1]->id);
336         $this->assertEquals($course->shortname, $result[1]->shortname);
337         $this->assertEquals($cm->id, $result[2]->id);
338         $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
339     }
341     /**
342      * Test looking for course contacts.
343      * @return void
344      */
345     public function test_has_coursecontact_role() {
346         global $DB, $CFG;
348         $this->resetAfterTest();
350         $users = $DB->get_records('user');
352         // Nobody is expected to have any course level roles.
353         $this->assertNotEmpty($CFG->coursecontact);
354         foreach($users as $user) {
355             $this->assertFalse(has_coursecontact_role($user->id));
356         }
358         $user = $this->getDataGenerator()->create_user();
359         $course = $this->getDataGenerator()->create_course();
360         role_assign($CFG->coursecontact, $user->id, context_course::instance($course->id));
361         $this->assertTrue(has_coursecontact_role($user->id));
362     }
364     /**
365      * Test creation of roles.
366      * @return void
367      */
368     public function test_create_role() {
369         global $DB;
371         $this->resetAfterTest();
373         $id = create_role('New student role', 'student2', 'New student description', 'student');
374         $role = $DB->get_record('role', array('id'=>$id));
376         $this->assertNotEmpty($role);
377         $this->assertEquals('New student role', $role->name);
378         $this->assertEquals('student2', $role->shortname);
379         $this->assertEquals('New student description', $role->description);
380         $this->assertEquals('student', $role->archetype);
381     }
383     /**
384      * Test adding of capabilities to roles.
385      */
386     public function test_assign_capability() {
387         global $DB;
389         $this->resetAfterTest();
391         $user = $this->getDataGenerator()->create_user();
392         $syscontext = context_system::instance();
393         $frontcontext = context_course::instance(SITEID);
394         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
395         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability assigned to student by default
396         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
397         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
399         $this->setUser($user);
400         $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id);
401         $this->assertTrue($result);
402         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
403         $this->assertNotEmpty($permission);
404         $this->assertEquals(CAP_ALLOW, $permission->permission);
405         $this->assertEquals($user->id, $permission->modifierid);
407         $this->setUser(0);
408         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false);
409         $this->assertTrue($result);
410         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
411         $this->assertNotEmpty($permission);
412         $this->assertEquals(CAP_ALLOW, $permission->permission);
413         $this->assertEquals(3, $permission->modifierid);
415         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true);
416         $this->assertTrue($result);
417         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
418         $this->assertNotEmpty($permission);
419         $this->assertEquals(CAP_PROHIBIT, $permission->permission);
420         $this->assertEquals(0, $permission->modifierid);
422         $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id);
423         $this->assertTrue($result);
424         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
425         $this->assertEmpty($permission);
426     }
428     /**
429      * Test removing of capabilities from roles.
430      */
431     public function test_unassign_capability() {
432         global $DB;
434         $this->resetAfterTest();
436         $syscontext = context_system::instance();
437         $frontcontext = context_course::instance(SITEID);
438         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
439         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability assigned to manager by default
440         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
442         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
443         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
445         $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id);
446         $this->assertTrue($result);
447         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
448         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
449         unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext);
450         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
452         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
453         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
454         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
456         $result = unassign_capability('moodle/backup:backupcourse', $manager->id);
457         $this->assertTrue($result);
458         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
459         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
460     }
462     /**
463      * Test role assigning
464      */
465     public function test_role_assign() {
466         global $DB, $USER;
468         $this->resetAfterTest();
470         $user = $this->getDataGenerator()->create_user();
471         $course = $this->getDataGenerator()->create_course();
472         $role = $DB->get_record('role', array('shortname'=>'student'));
474         $this->setUser(0);
475         $context = context_system::instance();
476         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
477         role_assign($role->id, $user->id, $context->id);
478         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
479         $this->assertNotEmpty($ras);
480         $this->assertSame('', $ras->component);
481         $this->assertSame('0', $ras->itemid);
482         $this->assertEquals($USER->id, $ras->modifierid);
484         $this->setAdminUser();
485         $context = context_course::instance($course->id);
486         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
487         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666);
488         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
489         $this->assertNotEmpty($ras);
490         $this->assertSame('enrol_self', $ras->component);
491         $this->assertSame('1', $ras->itemid);
492         $this->assertEquals($USER->id, $ras->modifierid);
493         $this->assertEquals(666, $ras->timemodified);
494     }
496     /**
497      * Test role unassigning
498      * @return void
499      */
500     public function test_role_unassign() {
501         global $DB;
503         $this->resetAfterTest();
505         $user = $this->getDataGenerator()->create_user();
506         $course = $this->getDataGenerator()->create_course();
507         $role = $DB->get_record('role', array('shortname'=>'student'));
509         $context = context_system::instance();
510         role_assign($role->id, $user->id, $context->id);
511         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
512         role_unassign($role->id, $user->id, $context->id);
513         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
515         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1);
516         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
517         role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1);
518         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
519     }
521     /**
522      * Test role unassigning
523      * @return void
524      */
525     public function test_role_unassign_all() {
526         global $DB;
528         $this->resetAfterTest();
530         $user = $this->getDataGenerator()->create_user();
531         $course = $this->getDataGenerator()->create_course();
532         $role = $DB->get_record('role', array('shortname'=>'student'));
533         $syscontext = context_system::instance();
534         $coursecontext = context_course::instance($course->id);
535         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
536         $modcontext = context_module::instance($page->cmid);
538         role_assign($role->id, $user->id, $syscontext->id);
539         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
540         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
541         role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id));
542         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
544         role_assign($role->id, $user->id, $syscontext->id);
545         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
546         role_assign($role->id, $user->id, $modcontext->id);
547         $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id)));
548         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false);
549         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
550         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true);
551         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
552         role_unassign_all(array('userid'=>$user->id));
553         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
555         role_assign($role->id, $user->id, $syscontext->id);
556         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
557         role_assign($role->id, $user->id, $coursecontext->id);
558         role_assign($role->id, $user->id, $modcontext->id);
559         $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id)));
560         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true);
561         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
562     }
564     /**
565      * Test role queries.
566      * @return void
567      */
568     public function test_get_roles_with_capability() {
569         global $DB;
571         $this->resetAfterTest();
573         $syscontext = context_system::instance();
574         $frontcontext = context_course::instance(SITEID);
575         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
576         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
578         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability is ok
579         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse'));
581         $roles = get_roles_with_capability('moodle/backup:backupcourse');
582         $this->assertEquals(array(), $roles);
584         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
585         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id);
586         assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id);
588         $roles = get_roles_with_capability('moodle/backup:backupcourse');
589         $this->assertEquals(array($teacher->id, $manager->id), array_keys($roles), '', 0, 10, true);
591         $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW);
592         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
594         $roles = get_roles_with_capability('moodle/backup:backupcourse', NULL, $syscontext);
595         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
596     }
598     /**
599      * Test deleting of roles.
600      * @return void
601      */
602     public function test_delete_role() {
603         global $DB;
605         $this->resetAfterTest();
607         $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
608         $user = $this->getDataGenerator()->create_user();
609         role_assign($role->id, $user->id, context_system::instance());
610         $course = $this->getDataGenerator()->create_course();
611         $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id);
612         $DB->insert_record('role_names', $rolename);
614         $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
615         $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
616         $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id)));
617         $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
618         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
619         $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
620         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
621         $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
623         $result = delete_role($role->id);
624         $this->assertTrue($result);
625         $this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
626         $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
627         $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
628         $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id)));
629         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
630         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
631         $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
632         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
633         $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
634     }
636     /**
637      * Test fetching of all roles.
638      * @return void
639      */
640     public function test_get_all_roles() {
641         global $DB;
643         $this->resetAfterTest();
645         $allroles = get_all_roles();
646         $this->assertEquals('array', gettype($allroles));
647         $this->assertCount(8, $allroles); // there are 8 roles is standard install
649         $role = reset($allroles);
650         $role = (array)$role;
652         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), array_keys($role), '', 0, 10, true);
654         foreach($allroles as $roleid => $role) {
655             $this->assertEquals($role->id, $roleid);
656         }
658         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
659         $course = $this->getDataGenerator()->create_course();
660         $coursecontext = context_course::instance($course->id);
661         $otherid = create_role('Other role', 'other', 'Some other role', '');
662         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
663         $DB->insert_record('role_names', $teacherename);
664         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
665         $DB->insert_record('role_names', $otherrename);
666         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid,name');
668         $allroles = get_all_roles($coursecontext);
669         $this->assertEquals('array', gettype($allroles));
670         $this->assertCount(9, $allroles);
671         $role = reset($allroles);
672         $role = (array)$role;
674         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role), '', 0, 10, true);
676         foreach($allroles as $roleid => $role) {
677             $this->assertEquals($role->id, $roleid);
678             if (isset($renames[$roleid])) {
679                 $this->assertSame($renames[$roleid], $role->coursealias);
680             } else {
681                 $this->assertSame(null, $role->coursealias);
682             }
683         }
684     }
686     /**
687      * Test getting of all archetypes.
688      * @return void
689      */
690     public function test_get_role_archetypes() {
691         $archetypes = get_role_archetypes();
692         $this->assertCount(8, $archetypes); // there are 8 archetypes in standard install
693         foreach ($archetypes as $k=>$v) {
694             $this->assertSame($k, $v);
695         }
696     }
698     /**
699      * Test getting of roles with given archetype.
700      * @return void
701      */
702     public function test_get_archetype_roles() {
703         $this->resetAfterTest();
705         // New install should have 1 role for each archetype.
706         $archetypes = get_role_archetypes();
707         foreach ($archetypes as $archetype) {
708             $roles = get_archetype_roles($archetype);
709             $this->assertCount(1, $roles);
710             $role = reset($roles);
711             $this->assertEquals($archetype, $role->archetype);
712         }
714         create_role('New student role', 'student2', 'New student description', 'student');
715         $roles = get_archetype_roles('student');
716         $this->assertCount(2, $roles);
717     }
719     /**
720      * Test aliased role names
721      * @return void
722      */
723     public function test_role_get_name() {
724         global $DB;
726         $this->resetAfterTest();
728         $allroles = $DB->get_records('role');
729         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
730         $course = $this->getDataGenerator()->create_course();
731         $coursecontext = context_course::instance($course->id);
732         $otherid = create_role('Other role', 'other', 'Some other role', '');
733         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
734         $DB->insert_record('role_names', $teacherename);
735         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
736         $DB->insert_record('role_names', $otherrename);
737         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid,name');
739         foreach ($allroles as $role) {
740             // Get localised name from lang pack.
741             $this->assertSame('', $role->name);
742             $name = role_get_name($role, null, ROLENAME_ORIGINAL);
743             $this->assertNotEmpty($name);
744             $this->assertNotEquals($role->shortname, $name);
746             if (isset($renames[$role->id])) {
747                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext));
748                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS));
749                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
750                 $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH));
751             } else {
752                 $this->assertSame($name, role_get_name($role, $coursecontext));
753                 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS));
754                 $this->assertSame(null, role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
755                 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH));
756             }
757             $this->assertSame($name, role_get_name($role));
758             $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL));
759             $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL));
760             $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT));
761             $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT));
762             $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT));
763             $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT));
764             $this->assertSame(null, role_get_name($role, null, ROLENAME_ALIAS_RAW));
765         }
766     }
768     /**
769      * Test tweaking of role name arrays
770      * @return void
771      */
772     public function test_role_fix_names() {
773         global $DB;
775         $this->resetAfterTest();
777         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
778         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
779         $otherid = create_role('Other role', 'other', 'Some other role', '');
780         $anotherid = create_role('Another role', 'another', 'Yet another other role', '');
781         $allroles = $DB->get_records('role');
783         $syscontext = context_system::instance();
784         $frontcontext = context_course::instance(SITEID);
785         $course = $this->getDataGenerator()->create_course();
786         $coursecontext = context_course::instance($course->id);
787         $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST);
788         $categorycontext = context_coursecat::instance($category->id);
790         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
791         $DB->insert_record('role_names', $teacherename);
792         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
793         $DB->insert_record('role_names', $otherrename);
794         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid,name');
796         // Make sure all localname contain proper values for each ROLENAME_ constant,
797         // note role_get_name() on frontpage is used to get the original name for future comatibility.
798         $roles = $allroles;
799         unset($roles[$student->id]); // Remove one roel to make sure no role is added or removed.
800         $rolenames = array();
801         foreach ($roles as $role) {
802             $rolenames[$role->id] = $role->name;
803         }
805         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
806         foreach ($alltypes as $type) {
807             $fixed = role_fix_names($roles, $coursecontext, $type);
808             $this->assertCount(count($roles), $fixed);
809             foreach($fixed as $roleid=>$rolename) {
810                 $this->assertInstanceOf('stdClass', $rolename);
811                 $role = $allroles[$roleid];
812                 $name = role_get_name($role, $coursecontext, $type);
813                 $this->assertSame($name, $rolename->localname);
814             }
815             $fixed = role_fix_names($rolenames, $coursecontext, $type);
816             $this->assertCount(count($rolenames), $fixed);
817             foreach($fixed as $roleid=>$rolename) {
818                 $role = $allroles[$roleid];
819                 $name = role_get_name($role, $coursecontext, $type);
820                 $this->assertSame($name, $rolename);
821             }
822         }
823     }
825     /**
826      * Test role default allows.
827      */
828     public function test_get_default_role_archetype_allows() {
829         $archetypes = get_role_archetypes();
830         foreach ($archetypes as $archetype) {
832             $result = get_default_role_archetype_allows('assign', $archetype);
833             $this->assertTrue(is_array($result));
835             $result = get_default_role_archetype_allows('override', $archetype);
836             $this->assertTrue(is_array($result));
838             $result = get_default_role_archetype_allows('switch', $archetype);
839             $this->assertTrue(is_array($result));
840         }
842         $result = get_default_role_archetype_allows('assign', '');
843         $this->assertSame(array(), $result);
845         $result = get_default_role_archetype_allows('override', '');
846         $this->assertSame(array(), $result);
848         $result = get_default_role_archetype_allows('switch', '');
849         $this->assertSame(array(), $result);
851         $result = get_default_role_archetype_allows('assign', 'wrongarchetype');
852         $this->assertSame(array(), $result);
853         $this->assertDebuggingCalled();
855         $result = get_default_role_archetype_allows('override', 'wrongarchetype');
856         $this->assertSame(array(), $result);
857         $this->assertDebuggingCalled();
859         $result = get_default_role_archetype_allows('switch', 'wrongarchetype');
860         $this->assertSame(array(), $result);
861         $this->assertDebuggingCalled();
862     }
864     /**
865      * Test allowing of role assignments.
866      * @return void
867      */
868     public function test_allow_assign() {
869         global $DB;
871         $this->resetAfterTest();
873         $otherid = create_role('Other role', 'other', 'Some other role', '');
874         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
876         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
877         allow_assign($otherid, $student->id);
878         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
879     }
881     /**
882      * Test allowing of role overrides.
883      * @return void
884      */
885     public function test_allow_override() {
886         global $DB;
888         $this->resetAfterTest();
890         $otherid = create_role('Other role', 'other', 'Some other role', '');
891         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
893         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
894         allow_override($otherid, $student->id);
895         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
896     }
898     /**
899      * Test allowing of role switching.
900      * @return void
901      */
902     public function test_allow_switch() {
903         global $DB;
905         $this->resetAfterTest();
907         $otherid = create_role('Other role', 'other', 'Some other role', '');
908         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
910         $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
911         allow_switch($otherid, $student->id);
912         $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
913     }
915     /**
916      * Test returning of assignable roles in context.
917      * @return void
918      */
919     public function test_get_assignable_roles() {
920         global $DB;
922         $this->resetAfterTest();
924         $course = $this->getDataGenerator()->create_course();
925         $coursecontext = context_course::instance($course->id);
927         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
928         $teacher = $this->getDataGenerator()->create_user();
929         role_assign($teacherrole->id, $teacher->id, $coursecontext);
930         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
931         $DB->insert_record('role_names', $teacherename);
933         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
934         $student = $this->getDataGenerator()->create_user();
935         role_assign($studentrole->id, $student->id, $coursecontext);
937         $contexts = $DB->get_records('context');
938         $users = $DB->get_records('user');
939         $allroles = $DB->get_records('role');
941         // Evaluate all results for all users in all contexts.
942         foreach($users as $user) {
943             $this->setUser($user);
944             foreach ($contexts as $contextid=>$unused) {
945                 $context = context_helper::instance_by_id($contextid);
946                 $roles = get_assignable_roles($context, ROLENAME_SHORT);
947                 foreach ($allroles as $roleid=>$role) {
948                     if (isset($roles[$roleid])) {
949                         if (is_siteadmin()) {
950                             $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)));
951                         } else {
952                             $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid");
953                         }
954                         $this->assertEquals($role->shortname, $roles[$roleid]);
955                     } else {
956                         $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid));
957                         if (is_siteadmin()) {
958                             $this->assertFalse($allowed);
959                         } else {
960                             $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel");
961                         }
962                     }
963                 }
964             }
965         }
967         // not-logged-in user
968         $this->setUser(0);
969         foreach ($contexts as $contextid=>$unused) {
970             $context = context_helper::instance_by_id($contextid);
971             $roles = get_assignable_roles($context, ROLENAME_SHORT);
972             $this->assertSame(array(), $roles);
973         }
975         // Test current user.
976         $this->setUser(0);
977         $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST);
978         $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin);
979         $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id);
980         $this->setAdminUser();
981         $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT);
982         $this->assertSame($roles1, $roles3);
983         $this->assertSame($roles2, $roles3);
985         // Test parameter defaults.
986         $this->setAdminUser();
987         $roles1 = get_assignable_roles($coursecontext);
988         $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
989         $this->assertEquals($roles2, $roles1);
991         // Verify returned names - let's allow all roles everywhere to simplify this a bit.
992         $alllevels = context_helper::get_all_levels();
993         $alllevels = array_keys($alllevels);
994         foreach($allroles as $roleid=>$role) {
995             set_role_contextlevels($roleid, $alllevels);
996         }
997         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
998         foreach ($alltypes as $type) {
999             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1000             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1001             foreach ($roles as $roleid=>$rolename) {
1002                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1003             }
1004         }
1006         // Verify counts.
1007         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1008         foreach ($alltypes as $type) {
1009             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1010             list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin);
1011             $this->assertEquals($roles, $rolenames);
1012             foreach ($rolenames as $roleid=>$name) {
1013                 if ($roleid == $teacherrole->id or $roleid == $studentrole->id) {
1014                     $this->assertEquals(1, $rolecounts[$roleid]);
1015                 } else {
1016                     $this->assertEquals(0, $rolecounts[$roleid]);
1017                 }
1018                 $this->assertEquals("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1019             }
1020         }
1021     }
1023     /**
1024      * Test getting of all switchable roles.
1025      * @retrun void
1026      */
1027     public function test_get_switchable_roles() {
1028         global $DB;
1030         $this->resetAfterTest();
1032         $course = $this->getDataGenerator()->create_course();
1033         $coursecontext = context_course::instance($course->id);
1035         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1036         $teacher = $this->getDataGenerator()->create_user();
1037         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1038         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1039         $DB->insert_record('role_names', $teacherename);
1041         $contexts = $DB->get_records('context');
1042         $users = $DB->get_records('user');
1043         $allroles = $DB->get_records('role');
1045         // Evaluate all results for all users in all contexts.
1046         foreach($users as $user) {
1047             $this->setUser($user);
1048             foreach ($contexts as $contextid=>$unused) {
1049                 $context = context_helper::instance_by_id($contextid);
1050                 $roles = get_switchable_roles($context);
1051                 foreach ($allroles as $roleid=>$role) {
1052                     if (is_siteadmin()) {
1053                         $this->assertTrue(isset($roles[$roleid]));
1054                     } else {
1055                         $parents = $context->get_parent_context_ids(true);
1056                         $pcontexts = implode(',' , $parents);
1057                         $allowed = $DB->record_exists_sql(
1058                             "SELECT r.id
1059                                FROM {role} r
1060                                JOIN {role_allow_switch} ras ON ras.allowswitch = r.id
1061                                JOIN {role_assignments} ra ON ra.roleid = ras.roleid
1062                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1063                             ",
1064                             array('userid'=>$user->id, 'roleid'=>$roleid)
1065                         );
1066                         if (isset($roles[$roleid])) {
1067                             $this->assertTrue($allowed);
1068                         } else {
1069                             $this->assertFalse($allowed);
1070                         }
1071                     }
1073                     if (isset($roles[$roleid])) {
1074                         $coursecontext = $context->get_course_context(false);
1075                         $this->assertEquals(role_get_name($role, $coursecontext), $roles[$roleid]);
1076                     }
1077                 }
1078             }
1079         }
1080     }
1082     /**
1083      * Test getting of all overridable roles.
1084      * @return void
1085      */
1086     public function test_get_overridable_roles() {
1087         global $DB;
1089         $this->resetAfterTest();
1091         $course = $this->getDataGenerator()->create_course();
1092         $coursecontext = context_course::instance($course->id);
1094         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1095         $teacher = $this->getDataGenerator()->create_user();
1096         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1097         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1098         $DB->insert_record('role_names', $teacherename);
1099         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability is ok
1100         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacher->id, $coursecontext->id);
1102         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1103         $student = $this->getDataGenerator()->create_user();
1104         role_assign($studentrole->id, $student->id, $coursecontext);
1106         $contexts = $DB->get_records('context');
1107         $users = $DB->get_records('user');
1108         $allroles = $DB->get_records('role');
1110         // Evaluate all results for all users in all contexts.
1111         foreach($users as $user) {
1112             $this->setUser($user);
1113             foreach ($contexts as $contextid=>$unused) {
1114                 $context = context_helper::instance_by_id($contextid);
1115                 $roles = get_overridable_roles($context, ROLENAME_SHORT);
1116                 foreach ($allroles as $roleid=>$role) {
1117                     $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context);
1118                     if (is_siteadmin()) {
1119                         $this->assertTrue(isset($roles[$roleid]));
1120                     } else {
1121                         $parents = $context->get_parent_context_ids(true);
1122                         $pcontexts = implode(',' , $parents);
1123                         $allowed = $DB->record_exists_sql(
1124                             "SELECT r.id
1125                                FROM {role} r
1126                                JOIN {role_allow_override} rao ON r.id = rao.allowoverride
1127                                JOIN {role_assignments} ra ON rao.roleid = ra.roleid
1128                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1129                             ",
1130                             array('userid'=>$user->id, 'roleid'=>$roleid)
1131                         );
1132                         if (isset($roles[$roleid])) {
1133                             $this->assertTrue($hascap);
1134                             $this->assertTrue($allowed);
1135                         } else {
1136                             $this->assertFalse($hascap and $allowed);
1137                         }
1138                     }
1140                     if (isset($roles[$roleid])) {
1141                         $this->assertEquals($role->shortname, $roles[$roleid]);
1142                     }
1143                 }
1144             }
1145         }
1147         // Test parameter defaults.
1148         $this->setAdminUser();
1149         $roles1 = get_overridable_roles($coursecontext);
1150         $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1151         $this->assertEquals($roles2, $roles1);
1153         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1154         foreach ($alltypes as $type) {
1155             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1156             $roles = get_overridable_roles($coursecontext, $type, false);
1157             foreach ($roles as $roleid=>$rolename) {
1158                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1159             }
1160         }
1162         // Verify counts.
1163         $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1164         list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true);
1165         $this->assertEquals($roles, $rolenames);
1166         foreach ($rolenames as $roleid=>$name) {
1167             if ($roleid == $teacherrole->id) {
1168                 $this->assertEquals(1, $rolecounts[$roleid]);
1169             } else {
1170                 $this->assertEquals(0, $rolecounts[$roleid]);
1171             }
1172             $this->assertEquals("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1173         }
1174     }
1176     /**
1177      * Test we have context level defaults.
1178      * @return void
1179      */
1180     public function test_get_default_contextlevels() {
1181         $archetypes = get_role_archetypes();
1182         $alllevels = context_helper::get_all_levels();
1183         foreach ($archetypes as $archetype) {
1184             $defaults = get_default_contextlevels($archetype);
1185             $this->assertTrue(is_array($defaults));
1186             foreach ($defaults as $level) {
1187                 $this->assertTrue(isset($alllevels[$level]));
1188             }
1189         }
1190     }
1192     /**
1193      * Test role context level setup.
1194      * @return void
1195      */
1196     public function test_set_role_contextlevels() {
1197         global $DB;
1199         $this->resetAfterTest();
1201         $roleid = create_role('New student role', 'student2', 'New student description', 'student');
1203         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid)));
1205         set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE));
1206         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1207         $this->assertCount(2, $levels);
1208         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1209         $this->assertTrue(isset($levels[CONTEXT_MODULE]));
1211         set_role_contextlevels($roleid, array(CONTEXT_COURSE));
1212         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1213         $this->assertCount(1, $levels);
1214         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1215     }
1217     /**
1218      * Test getting of role context levels
1219      * @return void
1220      */
1221     public function test_get_roles_for_contextlevels() {
1222         global $DB;
1224         $allroles = get_all_roles();
1225         foreach (context_helper::get_all_levels() as $level=>$unused) {
1226             $roles = get_roles_for_contextlevels($level);
1227             foreach ($allroles as $roleid=>$unused) {
1228                 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid));
1229                 if (in_array($roleid, $roles)) {
1230                     $this->assertTrue($exists);
1231                 } else {
1232                     $this->assertFalse($exists);
1233                 }
1234             }
1235         }
1236     }
1238     /**
1239      * Test default enrol roles.
1240      * @return void
1241      */
1242     public function test_get_default_enrol_roles() {
1243         $this->resetAfterTest();
1245         $course = $this->getDataGenerator()->create_course();
1246         $coursecontext = context_course::instance($course->id);
1248         $id2 = create_role('New student role', 'student2', 'New student description', 'student');
1249         set_role_contextlevels($id2, array(CONTEXT_COURSE));
1251         $allroles = get_all_roles();
1252         $expected = array($id2=>$allroles[$id2]);
1254         foreach(get_role_archetypes() as $archetype) {
1255             $defaults = get_default_contextlevels($archetype);
1256             if (in_array(CONTEXT_COURSE, $defaults)) {
1257                 $roles = get_archetype_roles($archetype);
1258                 foreach($roles as $role) {
1259                     $expected[$role->id] = $role;
1260                 }
1261             }
1262         }
1264         $roles = get_default_enrol_roles($coursecontext);
1265         foreach ($allroles as $role) {
1266             $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id]));
1267             if (isset($roles[$role->id])) {
1268                 $this->assertEquals(role_get_name($role, $coursecontext), $roles[$role->id]);
1269             }
1270         }
1271     }
1273     /**
1274      * Test getting of role users.
1275      * @return void
1276      */
1277     public function test_get_role_users() {
1278         global $DB;
1280         $this->resetAfterTest();
1282         $systemcontext = context_system::instance();
1283         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1284         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1285         $course = $this->getDataGenerator()->create_course();
1286         $coursecontext = context_course::instance($course->id);
1287         $otherid = create_role('Other role', 'other', 'Some other role', '');
1288         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1289         $DB->insert_record('role_names', $teacherrename);
1290         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1291         $DB->insert_record('role_names', $otherrename);
1293         $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith'));
1294         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1295         $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar'));
1296         role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1297         $user3 = $this->getDataGenerator()->create_user();
1298         $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id);
1299         $user4 = $this->getDataGenerator()->create_user();
1300         $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id);
1302         $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id));
1303         groups_add_member($group, $user3);
1305         $users = get_role_users($teacherrole->id, $coursecontext);
1306         $this->assertCount(2, $users);
1307         $this->assertArrayHasKey($user1->id, $users);
1308         $this->assertEquals($users[$user1->id]->id, $user1->id);
1309         $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id);
1310         $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name);
1311         $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname);
1312         $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name);
1313         $this->assertArrayHasKey($user3->id, $users);
1314         $this->assertEquals($users[$user3->id]->id, $user3->id);
1315         $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id);
1316         $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name);
1317         $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname);
1318         $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name);
1320         $users = get_role_users($teacherrole->id, $coursecontext, true);
1321         $this->assertCount(3, $users);
1323         $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1);
1324         $this->assertCount(1, $users);
1326         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber');
1327         $this->assertCount(2, $users);
1328         $this->assertArrayHasKey($user1->id, $users);
1329         $this->assertArrayHasKey($user3->id, $users);
1331         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id);
1332         $this->assertCount(1, $users);
1333         $this->assertArrayHasKey($user3->id, $users);
1335         $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'));
1336         $this->assertCount(1, $users);
1337         $this->assertArrayHasKey($user1->id, $users);
1338     }
1340     /**
1341      * Test used role query.
1342      * @return void
1343      */
1344     public function test_get_roles_used_in_context() {
1345         global $DB;
1347         $this->resetAfterTest();
1349         $systemcontext = context_system::instance();
1350         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1351         $course = $this->getDataGenerator()->create_course();
1352         $coursecontext = context_course::instance($course->id);
1353         $otherid = create_role('Other role', 'other', 'Some other role', '');
1354         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1355         $DB->insert_record('role_names', $teacherrename);
1356         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1357         $DB->insert_record('role_names', $otherrename);
1359         $user1 = $this->getDataGenerator()->create_user();
1360         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1362         $roles = get_roles_used_in_context($coursecontext);
1363         $this->assertCount(1, $roles);
1364         $role = reset($roles);
1365         $roleid = key($roles);
1366         $this->assertEquals($roleid, $role->id);
1367         $this->assertEquals($teacherrole->id, $role->id);
1368         $this->assertEquals($teacherrole->name, $role->name);
1369         $this->assertEquals($teacherrole->shortname, $role->shortname);
1370         $this->assertEquals($teacherrole->sortorder, $role->sortorder);
1371         $this->assertEquals($teacherrename->name, $role->coursealias);
1373         $user2 = $this->getDataGenerator()->create_user();
1374         role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1375         role_assign($otherid, $user2->id, $systemcontext->id);
1377         $roles = get_roles_used_in_context($systemcontext);
1378         $this->assertCount(2, $roles);
1379     }
1381     /**
1382      * Test roles used in course.
1383      * @return void
1384      */
1385     public function test_get_user_roles_in_course() {
1386         global $DB, $CFG;
1388         $this->resetAfterTest();
1390         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1391         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1392         $course = $this->getDataGenerator()->create_course();
1393         $coursecontext = context_course::instance($course->id);
1394         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1395         $DB->insert_record('role_names', $teacherrename);
1397         $roleids = explode(',', $CFG->profileroles); // should include teacher and student in new installs
1398         $this->assertTrue(in_array($teacherrole->id, $roleids));
1399         $this->assertTrue(in_array($studentrole->id, $roleids));
1401         $user1 = $this->getDataGenerator()->create_user();
1402         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1403         role_assign($studentrole->id, $user1->id, $coursecontext->id);
1404         $user2 = $this->getDataGenerator()->create_user();
1405         role_assign($studentrole->id, $user2->id, $coursecontext->id);
1406         $user3 = $this->getDataGenerator()->create_user();
1408         $roles = get_user_roles_in_course($user1->id, $course->id);
1409         $this->assertEquals(1, preg_match_all('/,/', $roles, $matches));
1410         $this->assertTrue(strpos($roles, role_get_name($teacherrole, $coursecontext)) !== false);
1412         $roles = get_user_roles_in_course($user2->id, $course->id);
1413         $this->assertEquals(0, preg_match_all('/,/', $roles, $matches));
1414         $this->assertTrue(strpos($roles, role_get_name($studentrole, $coursecontext)) !== false);
1416         $roles = get_user_roles_in_course($user3->id, $course->id);
1417         $this->assertSame('', $roles);
1418     }
1420     /**
1421      * Test has_capability(), has_any_capability() and has_all_capabilities().
1422      */
1423     public function test_has_capability_and_friends() {
1424         global $DB;
1426         $this->resetAfterTest();
1428         $course = $this->getDataGenerator()->create_course();
1429         $coursecontext = context_course::instance($course->id);
1430         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1431         $teacher = $this->getDataGenerator()->create_user();
1432         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1433         $admin = $DB->get_record('user', array('username'=>'admin'));
1435         // Note: Here are used default capabilities, the full test is in permission evaluation bellow,
1436         // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user.
1438         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection')));
1439         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse')));
1440         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse')));
1442         $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse');
1443         $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse');
1445         $this->setUser(0);
1446         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext));
1447         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext));
1448         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1449         $this->assertFalse(has_any_capability($sca, $coursecontext));
1450         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1452         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher));
1453         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher));
1454         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher));
1455         $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher));
1456         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher));
1457         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher));
1459         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin));
1460         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin));
1461         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin));
1462         $this->assertTrue(has_any_capability($sca, $coursecontext, $admin));
1463         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin));
1464         $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin));
1466         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false));
1467         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false));
1468         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false));
1469         $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false));
1470         $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false));
1471         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false));
1473         $this->setUser($teacher);
1474         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1475         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1476         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1477         $this->assertTrue(has_any_capability($sca, $coursecontext));
1478         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1479         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1481         $this->setAdminUser();
1482         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1483         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1484         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext));
1485         $this->assertTrue(has_any_capability($sca, $coursecontext));
1486         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1487         $this->assertTrue(has_all_capabilities($sca, $coursecontext));
1489         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0));
1490         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0));
1491         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0));
1492         $this->assertFalse(has_any_capability($sca, $coursecontext, 0));
1493         $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0));
1494     }
1496     /**
1497      * Test require_capability() exceptions.
1498      * @return void
1499      */
1500     public function test_require_capability() {
1501         $this->resetAfterTest();
1503         $syscontext = context_system::instance();
1505         $this->setUser(0);
1506         $this->assertFalse(has_capability('moodle/site:config', $syscontext));
1507         try {
1508             require_capability('moodle/site:config', $syscontext);
1509             $this->fail('Exception expected from require_capability()');
1510         } catch (Exception $e) {
1511             $this->assertInstanceOf('required_capability_exception', $e);
1512         }
1513         $this->setAdminUser();
1514         $this->assertFalse(has_capability('moodle/site:config', $syscontext, 0));
1515         try {
1516             require_capability('moodle/site:config', $syscontext, 0);
1517             $this->fail('Exception expected from require_capability()');
1518         } catch (Exception $e) {
1519             $this->assertInstanceOf('required_capability_exception', $e);
1520         }
1521         $this->assertFalse(has_capability('moodle/site:config', $syscontext, null, false));
1522         try {
1523             require_capability('moodle/site:config', $syscontext, null, false);
1524             $this->fail('Exception expected from require_capability()');
1525         } catch (Exception $e) {
1526             $this->assertInstanceOf('required_capability_exception', $e);
1527         }
1530     }
1532     /**
1533      * A small functional test of permission evaluations.
1534      * @return void
1535      */
1536     public function test_permission_evaluation() {
1537         global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE;
1539         $this->resetAfterTest(true);
1541         $generator = $this->getDataGenerator();
1543         // Fill the site with some real data
1544         $testcategories = array();
1545         $testcourses = array();
1546         $testpages = array();
1547         $testblocks = array();
1548         $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
1550         $systemcontext = context_system::instance();
1551         $frontpagecontext = context_course::instance(SITEID);
1553         // Add block to system context
1554         $bi = $generator->create_block('online_users');
1555         context_block::instance($bi->id);
1556         $testblocks[] = $bi->id;
1558         // Some users
1559         $testusers = array();
1560         for($i=0; $i<20; $i++) {
1561             $user = $generator->create_user();
1562             $testusers[$i] = $user->id;
1563             $usercontext = context_user::instance($user->id);
1565             // Add block to user profile
1566             $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id));
1567             $testblocks[] = $bi->id;
1568         }
1569         // Deleted user - should be ignored everywhere, can not have context
1570         $generator->create_user(array('deleted'=>1));
1572         // Add block to frontpage
1573         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id));
1574         $frontpageblockcontext = context_block::instance($bi->id);
1575         $testblocks[] = $bi->id;
1577         // Add a resource to frontpage
1578         $page = $generator->create_module('page', array('course'=>$SITE->id));
1579         $testpages[] = $page->id;
1580         $frontpagepagecontext = context_module::instance($page->cmid);
1582         // Add block to frontpage resource
1583         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id));
1584         $frontpagepageblockcontext = context_block::instance($bi->id);
1585         $testblocks[] = $bi->id;
1587         // Some nested course categories with courses
1588         $manualenrol = enrol_get_plugin('manual');
1589         $parentcat = 0;
1590         for($i=0; $i<5; $i++) {
1591             $cat = $generator->create_category(array('parent'=>$parentcat));
1592             $testcategories[] = $cat->id;
1593             $catcontext = context_coursecat::instance($cat->id);
1594             $parentcat = $cat->id;
1596             if ($i >= 4) {
1597                 continue;
1598             }
1600             // Add resource to each category
1601             $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id));
1602             context_block::instance($bi->id);
1604             // Add a few courses to each category
1605             for($j=0; $j<6; $j++) {
1606                 $course = $generator->create_course(array('category'=>$cat->id));
1607                 $testcourses[] = $course->id;
1608                 $coursecontext = context_course::instance($course->id);
1610                 if ($j >= 5) {
1611                     continue;
1612                 }
1613                 // Add manual enrol instance
1614                 $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id)));
1616                 // Add block to each course
1617                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
1618                 $testblocks[] = $bi->id;
1620                 // Add a resource to each course
1621                 $page = $generator->create_module('page', array('course'=>$course->id));
1622                 $testpages[] = $page->id;
1623                 $modcontext = context_module::instance($page->cmid);
1625                 // Add block to each module
1626                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id));
1627                 $testblocks[] = $bi->id;
1628             }
1629         }
1631         // Make sure all contexts were created properly
1632         $count = 1; //system
1633         $count += $DB->count_records('user', array('deleted'=>0));
1634         $count += $DB->count_records('course_categories');
1635         $count += $DB->count_records('course');
1636         $count += $DB->count_records('course_modules');
1637         $count += $DB->count_records('block_instances');
1638         $this->assertEquals($DB->count_records('context'), $count);
1639         $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0);
1640         $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0);
1643         // ====== context_helper::get_level_name() ================================
1645         $levels = context_helper::get_all_levels();
1646         foreach ($levels as $level=>$classname) {
1647             $name = context_helper::get_level_name($level);
1648             $this->assertFalse(empty($name));
1649         }
1652         // ======= context::instance_by_id(), context_xxx::instance();
1654         $context = context::instance_by_id($frontpagecontext->id);
1655         $this->assertSame($context->contextlevel, CONTEXT_COURSE);
1656         $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING));
1657         try {
1658             context::instance_by_id(-1);
1659             $this->fail('exception expected');
1660         } catch (Exception $e) {
1661             $this->assertTrue(true);
1662         }
1663         $this->assertTrue(context_system::instance() instanceof context_system);
1664         $this->assertTrue(context_coursecat::instance($testcategories[0]) instanceof context_coursecat);
1665         $this->assertTrue(context_course::instance($testcourses[0]) instanceof context_course);
1666         $this->assertTrue(context_module::instance($testpages[0]) instanceof context_module);
1667         $this->assertTrue(context_block::instance($testblocks[0]) instanceof context_block);
1669         $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING));
1670         $this->assertFalse(context_course::instance(-1, IGNORE_MISSING));
1671         $this->assertFalse(context_module::instance(-1, IGNORE_MISSING));
1672         $this->assertFalse(context_block::instance(-1, IGNORE_MISSING));
1673         try {
1674             context_coursecat::instance(-1);
1675             $this->fail('exception expected');
1676         } catch (Exception $e) {
1677             $this->assertTrue(true);
1678         }
1679         try {
1680             context_course::instance(-1);
1681             $this->fail('exception expected');
1682         } catch (Exception $e) {
1683             $this->assertTrue(true);
1684         }
1685         try {
1686             context_module::instance(-1);
1687             $this->fail('exception expected');
1688         } catch (Exception $e) {
1689             $this->assertTrue(true);
1690         }
1691         try {
1692             context_block::instance(-1);
1693             $this->fail('exception expected');
1694         } catch (Exception $e) {
1695             $this->assertTrue(true);
1696         }
1699         // ======= $context->get_url(), $context->get_context_name(), $context->get_capabilities() =========
1701         $testcontexts = array();
1702         $testcontexts[CONTEXT_SYSTEM]    = context_system::instance();
1703         $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]);
1704         $testcontexts[CONTEXT_COURSE]    = context_course::instance($testcourses[0]);
1705         $testcontexts[CONTEXT_MODULE]    = context_module::instance($testpages[0]);
1706         $testcontexts[CONTEXT_BLOCK]     = context_block::instance($testblocks[0]);
1708         foreach ($testcontexts as $context) {
1709             $name = $context->get_context_name(true, true);
1710             $this->assertFalse(empty($name));
1712             $this->assertTrue($context->get_url() instanceof moodle_url);
1714             $caps = $context->get_capabilities();
1715             $this->assertTrue(is_array($caps));
1716             foreach ($caps as $cap) {
1717                 $cap = (array)$cap;
1718                 $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask'));
1719             }
1720         }
1721         unset($testcontexts);
1723         // ===== $context->get_course_context() =========================================
1725         $this->assertFalse($systemcontext->get_course_context(false));
1726         try {
1727             $systemcontext->get_course_context();
1728             $this->fail('exception expected');
1729         } catch (Exception $e) {
1730             $this->assertTrue(true);
1731         }
1732         $context = context_coursecat::instance($testcategories[0]);
1733         $this->assertFalse($context->get_course_context(false));
1734         try {
1735             $context->get_course_context();
1736             $this->fail('exception expected');
1737         } catch (Exception $e) {
1738             $this->assertTrue(true);
1739         }
1740         $this->assertSame($frontpagecontext->get_course_context(true), $frontpagecontext);
1741         $this->assertSame($frontpagepagecontext->get_course_context(true), $frontpagecontext);
1742         $this->assertSame($frontpagepageblockcontext->get_course_context(true), $frontpagecontext);
1745         // ======= $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() =======
1747         $userid = reset($testusers);
1748         $usercontext = context_user::instance($userid);
1749         $this->assertSame($usercontext->get_parent_context(), $systemcontext);
1750         $this->assertSame($usercontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext));
1751         $this->assertSame($usercontext->get_parent_contexts(true), array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext));
1753         $this->assertSame($systemcontext->get_parent_contexts(), array());
1754         $this->assertSame($systemcontext->get_parent_contexts(true), array($systemcontext->id=>$systemcontext));
1755         $this->assertSame($systemcontext->get_parent_context_ids(), array());
1756         $this->assertSame($systemcontext->get_parent_context_ids(true), array($systemcontext->id));
1758         $this->assertSame($frontpagecontext->get_parent_context(), $systemcontext);
1759         $this->assertSame($frontpagecontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext));
1760         $this->assertSame($frontpagecontext->get_parent_contexts(true), array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext));
1761         $this->assertSame($frontpagecontext->get_parent_context_ids(), array($systemcontext->id));
1762         $this->assertEquals($frontpagecontext->get_parent_context_ids(true), array($frontpagecontext->id, $systemcontext->id));
1764         $this->assertSame($systemcontext->get_parent_context(), false);
1765         $frontpagecontext = context_course::instance($SITE->id);
1766         $parent = $systemcontext;
1767         foreach ($testcategories as $catid) {
1768             $catcontext = context_coursecat::instance($catid);
1769             $this->assertSame($catcontext->get_parent_context(), $parent);
1770             $parent = $catcontext;
1771         }
1772         $this->assertSame($frontpagepagecontext->get_parent_context(), $frontpagecontext);
1773         $this->assertSame($frontpageblockcontext->get_parent_context(), $frontpagecontext);
1774         $this->assertSame($frontpagepageblockcontext->get_parent_context(), $frontpagepagecontext);
1777         // ====== $context->get_child_contexts() ================================
1779         $children = $systemcontext->get_child_contexts();
1780         $this->resetDebugging();
1781         $this->assertEquals(count($children)+1, $DB->count_records('context'));
1783         $context = context_coursecat::instance($testcategories[3]);
1784         $children = $context->get_child_contexts();
1785         $countcats    = 0;
1786         $countcourses = 0;
1787         $countblocks  = 0;
1788         foreach ($children as $child) {
1789             if ($child->contextlevel == CONTEXT_COURSECAT) {
1790                 $countcats++;
1791             }
1792             if ($child->contextlevel == CONTEXT_COURSE) {
1793                 $countcourses++;
1794             }
1795             if ($child->contextlevel == CONTEXT_BLOCK) {
1796                 $countblocks++;
1797             }
1798         }
1799         $this->assertEquals(count($children), 8);
1800         $this->assertEquals($countcats, 1);
1801         $this->assertEquals($countcourses, 6);
1802         $this->assertEquals($countblocks, 1);
1804         $context = context_course::instance($testcourses[2]);
1805         $children = $context->get_child_contexts();
1806         $this->assertEquals(count($children), 7); // depends on number of default blocks
1808         $context = context_module::instance($testpages[3]);
1809         $children = $context->get_child_contexts();
1810         $this->assertEquals(count($children), 1);
1812         $context = context_block::instance($testblocks[1]);
1813         $children = $context->get_child_contexts();
1814         $this->assertEquals(count($children), 0);
1816         unset($children);
1817         unset($countcats);
1818         unset($countcourses);
1819         unset($countblocks);
1822         // ======= context_helper::reset_caches() ============================
1824         context_helper::reset_caches();
1825         $this->assertEquals(context_inspection::test_context_cache_size(), 0);
1826         context_course::instance($SITE->id);
1827         $this->assertEquals(context_inspection::test_context_cache_size(), 1);
1830         // ======= context preloading ========================================
1832         context_helper::reset_caches();
1833         $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')."
1834                   FROM {context} c
1835                  WHERE c.contextlevel <> ".CONTEXT_SYSTEM;
1836         $records = $DB->get_records_sql($sql);
1837         $firstrecord = reset($records);
1838         $columns = context_helper::get_preload_record_columns('c');
1839         $firstrecord = (array)$firstrecord;
1840         $this->assertSame(array_keys($firstrecord), array_values($columns));
1841         context_helper::reset_caches();
1842         foreach ($records as $record) {
1843             context_helper::preload_from_record($record);
1844             $this->assertEquals($record, new stdClass());
1845         }
1846         $this->assertEquals(context_inspection::test_context_cache_size(), count($records));
1847         unset($records);
1848         unset($columns);
1850         context_helper::reset_caches();
1851         context_helper::preload_course($SITE->id);
1852         $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id));
1853         $this->assertEquals(6 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // depends on number of default blocks
1855         // ====== assign_capability(), unassign_capability() ====================
1857         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1858         $this->assertFalse($rc);
1859         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id);
1860         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1861         $this->assertEquals($rc->permission, CAP_ALLOW);
1862         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id);
1863         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1864         $this->assertEquals($rc->permission, CAP_ALLOW);
1865         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true);
1866         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1867         $this->assertEquals($rc->permission, CAP_PREVENT);
1869         assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext);
1870         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1871         $this->assertFalse($rc);
1872         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext);
1873         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true);
1874         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1875         $this->assertFalse($rc);
1876         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true);
1877         unset($rc);
1879         accesslib_clear_all_caches(false); // must be done after assign_capability()
1882         // ======= role_assign(), role_unassign(), role_unassign_all() ==============
1884         $context = context_course::instance($testcourses[1]);
1885         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0);
1886         role_assign($allroles['teacher'], $testusers[1], $context->id);
1887         role_assign($allroles['teacher'], $testusers[2], $context->id);
1888         role_assign($allroles['manager'], $testusers[1], $context->id);
1889         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 3);
1890         role_unassign($allroles['teacher'], $testusers[1], $context->id);
1891         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 2);
1892         role_unassign_all(array('contextid'=>$context->id));
1893         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0);
1894         unset($context);
1896         accesslib_clear_all_caches(false); // just in case
1899         // ====== has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends ========================
1901         $adminid = get_admin()->id;
1902         $guestid = $CFG->siteguest;
1904         // Enrol some users into some courses
1905         $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST);
1906         $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST);
1907         $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id');
1908         $cm1 = reset($cms);
1909         $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id');
1910         $block1 = reset($blocks);
1911         $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id));
1912         $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id));
1913         for($i=0; $i<9; $i++) {
1914             $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']);
1915         }
1916         $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']);
1917         $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']);
1919         for($i=10; $i<15; $i++) {
1920             $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']);
1921         }
1922         $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']);
1924         // Add tons of role assignments - the more the better
1925         role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2]));
1926         role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1]));
1927         role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id));
1928         role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id));
1929         role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id));
1930         role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id));
1931         role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id));
1932         role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id));
1934         role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id));
1935         role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id));
1937         // Add tons of overrides - the more the better
1938         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true);
1939         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true);
1940         assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true);
1941         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true);
1942         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true);
1944         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true);
1945         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true);
1946         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true);
1947         assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true);
1948         assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true);
1950         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true);
1951         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true);
1952         assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true);
1953         assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true);
1955         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true);
1957         accesslib_clear_all_caches(false); // must be done after assign_capability()
1959         // Extra tests for guests and not-logged-in users because they can not be verified by cross checking
1960         // with get_users_by_capability() where they are ignored
1961         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid));
1962         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid));
1963         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid));
1964         $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid));
1966         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0));
1967         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0));
1968         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0));
1969         $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0));
1971         $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11]));
1972         $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11]));
1973         $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11]));
1974         $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11]));
1976         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9]));
1977         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9]));
1978         $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9]));
1980         // Test the list of enrolled users
1981         $coursecontext = context_course::instance($course1->id);
1982         $enrolled = get_enrolled_users($coursecontext);
1983         $this->assertEquals(count($enrolled), 10);
1984         for($i=0; $i<10; $i++) {
1985             $this->assertTrue(isset($enrolled[$testusers[$i]]));
1986         }
1987         $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update');
1988         $this->assertEquals(count($enrolled), 1);
1989         $this->assertTrue(isset($enrolled[$testusers[9]]));
1990         unset($enrolled);
1992         // role switching
1993         $userid = $testusers[9];
1994         $USER = $DB->get_record('user', array('id'=>$userid));
1995         load_all_capabilities();
1996         $coursecontext = context_course::instance($course1->id);
1997         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
1998         $this->assertFalse(is_role_switched($course1->id));
1999         role_switch($allroles['student'], $coursecontext);
2000         $this->assertTrue(is_role_switched($course1->id));
2001         $this->assertEquals($USER->access['rsw'][$coursecontext->path],  $allroles['student']);
2002         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2003         reload_all_capabilities();
2004         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2005         role_switch(0, $coursecontext);
2006         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2007         $userid = $adminid;
2008         $USER = $DB->get_record('user', array('id'=>$userid));
2009         load_all_capabilities();
2010         $coursecontext = context_course::instance($course1->id);
2011         $blockcontext = context_block::instance($block1->id);
2012         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
2013         role_switch($allroles['student'], $coursecontext);
2014         $this->assertEquals($USER->access['rsw'][$coursecontext->path],  $allroles['student']);
2015         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
2016         reload_all_capabilities();
2017         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
2018         load_all_capabilities();
2019         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
2021         // temp course role for enrol
2022         $DB->delete_records('cache_flags', array()); // this prevents problem with dirty contexts immediately resetting the temp role - this is a known problem...
2023         $userid = $testusers[5];
2024         $roleid = $allroles['editingteacher'];
2025         $USER = $DB->get_record('user', array('id'=>$userid));
2026         load_all_capabilities();
2027         $coursecontext = context_course::instance($course1->id);
2028         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2029         $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid]));
2030         load_temp_course_role($coursecontext, $roleid);
2031         $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid);
2032         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2033         remove_temp_course_roles($coursecontext);
2034         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
2035         load_temp_course_role($coursecontext, $roleid);
2036         reload_all_capabilities();
2037         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
2038         $USER = new stdClass();
2039         $USER->id = 0;
2041         // Now cross check has_capability() with get_users_by_capability(), each using different code paths,
2042         // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong,
2043         // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users)
2044         $contexts = $DB->get_records('context', array(), 'id');
2045         $contexts = array_values($contexts);
2046         $capabilities = $DB->get_records('capabilities', array(), 'id');
2047         $capabilities = array_values($capabilities);
2048         $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']);
2049         $userids = array_values($testusers);
2050         $userids[] = get_admin()->id;
2052         if (!PHPUNIT_LONGTEST) {
2053             $contexts = array_slice($contexts, 0, 10);
2054             $capabilities = array_slice($capabilities, 0, 5);
2055             $userids = array_slice($userids, 0, 5);
2056         }
2058         // Random time!
2059         //srand(666);
2060         foreach($userids as $userid) { // no guest or deleted
2061             // each user gets 0-10 random roles
2062             $rcount = rand(0, 10);
2063             for($j=0; $j<$rcount; $j++) {
2064                 $roleid = $roles[rand(0, count($roles)-1)];
2065                 $contextid = $contexts[rand(0, count($contexts)-1)]->id;
2066                 role_assign($roleid, $userid, $contextid);
2067             }
2068         }
2070         $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT);
2071         $maxoverrides = count($contexts)*10;
2072         for($j=0; $j<$maxoverrides; $j++) {
2073             $roleid = $roles[rand(0, count($roles)-1)];
2074             $contextid = $contexts[rand(0, count($contexts)-1)]->id;
2075             $permission = $permissions[rand(0,count($permissions)-1)];
2076             $capname = $capabilities[rand(0, count($capabilities)-1)]->name;
2077             assign_capability($capname, $permission, $roleid, $contextid, true);
2078         }
2079         unset($permissions);
2080         unset($roles);
2082         accesslib_clear_all_caches(false); // must be done after assign_capability()
2084         // Test time - let's set up some real user, just in case the logic for USER affects the others...
2085         $USER = $DB->get_record('user', array('id'=>$testusers[3]));
2086         load_all_capabilities();
2088         $userids[] = $CFG->siteguest;
2089         $userids[] = 0; // not-logged-in user
2090         $userids[] = -1; // non-existent user
2092         foreach ($contexts as $crecord) {
2093             $context = context::instance_by_id($crecord->id);
2094             if ($coursecontext = $context->get_course_context(false)) {
2095                 $enrolled = get_enrolled_users($context);
2096             } else {
2097                 $enrolled = array();
2098             }
2099             foreach ($capabilities as $cap) {
2100                 $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username');
2101                 if ($enrolled) {
2102                     $enrolledwithcap = get_enrolled_users($context, $cap->name);
2103                 } else {
2104                     $enrolledwithcap = array();
2105                 }
2106                 foreach ($userids as $userid) {
2107                     if ($userid == 0 or isguestuser($userid)) {
2108                         if ($userid == 0) {
2109                             $CFG->forcelogin = true;
2110                             $this->assertFalse(has_capability($cap->name, $context, $userid));
2111                             unset($CFG->forcelogin);
2112                         }
2113                         if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) {
2114                             $this->assertFalse(has_capability($cap->name, $context, $userid));
2115                         }
2116                         $this->assertFalse(isset($allowed[$userid]));
2117                     } else {
2118                         if (is_siteadmin($userid)) {
2119                             $this->assertTrue(has_capability($cap->name, $context, $userid, true));
2120                         }
2121                         $hascap = has_capability($cap->name, $context, $userid, false);
2122                         $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
2123                         if (isset($enrolled[$userid])) {
2124                             $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
2125                         }
2126                     }
2127                 }
2128             }
2129         }
2130         // Back to nobody
2131         $USER = new stdClass();
2132         $USER->id = 0;
2133         unset($contexts);
2134         unset($userids);
2135         unset($capabilities);
2137         // Now let's do all the remaining tests that break our carefully prepared fake site
2141         // ======= $context->mark_dirty() =======================================
2143         $DB->delete_records('cache_flags', array());
2144         accesslib_clear_all_caches(false);
2145         $systemcontext->mark_dirty();
2146         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2147         $this->assertTrue(isset($dirty[$systemcontext->path]));
2148         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path]));
2151         // ======= $context->reload_if_dirty(); =================================
2153         $DB->delete_records('cache_flags', array());
2154         accesslib_clear_all_caches(false);
2155         load_all_capabilities();
2156         $context = context_course::instance($testcourses[2]);
2157         $page = $DB->get_record('page', array('course'=>$testcourses[2]));
2158         $pagecm = get_coursemodule_from_instance('page', $page->id);
2159         $pagecontext = context_module::instance($pagecm->id);
2161         $context->mark_dirty();
2162         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2163         $USER->access['test'] = true;
2164         $context->reload_if_dirty();
2165         $this->assertFalse(isset($USER->access['test']));
2167         $context->mark_dirty();
2168         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2169         $USER->access['test'] = true;
2170         $pagecontext->reload_if_dirty();
2171         $this->assertFalse(isset($USER->access['test']));
2174         // ======= context_helper::build_all_paths() ============================
2176         $oldcontexts = $DB->get_records('context', array(), 'id');
2177         $DB->set_field_select('context', 'path', NULL, "contextlevel <> ".CONTEXT_SYSTEM);
2178         $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM);
2179         context_helper::build_all_paths();
2180         $newcontexts = $DB->get_records('context', array(), 'id');
2181         $this->assertEquals($oldcontexts, $newcontexts);
2182         unset($oldcontexts);
2183         unset($newcontexts);
2186         // ======= $context->reset_paths() ======================================
2188         $context = context_course::instance($testcourses[2]);
2189         $children = $context->get_child_contexts();
2190         $context->reset_paths(false);
2191         $this->assertSame($DB->get_field('context', 'path', array('id'=>$context->id)), NULL);
2192         $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), 0);
2193         foreach ($children as $child) {
2194             $this->assertSame($DB->get_field('context', 'path', array('id'=>$child->id)), NULL);
2195             $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$child->id)), 0);
2196         }
2197         $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0)));
2198         $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>NULL)));
2200         $context = context_course::instance($testcourses[2]);
2201         $context->reset_paths(true);
2202         $context = context_course::instance($testcourses[2]);
2203         $this->assertEquals($DB->get_field('context', 'path', array('id'=>$context->id)), $context->path);
2204         $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), $context->depth);
2205         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2206         $this->assertEquals(0, $DB->count_records('context', array('path'=>NULL)));
2209         // ====== $context->update_moved(); ======================================
2211         accesslib_clear_all_caches(false);
2212         $DB->delete_records('cache_flags', array());
2213         $course = $DB->get_record('course', array('id'=>$testcourses[0]));
2214         $context = context_course::instance($course->id);
2215         $oldpath = $context->path;
2216         $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2217         $categorycontext = context_coursecat::instance($miscid);
2218         $course->category = $miscid;
2219         $DB->update_record('course', $course);
2220         $context->update_moved($categorycontext);
2222         $context = context_course::instance($course->id);
2223         $this->assertEquals($context->get_parent_context(), $categorycontext);
2224         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2225         $this->assertTrue(isset($dirty[$oldpath]));
2226         $this->assertTrue(isset($dirty[$context->path]));
2229         // ====== $context->delete_content() =====================================
2231         context_helper::reset_caches();
2232         $context = context_module::instance($testpages[3]);
2233         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2234         $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2235         $context->delete_content();
2236         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2237         $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2240         // ====== $context->delete() =============================
2242         context_helper::reset_caches();
2243         $context = context_module::instance($testpages[4]);
2244         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2245         $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2246         $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id));
2247         $bicontext = context_block::instance($bi->id);
2248         $DB->delete_records('cache_flags', array());
2249         $context->delete(); // should delete also linked blocks
2250         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2251         $this->assertTrue(isset($dirty[$context->path]));
2252         $this->assertFalse($DB->record_exists('context', array('id'=>$context->id)));
2253         $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id)));
2254         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4])));
2255         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id)));
2256         $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2257         context_module::instance($testpages[4]);
2260         // ====== context_helper::delete_instance() =============================
2262         context_helper::reset_caches();
2263         $lastcourse = array_pop($testcourses);
2264         $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2265         $coursecontext = context_course::instance($lastcourse);
2266         $this->assertEquals(context_inspection::test_context_cache_size(), 1);
2267         $this->assertFalse($coursecontext->instanceid == CONTEXT_COURSE);
2268         $DB->delete_records('cache_flags', array());
2269         context_helper::delete_instance(CONTEXT_COURSE, $lastcourse);
2270         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2271         $this->assertTrue(isset($dirty[$coursecontext->path]));
2272         $this->assertEquals(context_inspection::test_context_cache_size(), 0);
2273         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2274         context_course::instance($lastcourse);
2277         // ======= context_helper::create_instances() ==========================
2279         $prevcount = $DB->count_records('context');
2280         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2281         context_helper::create_instances(null, true);
2282         $this->assertSame($DB->count_records('context'), $prevcount);
2283         $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0);
2284         $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0);
2286         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2287         $DB->delete_records('block_instances', array());
2288         $prevcount = $DB->count_records('context');
2289         $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM);
2290         context_helper::create_instances(null, true);
2291         $this->assertSame($DB->count_records('context'), $prevcount);
2292         $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0);
2293         $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0);
2296         // ======= context_helper::cleanup_instances() ==========================
2298         $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2299         $DB->delete_records('course', array('id'=>$lastcourse));
2300         $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2301         $DB->delete_records('course_categories', array('id'=>$lastcategory));
2302         $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2303         $DB->delete_records('user', array('id'=>$lastuser));
2304         $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2305         $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2306         context_helper::cleanup_instances();
2307         $count = 1; //system
2308         $count += $DB->count_records('user', array('deleted'=>0));
2309         $count += $DB->count_records('course_categories');
2310         $count += $DB->count_records('course');
2311         $count += $DB->count_records('course_modules');
2312         $count += $DB->count_records('block_instances');
2313         $this->assertEquals($DB->count_records('context'), $count);
2316         // ======= context cache size restrictions ==============================
2318         $testusers= array();
2319         for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2320             $user = $generator->create_user();
2321             $testusers[$i] = $user->id;
2322         }
2323         context_helper::create_instances(null, true);
2324         context_helper::reset_caches();
2325         for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2326             context_user::instance($testusers[$i]);
2327             if ($i == CONTEXT_CACHE_MAX_SIZE - 1) {
2328                 $this->assertEquals(context_inspection::test_context_cache_size(), CONTEXT_CACHE_MAX_SIZE);
2329             } else if ($i == CONTEXT_CACHE_MAX_SIZE) {
2330                 // once the limit is reached roughly 1/3 of records should be removed from cache
2331                 $this->assertEquals(context_inspection::test_context_cache_size(), (int)(CONTEXT_CACHE_MAX_SIZE * (2/3) +102));
2332             }
2333         }
2334         // We keep the first 100 cached
2335         $prevsize = context_inspection::test_context_cache_size();
2336         for ($i=0; $i<100; $i++) {
2337             context_user::instance($testusers[$i]);
2338             $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize);
2339         }
2340         context_user::instance($testusers[102]);
2341         $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize+1);
2342         unset($testusers);
2346         // =================================================================
2347         // ======= basic test of legacy functions ==========================
2348         // =================================================================
2349         // note: watch out, the fake site might be pretty borked already
2351         $this->assertSame(get_system_context(), context_system::instance());
2353         foreach ($DB->get_records('context') as $contextid=>$record) {
2354             $context = context::instance_by_id($contextid);
2355             $this->assertSame(get_context_instance_by_id($contextid, IGNORE_MISSING), $context);
2356             $this->assertSame(get_context_instance($record->contextlevel, $record->instanceid), $context);
2357             $this->assertSame(get_parent_contexts($context), $context->get_parent_context_ids());
2358             if ($context->id == SYSCONTEXTID) {
2359                 $this->assertSame(get_parent_contextid($context), false);
2360             } else {
2361                 $this->assertSame(get_parent_contextid($context), $context->get_parent_context()->id);
2362             }
2363         }
2365         $children = get_child_contexts($systemcontext);
2366         // Using assertEquals here as assertSame fails for some reason...
2367         $this->assertEquals($children, $systemcontext->get_child_contexts());
2368         $this->assertEquals(count($children), $DB->count_records('context')-1);
2369         $this->resetDebugging();
2370         unset($children);
2372         // Make sure a debugging is thrown.
2373         get_context_instance($record->contextlevel, $record->instanceid);
2374         $this->assertDebuggingCalled('get_context_instance() is deprecated, please use context_xxxx::instance() instead.', DEBUG_DEVELOPER);
2375         get_context_instance_by_id($record->id);
2376         $this->assertDebuggingCalled('get_context_instance_by_id() is deprecated, please use context::instance_by_id($id) instead.', DEBUG_DEVELOPER);
2377         get_system_context();
2378         $this->assertDebuggingCalled('get_system_context() is deprecated, please use context_system::instance() instead.', DEBUG_DEVELOPER);
2379         get_parent_contexts($context);
2380         $this->assertDebuggingCalled('get_parent_contexts() is deprecated, please use $context->get_parent_context_ids() instead.', DEBUG_DEVELOPER);
2381         get_parent_contextid($context);
2382         $this->assertDebuggingCalled('get_parent_contextid() is deprecated, please use $context->get_parent_context() instead.', DEBUG_DEVELOPER);
2383         get_child_contexts($frontpagecontext);
2384         $this->assertDebuggingCalled('get_child_contexts() is deprecated, please use $context->get_child_contexts() instead.', DEBUG_DEVELOPER);
2386         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2387         create_contexts();
2388         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK)));
2390         $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK));
2391         build_context_path();
2392         $this->assertFalse($DB->record_exists('context', array('depth'=>0)));
2394         $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2395         $DB->delete_records('course', array('id'=>$lastcourse));
2396         $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2397         $DB->delete_records('course_categories', array('id'=>$lastcategory));
2398         $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2399         $DB->delete_records('user', array('id'=>$lastuser));
2400         $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2401         $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2402         cleanup_contexts();
2403         $count = 1; //system
2404         $count += $DB->count_records('user', array('deleted'=>0));
2405         $count += $DB->count_records('course_categories');
2406         $count += $DB->count_records('course');
2407         $count += $DB->count_records('course_modules');
2408         $count += $DB->count_records('block_instances');
2409         $this->assertEquals($DB->count_records('context'), $count);
2411         context_helper::reset_caches();
2412         preload_course_contexts($SITE->id);
2413         $this->assertEquals(1 + $DB->count_records('course_modules', array('course' => $SITE->id)),
2414                 context_inspection::test_context_cache_size());
2416         context_helper::reset_caches();
2417         list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx');
2418         $sql = "SELECT c.id $select FROM {course_categories} c $join";
2419         $records = $DB->get_records_sql($sql);
2420         foreach ($records as $record) {
2421             context_instance_preload($record);
2422             $record = (array)$record;
2423             $this->assertEquals(1, count($record)); // only id left
2424         }
2425         $this->assertEquals(count($records), context_inspection::test_context_cache_size());
2427         accesslib_clear_all_caches(true);
2428         $DB->delete_records('cache_flags', array());
2429         mark_context_dirty($systemcontext->path);
2430         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2431         $this->assertTrue(isset($dirty[$systemcontext->path]));
2433         accesslib_clear_all_caches(false);
2434         $DB->delete_records('cache_flags', array());
2435         $course = $DB->get_record('course', array('id'=>$testcourses[2]));
2436         $context = context_course::instance($course->id);
2437         $oldpath = $context->path;
2438         $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2439         $categorycontext = context_coursecat::instance($miscid);
2440         $course->category = $miscid;
2441         $DB->update_record('course', $course);
2442         context_moved($context, $categorycontext);
2443         $context = context_course::instance($course->id);
2444         $this->assertEquals($context->get_parent_context(), $categorycontext);
2446         $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2447         delete_context(CONTEXT_COURSE, $testcourses[2]);
2448         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2450         $name = get_contextlevel_name(CONTEXT_COURSE);
2451         $this->assertFalse(empty($name));
2453         $context = context_course::instance($testcourses[2]);
2454         $name = print_context_name($context);
2455         $this->assertFalse(empty($name));
2457         $url = get_context_url($coursecontext);
2458         $this->assertFalse($url instanceof modole_url);
2460         $pagecm = get_coursemodule_from_instance('page', $testpages[7]);
2461         $context = context_module::instance($pagecm->id);
2462         $coursecontext = get_course_context($context);
2463         $this->assertEquals($coursecontext->contextlevel, CONTEXT_COURSE);
2464         $this->assertEquals(get_courseid_from_context($context), $pagecm->course);
2466         $caps = fetch_context_capabilities($systemcontext);
2467         $this->assertTrue(is_array($caps));
2468         unset($caps);
2469     }
2471     /**
2472      * Test updating of role capabilities during upgrade
2473      * @return void
2474      */
2475     public function test_update_capabilities() {
2476         global $DB, $SITE;
2478         $this->resetAfterTest(true);
2480         $froncontext = context_course::instance($SITE->id);
2481         $student = $DB->get_record('role', array('archetype'=>'student'));
2482         $teacher = $DB->get_record('role', array('archetype'=>'teacher'));
2484         $existingcaps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2486         $this->assertFalse(isset($existingcaps['moodle/site:restore']));         // moved to new 'moodle/restore:restorecourse'
2487         $this->assertTrue(isset($existingcaps['moodle/restore:restorecourse'])); // new cap from 'moodle/site:restore'
2488         $this->assertTrue(isset($existingcaps['moodle/site:sendmessage']));      // new capability
2489         $this->assertTrue(isset($existingcaps['moodle/backup:backupcourse']));
2490         $this->assertTrue(isset($existingcaps['moodle/backup:backupsection']));  // cloned from 'moodle/backup:backupcourse'
2491         $this->assertTrue(isset($existingcaps['moodle/site:approvecourse']));    // updated bitmask
2492         $this->assertTrue(isset($existingcaps['moodle/course:manageactivities']));
2493         $this->assertTrue(isset($existingcaps['mod/page:addinstance']));         // cloned from core 'moodle/course:manageactivities'
2495         // fake state before upgrade
2496         $DB->set_field('capabilities', 'name', 'moodle/site:restore', array('name'=>'moodle/restore:restorecourse'));
2497         $DB->set_field('role_capabilities', 'capability', 'moodle/site:restore', array('capability'=>'moodle/restore:restorecourse'));
2498         assign_capability('moodle/site:restore', CAP_PROHIBIT, $teacher->id, $froncontext->id, true);
2499         $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/site:restore', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2501         $DB->delete_records('role_capabilities', array('capability'=>'moodle/site:sendmessage'));
2502         $DB->delete_records('capabilities', array('name'=>'moodle/site:sendmessage'));
2504         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupsection'));
2505         $DB->delete_records('capabilities', array('name'=>'moodle/backup:backupsection'));
2506         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2507         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2509         $DB->set_field('capabilities', 'riskbitmask', 0, array('name'=>'moodle/site:approvecourse'));
2511         $DB->delete_records('role_capabilities', array('capability'=>'mod/page:addinstance'));
2512         $DB->delete_records('capabilities', array('name'=>'mod/page:addinstance'));
2513         assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2514         assign_capability('moodle/course:manageactivities', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2516         // execute core
2517         update_capabilities('moodle');
2519         // only core should be upgraded
2520         $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2522         $this->assertFalse(isset($existingcaps['moodle/site:restore']));
2523         $this->assertTrue(isset($caps['moodle/restore:restorecourse']));
2524         $this->assertEquals($existingcaps['moodle/restore:restorecourse'], $caps['moodle/restore:restorecourse']);
2525         $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/restore:restorecourse', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2526         $this->assertEquals($perms1, $perms2);
2528         $this->assertTrue(isset($caps['moodle/site:sendmessage']));
2529         $this->assertEquals($existingcaps['moodle/site:sendmessage'], $caps['moodle/site:sendmessage']);
2531         $this->assertTrue(isset($caps['moodle/backup:backupsection']));
2532         $this->assertEquals($existingcaps['moodle/backup:backupsection'], $caps['moodle/backup:backupsection']);
2533         $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/backup:backupcourse', 'moodle/backup:backupsection'));
2534         foreach ($roles as $role) {
2535             $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2536             $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupsection', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2537             $this->assertEquals($perms1, $perms2);
2538         }
2540         $this->assertTrue(isset($caps['moodle/site:approvecourse']));
2541         $this->assertEquals($existingcaps['moodle/site:approvecourse'], $caps['moodle/site:approvecourse']);
2543         $this->assertFalse(isset($caps['mod/page:addinstance']));
2545         // execute plugin
2546         update_capabilities('mod_page');
2547         $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2548         $this->assertTrue(isset($caps['mod/page:addinstance']));
2549         $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/course:manageactivities', 'mod/page:addinstance'));
2550         foreach ($roles as $role) {
2551             $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/course:manageactivities', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2552             $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'mod/page:addinstance', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2553         }
2554         $this->assertEquals($perms1, $perms2);
2555     }