49966c7e0cec0bba27e88b8f41dd7c4517626ede
[moodle.git] / lib / tests / accesslib_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Full functional accesslib test.
19  *
20  * @package    core
21  * @category   phpunit
22  * @copyright  2011 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Functional test for accesslib.php
31  *
32  * Note: execution may take many minutes especially on slower servers.
33  */
34 class core_accesslib_testcase extends advanced_testcase {
35     /**
36      * Verify comparison of context instances in phpunit asserts.
37      */
38     public function test_context_comparisons() {
39         $frontpagecontext1 = context_course::instance(SITEID);
40         context_helper::reset_caches();
41         $frontpagecontext2 = context_course::instance(SITEID);
42         $this->assertEquals($frontpagecontext1, $frontpagecontext2);
44         $user1 = context_user::instance(1);
45         $user2 = context_user::instance(2);
46         $this->assertNotEquals($user1, $user2);
47     }
49     /**
50      * Test resetting works.
51      */
52     public function test_accesslib_clear_all_caches() {
53         global $ACCESSLIB_PRIVATE;
55         $this->resetAfterTest();
57         $this->setAdminUser();
58         load_all_capabilities();
60         $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
61         $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
62         $this->assertNotEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
63         accesslib_clear_all_caches(true);
64         $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
65         $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
66         $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts);
67         $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
68     }
70     /**
71      * Test getting of role access
72      */
73     public function test_get_role_access() {
74         global $DB;
76         $roles = $DB->get_records('role');
77         foreach ($roles as $role) {
78             $access = get_role_access($role->id);
80             $this->assertTrue(is_array($access));
81             $this->assertTrue(is_array($access['ra']));
82             $this->assertTrue(is_array($access['rdef']));
83             $this->assertTrue(isset($access['rdef_count']));
84             $this->assertTrue(is_array($access['loaded']));
85             $this->assertTrue(isset($access['time']));
86             $this->assertTrue(is_array($access['rsw']));
87         }
89         // Note: the data is validated in the functional permission evaluation test at the end of this testcase.
90     }
92     /**
93      * Test getting of guest role.
94      */
95     public function test_get_guest_role() {
96         global $CFG;
98         $guest = get_guest_role();
99         $this->assertEquals('guest', $guest->archetype);
100         $this->assertEquals('guest', $guest->shortname);
102         $this->assertEquals($CFG->guestroleid, $guest->id);
103     }
105     /**
106      * Test if user is admin.
107      */
108     public function test_is_siteadmin() {
109         global $DB, $CFG;
111         $this->resetAfterTest();
113         $users = $DB->get_records('user');
115         foreach ($users as $user) {
116             $this->setUser(0);
117             if ($user->username === 'admin') {
118                 $this->assertTrue(is_siteadmin($user));
119                 $this->assertTrue(is_siteadmin($user->id));
120                 $this->setUser($user);
121                 $this->assertTrue(is_siteadmin());
122                 $this->assertTrue(is_siteadmin(null));
123             } else {
124                 $this->assertFalse(is_siteadmin($user));
125                 $this->assertFalse(is_siteadmin($user->id));
126                 $this->setUser($user);
127                 $this->assertFalse(is_siteadmin());
128                 $this->assertFalse(is_siteadmin(null));
129             }
130         }
132         // Change the site admin list and check that it still works with
133         // multiple admins. We do this with userids only (not real user
134         // accounts) because it makes the test simpler.
135         $before = $CFG->siteadmins;
136         set_config('siteadmins', '666,667,668');
137         $this->assertTrue(is_siteadmin(666));
138         $this->assertTrue(is_siteadmin(667));
139         $this->assertTrue(is_siteadmin(668));
140         $this->assertFalse(is_siteadmin(669));
141         set_config('siteadmins', '13');
142         $this->assertTrue(is_siteadmin(13));
143         $this->assertFalse(is_siteadmin(666));
144         set_config('siteadmins', $before);
145     }
147     /**
148      * Test if user is enrolled in a course
149      */
150     public function test_is_enrolled() {
151         global $DB;
153         $this->resetAfterTest();
155         // Generate data.
156         $user = $this->getDataGenerator()->create_user();
157         $course = $this->getDataGenerator()->create_course();
158         $coursecontext = context_course::instance($course->id);
159         $role = $DB->get_record('role', array('shortname'=>'student'));
161         // There should be a manual enrolment as part of the default install.
162         $plugin = enrol_get_plugin('manual');
163         $instance = $DB->get_record('enrol', array(
164             'courseid' => $course->id,
165             'enrol' => 'manual',
166         ));
167         $this->assertNotSame(false, $instance);
169         // Enrol the user in the course.
170         $plugin->enrol_user($instance, $user->id, $role->id);
172         // We'll test with the mod/assign:submit capability.
173         $capability= 'mod/assign:submit';
174         $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
176         // Switch to our user.
177         $this->setUser($user);
179         // Ensure that the user has the capability first.
180         $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
182         // We first test whether the user is enrolled on the course as this
183         // seeds the cache, then we test for the capability.
184         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
185         $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
187         // Prevent the capability for this user role.
188         assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
189         $coursecontext->mark_dirty();
190         $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
192         // Again, we seed the cache first by checking initial enrolment,
193         // and then we test the actual capability.
194         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
195         $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
196     }
198     /**
199      * Test logged in test.
200      */
201     public function test_isloggedin() {
202         global $USER;
204         $this->resetAfterTest();
206         $USER->id = 0;
207         $this->assertFalse(isloggedin());
208         $USER->id = 1;
209         $this->assertTrue(isloggedin());
210     }
212     /**
213      * Test guest user test.
214      */
215     public function test_isguestuser() {
216         global $DB;
218         $this->resetAfterTest();
220         $guest = $DB->get_record('user', array('username'=>'guest'));
221         $this->setUser(0);
222         $this->assertFalse(isguestuser());
223         $this->setAdminUser();
224         $this->assertFalse(isguestuser());
225         $this->assertTrue(isguestuser($guest));
226         $this->assertTrue(isguestuser($guest->id));
227         $this->setUser($guest);
228         $this->assertTrue(isguestuser());
230         $users = $DB->get_records('user');
231         foreach ($users as $user) {
232             if ($user->username === 'guest') {
233                 continue;
234             }
235             $this->assertFalse(isguestuser($user));
236         }
237     }
239     /**
240      * Test capability riskiness.
241      */
242     public function test_is_safe_capability() {
243         global $DB;
244         // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap.
245         $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST);
246         $this->assertFalse(is_safe_capability($capability));
247     }
249     /**
250      * Test context fetching.
251      */
252     public function test_get_context_info_array() {
253         $this->resetAfterTest();
255         $syscontext = context_system::instance();
256         $user = $this->getDataGenerator()->create_user();
257         $usercontext = context_user::instance($user->id);
258         $course = $this->getDataGenerator()->create_course();
259         $catcontext = context_coursecat::instance($course->category);
260         $coursecontext = context_course::instance($course->id);
261         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
262         $modcontext = context_module::instance($page->cmid);
263         $cm = get_coursemodule_from_instance('page', $page->id);
264         $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
265         $block1context = context_block::instance($block1->id);
266         $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id));
267         $block2context = context_block::instance($block2->id);
269         $result = get_context_info_array($syscontext->id);
270         $this->assertCount(3, $result);
271         $this->assertEquals($syscontext, $result[0]);
272         $this->assertNull($result[1]);
273         $this->assertNull($result[2]);
275         $result = get_context_info_array($usercontext->id);
276         $this->assertCount(3, $result);
277         $this->assertEquals($usercontext, $result[0]);
278         $this->assertNull($result[1]);
279         $this->assertNull($result[2]);
281         $result = get_context_info_array($catcontext->id);
282         $this->assertCount(3, $result);
283         $this->assertEquals($catcontext, $result[0]);
284         $this->assertNull($result[1]);
285         $this->assertNull($result[2]);
287         $result = get_context_info_array($coursecontext->id);
288         $this->assertCount(3, $result);
289         $this->assertEquals($coursecontext, $result[0]);
290         $this->assertEquals($course->id, $result[1]->id);
291         $this->assertSame($course->shortname, $result[1]->shortname);
292         $this->assertNull($result[2]);
294         $result = get_context_info_array($block1context->id);
295         $this->assertCount(3, $result);
296         $this->assertEquals($block1context, $result[0]);
297         $this->assertEquals($course->id, $result[1]->id);
298         $this->assertEquals($course->shortname, $result[1]->shortname);
299         $this->assertNull($result[2]);
301         $result = get_context_info_array($modcontext->id);
302         $this->assertCount(3, $result);
303         $this->assertEquals($modcontext, $result[0]);
304         $this->assertEquals($course->id, $result[1]->id);
305         $this->assertSame($course->shortname, $result[1]->shortname);
306         $this->assertEquals($cm->id, $result[2]->id);
307         $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
309         $result = get_context_info_array($block2context->id);
310         $this->assertCount(3, $result);
311         $this->assertEquals($block2context, $result[0]);
312         $this->assertEquals($course->id, $result[1]->id);
313         $this->assertSame($course->shortname, $result[1]->shortname);
314         $this->assertEquals($cm->id, $result[2]->id);
315         $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
316     }
318     /**
319      * Test looking for course contacts.
320      */
321     public function test_has_coursecontact_role() {
322         global $DB, $CFG;
324         $this->resetAfterTest();
326         $users = $DB->get_records('user');
328         // Nobody is expected to have any course level roles.
329         $this->assertNotEmpty($CFG->coursecontact);
330         foreach ($users as $user) {
331             $this->assertFalse(has_coursecontact_role($user->id));
332         }
334         $user = $this->getDataGenerator()->create_user();
335         $course = $this->getDataGenerator()->create_course();
336         role_assign($CFG->coursecontact, $user->id, context_course::instance($course->id));
337         $this->assertTrue(has_coursecontact_role($user->id));
338     }
340     /**
341      * Test creation of roles.
342      */
343     public function test_create_role() {
344         global $DB;
346         $this->resetAfterTest();
348         $id = create_role('New student role', 'student2', 'New student description', 'student');
349         $role = $DB->get_record('role', array('id'=>$id));
351         $this->assertNotEmpty($role);
352         $this->assertSame('New student role', $role->name);
353         $this->assertSame('student2', $role->shortname);
354         $this->assertSame('New student description', $role->description);
355         $this->assertSame('student', $role->archetype);
356     }
358     /**
359      * Test adding of capabilities to roles.
360      */
361     public function test_assign_capability() {
362         global $DB;
364         $this->resetAfterTest();
366         $user = $this->getDataGenerator()->create_user();
367         $syscontext = context_system::instance();
368         $frontcontext = context_course::instance(SITEID);
369         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
370         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to student by default.
371         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
372         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
374         $this->setUser($user);
375         $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id);
376         $this->assertTrue($result);
377         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
378         $this->assertNotEmpty($permission);
379         $this->assertEquals(CAP_ALLOW, $permission->permission);
380         $this->assertEquals($user->id, $permission->modifierid);
382         $this->setUser(0);
383         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false);
384         $this->assertTrue($result);
385         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
386         $this->assertNotEmpty($permission);
387         $this->assertEquals(CAP_ALLOW, $permission->permission);
388         $this->assertEquals(3, $permission->modifierid);
390         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true);
391         $this->assertTrue($result);
392         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
393         $this->assertNotEmpty($permission);
394         $this->assertEquals(CAP_PROHIBIT, $permission->permission);
395         $this->assertEquals(0, $permission->modifierid);
397         $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id);
398         $this->assertTrue($result);
399         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
400         $this->assertEmpty($permission);
401     }
403     /**
404      * Test removing of capabilities from roles.
405      */
406     public function test_unassign_capability() {
407         global $DB;
409         $this->resetAfterTest();
411         $syscontext = context_system::instance();
412         $frontcontext = context_course::instance(SITEID);
413         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
414         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to manager by default.
415         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
417         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
418         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
420         $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id);
421         $this->assertTrue($result);
422         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
423         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
424         unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext);
425         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
427         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
428         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
429         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
431         $result = unassign_capability('moodle/backup:backupcourse', $manager->id);
432         $this->assertTrue($result);
433         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
434         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
435     }
437     /**
438      * Test role assigning.
439      */
440     public function test_role_assign() {
441         global $DB, $USER;
443         $this->resetAfterTest();
445         $user = $this->getDataGenerator()->create_user();
446         $course = $this->getDataGenerator()->create_course();
447         $role = $DB->get_record('role', array('shortname'=>'student'));
449         $this->setUser(0);
450         $context = context_system::instance();
451         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
452         role_assign($role->id, $user->id, $context->id);
453         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
454         $this->assertNotEmpty($ras);
455         $this->assertSame('', $ras->component);
456         $this->assertSame('0', $ras->itemid);
457         $this->assertEquals($USER->id, $ras->modifierid);
459         $this->setAdminUser();
460         $context = context_course::instance($course->id);
461         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
462         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666);
463         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
464         $this->assertNotEmpty($ras);
465         $this->assertSame('enrol_self', $ras->component);
466         $this->assertSame('1', $ras->itemid);
467         $this->assertEquals($USER->id, $ras->modifierid);
468         $this->assertEquals(666, $ras->timemodified);
470         // Test event triggered.
472         $user2 = $this->getDataGenerator()->create_user();
473         $sink = $this->redirectEvents();
474         $raid = role_assign($role->id, $user2->id, $context->id);
475         $events = $sink->get_events();
476         $sink->close();
477         $this->assertCount(1, $events);
478         $event = $events[0];
479         $this->assertInstanceOf('\core\event\role_assigned', $event);
480         $this->assertSame('role', $event->target);
481         $this->assertSame('role', $event->objecttable);
482         $this->assertEquals($role->id, $event->objectid);
483         $this->assertEquals($context->id, $event->contextid);
484         $this->assertEquals($user2->id, $event->relateduserid);
485         $this->assertCount(3, $event->other);
486         $this->assertEquals($raid, $event->other['id']);
487         $this->assertSame('', $event->other['component']);
488         $this->assertEquals(0, $event->other['itemid']);
489     }
491     /**
492      * Test role unassigning.
493      */
494     public function test_role_unassign() {
495         global $DB;
497         $this->resetAfterTest();
499         $user = $this->getDataGenerator()->create_user();
500         $course = $this->getDataGenerator()->create_course();
501         $role = $DB->get_record('role', array('shortname'=>'student'));
503         $context = context_course::instance($course->id);
504         role_assign($role->id, $user->id, $context->id);
505         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
506         role_unassign($role->id, $user->id, $context->id);
507         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
509         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1);
510         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
511         role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1);
512         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
514         // Test event triggered.
516         role_assign($role->id, $user->id, $context->id);
517         $sink = $this->redirectEvents();
518         role_unassign($role->id, $user->id, $context->id);
519         $events = $sink->get_events();
520         $sink->close();
521         $this->assertCount(1, $events);
522         $event = $events[0];
523         $this->assertInstanceOf('\core\event\role_unassigned', $event);
524         $this->assertSame('role', $event->target);
525         $this->assertSame('role', $event->objecttable);
526         $this->assertEquals($role->id, $event->objectid);
527         $this->assertEquals($context->id, $event->contextid);
528         $this->assertEquals($user->id, $event->relateduserid);
529         $this->assertCount(3, $event->other);
530         $this->assertSame('', $event->other['component']);
531         $this->assertEquals(0, $event->other['itemid']);
532     }
534     /**
535      * Test role unassigning.
536      */
537     public function test_role_unassign_all() {
538         global $DB;
540         $this->resetAfterTest();
542         $user = $this->getDataGenerator()->create_user();
543         $course = $this->getDataGenerator()->create_course();
544         $role = $DB->get_record('role', array('shortname'=>'student'));
545         $role2 = $DB->get_record('role', array('shortname'=>'teacher'));
546         $syscontext = context_system::instance();
547         $coursecontext = context_course::instance($course->id);
548         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
549         $modcontext = context_module::instance($page->cmid);
551         role_assign($role->id, $user->id, $syscontext->id);
552         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
553         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
554         role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id));
555         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
557         role_assign($role->id, $user->id, $syscontext->id);
558         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
559         role_assign($role->id, $user->id, $modcontext->id);
560         $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id)));
561         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false);
562         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
563         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true);
564         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
565         role_unassign_all(array('userid'=>$user->id));
566         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
568         role_assign($role->id, $user->id, $syscontext->id);
569         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
570         role_assign($role->id, $user->id, $coursecontext->id);
571         role_assign($role->id, $user->id, $modcontext->id);
572         $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id)));
573         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true);
574         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
576         // Test events triggered.
578         role_assign($role2->id, $user->id, $coursecontext->id);
579         role_assign($role2->id, $user->id, $modcontext->id);
580         $sink = $this->redirectEvents();
581         role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role2->id));
582         $events = $sink->get_events();
583         $sink->close();
584         $this->assertCount(2, $events);
585         $this->assertInstanceOf('\core\event\role_unassigned', $events[0]);
586         $this->assertInstanceOf('\core\event\role_unassigned', $events[1]);
587     }
589     /**
590      * Test role queries.
591      */
592     public function test_get_roles_with_capability() {
593         global $DB;
595         $this->resetAfterTest();
597         $syscontext = context_system::instance();
598         $frontcontext = context_course::instance(SITEID);
599         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
600         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
602         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
603         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse'));
605         $roles = get_roles_with_capability('moodle/backup:backupcourse');
606         $this->assertEquals(array(), $roles);
608         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
609         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id);
610         assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id);
612         $roles = get_roles_with_capability('moodle/backup:backupcourse');
613         $this->assertEquals(array($teacher->id, $manager->id), array_keys($roles), '', 0, 10, true);
615         $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW);
616         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
618         $roles = get_roles_with_capability('moodle/backup:backupcourse', null, $syscontext);
619         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
620     }
622     /**
623      * Test deleting of roles.
624      */
625     public function test_delete_role() {
626         global $DB;
628         $this->resetAfterTest();
630         $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
631         $user = $this->getDataGenerator()->create_user();
632         role_assign($role->id, $user->id, context_system::instance());
633         $course = $this->getDataGenerator()->create_course();
634         $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id);
635         $DB->insert_record('role_names', $rolename);
637         $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
638         $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
639         $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id)));
640         $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
641         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
642         $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
643         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
644         $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
646         $result = delete_role($role->id);
647         $this->assertTrue($result);
648         $this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
649         $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
650         $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
651         $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id)));
652         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
653         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
654         $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
655         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
656         $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
657     }
659     /**
660      * Test fetching of all roles.
661      */
662     public function test_get_all_roles() {
663         global $DB;
665         $this->resetAfterTest();
667         $allroles = get_all_roles();
668         $this->assertEquals('array', gettype($allroles));
669         $this->assertCount(8, $allroles); // There are 8 roles is standard install.
671         $role = reset($allroles);
672         $role = (array)$role;
674         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), array_keys($role), '', 0, 10, true);
676         foreach ($allroles as $roleid => $role) {
677             $this->assertEquals($role->id, $roleid);
678         }
680         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
681         $course = $this->getDataGenerator()->create_course();
682         $coursecontext = context_course::instance($course->id);
683         $otherid = create_role('Other role', 'other', 'Some other role', '');
684         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
685         $DB->insert_record('role_names', $teacherename);
686         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
687         $DB->insert_record('role_names', $otherrename);
688         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
690         $allroles = get_all_roles($coursecontext);
691         $this->assertEquals('array', gettype($allroles));
692         $this->assertCount(9, $allroles);
693         $role = reset($allroles);
694         $role = (array)$role;
696         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role), '', 0, 10, true);
698         foreach ($allroles as $roleid => $role) {
699             $this->assertEquals($role->id, $roleid);
700             if (isset($renames[$roleid])) {
701                 $this->assertSame($renames[$roleid], $role->coursealias);
702             } else {
703                 $this->assertNull($role->coursealias);
704             }
705         }
706     }
708     /**
709      * Test getting of all archetypes.
710      */
711     public function test_get_role_archetypes() {
712         $archetypes = get_role_archetypes();
713         $this->assertCount(8, $archetypes); // There are 8 archetypes in standard install.
714         foreach ($archetypes as $k => $v) {
715             $this->assertSame($k, $v);
716         }
717     }
719     /**
720      * Test getting of roles with given archetype.
721      */
722     public function test_get_archetype_roles() {
723         $this->resetAfterTest();
725         // New install should have 1 role for each archetype.
726         $archetypes = get_role_archetypes();
727         foreach ($archetypes as $archetype) {
728             $roles = get_archetype_roles($archetype);
729             $this->assertCount(1, $roles);
730             $role = reset($roles);
731             $this->assertSame($archetype, $role->archetype);
732         }
734         create_role('New student role', 'student2', 'New student description', 'student');
735         $roles = get_archetype_roles('student');
736         $this->assertCount(2, $roles);
737     }
739     /**
740      * Test aliased role names.
741      */
742     public function test_role_get_name() {
743         global $DB;
745         $this->resetAfterTest();
747         $allroles = $DB->get_records('role');
748         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
749         $course = $this->getDataGenerator()->create_course();
750         $coursecontext = context_course::instance($course->id);
751         $otherid = create_role('Other role', 'other', 'Some other role', '');
752         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
753         $DB->insert_record('role_names', $teacherename);
754         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
755         $DB->insert_record('role_names', $otherrename);
756         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
758         foreach ($allroles as $role) {
759             // Get localised name from lang pack.
760             $this->assertSame('', $role->name);
761             $name = role_get_name($role, null, ROLENAME_ORIGINAL);
762             $this->assertNotEmpty($name);
763             $this->assertNotEquals($role->shortname, $name);
765             if (isset($renames[$role->id])) {
766                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext));
767                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS));
768                 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
769                 $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH));
770             } else {
771                 $this->assertSame($name, role_get_name($role, $coursecontext));
772                 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS));
773                 $this->assertNull(role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
774                 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH));
775             }
776             $this->assertSame($name, role_get_name($role));
777             $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL));
778             $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL));
779             $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT));
780             $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT));
781             $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT));
782             $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT));
783             $this->assertNull(role_get_name($role, null, ROLENAME_ALIAS_RAW));
784         }
785     }
787     /**
788      * Test tweaking of role name arrays.
789      */
790     public function test_role_fix_names() {
791         global $DB;
793         $this->resetAfterTest();
795         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
796         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
797         $otherid = create_role('Other role', 'other', 'Some other role', '');
798         $anotherid = create_role('Another role', 'another', 'Yet another other role', '');
799         $allroles = $DB->get_records('role');
801         $syscontext = context_system::instance();
802         $frontcontext = context_course::instance(SITEID);
803         $course = $this->getDataGenerator()->create_course();
804         $coursecontext = context_course::instance($course->id);
805         $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST);
806         $categorycontext = context_coursecat::instance($category->id);
808         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
809         $DB->insert_record('role_names', $teacherename);
810         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
811         $DB->insert_record('role_names', $otherrename);
812         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
814         // Make sure all localname contain proper values for each ROLENAME_ constant,
815         // note role_get_name() on frontpage is used to get the original name for future compatibility.
816         $roles = $allroles;
817         unset($roles[$student->id]); // Remove one role to make sure no role is added or removed.
818         $rolenames = array();
819         foreach ($roles as $role) {
820             $rolenames[$role->id] = $role->name;
821         }
823         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
824         foreach ($alltypes as $type) {
825             $fixed = role_fix_names($roles, $coursecontext, $type);
826             $this->assertCount(count($roles), $fixed);
827             foreach ($fixed as $roleid => $rolename) {
828                 $this->assertInstanceOf('stdClass', $rolename);
829                 $role = $allroles[$roleid];
830                 $name = role_get_name($role, $coursecontext, $type);
831                 $this->assertSame($name, $rolename->localname);
832             }
833             $fixed = role_fix_names($rolenames, $coursecontext, $type);
834             $this->assertCount(count($rolenames), $fixed);
835             foreach ($fixed as $roleid => $rolename) {
836                 $role = $allroles[$roleid];
837                 $name = role_get_name($role, $coursecontext, $type);
838                 $this->assertSame($name, $rolename);
839             }
840         }
841     }
843     /**
844      * Test role default allows.
845      */
846     public function test_get_default_role_archetype_allows() {
847         $archetypes = get_role_archetypes();
848         foreach ($archetypes as $archetype) {
850             $result = get_default_role_archetype_allows('assign', $archetype);
851             $this->assertEquals('array', gettype($result));
853             $result = get_default_role_archetype_allows('override', $archetype);
854             $this->assertEquals('array', gettype($result));
856             $result = get_default_role_archetype_allows('switch', $archetype);
857             $this->assertEquals('array', gettype($result));
858         }
860         $result = get_default_role_archetype_allows('assign', '');
861         $this->assertSame(array(), $result);
863         $result = get_default_role_archetype_allows('override', '');
864         $this->assertSame(array(), $result);
866         $result = get_default_role_archetype_allows('switch', '');
867         $this->assertSame(array(), $result);
869         $result = get_default_role_archetype_allows('assign', 'wrongarchetype');
870         $this->assertSame(array(), $result);
871         $this->assertDebuggingCalled();
873         $result = get_default_role_archetype_allows('override', 'wrongarchetype');
874         $this->assertSame(array(), $result);
875         $this->assertDebuggingCalled();
877         $result = get_default_role_archetype_allows('switch', 'wrongarchetype');
878         $this->assertSame(array(), $result);
879         $this->assertDebuggingCalled();
880     }
882     /**
883      * Test allowing of role assignments.
884      */
885     public function test_allow_assign() {
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_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
894         allow_assign($otherid, $student->id);
895         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
896     }
898     /**
899      * Test allowing of role overrides.
900      */
901     public function test_allow_override() {
902         global $DB;
904         $this->resetAfterTest();
906         $otherid = create_role('Other role', 'other', 'Some other role', '');
907         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
909         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
910         allow_override($otherid, $student->id);
911         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
912     }
914     /**
915      * Test allowing of role switching.
916      */
917     public function test_allow_switch() {
918         global $DB;
920         $this->resetAfterTest();
922         $otherid = create_role('Other role', 'other', 'Some other role', '');
923         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
925         $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
926         allow_switch($otherid, $student->id);
927         $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
928     }
930     /**
931      * Test returning of assignable roles in context.
932      */
933     public function test_get_assignable_roles() {
934         global $DB;
936         $this->resetAfterTest();
938         $course = $this->getDataGenerator()->create_course();
939         $coursecontext = context_course::instance($course->id);
941         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
942         $teacher = $this->getDataGenerator()->create_user();
943         role_assign($teacherrole->id, $teacher->id, $coursecontext);
944         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
945         $DB->insert_record('role_names', $teacherename);
947         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
948         $student = $this->getDataGenerator()->create_user();
949         role_assign($studentrole->id, $student->id, $coursecontext);
951         $contexts = $DB->get_records('context');
952         $users = $DB->get_records('user');
953         $allroles = $DB->get_records('role');
955         // Evaluate all results for all users in all contexts.
956         foreach ($users as $user) {
957             $this->setUser($user);
958             foreach ($contexts as $contextid => $unused) {
959                 $context = context_helper::instance_by_id($contextid);
960                 $roles = get_assignable_roles($context, ROLENAME_SHORT);
961                 foreach ($allroles as $roleid => $role) {
962                     if (isset($roles[$roleid])) {
963                         if (is_siteadmin()) {
964                             $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)));
965                         } else {
966                             $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid");
967                         }
968                         $this->assertEquals($role->shortname, $roles[$roleid]);
969                     } else {
970                         $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid));
971                         if (is_siteadmin()) {
972                             $this->assertFalse($allowed);
973                         } else {
974                             $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel");
975                         }
976                     }
977                 }
978             }
979         }
981         // Not-logged-in user.
982         $this->setUser(0);
983         foreach ($contexts as $contextid => $unused) {
984             $context = context_helper::instance_by_id($contextid);
985             $roles = get_assignable_roles($context, ROLENAME_SHORT);
986             $this->assertSame(array(), $roles);
987         }
989         // Test current user.
990         $this->setUser(0);
991         $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST);
992         $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin);
993         $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id);
994         $this->setAdminUser();
995         $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT);
996         $this->assertSame($roles1, $roles3);
997         $this->assertSame($roles2, $roles3);
999         // Test parameter defaults.
1000         $this->setAdminUser();
1001         $roles1 = get_assignable_roles($coursecontext);
1002         $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
1003         $this->assertEquals($roles2, $roles1);
1005         // Verify returned names - let's allow all roles everywhere to simplify this a bit.
1006         $alllevels = context_helper::get_all_levels();
1007         $alllevels = array_keys($alllevels);
1008         foreach ($allroles as $roleid => $role) {
1009             set_role_contextlevels($roleid, $alllevels);
1010         }
1011         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1012         foreach ($alltypes as $type) {
1013             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1014             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1015             foreach ($roles as $roleid => $rolename) {
1016                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1017             }
1018         }
1020         // Verify counts.
1021         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1022         foreach ($alltypes as $type) {
1023             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
1024             list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin);
1025             $this->assertEquals($roles, $rolenames);
1026             foreach ($rolenames as $roleid => $name) {
1027                 if ($roleid == $teacherrole->id or $roleid == $studentrole->id) {
1028                     $this->assertEquals(1, $rolecounts[$roleid]);
1029                 } else {
1030                     $this->assertEquals(0, $rolecounts[$roleid]);
1031                 }
1032                 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1033             }
1034         }
1035     }
1037     /**
1038      * Test getting of all switchable roles.
1039      */
1040     public function test_get_switchable_roles() {
1041         global $DB;
1043         $this->resetAfterTest();
1045         $course = $this->getDataGenerator()->create_course();
1046         $coursecontext = context_course::instance($course->id);
1048         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1049         $teacher = $this->getDataGenerator()->create_user();
1050         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1051         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1052         $DB->insert_record('role_names', $teacherename);
1054         $contexts = $DB->get_records('context');
1055         $users = $DB->get_records('user');
1056         $allroles = $DB->get_records('role');
1058         // Evaluate all results for all users in all contexts.
1059         foreach ($users as $user) {
1060             $this->setUser($user);
1061             foreach ($contexts as $contextid => $unused) {
1062                 $context = context_helper::instance_by_id($contextid);
1063                 $roles = get_switchable_roles($context);
1064                 foreach ($allroles as $roleid => $role) {
1065                     if (is_siteadmin()) {
1066                         $this->assertTrue(isset($roles[$roleid]));
1067                     } else {
1068                         $parents = $context->get_parent_context_ids(true);
1069                         $pcontexts = implode(',' , $parents);
1070                         $allowed = $DB->record_exists_sql(
1071                             "SELECT r.id
1072                                FROM {role} r
1073                                JOIN {role_allow_switch} ras ON ras.allowswitch = r.id
1074                                JOIN {role_assignments} ra ON ra.roleid = ras.roleid
1075                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1076                             ",
1077                             array('userid'=>$user->id, 'roleid'=>$roleid)
1078                         );
1079                         if (isset($roles[$roleid])) {
1080                             $this->assertTrue($allowed);
1081                         } else {
1082                             $this->assertFalse($allowed);
1083                         }
1084                     }
1086                     if (isset($roles[$roleid])) {
1087                         $coursecontext = $context->get_course_context(false);
1088                         $this->assertSame(role_get_name($role, $coursecontext), $roles[$roleid]);
1089                     }
1090                 }
1091             }
1092         }
1093     }
1095     /**
1096      * Test getting of all overridable roles.
1097      */
1098     public function test_get_overridable_roles() {
1099         global $DB;
1101         $this->resetAfterTest();
1103         $course = $this->getDataGenerator()->create_course();
1104         $coursecontext = context_course::instance($course->id);
1106         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1107         $teacher = $this->getDataGenerator()->create_user();
1108         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1109         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1110         $DB->insert_record('role_names', $teacherename);
1111         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
1112         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacher->id, $coursecontext->id);
1114         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1115         $student = $this->getDataGenerator()->create_user();
1116         role_assign($studentrole->id, $student->id, $coursecontext);
1118         $contexts = $DB->get_records('context');
1119         $users = $DB->get_records('user');
1120         $allroles = $DB->get_records('role');
1122         // Evaluate all results for all users in all contexts.
1123         foreach ($users as $user) {
1124             $this->setUser($user);
1125             foreach ($contexts as $contextid => $unused) {
1126                 $context = context_helper::instance_by_id($contextid);
1127                 $roles = get_overridable_roles($context, ROLENAME_SHORT);
1128                 foreach ($allroles as $roleid => $role) {
1129                     $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context);
1130                     if (is_siteadmin()) {
1131                         $this->assertTrue(isset($roles[$roleid]));
1132                     } else {
1133                         $parents = $context->get_parent_context_ids(true);
1134                         $pcontexts = implode(',' , $parents);
1135                         $allowed = $DB->record_exists_sql(
1136                             "SELECT r.id
1137                                FROM {role} r
1138                                JOIN {role_allow_override} rao ON r.id = rao.allowoverride
1139                                JOIN {role_assignments} ra ON rao.roleid = ra.roleid
1140                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1141                             ",
1142                             array('userid'=>$user->id, 'roleid'=>$roleid)
1143                         );
1144                         if (isset($roles[$roleid])) {
1145                             $this->assertTrue($hascap);
1146                             $this->assertTrue($allowed);
1147                         } else {
1148                             $this->assertFalse($hascap and $allowed);
1149                         }
1150                     }
1152                     if (isset($roles[$roleid])) {
1153                         $this->assertEquals($role->shortname, $roles[$roleid]);
1154                     }
1155                 }
1156             }
1157         }
1159         // Test parameter defaults.
1160         $this->setAdminUser();
1161         $roles1 = get_overridable_roles($coursecontext);
1162         $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1163         $this->assertEquals($roles2, $roles1);
1165         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1166         foreach ($alltypes as $type) {
1167             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1168             $roles = get_overridable_roles($coursecontext, $type, false);
1169             foreach ($roles as $roleid => $rolename) {
1170                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1171             }
1172         }
1174         // Verify counts.
1175         $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1176         list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true);
1177         $this->assertEquals($roles, $rolenames);
1178         foreach ($rolenames as $roleid => $name) {
1179             if ($roleid == $teacherrole->id) {
1180                 $this->assertEquals(1, $rolecounts[$roleid]);
1181             } else {
1182                 $this->assertEquals(0, $rolecounts[$roleid]);
1183             }
1184             $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1185         }
1186     }
1188     /**
1189      * Test we have context level defaults.
1190      */
1191     public function test_get_default_contextlevels() {
1192         $archetypes = get_role_archetypes();
1193         $alllevels = context_helper::get_all_levels();
1194         foreach ($archetypes as $archetype) {
1195             $defaults = get_default_contextlevels($archetype);
1196             $this->assertEquals('array', gettype($defaults));
1197             foreach ($defaults as $level) {
1198                 $this->assertTrue(isset($alllevels[$level]));
1199             }
1200         }
1201     }
1203     /**
1204      * Test role context level setup.
1205      */
1206     public function test_set_role_contextlevels() {
1207         global $DB;
1209         $this->resetAfterTest();
1211         $roleid = create_role('New student role', 'student2', 'New student description', 'student');
1213         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid)));
1215         set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE));
1216         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1217         $this->assertCount(2, $levels);
1218         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1219         $this->assertTrue(isset($levels[CONTEXT_MODULE]));
1221         set_role_contextlevels($roleid, array(CONTEXT_COURSE));
1222         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1223         $this->assertCount(1, $levels);
1224         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1225     }
1227     /**
1228      * Test getting of role context levels
1229      */
1230     public function test_get_roles_for_contextlevels() {
1231         global $DB;
1233         $allroles = get_all_roles();
1234         foreach (context_helper::get_all_levels() as $level => $unused) {
1235             $roles = get_roles_for_contextlevels($level);
1236             foreach ($allroles as $roleid => $unused) {
1237                 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid));
1238                 if (in_array($roleid, $roles)) {
1239                     $this->assertTrue($exists);
1240                 } else {
1241                     $this->assertFalse($exists);
1242                 }
1243             }
1244         }
1245     }
1247     /**
1248      * Test default enrol roles.
1249      */
1250     public function test_get_default_enrol_roles() {
1251         $this->resetAfterTest();
1253         $course = $this->getDataGenerator()->create_course();
1254         $coursecontext = context_course::instance($course->id);
1256         $id2 = create_role('New student role', 'student2', 'New student description', 'student');
1257         set_role_contextlevels($id2, array(CONTEXT_COURSE));
1259         $allroles = get_all_roles();
1260         $expected = array($id2=>$allroles[$id2]);
1262         foreach (get_role_archetypes() as $archetype) {
1263             $defaults = get_default_contextlevels($archetype);
1264             if (in_array(CONTEXT_COURSE, $defaults)) {
1265                 $roles = get_archetype_roles($archetype);
1266                 foreach ($roles as $role) {
1267                     $expected[$role->id] = $role;
1268                 }
1269             }
1270         }
1272         $roles = get_default_enrol_roles($coursecontext);
1273         foreach ($allroles as $role) {
1274             $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id]));
1275             if (isset($roles[$role->id])) {
1276                 $this->assertSame(role_get_name($role, $coursecontext), $roles[$role->id]);
1277             }
1278         }
1279     }
1281     /**
1282      * Test getting of role users.
1283      */
1284     public function test_get_role_users() {
1285         global $DB;
1287         $this->resetAfterTest();
1289         $systemcontext = context_system::instance();
1290         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1291         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1292         $course = $this->getDataGenerator()->create_course();
1293         $coursecontext = context_course::instance($course->id);
1294         $otherid = create_role('Other role', 'other', 'Some other role', '');
1295         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1296         $DB->insert_record('role_names', $teacherrename);
1297         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1298         $DB->insert_record('role_names', $otherrename);
1300         $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith'));
1301         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1302         $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar'));
1303         role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1304         $user3 = $this->getDataGenerator()->create_user();
1305         $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id);
1306         $user4 = $this->getDataGenerator()->create_user();
1307         $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id);
1309         $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id));
1310         groups_add_member($group, $user3);
1312         $users = get_role_users($teacherrole->id, $coursecontext);
1313         $this->assertCount(2, $users);
1314         $this->assertArrayHasKey($user1->id, $users);
1315         $this->assertEquals($users[$user1->id]->id, $user1->id);
1316         $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id);
1317         $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name);
1318         $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname);
1319         $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name);
1320         $this->assertArrayHasKey($user3->id, $users);
1321         $this->assertEquals($users[$user3->id]->id, $user3->id);
1322         $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id);
1323         $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name);
1324         $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname);
1325         $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name);
1327         $users = get_role_users($teacherrole->id, $coursecontext, true);
1328         $this->assertCount(3, $users);
1330         $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1);
1331         $this->assertCount(1, $users);
1333         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber');
1334         $this->assertCount(2, $users);
1335         $this->assertArrayHasKey($user1->id, $users);
1336         $this->assertArrayHasKey($user3->id, $users);
1338         $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id);
1339         $this->assertCount(1, $users);
1340         $this->assertArrayHasKey($user3->id, $users);
1342         $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'));
1343         $this->assertCount(1, $users);
1344         $this->assertArrayHasKey($user1->id, $users);
1345     }
1347     /**
1348      * Test used role query.
1349      */
1350     public function test_get_roles_used_in_context() {
1351         global $DB;
1353         $this->resetAfterTest();
1355         $systemcontext = context_system::instance();
1356         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1357         $course = $this->getDataGenerator()->create_course();
1358         $coursecontext = context_course::instance($course->id);
1359         $otherid = create_role('Other role', 'other', 'Some other role', '');
1360         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1361         $DB->insert_record('role_names', $teacherrename);
1362         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
1363         $DB->insert_record('role_names', $otherrename);
1365         $user1 = $this->getDataGenerator()->create_user();
1366         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1368         $roles = get_roles_used_in_context($coursecontext);
1369         $this->assertCount(1, $roles);
1370         $role = reset($roles);
1371         $roleid = key($roles);
1372         $this->assertEquals($roleid, $role->id);
1373         $this->assertEquals($teacherrole->id, $role->id);
1374         $this->assertSame($teacherrole->name, $role->name);
1375         $this->assertSame($teacherrole->shortname, $role->shortname);
1376         $this->assertEquals($teacherrole->sortorder, $role->sortorder);
1377         $this->assertSame($teacherrename->name, $role->coursealias);
1379         $user2 = $this->getDataGenerator()->create_user();
1380         role_assign($teacherrole->id, $user2->id, $systemcontext->id);
1381         role_assign($otherid, $user2->id, $systemcontext->id);
1383         $roles = get_roles_used_in_context($systemcontext);
1384         $this->assertCount(2, $roles);
1385     }
1387     /**
1388      * Test roles used in course.
1389      */
1390     public function test_get_user_roles_in_course() {
1391         global $DB, $CFG;
1393         $this->resetAfterTest();
1395         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1396         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1397         $course = $this->getDataGenerator()->create_course();
1398         $coursecontext = context_course::instance($course->id);
1399         $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1400         $DB->insert_record('role_names', $teacherrename);
1402         $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
1403         $this->assertTrue(in_array($teacherrole->id, $roleids));
1404         $this->assertTrue(in_array($studentrole->id, $roleids));
1406         $user1 = $this->getDataGenerator()->create_user();
1407         role_assign($teacherrole->id, $user1->id, $coursecontext->id);
1408         role_assign($studentrole->id, $user1->id, $coursecontext->id);
1409         $user2 = $this->getDataGenerator()->create_user();
1410         role_assign($studentrole->id, $user2->id, $coursecontext->id);
1411         $user3 = $this->getDataGenerator()->create_user();
1413         $roles = get_user_roles_in_course($user1->id, $course->id);
1414         $this->assertEquals(1, preg_match_all('/,/', $roles, $matches));
1415         $this->assertTrue(strpos($roles, role_get_name($teacherrole, $coursecontext)) !== false);
1417         $roles = get_user_roles_in_course($user2->id, $course->id);
1418         $this->assertEquals(0, preg_match_all('/,/', $roles, $matches));
1419         $this->assertTrue(strpos($roles, role_get_name($studentrole, $coursecontext)) !== false);
1421         $roles = get_user_roles_in_course($user3->id, $course->id);
1422         $this->assertSame('', $roles);
1423     }
1425     /**
1426      * Test has_capability(), has_any_capability() and has_all_capabilities().
1427      */
1428     public function test_has_capability_and_friends() {
1429         global $DB;
1431         $this->resetAfterTest();
1433         $course = $this->getDataGenerator()->create_course();
1434         $coursecontext = context_course::instance($course->id);
1435         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1436         $teacher = $this->getDataGenerator()->create_user();
1437         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1438         $admin = $DB->get_record('user', array('username'=>'admin'));
1440         // Note: Here are used default capabilities, the full test is in permission evaluation bellow,
1441         // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user.
1443         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection')));
1444         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse')));
1445         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse')));
1447         $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse');
1448         $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse');
1450         $this->setUser(0);
1451         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext));
1452         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext));
1453         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1454         $this->assertFalse(has_any_capability($sca, $coursecontext));
1455         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1457         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher));
1458         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher));
1459         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher));
1460         $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher));
1461         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher));
1462         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher));
1464         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin));
1465         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin));
1466         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin));
1467         $this->assertTrue(has_any_capability($sca, $coursecontext, $admin));
1468         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin));
1469         $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin));
1471         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false));
1472         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false));
1473         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false));
1474         $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false));
1475         $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false));
1476         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false));
1478         $this->setUser($teacher);
1479         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1480         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1481         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1482         $this->assertTrue(has_any_capability($sca, $coursecontext));
1483         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1484         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1486         $this->setAdminUser();
1487         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1488         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1489         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext));
1490         $this->assertTrue(has_any_capability($sca, $coursecontext));
1491         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1492         $this->assertTrue(has_all_capabilities($sca, $coursecontext));
1494         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0));
1495         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0));
1496         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0));
1497         $this->assertFalse(has_any_capability($sca, $coursecontext, 0));
1498         $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0));
1499     }
1501     /**
1502      * Test if course creator future capability lookup works.
1503      */
1504     public function test_guess_if_creator_will_have_course_capability() {
1505         global $DB, $CFG, $USER;
1507         $this->resetAfterTest();
1509         $category = $this->getDataGenerator()->create_category();
1510         $course = $this->getDataGenerator()->create_course(array('category'=>$category->id));
1512         $syscontext = context_system::instance();
1513         $categorycontext = context_coursecat::instance($category->id);
1514         $coursecontext = context_course::instance($course->id);
1515         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1516         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1517         $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST);
1518         $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
1520         $this->assertEquals($teacherrole->id, $CFG->creatornewroleid);
1522         $creator = $this->getDataGenerator()->create_user();
1523         $manager = $this->getDataGenerator()->create_user();
1524         role_assign($managerrole->id, $manager->id, $categorycontext);
1526         $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator));
1527         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
1528         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
1529         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
1530         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
1531         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
1533         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1534         $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager));
1535         $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager));
1536         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id));
1537         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id));
1539         $this->assertEquals(0, $USER->id);
1540         $this->assertFalse(has_capability('moodle/course:view', $categorycontext));
1541         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext));
1542         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext));
1543         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext));
1544         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
1545         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
1547         $this->setUser($manager);
1548         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
1549         $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
1550         $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
1551         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
1552         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
1554         $this->setAdminUser();
1555         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
1556         $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
1557         $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
1558         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
1559         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
1560         $this->setUser(0);
1562         role_assign($creatorrole->id, $creator->id, $categorycontext);
1564         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
1565         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
1566         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
1567         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
1568         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
1570         $this->setUser($creator);
1571         $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, null));
1572         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, null));
1573         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, null));
1574         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, null));
1575         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, null));
1576         $this->setUser(0);
1578         set_config('creatornewroleid', $studentrole->id);
1580         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
1581         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
1582         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
1583         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
1585         set_config('creatornewroleid', $teacherrole->id);
1587         role_change_permission($managerrole->id, $categorycontext, 'moodle/course:visibility', CAP_PREVENT);
1588         role_assign($creatorrole->id, $manager->id, $categorycontext);
1590         $this->assertTrue(has_capability('moodle/course:view', $categorycontext, $manager));
1591         $this->assertTrue(has_capability('moodle/course:view', $coursecontext, $manager));
1592         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1593         $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager));
1594         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
1595         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
1596         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
1597         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
1599         role_change_permission($managerrole->id, $categorycontext, 'moodle/course:view', CAP_PREVENT);
1600         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1601         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
1602         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
1603         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
1604         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
1606         $this->getDataGenerator()->enrol_user($manager->id, $course->id, 0);
1608         $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
1609         $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager));
1610         $this->assertTrue(is_enrolled($coursecontext, $manager));
1611         $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager));
1612         $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager));
1613         $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager));
1614         $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager));
1616         // Test problems.
1618         try {
1619             guess_if_creator_will_have_course_capability('moodle/course:visibility', $syscontext, $creator);
1620             $this->fail('Exception expected when non course/category context passed to guess_if_creator_will_have_course_capability()');
1621         } catch (moodle_exception $e) {
1622             $this->assertInstanceOf('coding_exception', $e);
1623         }
1624     }
1626     /**
1627      * Test require_capability() exceptions.
1628      */
1629     public function test_require_capability() {
1630         $this->resetAfterTest();
1632         $syscontext = context_system::instance();
1634         $this->setUser(0);
1635         $this->assertFalse(has_capability('moodle/site:config', $syscontext));
1636         try {
1637             require_capability('moodle/site:config', $syscontext);
1638             $this->fail('Exception expected from require_capability()');
1639         } catch (moodle_exception $e) {
1640             $this->assertInstanceOf('required_capability_exception', $e);
1641         }
1642         $this->setAdminUser();
1643         $this->assertFalse(has_capability('moodle/site:config', $syscontext, 0));
1644         try {
1645             require_capability('moodle/site:config', $syscontext, 0);
1646             $this->fail('Exception expected from require_capability()');
1647         } catch (moodle_exception $e) {
1648             $this->assertInstanceOf('required_capability_exception', $e);
1649         }
1650         $this->assertFalse(has_capability('moodle/site:config', $syscontext, null, false));
1651         try {
1652             require_capability('moodle/site:config', $syscontext, null, false);
1653             $this->fail('Exception expected from require_capability()');
1654         } catch (moodle_exception $e) {
1655             $this->assertInstanceOf('required_capability_exception', $e);
1656         }
1657     }
1659     /**
1660      * A small functional test of permission evaluations.
1661      */
1662     public function test_permission_evaluation() {
1663         global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE;
1665         $this->resetAfterTest();
1667         $generator = $this->getDataGenerator();
1669         // Fill the site with some real data.
1670         $testcategories = array();
1671         $testcourses = array();
1672         $testpages = array();
1673         $testblocks = array();
1674         $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
1676         $systemcontext = context_system::instance();
1677         $frontpagecontext = context_course::instance(SITEID);
1679         // Add block to system context.
1680         $bi = $generator->create_block('online_users');
1681         context_block::instance($bi->id);
1682         $testblocks[] = $bi->id;
1684         // Some users.
1685         $testusers = array();
1686         for ($i=0; $i<20; $i++) {
1687             $user = $generator->create_user();
1688             $testusers[$i] = $user->id;
1689             $usercontext = context_user::instance($user->id);
1691             // Add block to user profile.
1692             $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id));
1693             $testblocks[] = $bi->id;
1694         }
1695         // Deleted user - should be ignored everywhere, can not have context.
1696         $generator->create_user(array('deleted'=>1));
1698         // Add block to frontpage.
1699         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id));
1700         $frontpageblockcontext = context_block::instance($bi->id);
1701         $testblocks[] = $bi->id;
1703         // Add a resource to frontpage.
1704         $page = $generator->create_module('page', array('course'=>$SITE->id));
1705         $testpages[] = $page->id;
1706         $frontpagepagecontext = context_module::instance($page->cmid);
1708         // Add block to frontpage resource.
1709         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id));
1710         $frontpagepageblockcontext = context_block::instance($bi->id);
1711         $testblocks[] = $bi->id;
1713         // Some nested course categories with courses.
1714         $manualenrol = enrol_get_plugin('manual');
1715         $parentcat = 0;
1716         for ($i=0; $i<5; $i++) {
1717             $cat = $generator->create_category(array('parent'=>$parentcat));
1718             $testcategories[] = $cat->id;
1719             $catcontext = context_coursecat::instance($cat->id);
1720             $parentcat = $cat->id;
1722             if ($i >= 4) {
1723                 continue;
1724             }
1726             // Add resource to each category.
1727             $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id));
1728             context_block::instance($bi->id);
1730             // Add a few courses to each category.
1731             for ($j=0; $j<6; $j++) {
1732                 $course = $generator->create_course(array('category'=>$cat->id));
1733                 $testcourses[] = $course->id;
1734                 $coursecontext = context_course::instance($course->id);
1736                 if ($j >= 5) {
1737                     continue;
1738                 }
1739                 // Add manual enrol instance.
1740                 $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id)));
1742                 // Add block to each course.
1743                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
1744                 $testblocks[] = $bi->id;
1746                 // Add a resource to each course.
1747                 $page = $generator->create_module('page', array('course'=>$course->id));
1748                 $testpages[] = $page->id;
1749                 $modcontext = context_module::instance($page->cmid);
1751                 // Add block to each module.
1752                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id));
1753                 $testblocks[] = $bi->id;
1754             }
1755         }
1757         // Make sure all contexts were created properly.
1758         $count = 1; // System.
1759         $count += $DB->count_records('user', array('deleted'=>0));
1760         $count += $DB->count_records('course_categories');
1761         $count += $DB->count_records('course');
1762         $count += $DB->count_records('course_modules');
1763         $count += $DB->count_records('block_instances');
1764         $this->assertEquals($count, $DB->count_records('context'));
1765         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
1766         $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
1769         // Test context_helper::get_level_name() method.
1771         $levels = context_helper::get_all_levels();
1772         foreach ($levels as $level => $classname) {
1773             $name = context_helper::get_level_name($level);
1774             $this->assertNotEmpty($name);
1775         }
1778         // Test context::instance_by_id(), context_xxx::instance() methods.
1780         $context = context::instance_by_id($frontpagecontext->id);
1781         $this->assertSame(CONTEXT_COURSE, $context->contextlevel);
1782         $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING));
1783         try {
1784             context::instance_by_id(-1);
1785             $this->fail('exception expected');
1786         } catch (moodle_exception $e) {
1787             $this->assertTrue(true);
1788         }
1789         $this->assertInstanceOf('context_system', context_system::instance());
1790         $this->assertInstanceOf('context_coursecat', context_coursecat::instance($testcategories[0]));
1791         $this->assertInstanceOf('context_course', context_course::instance($testcourses[0]));
1792         $this->assertInstanceOf('context_module', context_module::instance($testpages[0]));
1793         $this->assertInstanceOf('context_block', context_block::instance($testblocks[0]));
1795         $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING));
1796         $this->assertFalse(context_course::instance(-1, IGNORE_MISSING));
1797         $this->assertFalse(context_module::instance(-1, IGNORE_MISSING));
1798         $this->assertFalse(context_block::instance(-1, IGNORE_MISSING));
1799         try {
1800             context_coursecat::instance(-1);
1801             $this->fail('exception expected');
1802         } catch (moodle_exception $e) {
1803             $this->assertTrue(true);
1804         }
1805         try {
1806             context_course::instance(-1);
1807             $this->fail('exception expected');
1808         } catch (moodle_exception $e) {
1809             $this->assertTrue(true);
1810         }
1811         try {
1812             context_module::instance(-1);
1813             $this->fail('exception expected');
1814         } catch (moodle_exception $e) {
1815             $this->assertTrue(true);
1816         }
1817         try {
1818             context_block::instance(-1);
1819             $this->fail('exception expected');
1820         } catch (moodle_exception $e) {
1821             $this->assertTrue(true);
1822         }
1825         // Test $context->get_url(), $context->get_context_name(), $context->get_capabilities() methods.
1827         $testcontexts = array();
1828         $testcontexts[CONTEXT_SYSTEM]    = context_system::instance();
1829         $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]);
1830         $testcontexts[CONTEXT_COURSE]    = context_course::instance($testcourses[0]);
1831         $testcontexts[CONTEXT_MODULE]    = context_module::instance($testpages[0]);
1832         $testcontexts[CONTEXT_BLOCK]     = context_block::instance($testblocks[0]);
1834         foreach ($testcontexts as $context) {
1835             $name = $context->get_context_name(true, true);
1836             $this->assertNotEmpty($name);
1838             $this->assertInstanceOf('moodle_url', $context->get_url());
1840             $caps = $context->get_capabilities();
1841             $this->assertTrue(is_array($caps));
1842             foreach ($caps as $cap) {
1843                 $cap = (array)$cap;
1844                 $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask'));
1845             }
1846         }
1847         unset($testcontexts);
1849         // Test $context->get_course_context() method.
1851         $this->assertFalse($systemcontext->get_course_context(false));
1852         try {
1853             $systemcontext->get_course_context();
1854             $this->fail('exception expected');
1855         } catch (moodle_exception $e) {
1856             $this->assertInstanceOf('coding_exception', $e);
1857         }
1858         $context = context_coursecat::instance($testcategories[0]);
1859         $this->assertFalse($context->get_course_context(false));
1860         try {
1861             $context->get_course_context();
1862             $this->fail('exception expected');
1863         } catch (moodle_exception $e) {
1864             $this->assertInstanceOf('coding_exception', $e);
1865         }
1866         $this->assertEquals($frontpagecontext, $frontpagecontext->get_course_context(true));
1867         $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_course_context(true));
1868         $this->assertEquals($frontpagecontext, $frontpagepageblockcontext->get_course_context(true));
1871         // Test $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() methods.
1873         $userid = reset($testusers);
1874         $usercontext = context_user::instance($userid);
1875         $this->assertEquals($systemcontext, $usercontext->get_parent_context());
1876         $this->assertEquals(array($systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts());
1877         $this->assertEquals(array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts(true));
1879         $this->assertEquals(array(), $systemcontext->get_parent_contexts());
1880         $this->assertEquals(array($systemcontext->id=>$systemcontext), $systemcontext->get_parent_contexts(true));
1881         $this->assertEquals(array(), $systemcontext->get_parent_context_ids());
1882         $this->assertEquals(array($systemcontext->id), $systemcontext->get_parent_context_ids(true));
1884         $this->assertEquals($systemcontext, $frontpagecontext->get_parent_context());
1885         $this->assertEquals(array($systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts());
1886         $this->assertEquals(array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts(true));
1887         $this->assertEquals(array($systemcontext->id), $frontpagecontext->get_parent_context_ids());
1888         $this->assertEquals(array($frontpagecontext->id, $systemcontext->id), $frontpagecontext->get_parent_context_ids(true));
1890         $this->assertFalse($systemcontext->get_parent_context());
1891         $frontpagecontext = context_course::instance($SITE->id);
1892         $parent = $systemcontext;
1893         foreach ($testcategories as $catid) {
1894             $catcontext = context_coursecat::instance($catid);
1895             $this->assertEquals($parent, $catcontext->get_parent_context());
1896             $parent = $catcontext;
1897         }
1898         $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_parent_context());
1899         $this->assertEquals($frontpagecontext, $frontpageblockcontext->get_parent_context());
1900         $this->assertEquals($frontpagepagecontext, $frontpagepageblockcontext->get_parent_context());
1903         // Test $context->get_child_contexts() method.
1905         $children = $systemcontext->get_child_contexts();
1906         $this->resetDebugging();
1907         $this->assertEquals(count($children)+1, $DB->count_records('context'));
1909         $context = context_coursecat::instance($testcategories[3]);
1910         $children = $context->get_child_contexts();
1911         $countcats    = 0;
1912         $countcourses = 0;
1913         $countblocks  = 0;
1914         foreach ($children as $child) {
1915             if ($child->contextlevel == CONTEXT_COURSECAT) {
1916                 $countcats++;
1917             }
1918             if ($child->contextlevel == CONTEXT_COURSE) {
1919                 $countcourses++;
1920             }
1921             if ($child->contextlevel == CONTEXT_BLOCK) {
1922                 $countblocks++;
1923             }
1924         }
1925         $this->assertCount(8, $children);
1926         $this->assertEquals(1, $countcats);
1927         $this->assertEquals(6, $countcourses);
1928         $this->assertEquals(1, $countblocks);
1930         $context = context_course::instance($testcourses[2]);
1931         $children = $context->get_child_contexts();
1932         $this->assertCount(7, $children); // Depends on number of default blocks.
1934         $context = context_module::instance($testpages[3]);
1935         $children = $context->get_child_contexts();
1936         $this->assertCount(1, $children);
1938         $context = context_block::instance($testblocks[1]);
1939         $children = $context->get_child_contexts();
1940         $this->assertCount(0, $children);
1942         unset($children);
1943         unset($countcats);
1944         unset($countcourses);
1945         unset($countblocks);
1948         // Test context_helper::reset_caches() method.
1950         context_helper::reset_caches();
1951         $this->assertEquals(0, context_inspection::test_context_cache_size());
1952         context_course::instance($SITE->id);
1953         $this->assertEquals(1, context_inspection::test_context_cache_size());
1956         // Test context preloading.
1958         context_helper::reset_caches();
1959         $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')."
1960                   FROM {context} c
1961                  WHERE c.contextlevel <> ".CONTEXT_SYSTEM;
1962         $records = $DB->get_records_sql($sql);
1963         $firstrecord = reset($records);
1964         $columns = context_helper::get_preload_record_columns('c');
1965         $firstrecord = (array)$firstrecord;
1966         $this->assertSame(array_keys($firstrecord), array_values($columns));
1967         context_helper::reset_caches();
1968         foreach ($records as $record) {
1969             context_helper::preload_from_record($record);
1970             $this->assertEquals(new stdClass(), $record);
1971         }
1972         $this->assertEquals(count($records), context_inspection::test_context_cache_size());
1973         unset($records);
1974         unset($columns);
1976         context_helper::reset_caches();
1977         context_helper::preload_course($SITE->id);
1978         $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id));
1979         $this->assertEquals(6 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // Depends on number of default blocks.
1981         // Test assign_capability(), unassign_capability() functions.
1983         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1984         $this->assertFalse($rc);
1985         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id);
1986         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1987         $this->assertEquals(CAP_ALLOW, $rc->permission);
1988         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id);
1989         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1990         $this->assertEquals(CAP_ALLOW, $rc->permission);
1991         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true);
1992         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1993         $this->assertEquals(CAP_PREVENT, $rc->permission);
1995         assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext);
1996         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1997         $this->assertFalse($rc);
1998         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext);
1999         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true);
2000         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
2001         $this->assertFalse($rc);
2002         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true);
2003         unset($rc);
2005         accesslib_clear_all_caches(false); // Must be done after assign_capability().
2008         // Test role_assign(), role_unassign(), role_unassign_all() functions.
2010         $context = context_course::instance($testcourses[1]);
2011         $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2012         role_assign($allroles['teacher'], $testusers[1], $context->id);
2013         role_assign($allroles['teacher'], $testusers[2], $context->id);
2014         role_assign($allroles['manager'], $testusers[1], $context->id);
2015         $this->assertEquals(3, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2016         role_unassign($allroles['teacher'], $testusers[1], $context->id);
2017         $this->assertEquals(2, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2018         role_unassign_all(array('contextid'=>$context->id));
2019         $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id)));
2020         unset($context);
2022         accesslib_clear_all_caches(false); // Just in case.
2025         // Test has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends functions.
2027         $adminid = get_admin()->id;
2028         $guestid = $CFG->siteguest;
2030         // Enrol some users into some courses.
2031         $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST);
2032         $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST);
2033         $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id');
2034         $cm1 = reset($cms);
2035         $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id');
2036         $block1 = reset($blocks);
2037         $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id));
2038         $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id));
2039         for ($i=0; $i<9; $i++) {
2040             $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']);
2041         }
2042         $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']);
2043         $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']);
2045         for ($i=10; $i<15; $i++) {
2046             $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']);
2047         }
2048         $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']);
2050         // Add tons of role assignments - the more the better.
2051         role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2]));
2052         role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1]));
2053         role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id));
2054         role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id));
2055         role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id));
2056         role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id));
2057         role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id));
2058         role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id));
2060         role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id));
2061         role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id));
2063         // Add tons of overrides - the more the better.
2064         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true);
2065         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true);
2066         assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true);
2067         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true);
2068         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true);
2070         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true);
2071         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true);
2072         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true);
2073         assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true);
2074         assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true);
2076         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true);
2077         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true);
2078         assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true);
2079         assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true);
2081         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true);
2083         accesslib_clear_all_caches(false); // Must be done after assign_capability().
2085         // Extra tests for guests and not-logged-in users because they can not be verified by cross checking
2086         // with get_users_by_capability() where they are ignored.
2087         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid));
2088         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid));
2089         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid));
2090         $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid));
2092         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0));
2093         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0));
2094         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0));
2095         $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0));
2097         $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11]));
2098         $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11]));
2099         $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11]));
2100         $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11]));
2102         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9]));
2103         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9]));
2104         $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9]));
2106         // Test the list of enrolled users.
2107         $coursecontext = context_course::instance($course1->id);
2108         $enrolled = get_enrolled_users($coursecontext);
2109         $this->assertCount(10, $enrolled);
2110         for ($i=0; $i<10; $i++) {
2111             $this->assertTrue(isset($enrolled[$testusers[$i]]));
2112         }
2113         $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update');
2114         $this->assertCount(1, $enrolled);
2115         $this->assertTrue(isset($enrolled[$testusers[9]]));
2116         unset($enrolled);
2118         // Role switching.
2119         $userid = $testusers[9];
2120         $USER = $DB->get_record('user', array('id'=>$userid));
2121         load_all_capabilities();
2122         $coursecontext = context_course::instance($course1->id);
2123         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2124         $this->assertFalse(is_role_switched($course1->id));
2125         role_switch($allroles['student'], $coursecontext);
2126         $this->assertTrue(is_role_switched($course1->id));
2127         $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]);
2128         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2129         reload_all_capabilities();
2130         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2131         role_switch(0, $coursecontext);
2132         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2133         $userid = $adminid;
2134         $USER = $DB->get_record('user', array('id'=>$userid));
2135         load_all_capabilities();
2136         $coursecontext = context_course::instance($course1->id);
2137         $blockcontext = context_block::instance($block1->id);
2138         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
2139         role_switch($allroles['student'], $coursecontext);
2140         $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]);
2141         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
2142         reload_all_capabilities();
2143         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
2144         load_all_capabilities();
2145         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
2147         // Temp course role for enrol.
2148         $DB->delete_records('cache_flags', array()); // This prevents problem with dirty contexts immediately resetting the temp role - this is a known problem...
2149         $userid = $testusers[5];
2150         $roleid = $allroles['editingteacher'];
2151         $USER = $DB->get_record('user', array('id'=>$userid));
2152         load_all_capabilities();
2153         $coursecontext = context_course::instance($course1->id);
2154         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
2155         $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid]));
2156         load_temp_course_role($coursecontext, $roleid);
2157         $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid);
2158         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
2159         remove_temp_course_roles($coursecontext);
2160         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
2161         load_temp_course_role($coursecontext, $roleid);
2162         reload_all_capabilities();
2163         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
2164         $USER = new stdClass();
2165         $USER->id = 0;
2167         // Now cross check has_capability() with get_users_by_capability(), each using different code paths,
2168         // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong,
2169         // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users).
2170         $contexts = $DB->get_records('context', array(), 'id');
2171         $contexts = array_values($contexts);
2172         $capabilities = $DB->get_records('capabilities', array(), 'id');
2173         $capabilities = array_values($capabilities);
2174         $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']);
2175         $userids = array_values($testusers);
2176         $userids[] = get_admin()->id;
2178         if (!PHPUNIT_LONGTEST) {
2179             $contexts = array_slice($contexts, 0, 10);
2180             $capabilities = array_slice($capabilities, 0, 5);
2181             $userids = array_slice($userids, 0, 5);
2182         }
2184         // Random time!
2185         // srand(666);
2186         foreach ($userids as $userid) { // No guest or deleted.
2187             // Each user gets 0-10 random roles.
2188             $rcount = rand(0, 10);
2189             for ($j=0; $j<$rcount; $j++) {
2190                 $roleid = $roles[rand(0, count($roles)-1)];
2191                 $contextid = $contexts[rand(0, count($contexts)-1)]->id;
2192                 role_assign($roleid, $userid, $contextid);
2193             }
2194         }
2196         $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT);
2197         $maxoverrides = count($contexts)*10;
2198         for ($j=0; $j<$maxoverrides; $j++) {
2199             $roleid = $roles[rand(0, count($roles)-1)];
2200             $contextid = $contexts[rand(0, count($contexts)-1)]->id;
2201             $permission = $permissions[rand(0, count($permissions)-1)];
2202             $capname = $capabilities[rand(0, count($capabilities)-1)]->name;
2203             assign_capability($capname, $permission, $roleid, $contextid, true);
2204         }
2205         unset($permissions);
2206         unset($roles);
2208         accesslib_clear_all_caches(false); // Must be done after assign_capability().
2210         // Test time - let's set up some real user, just in case the logic for USER affects the others...
2211         $USER = $DB->get_record('user', array('id'=>$testusers[3]));
2212         load_all_capabilities();
2214         $userids[] = $CFG->siteguest;
2215         $userids[] = 0; // Not-logged-in user.
2216         $userids[] = -1; // Non-existent user.
2218         foreach ($contexts as $crecord) {
2219             $context = context::instance_by_id($crecord->id);
2220             if ($coursecontext = $context->get_course_context(false)) {
2221                 $enrolled = get_enrolled_users($context);
2222             } else {
2223                 $enrolled = array();
2224             }
2225             foreach ($capabilities as $cap) {
2226                 $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username');
2227                 if ($enrolled) {
2228                     $enrolledwithcap = get_enrolled_users($context, $cap->name);
2229                 } else {
2230                     $enrolledwithcap = array();
2231                 }
2232                 foreach ($userids as $userid) {
2233                     if ($userid == 0 or isguestuser($userid)) {
2234                         if ($userid == 0) {
2235                             $CFG->forcelogin = true;
2236                             $this->assertFalse(has_capability($cap->name, $context, $userid));
2237                             unset($CFG->forcelogin);
2238                         }
2239                         if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) {
2240                             $this->assertFalse(has_capability($cap->name, $context, $userid));
2241                         }
2242                         $this->assertFalse(isset($allowed[$userid]));
2243                     } else {
2244                         if (is_siteadmin($userid)) {
2245                             $this->assertTrue(has_capability($cap->name, $context, $userid, true));
2246                         }
2247                         $hascap = has_capability($cap->name, $context, $userid, false);
2248                         $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
2249                         if (isset($enrolled[$userid])) {
2250                             $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
2251                         }
2252                     }
2253                 }
2254             }
2255         }
2256         // Back to nobody.
2257         $USER = new stdClass();
2258         $USER->id = 0;
2259         unset($contexts);
2260         unset($userids);
2261         unset($capabilities);
2263         // Now let's do all the remaining tests that break our carefully prepared fake site.
2266         // Test $context->mark_dirty() method.
2268         $DB->delete_records('cache_flags', array());
2269         accesslib_clear_all_caches(false);
2270         $systemcontext->mark_dirty();
2271         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2272         $this->assertTrue(isset($dirty[$systemcontext->path]));
2273         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path]));
2276         // Test $context->reload_if_dirty() method.
2278         $DB->delete_records('cache_flags', array());
2279         accesslib_clear_all_caches(false);
2280         load_all_capabilities();
2281         $context = context_course::instance($testcourses[2]);
2282         $page = $DB->get_record('page', array('course'=>$testcourses[2]));
2283         $pagecm = get_coursemodule_from_instance('page', $page->id);
2284         $pagecontext = context_module::instance($pagecm->id);
2286         $context->mark_dirty();
2287         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2288         $USER->access['test'] = true;
2289         $context->reload_if_dirty();
2290         $this->assertFalse(isset($USER->access['test']));
2292         $context->mark_dirty();
2293         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2294         $USER->access['test'] = true;
2295         $pagecontext->reload_if_dirty();
2296         $this->assertFalse(isset($USER->access['test']));
2299         // Test context_helper::build_all_paths() method.
2301         $oldcontexts = $DB->get_records('context', array(), 'id');
2302         $DB->set_field_select('context', 'path', null, "contextlevel <> ".CONTEXT_SYSTEM);
2303         $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM);
2304         context_helper::build_all_paths();
2305         $newcontexts = $DB->get_records('context', array(), 'id');
2306         $this->assertEquals($oldcontexts, $newcontexts);
2307         unset($oldcontexts);
2308         unset($newcontexts);
2311         // Test $context->reset_paths() method.
2313         $context = context_course::instance($testcourses[2]);
2314         $children = $context->get_child_contexts();
2315         $context->reset_paths(false);
2316         $this->assertNull($DB->get_field('context', 'path', array('id'=>$context->id)));
2317         $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$context->id)));
2318         foreach ($children as $child) {
2319             $this->assertNull($DB->get_field('context', 'path', array('id'=>$child->id)));
2320             $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$child->id)));
2321         }
2322         $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0)));
2323         $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>null)));
2325         $context = context_course::instance($testcourses[2]);
2326         $context->reset_paths(true);
2327         $context = context_course::instance($testcourses[2]);
2328         $this->assertSame($context->path, $DB->get_field('context', 'path', array('id'=>$context->id)));
2329         $this->assertSame($context->depth, $DB->get_field('context', 'depth', array('id'=>$context->id)));
2330         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2331         $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2334         // Test $context->update_moved() method.
2336         accesslib_clear_all_caches(false);
2337         $DB->delete_records('cache_flags', array());
2338         $course = $DB->get_record('course', array('id'=>$testcourses[0]));
2339         $context = context_course::instance($course->id);
2340         $oldpath = $context->path;
2341         $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2342         $categorycontext = context_coursecat::instance($miscid);
2343         $course->category = $miscid;
2344         $DB->update_record('course', $course);
2345         $context->update_moved($categorycontext);
2347         $context = context_course::instance($course->id);
2348         $this->assertEquals($categorycontext, $context->get_parent_context());
2349         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2350         $this->assertTrue(isset($dirty[$oldpath]));
2351         $this->assertTrue(isset($dirty[$context->path]));
2354         // Test $context->delete_content() method.
2356         context_helper::reset_caches();
2357         $context = context_module::instance($testpages[3]);
2358         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2359         $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2360         $context->delete_content();
2361         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2362         $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2365         // Test $context->delete() method.
2367         context_helper::reset_caches();
2368         $context = context_module::instance($testpages[4]);
2369         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2370         $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2371         $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id));
2372         $bicontext = context_block::instance($bi->id);
2373         $DB->delete_records('cache_flags', array());
2374         $context->delete(); // Should delete also linked blocks.
2375         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2376         $this->assertTrue(isset($dirty[$context->path]));
2377         $this->assertFalse($DB->record_exists('context', array('id'=>$context->id)));
2378         $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id)));
2379         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4])));
2380         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id)));
2381         $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2382         context_module::instance($testpages[4]);
2385         // Test context_helper::delete_instance() method.
2387         context_helper::reset_caches();
2388         $lastcourse = array_pop($testcourses);
2389         $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2390         $coursecontext = context_course::instance($lastcourse);
2391         $this->assertEquals(1, context_inspection::test_context_cache_size());
2392         $this->assertNotEquals(CONTEXT_COURSE, $coursecontext->instanceid);
2393         $DB->delete_records('cache_flags', array());
2394         context_helper::delete_instance(CONTEXT_COURSE, $lastcourse);
2395         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2396         $this->assertTrue(isset($dirty[$coursecontext->path]));
2397         $this->assertEquals(0, context_inspection::test_context_cache_size());
2398         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2399         context_course::instance($lastcourse);
2402         // Test context_helper::create_instances() method.
2404         $prevcount = $DB->count_records('context');
2405         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2406         context_helper::create_instances(null, true);
2407         $this->assertSame($DB->count_records('context'), $prevcount);
2408         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2409         $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2411         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2412         $DB->delete_records('block_instances', array());
2413         $prevcount = $DB->count_records('context');
2414         $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM);
2415         context_helper::create_instances(null, true);
2416         $this->assertSame($prevcount, $DB->count_records('context'));
2417         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2418         $this->assertEquals(0, $DB->count_records('context', array('path'=>null)));
2420         // Test context_helper::cleanup_instances() method.
2422         $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2423         $DB->delete_records('course', array('id'=>$lastcourse));
2424         $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2425         $DB->delete_records('course_categories', array('id'=>$lastcategory));
2426         $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2427         $DB->delete_records('user', array('id'=>$lastuser));
2428         $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2429         $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2430         context_helper::cleanup_instances();
2431         $count = 1; // System.
2432         $count += $DB->count_records('user', array('deleted'=>0));
2433         $count += $DB->count_records('course_categories');
2434         $count += $DB->count_records('course');
2435         $count += $DB->count_records('course_modules');
2436         $count += $DB->count_records('block_instances');
2437         $this->assertEquals($count, $DB->count_records('context'));
2440         // Test context cache size restrictions.
2442         $testusers= array();
2443         for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2444             $user = $generator->create_user();
2445             $testusers[$i] = $user->id;
2446         }
2447         context_helper::create_instances(null, true);
2448         context_helper::reset_caches();
2449         for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2450             context_user::instance($testusers[$i]);
2451             if ($i == CONTEXT_CACHE_MAX_SIZE - 1) {
2452                 $this->assertEquals(CONTEXT_CACHE_MAX_SIZE, context_inspection::test_context_cache_size());
2453             } else if ($i == CONTEXT_CACHE_MAX_SIZE) {
2454                 // Once the limit is reached roughly 1/3 of records should be removed from cache.
2455                 $this->assertEquals((int)ceil(CONTEXT_CACHE_MAX_SIZE * (2/3) + 101), context_inspection::test_context_cache_size());
2456             }
2457         }
2458         // We keep the first 100 cached.
2459         $prevsize = context_inspection::test_context_cache_size();
2460         for ($i=0; $i<100; $i++) {
2461             context_user::instance($testusers[$i]);
2462             $this->assertEquals($prevsize, context_inspection::test_context_cache_size());
2463         }
2464         context_user::instance($testusers[102]);
2465         $this->assertEquals($prevsize+1, context_inspection::test_context_cache_size());
2466         unset($testusers);
2470         // Test basic test of legacy functions.
2471         // Note: watch out, the fake site might be pretty borked already.
2473         $this->assertEquals(get_system_context(), context_system::instance());
2475         foreach ($DB->get_records('context') as $contextid => $record) {
2476             $context = context::instance_by_id($contextid);
2477             $this->assertEquals($context, get_context_instance_by_id($contextid, IGNORE_MISSING));
2478             $this->assertEquals($context, get_context_instance($record->contextlevel, $record->instanceid));
2479             $this->assertEquals($context->get_parent_context_ids(), get_parent_contexts($context));
2480             if ($context->id == SYSCONTEXTID) {
2481                 $this->assertFalse(get_parent_contextid($context));
2482             } else {
2483                 $this->assertSame($context->get_parent_context()->id, get_parent_contextid($context));
2484             }
2485         }
2487         $children = get_child_contexts($systemcontext);
2488         // Using assertEquals here as assertSame fails for some reason...
2489         $this->assertEquals($children, $systemcontext->get_child_contexts());
2490         $this->assertEquals(count($children), $DB->count_records('context')-1);
2491         $this->resetDebugging();
2492         unset($children);
2494         // Make sure a debugging is thrown.
2495         get_context_instance($record->contextlevel, $record->instanceid);
2496         $this->assertDebuggingCalled('get_context_instance() is deprecated, please use context_xxxx::instance() instead.', DEBUG_DEVELOPER);
2497         get_context_instance_by_id($record->id);
2498         $this->assertDebuggingCalled('get_context_instance_by_id() is deprecated, please use context::instance_by_id($id) instead.', DEBUG_DEVELOPER);
2499         get_system_context();
2500         $this->assertDebuggingCalled('get_system_context() is deprecated, please use context_system::instance() instead.', DEBUG_DEVELOPER);
2501         get_parent_contexts($context);
2502         $this->assertDebuggingCalled('get_parent_contexts() is deprecated, please use $context->get_parent_context_ids() instead.', DEBUG_DEVELOPER);
2503         get_parent_contextid($context);
2504         $this->assertDebuggingCalled('get_parent_contextid() is deprecated, please use $context->get_parent_context() instead.', DEBUG_DEVELOPER);
2505         get_child_contexts($frontpagecontext);
2506         $this->assertDebuggingCalled('get_child_contexts() is deprecated, please use $context->get_child_contexts() instead.', DEBUG_DEVELOPER);
2508         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2509         create_contexts();
2510         $this->assertDebuggingCalled('create_contexts() is deprecated, please use context_helper::create_instances() instead.', DEBUG_DEVELOPER);
2511         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK)));
2513         $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK));
2514         build_context_path();
2515         $this->assertDebuggingCalled('build_context_path() is deprecated, please use context_helper::build_all_paths() instead.', DEBUG_DEVELOPER);
2516         $this->assertFalse($DB->record_exists('context', array('depth'=>0)));
2518         $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2519         $DB->delete_records('course', array('id'=>$lastcourse));
2520         $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2521         $DB->delete_records('course_categories', array('id'=>$lastcategory));
2522         $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2523         $DB->delete_records('user', array('id'=>$lastuser));
2524         $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2525         $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2526         cleanup_contexts();
2527         $this->assertDebuggingCalled('cleanup_contexts() is deprecated, please use context_helper::cleanup_instances() instead.', DEBUG_DEVELOPER);
2528         $count = 1; // System.
2529         $count += $DB->count_records('user', array('deleted'=>0));
2530         $count += $DB->count_records('course_categories');
2531         $count += $DB->count_records('course');
2532         $count += $DB->count_records('course_modules');
2533         $count += $DB->count_records('block_instances');
2534         $this->assertEquals($count, $DB->count_records('context'));
2536         // Test legacy rebuild_contexts().
2537         $context = context_course::instance($testcourses[2]);
2538         rebuild_contexts(array($context));
2539         $this->assertDebuggingCalled('rebuild_contexts() is deprecated, please use $context->reset_paths(true) instead.', DEBUG_DEVELOPER);
2540         $context = context_course::instance($testcourses[2]);
2541         $this->assertSame($context->path, $DB->get_field('context', 'path', array('id' => $context->id)));
2542         $this->assertSame($context->depth, $DB->get_field('context', 'depth', array('id' => $context->id)));
2543         $this->assertEquals(0, $DB->count_records('context', array('depth' => 0)));
2544         $this->assertEquals(0, $DB->count_records('context', array('path' => null)));
2546         context_helper::reset_caches();
2547         preload_course_contexts($SITE->id);
2548         $this->assertDebuggingCalled('preload_course_contexts() is deprecated, please use context_helper::preload_course() instead.', DEBUG_DEVELOPER);
2549         $this->assertEquals(1 + $DB->count_records('course_modules', array('course' => $SITE->id)),
2550                 context_inspection::test_context_cache_size());
2552         context_helper::reset_caches();
2553         list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx');
2554         $this->assertDebuggingCalled('context_instance_preload_sql() is deprecated, please use context_helper::get_preload_record_columns_sql() instead.', DEBUG_DEVELOPER);
2555         $this->assertEquals(', ' . context_helper::get_preload_record_columns_sql('ctx'), $select);
2556         $this->assertEquals('LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = ' . CONTEXT_COURSECAT . ')', $join);
2557         $sql = "SELECT c.id $select FROM {course_categories} c $join";
2558         $records = $DB->get_records_sql($sql);
2559         foreach ($records as $record) {
2560             context_instance_preload($record);
2561             $this->assertDebuggingCalled('context_instance_preload() is deprecated, please use context_helper::preload_from_record() instead.',
2562                     DEBUG_DEVELOPER);
2563             $record = (array)$record;
2564             $this->assertEquals(1, count($record)); // Only id left.
2565         }
2566         $this->assertEquals(count($records), context_inspection::test_context_cache_size());
2568         accesslib_clear_all_caches(true);
2569         $DB->delete_records('cache_flags', array());
2570         mark_context_dirty($systemcontext->path);
2571         $this->assertDebuggingCalled('mark_context_dirty() is deprecated, please use $context->mark_dirty() instead.', DEBUG_DEVELOPER);
2572         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2573         $this->assertTrue(isset($dirty[$systemcontext->path]));
2575         accesslib_clear_all_caches(false);
2576         $DB->delete_records('cache_flags', array());
2577         $course = $DB->get_record('course', array('id'=>$testcourses[2]));
2578         $context = context_course::instance($course->id);
2579         $oldpath = $context->path;
2580         $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2581         $categorycontext = context_coursecat::instance($miscid);
2582         $course->category = $miscid;
2583         $DB->update_record('course', $course);
2584         context_moved($context, $categorycontext);
2585         $this->assertDebuggingCalled('context_moved() is deprecated, please use context::update_moved() instead.', DEBUG_DEVELOPER);
2586         $context = context_course::instance($course->id);
2587         $this->assertEquals($categorycontext, $context->get_parent_context());
2589         $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2590         delete_context(CONTEXT_COURSE, $testcourses[2]);
2591         $this->assertDebuggingCalled('delete_context() is deprecated, please use context_helper::delete_instance() instead.', DEBUG_DEVELOPER);
2592         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2593         delete_context(CONTEXT_COURSE, $testcourses[2], false);
2594         $this->assertDebuggingCalled('delete_context() is deprecated, please use $context->delete_content() instead.', DEBUG_DEVELOPER);
2596         $name = get_contextlevel_name(CONTEXT_COURSE);
2597         $this->assertDebuggingCalled('get_contextlevel_name() is deprecated, please use context_helper::get_level_name() instead.', DEBUG_DEVELOPER);
2598         $this->assertFalse(empty($name));
2600         $context = context_course::instance($testcourses[2]);
2601         $name = print_context_name($context);
2602         $this->assertDebuggingCalled('print_context_name() is deprecated, please use $context->get_context_name() instead.', DEBUG_DEVELOPER);
2603         $this->assertFalse(empty($name));
2605         $url1 = get_context_url($coursecontext);
2606         $this->assertDebuggingCalled('get_context_url() is deprecated, please use $context->get_url() instead.', DEBUG_DEVELOPER);
2607         $url2 = $coursecontext->get_url();
2608         $this->assertEquals($url1, $url2);
2609         $this->assertInstanceOf('moodle_url', $url2);
2611         $pagecm = get_coursemodule_from_instance('page', $testpages[7]);
2612         $context = context_module::instance($pagecm->id);
2613         $coursecontext1 = get_course_context($context);
2614         $this->assertDebuggingCalled('get_course_context() is deprecated, please use $context->get_course_context(true) instead.', DEBUG_DEVELOPER);
2615         $coursecontext2 = $context->get_course_context(true);
2616         $this->assertEquals($coursecontext1, $coursecontext2);
2617         $this->assertEquals(CONTEXT_COURSE, $coursecontext2->contextlevel);
2618         $this->assertEquals($pagecm->course, get_courseid_from_context($context));
2619         $this->assertDebuggingCalled('get_courseid_from_context() is deprecated, please use $context->get_course_context(false) instead.', DEBUG_DEVELOPER);
2621         $caps = fetch_context_capabilities($systemcontext);
2622         $this->assertDebuggingCalled('fetch_context_capabilities() is deprecated, please use $context->get_capabilities() instead.', DEBUG_DEVELOPER);
2623         $this->assertEquals($caps, $systemcontext->get_capabilities());
2624         unset($caps);
2625     }
2627     /**
2628      * Test updating of role capabilities during upgrade
2629      */
2630     public function test_update_capabilities() {
2631         global $DB, $SITE;
2633         $this->resetAfterTest(true);
2635         $froncontext = context_course::instance($SITE->id);
2636         $student = $DB->get_record('role', array('archetype'=>'student'));
2637         $teacher = $DB->get_record('role', array('archetype'=>'teacher'));
2639         $existingcaps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2641         $this->assertFalse(isset($existingcaps['moodle/site:restore']));         // Moved to new 'moodle/restore:restorecourse'.
2642         $this->assertTrue(isset($existingcaps['moodle/restore:restorecourse'])); // New cap from 'moodle/site:restore'.
2643         $this->assertTrue(isset($existingcaps['moodle/site:sendmessage']));      // New capability.
2644         $this->assertTrue(isset($existingcaps['moodle/backup:backupcourse']));
2645         $this->assertTrue(isset($existingcaps['moodle/backup:backupsection']));  // Cloned from 'moodle/backup:backupcourse'.
2646         $this->assertTrue(isset($existingcaps['moodle/site:approvecourse']));    // Updated bitmask.
2647         $this->assertTrue(isset($existingcaps['moodle/course:manageactivities']));
2648         $this->assertTrue(isset($existingcaps['mod/page:addinstance']));         // Cloned from core 'moodle/course:manageactivities'.
2650         // Fake state before upgrade.
2651         $DB->set_field('capabilities', 'name', 'moodle/site:restore', array('name'=>'moodle/restore:restorecourse'));
2652         $DB->set_field('role_capabilities', 'capability', 'moodle/site:restore', array('capability'=>'moodle/restore:restorecourse'));
2653         assign_capability('moodle/site:restore', CAP_PROHIBIT, $teacher->id, $froncontext->id, true);
2654         $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/site:restore', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2656         $DB->delete_records('role_capabilities', array('capability'=>'moodle/site:sendmessage'));
2657         $DB->delete_records('capabilities', array('name'=>'moodle/site:sendmessage'));
2659         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupsection'));
2660         $DB->delete_records('capabilities', array('name'=>'moodle/backup:backupsection'));
2661         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2662         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2664         $DB->set_field('capabilities', 'riskbitmask', 0, array('name'=>'moodle/site:approvecourse'));
2666         $DB->delete_records('role_capabilities', array('capability'=>'mod/page:addinstance'));
2667         $DB->delete_records('capabilities', array('name'=>'mod/page:addinstance'));
2668         assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2669         assign_capability('moodle/course:manageactivities', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2671         // Execute core.
2672         update_capabilities('moodle');
2674         // Only core should be upgraded.
2675         $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2677         $this->assertFalse(isset($existingcaps['moodle/site:restore']));
2678         $this->assertTrue(isset($caps['moodle/restore:restorecourse']));
2679         $this->assertEquals($existingcaps['moodle/restore:restorecourse'], $caps['moodle/restore:restorecourse']);
2680         $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/restore:restorecourse', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2681         $this->assertEquals($perms1, $perms2);
2683         $this->assertTrue(isset($caps['moodle/site:sendmessage']));
2684         $this->assertEquals($existingcaps['moodle/site:sendmessage'], $caps['moodle/site:sendmessage']);
2686         $this->assertTrue(isset($caps['moodle/backup:backupsection']));
2687         $this->assertEquals($existingcaps['moodle/backup:backupsection'], $caps['moodle/backup:backupsection']);
2688         $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/backup:backupcourse', 'moodle/backup:backupsection'));
2689         foreach ($roles as $role) {
2690             $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2691             $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupsection', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2692             $this->assertEquals($perms1, $perms2);
2693         }
2695         $this->assertTrue(isset($caps['moodle/site:approvecourse']));
2696         $this->assertEquals($existingcaps['moodle/site:approvecourse'], $caps['moodle/site:approvecourse']);
2698         $this->assertFalse(isset($caps['mod/page:addinstance']));
2700         // Execute plugin.
2701         update_capabilities('mod_page');
2702         $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2703         $this->assertTrue(isset($caps['mod/page:addinstance']));
2704         $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/course:manageactivities', 'mod/page:addinstance'));
2705         foreach ($roles as $role) {
2706             $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/course:manageactivities', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2707             $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'mod/page:addinstance', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2708         }
2709         $this->assertEquals($perms1, $perms2);
2710     }
2713 /**
2714  * Context caching fixture
2715  */
2716 class context_inspection extends context_helper {
2717     public static function test_context_cache_size() {
2718         return self::$cache_count;
2719     }