Merge branch 'MDL-36646_23' of git://github.com/timhunt/moodle into MOODLE_23_STABLE
[moodle.git] / lib / tests / accesslib_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Full functional accesslib test
19  *
20  * @package    core
21  * @category   phpunit
22  * @copyright  2011 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Context caching fixture
31  */
32 class context_inspection extends context_helper {
33     public static function test_context_cache_size() {
34         return self::$cache_count;
35     }
36 }
39 /**
40  * Functional test for accesslib.php
41  *
42  * Note: execution may take many minutes especially on slower servers.
43  */
44 class accesslib_testcase extends advanced_testcase {
46     //TODO: add more tests for the remaining accesslib parts such as enrol related api
48     /**
49      * Verify comparison of context instances in phpunit asserts
50      * @return void
51      */
52     public function test_context_comparisons() {
53         $frontpagecontext1 = context_course::instance(SITEID);
54         context_helper::reset_caches();
55         $frontpagecontext2 = context_course::instance(SITEID);
56         $this->assertEquals($frontpagecontext1, $frontpagecontext2);
58         $user1 = context_user::instance(1);
59         $user2 = context_user::instance(2);
60         $this->assertNotEquals($user1, $user2);
61     }
63     /**
64      * Test resetting works.
65      */
66     public function test_accesslib_clear_all_caches() {
67         global $ACCESSLIB_PRIVATE;
69         $this->resetAfterTest();
71         $this->setAdminUser();
72         load_all_capabilities();
74         $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
75         $this->assertNotEmpty($ACCESSLIB_PRIVATE->rolepermissions);
76         $this->assertNotEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
77         accesslib_clear_all_caches(true);
78         $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
79         $this->assertEmpty($ACCESSLIB_PRIVATE->rolepermissions);
80         $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts);
81         $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
82     }
84     /**
85      * Test getting of role access
86      * @return void
87      */
88     public function test_get_role_access() {
89         global $DB;
91         $roles = $DB->get_records('role');
92         foreach ($roles as $role) {
93             $access = get_role_access($role->id);
95             $this->assertTrue(is_array($access));
96             $this->assertTrue(is_array($access['ra']));
97             $this->assertTrue(is_array($access['rdef']));
98             $this->assertTrue(isset($access['rdef_count']));
99             $this->assertTrue(is_array($access['loaded']));
100             $this->assertTrue(isset($access['time']));
101             $this->assertTrue(is_array($access['rsw']));
102         }
104         // Note: the data is validated in the functional permission evaluation test at the end of this testcase.
105     }
107     /**
108      * Test getting of guest role.
109      * @return void
110      */
111     public function test_get_guest_role() {
112         global $CFG;
114         $guest = get_guest_role();
115         $this->assertEquals('guest', $guest->archetype);
116         $this->assertEquals('guest', $guest->shortname);
118         $this->assertEquals($CFG->guestroleid, $guest->id);
119     }
121     /**
122      * Test if user is admin.
123      * @return void
124      */
125     public function test_is_siteadmin() {
126         global $DB;
128         $this->resetAfterTest();
130         $users = $DB->get_records('user');
132         foreach ($users as $user) {
133             $this->setUser(0);
134             if ($user->username === 'admin') {
135                 $this->assertTrue(is_siteadmin($user));
136                 $this->assertTrue(is_siteadmin($user->id));
137                 $this->setUser($user);
138                 $this->assertTrue(is_siteadmin());
139                 $this->assertTrue(is_siteadmin(null));
140             } else {
141                 $this->assertFalse(is_siteadmin($user));
142                 $this->assertFalse(is_siteadmin($user->id));
143                 $this->setUser($user);
144                 $this->assertFalse(is_siteadmin());
145                 $this->assertFalse(is_siteadmin(null));
146             }
147         }
148     }
150     /**
151      * Test if user is enrolled in a course
152      * @return void
153      */
154     public function test_is_enrolled() {
155         global $DB;
157         // Generate data
158         $user = $this->getDataGenerator()->create_user();
159         $course = $this->getDataGenerator()->create_course();
160         $coursecontext = context_course::instance($course->id);
161         $role = $DB->get_record('role', array('shortname'=>'student'));
163         // There should be a manual enrolment as part of the default install
164         $plugin = enrol_get_plugin('manual');
165         $instance = $DB->get_record('enrol', array(
166             'courseid' => $course->id,
167             'enrol' => 'manual',
168         ));
169         $this->assertNotEquals($instance, false);
171         // Enrol the user in the course
172         $plugin->enrol_user($instance, $user->id, $role->id);
174         // We'll test with the mod/assign:submit capability
175         $capability= 'mod/assign:submit';
176         $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
178         // Switch to our user
179         $this->setUser($user);
181         // Ensure that the user has the capability first
182         $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
184         // We first test whether the user is enrolled on the course as this
185         // seeds the cache, then we test for the capability
186         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
187         $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
189         // Prevent the capability for this user role
190         assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
191         $coursecontext->mark_dirty();
192         $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
194         // Again, we seed the cache first by checking initial enrolment,
195         // and then we test the actual capability
196         $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
197         $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
199         // We need variable states to be reset for the next test
200         $this->resetAfterTest(true);
201     }
203     /**
204      * Test logged in test.
205      * @return void
206      */
207     public function test_isloggedin() {
208         global $USER;
210         $this->resetAfterTest();
212         $USER->id = 0;
213         $this->assertFalse(isloggedin());
214         $USER->id = 1;
215         $this->assertTrue(isloggedin());
216     }
218     /**
219      * Test guest user test.
220      * @return void
221      */
222     public function test_isguestuser() {
223         global $DB;
225         $this->resetAfterTest();
227         $guest = $DB->get_record('user', array('username'=>'guest'));
228         $this->setUser(0);
229         $this->assertFalse(isguestuser());
230         $this->setAdminUser();
231         $this->assertFalse(isguestuser());
232         $this->assertTrue(isguestuser($guest));
233         $this->assertTrue(isguestuser($guest->id));
234         $this->setUser($guest);
235         $this->assertTrue(isguestuser());
237         $users = $DB->get_records('user');
238         foreach ($users as $user) {
239             if ($user->username === 'guest') {
240                 continue;
241             }
242             $this->assertFalse(isguestuser($user));
243         }
244     }
246     /**
247      * Test capability riskiness.
248      * @return void
249      */
250     public function test_is_safe_capability() {
251         global $DB;
252         // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap.
253         $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST);
254         $this->assertFalse(is_safe_capability($capability));
255     }
257     /**
258      * Test context fetching.
259      * @return void
260      */
261     public function test_get_context_info_array() {
262         $this->resetAfterTest();
264         $syscontext = context_system::instance();
265         $user = $this->getDataGenerator()->create_user();
266         $usercontext = context_user::instance($user->id);
267         $course = $this->getDataGenerator()->create_course();
268         $catcontext = context_coursecat::instance($course->category);
269         $coursecontext = context_course::instance($course->id);
270         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
271         $modcontext = context_module::instance($page->cmid);
272         $cm = get_coursemodule_from_instance('page', $page->id);
273         $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
274         $block1context = context_block::instance($block1->id);
275         $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id));
276         $block2context = context_block::instance($block2->id);
278         $result = get_context_info_array($syscontext->id);
279         $this->assertCount(3, $result);
280         $this->assertSame($syscontext, $result[0]);
281         $this->assertSame(null, $result[1]);
282         $this->assertSame(null, $result[2]);
284         $result = get_context_info_array($usercontext->id);
285         $this->assertCount(3, $result);
286         $this->assertSame($usercontext, $result[0]);
287         $this->assertSame(null, $result[1]);
288         $this->assertSame(null, $result[2]);
290         $result = get_context_info_array($catcontext->id);
291         $this->assertCount(3, $result);
292         $this->assertSame($catcontext, $result[0]);
293         $this->assertSame(null, $result[1]);
294         $this->assertSame(null, $result[2]);
296         $result = get_context_info_array($coursecontext->id);
297         $this->assertCount(3, $result);
298         $this->assertSame($coursecontext, $result[0]);
299         $this->assertEquals($course->id, $result[1]->id);
300         $this->assertEquals($course->shortname, $result[1]->shortname);
301         $this->assertSame(null, $result[2]);
303         $result = get_context_info_array($block1context->id);
304         $this->assertCount(3, $result);
305         $this->assertSame($block1context, $result[0]);
306         $this->assertEquals($course->id, $result[1]->id);
307         $this->assertEquals($course->shortname, $result[1]->shortname);
308         $this->assertSame(null, $result[2]);
310         $result = get_context_info_array($modcontext->id);
311         $this->assertCount(3, $result);
312         $this->assertSame($modcontext, $result[0]);
313         $this->assertEquals($course->id, $result[1]->id);
314         $this->assertEquals($course->shortname, $result[1]->shortname);
315         $this->assertEquals($cm->id, $result[2]->id);
316         $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
318         $result = get_context_info_array($block2context->id);
319         $this->assertCount(3, $result);
320         $this->assertSame($block2context, $result[0]);
321         $this->assertEquals($course->id, $result[1]->id);
322         $this->assertEquals($course->shortname, $result[1]->shortname);
323         $this->assertEquals($cm->id, $result[2]->id);
324         $this->assertEquals($cm->groupmembersonly, $result[2]->groupmembersonly);
325     }
327     /**
328      * Test looking for course contacts.
329      * @return void
330      */
331     public function test_has_coursecontact_role() {
332         global $DB, $CFG;
334         $this->resetAfterTest();
336         $users = $DB->get_records('user');
338         // Nobody is expected to have any course level roles.
339         $this->assertNotEmpty($CFG->coursecontact);
340         foreach($users as $user) {
341             $this->assertFalse(has_coursecontact_role($user->id));
342         }
344         $user = $this->getDataGenerator()->create_user();
345         $course = $this->getDataGenerator()->create_course();
346         role_assign($CFG->coursecontact, $user->id, context_course::instance($course->id));
347         $this->assertTrue(has_coursecontact_role($user->id));
348     }
350     /**
351      * Test creation of roles.
352      * @return void
353      */
354     public function test_create_role() {
355         global $DB;
357         $this->resetAfterTest();
359         $id = create_role('New student role', 'student2', 'New student description', 'student');
360         $role = $DB->get_record('role', array('id'=>$id));
362         $this->assertNotEmpty($role);
363         $this->assertEquals('New student role', $role->name);
364         $this->assertEquals('student2', $role->shortname);
365         $this->assertEquals('New student description', $role->description);
366         $this->assertEquals('student', $role->archetype);
367     }
369     /**
370      * Test adding of capabilities to roles.
371      */
372     public function test_assign_capability() {
373         global $DB;
375         $this->resetAfterTest();
377         $user = $this->getDataGenerator()->create_user();
378         $syscontext = context_system::instance();
379         $frontcontext = context_course::instance(SITEID);
380         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
381         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability assigned to student by default
382         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
383         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
385         $this->setUser($user);
386         $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id);
387         $this->assertTrue($result);
388         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
389         $this->assertNotEmpty($permission);
390         $this->assertEquals(CAP_ALLOW, $permission->permission);
391         $this->assertEquals($user->id, $permission->modifierid);
393         $this->setUser(0);
394         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false);
395         $this->assertTrue($result);
396         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
397         $this->assertNotEmpty($permission);
398         $this->assertEquals(CAP_ALLOW, $permission->permission);
399         $this->assertEquals(3, $permission->modifierid);
401         $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true);
402         $this->assertTrue($result);
403         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
404         $this->assertNotEmpty($permission);
405         $this->assertEquals(CAP_PROHIBIT, $permission->permission);
406         $this->assertEquals(0, $permission->modifierid);
408         $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id);
409         $this->assertTrue($result);
410         $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
411         $this->assertEmpty($permission);
412     }
414     /**
415      * Test removing of capabilities from roles.
416      */
417     public function test_unassign_capability() {
418         global $DB;
420         $this->resetAfterTest();
422         $syscontext = context_system::instance();
423         $frontcontext = context_course::instance(SITEID);
424         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
425         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability assigned to manager by default
426         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
428         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
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, $syscontext->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->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
435         unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext);
436         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
438         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
439         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
440         $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
442         $result = unassign_capability('moodle/backup:backupcourse', $manager->id);
443         $this->assertTrue($result);
444         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
445         $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
446     }
448     /**
449      * Test role assigning
450      */
451     public function test_role_assign() {
452         global $DB, $USER;
454         $this->resetAfterTest();
456         $user = $this->getDataGenerator()->create_user();
457         $course = $this->getDataGenerator()->create_course();
458         $role = $DB->get_record('role', array('shortname'=>'student'));
460         $this->setUser(0);
461         $context = context_system::instance();
462         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
463         role_assign($role->id, $user->id, $context->id);
464         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
465         $this->assertNotEmpty($ras);
466         $this->assertSame('', $ras->component);
467         $this->assertSame('0', $ras->itemid);
468         $this->assertEquals($USER->id, $ras->modifierid);
470         $this->setAdminUser();
471         $context = context_course::instance($course->id);
472         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
473         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666);
474         $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
475         $this->assertNotEmpty($ras);
476         $this->assertSame('enrol_self', $ras->component);
477         $this->assertSame('1', $ras->itemid);
478         $this->assertEquals($USER->id, $ras->modifierid);
479         $this->assertEquals(666, $ras->timemodified);
480     }
482     /**
483      * Test role unassigning
484      * @return void
485      */
486     public function test_role_unassign() {
487         global $DB;
489         $this->resetAfterTest();
491         $user = $this->getDataGenerator()->create_user();
492         $course = $this->getDataGenerator()->create_course();
493         $role = $DB->get_record('role', array('shortname'=>'student'));
495         $context = context_system::instance();
496         role_assign($role->id, $user->id, $context->id);
497         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
498         role_unassign($role->id, $user->id, $context->id);
499         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
501         role_assign($role->id, $user->id, $context->id, 'enrol_self', 1);
502         $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
503         role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1);
504         $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
505     }
507     /**
508      * Test role unassigning
509      * @return void
510      */
511     public function test_role_unassign_all() {
512         global $DB;
514         $this->resetAfterTest();
516         $user = $this->getDataGenerator()->create_user();
517         $course = $this->getDataGenerator()->create_course();
518         $role = $DB->get_record('role', array('shortname'=>'student'));
519         $syscontext = context_system::instance();
520         $coursecontext = context_course::instance($course->id);
521         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
522         $modcontext = context_module::instance($page->cmid);
524         role_assign($role->id, $user->id, $syscontext->id);
525         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
526         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
527         role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id));
528         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
530         role_assign($role->id, $user->id, $syscontext->id);
531         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
532         role_assign($role->id, $user->id, $modcontext->id);
533         $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id)));
534         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false);
535         $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
536         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true);
537         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
538         role_unassign_all(array('userid'=>$user->id));
539         $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
541         role_assign($role->id, $user->id, $syscontext->id);
542         role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
543         role_assign($role->id, $user->id, $coursecontext->id);
544         role_assign($role->id, $user->id, $modcontext->id);
545         $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id)));
546         role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true);
547         $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
548     }
550     /**
551      * Test role queries.
552      * @return void
553      */
554     public function test_get_roles_with_capability() {
555         global $DB;
557         $this->resetAfterTest();
559         $syscontext = context_system::instance();
560         $frontcontext = context_course::instance(SITEID);
561         $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
562         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
564         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability is ok
565         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse'));
567         $roles = get_roles_with_capability('moodle/backup:backupcourse');
568         $this->assertEquals(array(), $roles);
570         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
571         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id);
572         assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id);
574         $roles = get_roles_with_capability('moodle/backup:backupcourse');
575         $this->assertEquals(array($teacher->id, $manager->id), array_keys($roles), '', 0, 10, true);
577         $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW);
578         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
580         $roles = get_roles_with_capability('moodle/backup:backupcourse', NULL, $syscontext);
581         $this->assertEquals(array($manager->id), array_keys($roles), '', 0, 10, true);
582     }
584     /**
585      * Test deleting of roles.
586      * @return void
587      */
588     public function test_delete_role() {
589         global $DB;
591         $this->resetAfterTest();
593         $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
594         $user = $this->getDataGenerator()->create_user();
595         role_assign($role->id, $user->id, context_system::instance());
596         $course = $this->getDataGenerator()->create_course();
597         $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id);
598         $DB->insert_record('role_names', $rolename);
600         $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
601         $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
602         $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id)));
603         $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
604         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
605         $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
606         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
607         $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
609         $result = delete_role($role->id);
610         $this->assertTrue($result);
611         $this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
612         $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
613         $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
614         $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id)));
615         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
616         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
617         $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
618         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
619         $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
620     }
622     /**
623      * Test fetching of all roles.
624      * @return void
625      */
626     public function test_get_all_roles() {
627         $allroles = get_all_roles();
628         $this->assertEquals('array', gettype($allroles));
629         $this->assertCount(8, $allroles); // there are 8 roles is standard install
631         $role = reset($allroles);
632         $role = (array)$role;
634         $this->assertEquals(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), array_keys($role), '', 0, 10, true);
636         foreach($allroles as $roleid => $role) {
637             $this->assertEquals($role->id, $roleid);
638         }
639     }
641     /**
642      * Test getting of all archetypes.
643      * @return void
644      */
645     public function test_get_role_archetypes() {
646         $archetypes = get_role_archetypes();
647         $this->assertCount(8, $archetypes); // there are 8 archetypes in standard install
648         foreach ($archetypes as $k=>$v) {
649             $this->assertSame($k, $v);
650         }
651     }
653     /**
654      * Test getting of roles with given archetype.
655      * @return void
656      */
657     public function test_get_archetype_roles() {
658         $this->resetAfterTest();
660         // New install should have 1 role for each archetype.
661         $archetypes = get_role_archetypes();
662         foreach ($archetypes as $archetype) {
663             $roles = get_archetype_roles($archetype);
664             $this->assertCount(1, $roles);
665             $role = reset($roles);
666             $this->assertEquals($archetype, $role->archetype);
667         }
669         create_role('New student role', 'student2', 'New student description', 'student');
670         $roles = get_archetype_roles('student');
671         $this->assertCount(2, $roles);
672     }
674     /**
675      * Test aliased role names
676      * @return void
677      */
678     public function test_role_get_name() {
679         global $DB;
681         $this->resetAfterTest();
683         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
684         $allroles = $DB->get_records('role');
685         $course = $this->getDataGenerator()->create_course();
686         $coursecontext = context_course::instance($course->id);
688         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
689         $DB->insert_record('role_names', $teacherename);
691         foreach ($allroles as $role) {
692             $this->assertNotEmpty(role_get_name($role, $coursecontext));
693             if ($role->id == $teacher->id) {
694                 $this->assertSame($teacherename->name, role_get_name($role, $coursecontext));
695             }
696         }
697     }
699     /**
700      * Test tweaking of role name arrays
701      * @return void
702      */
703     public function test_role_fix_names() {
704         global $DB;
706         $this->resetAfterTest();
708         $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
709         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
710         $otherid = create_role('Other role', 'other', 'Some other role', '');
711         $anotherid = create_role('Another role', 'another', 'Yet another other role', '');
712         $allroles = $DB->get_records('role');
714         $syscontext = context_system::instance();
715         $frontcontext = context_course::instance(SITEID);
716         $course = $this->getDataGenerator()->create_course();
717         $coursecontext = context_course::instance($course->id);
718         $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST);
719         $categorycontext = context_coursecat::instance($category->id);
721         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
722         $DB->insert_record('role_names', $teacherename);
723         $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
724         $DB->insert_record('role_names', $otherrename);
725         $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid,name');
727         // Make sure all localname contain proper values for each ROLENAME_ constant,
728         // note role_get_name() on frontpage is used to get the original name for future comatibility.
729         $roles = $allroles;
730         unset($roles[$student->id]); // Remove one roel to make sure no role is added or removed.
731         $rolenames = array();
732         foreach ($roles as $role) {
733             $rolenames[$role->id] = $role->name;
734         }
736         /* TODO: unsupported! MDL-8249
737         $fixed = role_fix_names($roles, $coursecontext, ROLENAME_SHORT);
738         $this->assertCount(count($roles), $fixed);
739         foreach($fixed as $rolename) {
740             $this->assertInstanceOf('stdClass', $rolename);
741             $role = $roles[$rolename->id];
742             $this->assertSame($role->shortname, $rolename->localname);
743         }
744         */
746         /* TODO: unsupported! MDL-8249
747         $fixed = role_fix_names($roles, $coursecontext, ROLENAME_ORIGINALANDSHORT);
748         $this->assertCount(count($roles), $fixed);
749         foreach($fixed as $rolename) {
750             $this->assertInstanceOf('stdClass', $rolename);
751             $role = $roles[$rolename->id];
752             $this->assertSame("$role->name ($role->shortname)", $rolename->localname);
753         }
754         */
756         $fixed = role_fix_names($roles, $coursecontext, ROLENAME_ORIGINAL);
757         $this->assertCount(count($roles), $fixed);
758         foreach($fixed as $roleid=>$rolename) {
759             $this->assertInstanceOf('stdClass', $rolename);
760             $role = $roles[$roleid];
761             $name = role_get_name($role, $frontcontext);
762             $this->assertSame($name, $rolename->localname);
763         }
764         $fixed = role_fix_names($rolenames, $coursecontext, ROLENAME_ORIGINAL);
765         $this->assertCount(count($rolenames), $fixed);
766         foreach($fixed as $roleid=>$rolename) {
767             $role = $roles[$roleid];
768             $name = role_get_name($role, $frontcontext);
769             $this->assertSame($name, $rolename);
770         }
772         $fixed = role_fix_names($roles, $coursecontext, ROLENAME_ALIAS);
773         $this->assertCount(count($roles), $fixed);
774         foreach($fixed as $roleid=>$rolename) {
775             $this->assertInstanceOf('stdClass', $rolename);
776             $role = $roles[$roleid];
777             $this->assertSame(role_get_name($role, $coursecontext), $rolename->localname);
778         }
779         $fixed = role_fix_names($rolenames, $coursecontext, ROLENAME_ALIAS);
780         $this->assertCount(count($rolenames), $fixed);
781         foreach($fixed as $roleid=>$rolename) {
782             $role = $roles[$roleid];
783             $this->assertSame(role_get_name($role, $coursecontext), $rolename);
784         }
786         /* TODO: buggy! MDL-8249
787         $fixed = role_fix_names($roles, $coursecontext, ROLENAME_BOTH);
788         $this->assertCount(count($roles), $fixed);
789         foreach($fixed as $roleid=>$rolename) {
790             $this->assertInstanceOf('stdClass', $rolename);
791             $role = $roles[$roleid];
792             $name = role_get_name($role, $frontcontext);
793             if (isset($renames[$roleid])) {
794                 $this->assertSame("$renames[$roleid] ($name)", $rolename->localname);
795             } else {
796                 $this->assertSame(role_get_name($role, $coursecontext), $rolename->localname);
797             }
798         }
799         */
800         $fixed = role_fix_names($rolenames, $coursecontext, ROLENAME_BOTH);
801         $this->assertCount(count($rolenames), $fixed);
802         foreach($fixed as $roleid=>$rolename) {
803             $role = $roles[$roleid];
804             if (isset($renames[$roleid])) {
805                 $name = role_get_name($role, $frontcontext);
806                 $this->assertSame("$renames[$roleid] ($name)", $rolename);
807             } else {
808                 $this->assertSame(role_get_name($role, $coursecontext), $rolename);
809             }
810         }
812         $fixed = role_fix_names($roles, $coursecontext, ROLENAME_ALIAS_RAW);
813         $this->assertCount(count($roles), $fixed);
814         foreach($fixed as $roleid=>$rolename) {
815             $this->assertInstanceOf('stdClass', $rolename);
816             if (isset($renames[$roleid])) {
817                 $this->assertSame($renames[$roleid], $rolename->localname);
818             } else {
819                 $this->assertSame('', $rolename->localname);
820             }
821         }
822         $fixed = role_fix_names($rolenames, $coursecontext, ROLENAME_ALIAS_RAW);
823         $this->assertCount(count($rolenames), $fixed);
824         foreach($fixed as $roleid=>$rolename) {
825             if (isset($renames[$roleid])) {
826                 $this->assertSame($renames[$roleid], $rolename);
827             } else {
828                 $this->assertSame('', $rolename);
829             }
830         }
831     }
833     /**
834      * Test allowing of role assignments.
835      * @return void
836      */
837     public function test_allow_assign() {
838         global $DB;
840         $this->resetAfterTest();
842         $otherid = create_role('Other role', 'other', 'Some other role', '');
843         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
845         $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
846         allow_assign($otherid, $student->id);
847         $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
848     }
850     /**
851      * Test allowing of role overrides.
852      * @return void
853      */
854     public function test_allow_override() {
855         global $DB;
857         $this->resetAfterTest();
859         $otherid = create_role('Other role', 'other', 'Some other role', '');
860         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
862         $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
863         allow_override($otherid, $student->id);
864         $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
865     }
867     /**
868      * Test allowing of role switching.
869      * @return void
870      */
871     public function test_allow_switch() {
872         global $DB;
874         $this->resetAfterTest();
876         $otherid = create_role('Other role', 'other', 'Some other role', '');
877         $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
879         $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
880         allow_switch($otherid, $student->id);
881         $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
882     }
884     /**
885      * Test returning of assignable roles in context.
886      * @return void
887      */
888     public function test_get_assignable_roles() {
889         global $DB;
891         $this->resetAfterTest();
893         $course = $this->getDataGenerator()->create_course();
894         $coursecontext = context_course::instance($course->id);
896         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
897         $teacher = $this->getDataGenerator()->create_user();
898         role_assign($teacherrole->id, $teacher->id, $coursecontext);
899         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
900         $DB->insert_record('role_names', $teacherename);
902         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
903         $student = $this->getDataGenerator()->create_user();
904         role_assign($studentrole->id, $student->id, $coursecontext);
906         $contexts = $DB->get_records('context');
907         $users = $DB->get_records('user');
908         $allroles = $DB->get_records('role');
910         // Evaluate all results for all users in all contexts.
911         foreach($users as $user) {
912             $this->setUser($user);
913             foreach ($contexts as $contextid=>$unused) {
914                 $context = context_helper::instance_by_id($contextid);
915                 $roles = get_assignable_roles($context, ROLENAME_SHORT);
916                 foreach ($allroles as $roleid=>$role) {
917                     if (isset($roles[$roleid])) {
918                         if (is_siteadmin()) {
919                             $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)));
920                         } else {
921                             $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid");
922                         }
923                         $this->assertEquals($role->shortname, $roles[$roleid]);
924                     } else {
925                         $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid));
926                         if (is_siteadmin()) {
927                             $this->assertFalse($allowed);
928                         } else {
929                             $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel");
930                         }
931                     }
932                 }
933             }
934         }
936         // not-logged-in user
937         $this->setUser(0);
938         foreach ($contexts as $contextid=>$unused) {
939             $context = context_helper::instance_by_id($contextid);
940             $roles = get_assignable_roles($context, ROLENAME_SHORT);
941             $this->assertSame(array(), $roles);
942         }
944         // Test current user.
945         $this->setUser(0);
946         $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST);
947         $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin);
948         $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id);
949         $this->setAdminUser();
950         $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT);
951         $this->assertSame($roles1, $roles3);
952         $this->assertSame($roles2, $roles3);
954         // Test parameter defaults.
955         $this->setAdminUser();
956         $roles1 = get_assignable_roles($coursecontext);
957         $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
958         $this->assertEquals($roles2, $roles1);
960         // Verify returned names - let's allow all roles everywhere to simplify this a bit.
961         $alllevels = context_helper::get_all_levels();
962         $alllevels = array_keys($alllevels);
963         foreach($allroles as $roleid=>$role) {
964             set_role_contextlevels($roleid, $alllevels);
965         }
966         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
967         foreach ($alltypes as $type) {
968             if ($type == ROLENAME_SHORT or $type == ROLENAME_ORIGINALANDSHORT or $type == ROLENAME_BOTH) {
969                 // TODO: skip for now, remove after role_fix_names() is fixed and supports all types MDL-8249
970                 continue;
971             }
972             $rolenames = role_fix_names($allroles, $coursecontext, $type);
973             $roles = get_assignable_roles($coursecontext, $type, false, $admin);
974             foreach ($roles as $roleid=>$rolename) {
975                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
976             }
977         }
979         // Verify counts.
980         //TODO: test all types - ROLENAME_SHORT is borked here for example MDL-8249
981         $roles = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
982         list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, ROLENAME_ALIAS, true, $admin);
983         $this->assertEquals($roles, $rolenames);
984         foreach ($rolenames as $roleid=>$name) {
985             if ($roleid == $teacherrole->id or $roleid == $studentrole->id) {
986                 $this->assertEquals(1, $rolecounts[$roleid]);
987             } else {
988                 $this->assertEquals(0, $rolecounts[$roleid]);
989             }
990             $this->assertEquals("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
991         }
992     }
994     /**
995      * Test getting of all switchable roles.
996      * @retrun void
997      */
998     public function test_get_switchable_roles() {
999         global $DB;
1001         $this->resetAfterTest();
1003         $course = $this->getDataGenerator()->create_course();
1004         $coursecontext = context_course::instance($course->id);
1006         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1007         $teacher = $this->getDataGenerator()->create_user();
1008         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1009         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1010         $DB->insert_record('role_names', $teacherename);
1012         $contexts = $DB->get_records('context');
1013         $users = $DB->get_records('user');
1014         $allroles = $DB->get_records('role');
1016         // Evaluate all results for all users in all contexts.
1017         foreach($users as $user) {
1018             $this->setUser($user);
1019             foreach ($contexts as $contextid=>$unused) {
1020                 $context = context_helper::instance_by_id($contextid);
1021                 $roles = get_switchable_roles($context);
1022                 foreach ($allroles as $roleid=>$role) {
1023                     if (is_siteadmin()) {
1024                         $this->assertTrue(isset($roles[$roleid]));
1025                     } else {
1026                         $parents = $context->get_parent_context_ids(true);
1027                         $pcontexts = implode(',' , $parents);
1028                         $allowed = $DB->record_exists_sql(
1029                             "SELECT r.id
1030                                FROM {role} r
1031                                JOIN {role_allow_switch} ras ON ras.allowswitch = r.id
1032                                JOIN {role_assignments} ra ON ra.roleid = ras.roleid
1033                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1034                             ",
1035                             array('userid'=>$user->id, 'roleid'=>$roleid)
1036                         );
1037                         if (isset($roles[$roleid])) {
1038                             $this->assertTrue($allowed);
1039                         } else {
1040                             $this->assertFalse($allowed);
1041                         }
1042                     }
1044                     if (isset($roles[$roleid])) {
1045                         $coursecontext = $context->get_course_context(false);
1046                         if ($coursecontext) {
1047                             $this->assertEquals(role_get_name($role, $coursecontext), $roles[$roleid]);
1048                         } else {
1049                             // TODO: switch to role_get_name() once it supports all contexts and rolename types MDL-8249
1050                             $this->assertEquals($role->name, $roles[$roleid]);
1051                         }
1052                     }
1053                 }
1054             }
1055         }
1056     }
1058     /**
1059      * Test getting of all overridable roles.
1060      * @return void
1061      */
1062     public function test_get_overridable_roles() {
1063         global $DB;
1065         $this->resetAfterTest();
1067         $course = $this->getDataGenerator()->create_course();
1068         $coursecontext = context_course::instance($course->id);
1070         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1071         $teacher = $this->getDataGenerator()->create_user();
1072         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1073         $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
1074         $DB->insert_record('role_names', $teacherename);
1075         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // any capability is ok
1076         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacher->id, $coursecontext->id);
1078         $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
1079         $student = $this->getDataGenerator()->create_user();
1080         role_assign($studentrole->id, $student->id, $coursecontext);
1082         $contexts = $DB->get_records('context');
1083         $users = $DB->get_records('user');
1084         $allroles = $DB->get_records('role');
1086         // Evaluate all results for all users in all contexts.
1087         foreach($users as $user) {
1088             $this->setUser($user);
1089             foreach ($contexts as $contextid=>$unused) {
1090                 $context = context_helper::instance_by_id($contextid);
1091                 $roles = get_overridable_roles($context, ROLENAME_SHORT);
1092                 foreach ($allroles as $roleid=>$role) {
1093                     $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context);
1094                     if (is_siteadmin()) {
1095                         $this->assertTrue(isset($roles[$roleid]));
1096                     } else {
1097                         $parents = $context->get_parent_context_ids(true);
1098                         $pcontexts = implode(',' , $parents);
1099                         $allowed = $DB->record_exists_sql(
1100                             "SELECT r.id
1101                                FROM {role} r
1102                                JOIN {role_allow_override} rao ON r.id = rao.allowoverride
1103                                JOIN {role_assignments} ra ON rao.roleid = ra.roleid
1104                               WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
1105                             ",
1106                             array('userid'=>$user->id, 'roleid'=>$roleid)
1107                         );
1108                         if (isset($roles[$roleid])) {
1109                             $this->assertTrue($hascap);
1110                             $this->assertTrue($allowed);
1111                         } else {
1112                             $this->assertFalse($hascap and $allowed);
1113                         }
1114                     }
1116                     if (isset($roles[$roleid])) {
1117                         //TODO: ROLENAME_SHORT borked! MDL-8249
1118                         //$this->assertEquals($role->shortname, $roles[$roleid]);
1119                     }
1120                 }
1121             }
1122         }
1124         // Test parameter defaults.
1125         $this->setAdminUser();
1126         $roles1 = get_overridable_roles($coursecontext);
1127         $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1128         $this->assertEquals($roles2, $roles1);
1130         $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
1131         foreach ($alltypes as $type) {
1132             if ($type == ROLENAME_SHORT or $type == ROLENAME_ORIGINALANDSHORT or $type == ROLENAME_BOTH) {
1133                 // TODO: skip for now, remove after role_fix_names() is fixed and supports all types MDL-8249
1134                 continue;
1135             }
1136             $rolenames = role_fix_names($allroles, $coursecontext, $type);
1137             $roles = get_overridable_roles($coursecontext, $type, false);
1138             foreach ($roles as $roleid=>$rolename) {
1139                 $this->assertSame($rolenames[$roleid]->localname, $rolename);
1140             }
1141         }
1143         // Verify counts.
1144         $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
1145         list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true);
1146         $this->assertEquals($roles, $rolenames);
1147         foreach ($rolenames as $roleid=>$name) {
1148             if ($roleid == $teacherrole->id) {
1149                 $this->assertEquals(1, $rolecounts[$roleid]);
1150             } else {
1151                 $this->assertEquals(0, $rolecounts[$roleid]);
1152             }
1153             $this->assertEquals("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
1154         }
1155     }
1157     /**
1158      * Test we have context level defaults.
1159      * @return void
1160      */
1161     public function test_get_default_contextlevels() {
1162         $archetypes = get_role_archetypes();
1163         $alllevels = context_helper::get_all_levels();
1164         foreach ($archetypes as $archetype) {
1165             $defaults = get_default_contextlevels($archetype);
1166             $this->assertTrue(is_array($defaults));
1167             foreach ($defaults as $level) {
1168                 $this->assertTrue(isset($alllevels[$level]));
1169             }
1170         }
1171     }
1173     /**
1174      * Test role context level setup.
1175      * @return void
1176      */
1177     public function test_set_role_contextlevels() {
1178         global $DB;
1180         $this->resetAfterTest();
1182         $roleid = create_role('New student role', 'student2', 'New student description', 'student');
1184         $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid)));
1186         set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE));
1187         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1188         $this->assertCount(2, $levels);
1189         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1190         $this->assertTrue(isset($levels[CONTEXT_MODULE]));
1192         set_role_contextlevels($roleid, array(CONTEXT_COURSE));
1193         $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
1194         $this->assertCount(1, $levels);
1195         $this->assertTrue(isset($levels[CONTEXT_COURSE]));
1196     }
1198     /**
1199      * Test getting of role context levels
1200      * @return void
1201      */
1202     public function test_get_roles_for_contextlevels() {
1203         global $DB;
1205         $allroles = get_all_roles();
1206         foreach (context_helper::get_all_levels() as $level=>$unused) {
1207             $roles = get_roles_for_contextlevels($level);
1208             foreach ($allroles as $roleid=>$unused) {
1209                 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid));
1210                 if (in_array($roleid, $roles)) {
1211                     $this->assertTrue($exists);
1212                 } else {
1213                     $this->assertFalse($exists);
1214                 }
1215             }
1216         }
1217     }
1219     /**
1220      * Test default enrol roles.
1221      * @return void
1222      */
1223     public function test_get_default_enrol_roles() {
1224         $this->resetAfterTest();
1226         $course = $this->getDataGenerator()->create_course();
1227         $coursecontext = context_course::instance($course->id);
1229         $id2 = create_role('New student role', 'student2', 'New student description', 'student');
1230         set_role_contextlevels($id2, array(CONTEXT_COURSE));
1232         //TODO: add role name alias MDL-8249
1234         $allroles = get_all_roles();
1235         $expected = array($id2=>$allroles[$id2]);
1237         foreach(get_role_archetypes() as $archetype) {
1238             $defaults = get_default_contextlevels($archetype);
1239             if (in_array(CONTEXT_COURSE, $defaults)) {
1240                 $roles = get_archetype_roles($archetype);
1241                 foreach($roles as $role) {
1242                     $expected[$role->id] = $role;
1243                 }
1244             }
1245         }
1247         $roles = get_default_enrol_roles($coursecontext);
1248         foreach ($allroles as $role) {
1249             $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id]));
1250             if (isset($roles[$role->id])) {
1251                 $this->assertEquals(role_get_name($role, $coursecontext), $roles[$role->id]);
1252             }
1253         }
1254     }
1256     /**
1257      * Test has_capability(), has_any_capability() and has_all_capabilities().
1258      */
1259     public function test_has_capability_and_friends() {
1260         global $DB;
1262         $this->resetAfterTest();
1264         $course = $this->getDataGenerator()->create_course();
1265         $coursecontext = context_course::instance($course->id);
1266         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
1267         $teacher = $this->getDataGenerator()->create_user();
1268         role_assign($teacherrole->id, $teacher->id, $coursecontext);
1269         $admin = $DB->get_record('user', array('username'=>'admin'));
1271         // Note: Here are used default capabilities, the full test is in permission evaluation bellow,
1272         // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user.
1274         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection')));
1275         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse')));
1276         $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse')));
1278         $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse');
1279         $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse');
1281         $this->setUser(0);
1282         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext));
1283         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext));
1284         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1285         $this->assertFalse(has_any_capability($sca, $coursecontext));
1286         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1288         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher));
1289         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher));
1290         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher));
1291         $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher));
1292         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher));
1293         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher));
1295         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin));
1296         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin));
1297         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin));
1298         $this->assertTrue(has_any_capability($sca, $coursecontext, $admin));
1299         $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin));
1300         $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin));
1302         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false));
1303         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false));
1304         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false));
1305         $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false));
1306         $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false));
1307         $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false));
1309         $this->setUser($teacher);
1310         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1311         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1312         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
1313         $this->assertTrue(has_any_capability($sca, $coursecontext));
1314         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1315         $this->assertFalse(has_all_capabilities($sca, $coursecontext));
1317         $this->setAdminUser();
1318         $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
1319         $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
1320         $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext));
1321         $this->assertTrue(has_any_capability($sca, $coursecontext));
1322         $this->assertTrue(has_all_capabilities($sc, $coursecontext));
1323         $this->assertTrue(has_all_capabilities($sca, $coursecontext));
1325         $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0));
1326         $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0));
1327         $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0));
1328         $this->assertFalse(has_any_capability($sca, $coursecontext, 0));
1329         $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0));
1330     }
1332     /**
1333      * Test require_capability() exceptions.
1334      * @return void
1335      */
1336     public function test_require_capability() {
1337         $this->resetAfterTest();
1339         $syscontext = context_system::instance();
1341         $this->setUser(0);
1342         $this->assertFalse(has_capability('moodle/site:config', $syscontext));
1343         try {
1344             require_capability('moodle/site:config', $syscontext);
1345             $this->fail('Exception expected from require_capability()');
1346         } catch (Exception $e) {
1347             $this->assertInstanceOf('required_capability_exception', $e);
1348         }
1349         $this->setAdminUser();
1350         $this->assertFalse(has_capability('moodle/site:config', $syscontext, 0));
1351         try {
1352             require_capability('moodle/site:config', $syscontext, 0);
1353             $this->fail('Exception expected from require_capability()');
1354         } catch (Exception $e) {
1355             $this->assertInstanceOf('required_capability_exception', $e);
1356         }
1357         $this->assertFalse(has_capability('moodle/site:config', $syscontext, null, false));
1358         try {
1359             require_capability('moodle/site:config', $syscontext, null, false);
1360             $this->fail('Exception expected from require_capability()');
1361         } catch (Exception $e) {
1362             $this->assertInstanceOf('required_capability_exception', $e);
1363         }
1366     }
1368     /**
1369      * A small functional test of permission evaluations.
1370      * @return void
1371      */
1372     public function test_permission_evaluation() {
1373         global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE;
1375         $this->resetAfterTest(true);
1377         $generator = $this->getDataGenerator();
1379         // Fill the site with some real data
1380         $testcategories = array();
1381         $testcourses = array();
1382         $testpages = array();
1383         $testblocks = array();
1384         $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id');
1386         $systemcontext = context_system::instance();
1387         $frontpagecontext = context_course::instance(SITEID);
1389         // Add block to system context
1390         $bi = $generator->create_block('online_users');
1391         context_block::instance($bi->id);
1392         $testblocks[] = $bi->id;
1394         // Some users
1395         $testusers = array();
1396         for($i=0; $i<20; $i++) {
1397             $user = $generator->create_user();
1398             $testusers[$i] = $user->id;
1399             $usercontext = context_user::instance($user->id);
1401             // Add block to user profile
1402             $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id));
1403             $testblocks[] = $bi->id;
1404         }
1405         // Deleted user - should be ignored everywhere, can not have context
1406         $generator->create_user(array('deleted'=>1));
1408         // Add block to frontpage
1409         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id));
1410         $frontpageblockcontext = context_block::instance($bi->id);
1411         $testblocks[] = $bi->id;
1413         // Add a resource to frontpage
1414         $page = $generator->create_module('page', array('course'=>$SITE->id));
1415         $testpages[] = $page->id;
1416         $frontpagepagecontext = context_module::instance($page->cmid);
1418         // Add block to frontpage resource
1419         $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id));
1420         $frontpagepageblockcontext = context_block::instance($bi->id);
1421         $testblocks[] = $bi->id;
1423         // Some nested course categories with courses
1424         $manualenrol = enrol_get_plugin('manual');
1425         $parentcat = 0;
1426         for($i=0; $i<5; $i++) {
1427             $cat = $generator->create_category(array('parent'=>$parentcat));
1428             $testcategories[] = $cat->id;
1429             $catcontext = context_coursecat::instance($cat->id);
1430             $parentcat = $cat->id;
1432             if ($i >= 4) {
1433                 continue;
1434             }
1436             // Add resource to each category
1437             $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id));
1438             context_block::instance($bi->id);
1440             // Add a few courses to each category
1441             for($j=0; $j<6; $j++) {
1442                 $course = $generator->create_course(array('category'=>$cat->id));
1443                 $testcourses[] = $course->id;
1444                 $coursecontext = context_course::instance($course->id);
1446                 if ($j >= 5) {
1447                     continue;
1448                 }
1449                 // Add manual enrol instance
1450                 $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id)));
1452                 // Add block to each course
1453                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
1454                 $testblocks[] = $bi->id;
1456                 // Add a resource to each course
1457                 $page = $generator->create_module('page', array('course'=>$course->id));
1458                 $testpages[] = $page->id;
1459                 $modcontext = context_module::instance($page->cmid);
1461                 // Add block to each module
1462                 $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id));
1463                 $testblocks[] = $bi->id;
1464             }
1465         }
1467         // Make sure all contexts were created properly
1468         $count = 1; //system
1469         $count += $DB->count_records('user', array('deleted'=>0));
1470         $count += $DB->count_records('course_categories');
1471         $count += $DB->count_records('course');
1472         $count += $DB->count_records('course_modules');
1473         $count += $DB->count_records('block_instances');
1474         $this->assertEquals($DB->count_records('context'), $count);
1475         $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0);
1476         $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0);
1479         // ====== context_helper::get_level_name() ================================
1481         $levels = context_helper::get_all_levels();
1482         foreach ($levels as $level=>$classname) {
1483             $name = context_helper::get_level_name($level);
1484             $this->assertFalse(empty($name));
1485         }
1488         // ======= context::instance_by_id(), context_xxx::instance();
1490         $context = context::instance_by_id($frontpagecontext->id);
1491         $this->assertSame($context->contextlevel, CONTEXT_COURSE);
1492         $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING));
1493         try {
1494             context::instance_by_id(-1);
1495             $this->fail('exception expected');
1496         } catch (Exception $e) {
1497             $this->assertTrue(true);
1498         }
1499         $this->assertTrue(context_system::instance() instanceof context_system);
1500         $this->assertTrue(context_coursecat::instance($testcategories[0]) instanceof context_coursecat);
1501         $this->assertTrue(context_course::instance($testcourses[0]) instanceof context_course);
1502         $this->assertTrue(context_module::instance($testpages[0]) instanceof context_module);
1503         $this->assertTrue(context_block::instance($testblocks[0]) instanceof context_block);
1505         $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING));
1506         $this->assertFalse(context_course::instance(-1, IGNORE_MISSING));
1507         $this->assertFalse(context_module::instance(-1, IGNORE_MISSING));
1508         $this->assertFalse(context_block::instance(-1, IGNORE_MISSING));
1509         try {
1510             context_coursecat::instance(-1);
1511             $this->fail('exception expected');
1512         } catch (Exception $e) {
1513             $this->assertTrue(true);
1514         }
1515         try {
1516             context_course::instance(-1);
1517             $this->fail('exception expected');
1518         } catch (Exception $e) {
1519             $this->assertTrue(true);
1520         }
1521         try {
1522             context_module::instance(-1);
1523             $this->fail('exception expected');
1524         } catch (Exception $e) {
1525             $this->assertTrue(true);
1526         }
1527         try {
1528             context_block::instance(-1);
1529             $this->fail('exception expected');
1530         } catch (Exception $e) {
1531             $this->assertTrue(true);
1532         }
1535         // ======= $context->get_url(), $context->get_context_name(), $context->get_capabilities() =========
1537         $testcontexts = array();
1538         $testcontexts[CONTEXT_SYSTEM]    = context_system::instance();
1539         $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]);
1540         $testcontexts[CONTEXT_COURSE]    = context_course::instance($testcourses[0]);
1541         $testcontexts[CONTEXT_MODULE]    = context_module::instance($testpages[0]);
1542         $testcontexts[CONTEXT_BLOCK]     = context_block::instance($testblocks[0]);
1544         foreach ($testcontexts as $context) {
1545             $name = $context->get_context_name(true, true);
1546             $this->assertFalse(empty($name));
1548             $this->assertTrue($context->get_url() instanceof moodle_url);
1550             $caps = $context->get_capabilities();
1551             $this->assertTrue(is_array($caps));
1552             foreach ($caps as $cap) {
1553                 $cap = (array)$cap;
1554                 $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask'));
1555             }
1556         }
1557         unset($testcontexts);
1559         // ===== $context->get_course_context() =========================================
1561         $this->assertFalse($systemcontext->get_course_context(false));
1562         try {
1563             $systemcontext->get_course_context();
1564             $this->fail('exception expected');
1565         } catch (Exception $e) {
1566             $this->assertTrue(true);
1567         }
1568         $context = context_coursecat::instance($testcategories[0]);
1569         $this->assertFalse($context->get_course_context(false));
1570         try {
1571             $context->get_course_context();
1572             $this->fail('exception expected');
1573         } catch (Exception $e) {
1574             $this->assertTrue(true);
1575         }
1576         $this->assertSame($frontpagecontext->get_course_context(true), $frontpagecontext);
1577         $this->assertSame($frontpagepagecontext->get_course_context(true), $frontpagecontext);
1578         $this->assertSame($frontpagepageblockcontext->get_course_context(true), $frontpagecontext);
1581         // ======= $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() =======
1583         $userid = reset($testusers);
1584         $usercontext = context_user::instance($userid);
1585         $this->assertSame($usercontext->get_parent_context(), $systemcontext);
1586         $this->assertSame($usercontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext));
1587         $this->assertSame($usercontext->get_parent_contexts(true), array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext));
1589         $this->assertSame($systemcontext->get_parent_contexts(), array());
1590         $this->assertSame($systemcontext->get_parent_contexts(true), array($systemcontext->id=>$systemcontext));
1591         $this->assertSame($systemcontext->get_parent_context_ids(), array());
1592         $this->assertSame($systemcontext->get_parent_context_ids(true), array($systemcontext->id));
1594         $this->assertSame($frontpagecontext->get_parent_context(), $systemcontext);
1595         $this->assertSame($frontpagecontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext));
1596         $this->assertSame($frontpagecontext->get_parent_contexts(true), array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext));
1597         $this->assertSame($frontpagecontext->get_parent_context_ids(), array($systemcontext->id));
1598         $this->assertEquals($frontpagecontext->get_parent_context_ids(true), array($frontpagecontext->id, $systemcontext->id));
1600         $this->assertSame($systemcontext->get_parent_context(), false);
1601         $frontpagecontext = context_course::instance($SITE->id);
1602         $parent = $systemcontext;
1603         foreach ($testcategories as $catid) {
1604             $catcontext = context_coursecat::instance($catid);
1605             $this->assertSame($catcontext->get_parent_context(), $parent);
1606             $parent = $catcontext;
1607         }
1608         $this->assertSame($frontpagepagecontext->get_parent_context(), $frontpagecontext);
1609         $this->assertSame($frontpageblockcontext->get_parent_context(), $frontpagecontext);
1610         $this->assertSame($frontpagepageblockcontext->get_parent_context(), $frontpagepagecontext);
1613         // ====== $context->get_child_contexts() ================================
1615         $CFG->debug = 0;
1616         $children = $systemcontext->get_child_contexts();
1617         $CFG->debug = DEBUG_DEVELOPER;
1618         $this->assertEquals(count($children)+1, $DB->count_records('context'));
1620         $context = context_coursecat::instance($testcategories[3]);
1621         $children = $context->get_child_contexts();
1622         $countcats    = 0;
1623         $countcourses = 0;
1624         $countblocks  = 0;
1625         foreach ($children as $child) {
1626             if ($child->contextlevel == CONTEXT_COURSECAT) {
1627                 $countcats++;
1628             }
1629             if ($child->contextlevel == CONTEXT_COURSE) {
1630                 $countcourses++;
1631             }
1632             if ($child->contextlevel == CONTEXT_BLOCK) {
1633                 $countblocks++;
1634             }
1635         }
1636         $this->assertEquals(count($children), 8);
1637         $this->assertEquals($countcats, 1);
1638         $this->assertEquals($countcourses, 6);
1639         $this->assertEquals($countblocks, 1);
1641         $context = context_course::instance($testcourses[2]);
1642         $children = $context->get_child_contexts();
1643         $this->assertEquals(count($children), 7); // depends on number of default blocks
1645         $context = context_module::instance($testpages[3]);
1646         $children = $context->get_child_contexts();
1647         $this->assertEquals(count($children), 1);
1649         $context = context_block::instance($testblocks[1]);
1650         $children = $context->get_child_contexts();
1651         $this->assertEquals(count($children), 0);
1653         unset($children);
1654         unset($countcats);
1655         unset($countcourses);
1656         unset($countblocks);
1659         // ======= context_helper::reset_caches() ============================
1661         context_helper::reset_caches();
1662         $this->assertEquals(context_inspection::test_context_cache_size(), 0);
1663         context_course::instance($SITE->id);
1664         $this->assertEquals(context_inspection::test_context_cache_size(), 1);
1667         // ======= context preloading ========================================
1669         context_helper::reset_caches();
1670         $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')."
1671                   FROM {context} c
1672                  WHERE c.contextlevel <> ".CONTEXT_SYSTEM;
1673         $records = $DB->get_records_sql($sql);
1674         $firstrecord = reset($records);
1675         $columns = context_helper::get_preload_record_columns('c');
1676         $firstrecord = (array)$firstrecord;
1677         $this->assertSame(array_keys($firstrecord), array_values($columns));
1678         context_helper::reset_caches();
1679         foreach ($records as $record) {
1680             context_helper::preload_from_record($record);
1681             $this->assertEquals($record, new stdClass());
1682         }
1683         $this->assertEquals(context_inspection::test_context_cache_size(), count($records));
1684         unset($records);
1685         unset($columns);
1687         context_helper::reset_caches();
1688         context_helper::preload_course($SITE->id);
1689         $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id));
1690         $this->assertEquals(6 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // depends on number of default blocks
1692         // ====== assign_capability(), unassign_capability() ====================
1694         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1695         $this->assertFalse($rc);
1696         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id);
1697         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1698         $this->assertEquals($rc->permission, CAP_ALLOW);
1699         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id);
1700         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1701         $this->assertEquals($rc->permission, CAP_ALLOW);
1702         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true);
1703         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1704         $this->assertEquals($rc->permission, CAP_PREVENT);
1706         assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext);
1707         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1708         $this->assertFalse($rc);
1709         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext);
1710         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true);
1711         $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups'));
1712         $this->assertFalse($rc);
1713         unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true);
1714         unset($rc);
1716         accesslib_clear_all_caches(false); // must be done after assign_capability()
1719         // ======= role_assign(), role_unassign(), role_unassign_all() ==============
1721         $context = context_course::instance($testcourses[1]);
1722         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0);
1723         role_assign($allroles['teacher'], $testusers[1], $context->id);
1724         role_assign($allroles['teacher'], $testusers[2], $context->id);
1725         role_assign($allroles['manager'], $testusers[1], $context->id);
1726         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 3);
1727         role_unassign($allroles['teacher'], $testusers[1], $context->id);
1728         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 2);
1729         role_unassign_all(array('contextid'=>$context->id));
1730         $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0);
1731         unset($context);
1733         accesslib_clear_all_caches(false); // just in case
1736         // ====== has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends ========================
1738         $adminid = get_admin()->id;
1739         $guestid = $CFG->siteguest;
1741         // Enrol some users into some courses
1742         $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST);
1743         $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST);
1744         $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id');
1745         $cm1 = reset($cms);
1746         $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id');
1747         $block1 = reset($blocks);
1748         $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id));
1749         $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id));
1750         for($i=0; $i<9; $i++) {
1751             $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']);
1752         }
1753         $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']);
1754         $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']);
1756         for($i=10; $i<15; $i++) {
1757             $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']);
1758         }
1759         $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']);
1761         // Add tons of role assignments - the more the better
1762         role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2]));
1763         role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1]));
1764         role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id));
1765         role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id));
1766         role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id));
1767         role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id));
1768         role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id));
1769         role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id));
1771         role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id));
1772         role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id));
1774         // Add tons of overrides - the more the better
1775         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true);
1776         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true);
1777         assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true);
1778         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true);
1779         assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true);
1781         assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true);
1782         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true);
1783         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true);
1784         assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true);
1785         assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true);
1787         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true);
1788         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true);
1789         assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true);
1790         assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true);
1792         assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true);
1794         accesslib_clear_all_caches(false); // must be done after assign_capability()
1796         // Extra tests for guests and not-logged-in users because they can not be verified by cross checking
1797         // with get_users_by_capability() where they are ignored
1798         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid));
1799         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid));
1800         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid));
1801         $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid));
1803         $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0));
1804         $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0));
1805         $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0));
1806         $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0));
1808         $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11]));
1809         $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11]));
1810         $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11]));
1811         $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11]));
1813         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9]));
1814         $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9]));
1815         $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9]));
1817         // Test the list of enrolled users
1818         $coursecontext = context_course::instance($course1->id);
1819         $enrolled = get_enrolled_users($coursecontext);
1820         $this->assertEquals(count($enrolled), 10);
1821         for($i=0; $i<10; $i++) {
1822             $this->assertTrue(isset($enrolled[$testusers[$i]]));
1823         }
1824         $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update');
1825         $this->assertEquals(count($enrolled), 1);
1826         $this->assertTrue(isset($enrolled[$testusers[9]]));
1827         unset($enrolled);
1829         // role switching
1830         $userid = $testusers[9];
1831         $USER = $DB->get_record('user', array('id'=>$userid));
1832         load_all_capabilities();
1833         $coursecontext = context_course::instance($course1->id);
1834         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
1835         $this->assertFalse(is_role_switched($course1->id));
1836         role_switch($allroles['student'], $coursecontext);
1837         $this->assertTrue(is_role_switched($course1->id));
1838         $this->assertEquals($USER->access['rsw'][$coursecontext->path],  $allroles['student']);
1839         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
1840         reload_all_capabilities();
1841         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
1842         role_switch(0, $coursecontext);
1843         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
1844         $userid = $adminid;
1845         $USER = $DB->get_record('user', array('id'=>$userid));
1846         load_all_capabilities();
1847         $coursecontext = context_course::instance($course1->id);
1848         $blockcontext = context_block::instance($block1->id);
1849         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
1850         role_switch($allroles['student'], $coursecontext);
1851         $this->assertEquals($USER->access['rsw'][$coursecontext->path],  $allroles['student']);
1852         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
1853         reload_all_capabilities();
1854         $this->assertFalse(has_capability('moodle/course:update', $blockcontext));
1855         load_all_capabilities();
1856         $this->assertTrue(has_capability('moodle/course:update', $blockcontext));
1858         // temp course role for enrol
1859         $DB->delete_records('cache_flags', array()); // this prevents problem with dirty contexts immediately resetting the temp role - this is a known problem...
1860         $userid = $testusers[5];
1861         $roleid = $allroles['editingteacher'];
1862         $USER = $DB->get_record('user', array('id'=>$userid));
1863         load_all_capabilities();
1864         $coursecontext = context_course::instance($course1->id);
1865         $this->assertFalse(has_capability('moodle/course:update', $coursecontext));
1866         $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid]));
1867         load_temp_course_role($coursecontext, $roleid);
1868         $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid);
1869         $this->assertTrue(has_capability('moodle/course:update', $coursecontext));
1870         remove_temp_course_roles($coursecontext);
1871         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
1872         load_temp_course_role($coursecontext, $roleid);
1873         reload_all_capabilities();
1874         $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid));
1875         $USER = new stdClass();
1876         $USER->id = 0;
1878         // Now cross check has_capability() with get_users_by_capability(), each using different code paths,
1879         // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong,
1880         // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users)
1881         $contexts = $DB->get_records('context', array(), 'id');
1882         $contexts = array_values($contexts);
1883         $capabilities = $DB->get_records('capabilities', array(), 'id');
1884         $capabilities = array_values($capabilities);
1885         $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']);
1886         $userids = array_values($testusers);
1887         $userids[] = get_admin()->id;
1889         if (!PHPUNIT_LONGTEST) {
1890             $contexts = array_slice($contexts, 0, 10);
1891             $capabilities = array_slice($capabilities, 0, 5);
1892             $userids = array_slice($userids, 0, 5);
1893         }
1895         // Random time!
1896         //srand(666);
1897         foreach($userids as $userid) { // no guest or deleted
1898             // each user gets 0-10 random roles
1899             $rcount = rand(0, 10);
1900             for($j=0; $j<$rcount; $j++) {
1901                 $roleid = $roles[rand(0, count($roles)-1)];
1902                 $contextid = $contexts[rand(0, count($contexts)-1)]->id;
1903                 role_assign($roleid, $userid, $contextid);
1904             }
1905         }
1907         $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT);
1908         $maxoverrides = count($contexts)*10;
1909         for($j=0; $j<$maxoverrides; $j++) {
1910             $roleid = $roles[rand(0, count($roles)-1)];
1911             $contextid = $contexts[rand(0, count($contexts)-1)]->id;
1912             $permission = $permissions[rand(0,count($permissions)-1)];
1913             $capname = $capabilities[rand(0, count($capabilities)-1)]->name;
1914             assign_capability($capname, $permission, $roleid, $contextid, true);
1915         }
1916         unset($permissions);
1917         unset($roles);
1919         accesslib_clear_all_caches(false); // must be done after assign_capability()
1921         // Test time - let's set up some real user, just in case the logic for USER affects the others...
1922         $USER = $DB->get_record('user', array('id'=>$testusers[3]));
1923         load_all_capabilities();
1925         $userids[] = $CFG->siteguest;
1926         $userids[] = 0; // not-logged-in user
1927         $userids[] = -1; // non-existent user
1929         foreach ($contexts as $crecord) {
1930             $context = context::instance_by_id($crecord->id);
1931             if ($coursecontext = $context->get_course_context(false)) {
1932                 $enrolled = get_enrolled_users($context);
1933             } else {
1934                 $enrolled = array();
1935             }
1936             foreach ($capabilities as $cap) {
1937                 $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username');
1938                 if ($enrolled) {
1939                     $enrolledwithcap = get_enrolled_users($context, $cap->name);
1940                 } else {
1941                     $enrolledwithcap = array();
1942                 }
1943                 foreach ($userids as $userid) {
1944                     if ($userid == 0 or isguestuser($userid)) {
1945                         if ($userid == 0) {
1946                             $CFG->forcelogin = true;
1947                             $this->assertFalse(has_capability($cap->name, $context, $userid));
1948                             unset($CFG->forcelogin);
1949                         }
1950                         if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) {
1951                             $this->assertFalse(has_capability($cap->name, $context, $userid));
1952                         }
1953                         $this->assertFalse(isset($allowed[$userid]));
1954                     } else {
1955                         if (is_siteadmin($userid)) {
1956                             $this->assertTrue(has_capability($cap->name, $context, $userid, true));
1957                         }
1958                         $hascap = has_capability($cap->name, $context, $userid, false);
1959                         $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
1960                         if (isset($enrolled[$userid])) {
1961                             $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." ");
1962                         }
1963                     }
1964                 }
1965             }
1966         }
1967         // Back to nobody
1968         $USER = new stdClass();
1969         $USER->id = 0;
1970         unset($contexts);
1971         unset($userids);
1972         unset($capabilities);
1974         // Now let's do all the remaining tests that break our carefully prepared fake site
1978         // ======= $context->mark_dirty() =======================================
1980         $DB->delete_records('cache_flags', array());
1981         accesslib_clear_all_caches(false);
1982         $systemcontext->mark_dirty();
1983         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
1984         $this->assertTrue(isset($dirty[$systemcontext->path]));
1985         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path]));
1988         // ======= $context->reload_if_dirty(); =================================
1990         $DB->delete_records('cache_flags', array());
1991         accesslib_clear_all_caches(false);
1992         load_all_capabilities();
1993         $context = context_course::instance($testcourses[2]);
1994         $page = $DB->get_record('page', array('course'=>$testcourses[2]));
1995         $pagecm = get_coursemodule_from_instance('page', $page->id);
1996         $pagecontext = context_module::instance($pagecm->id);
1998         $context->mark_dirty();
1999         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2000         $USER->access['test'] = true;
2001         $context->reload_if_dirty();
2002         $this->assertFalse(isset($USER->access['test']));
2004         $context->mark_dirty();
2005         $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path]));
2006         $USER->access['test'] = true;
2007         $pagecontext->reload_if_dirty();
2008         $this->assertFalse(isset($USER->access['test']));
2011         // ======= context_helper::build_all_paths() ============================
2013         $oldcontexts = $DB->get_records('context', array(), 'id');
2014         $DB->set_field_select('context', 'path', NULL, "contextlevel <> ".CONTEXT_SYSTEM);
2015         $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM);
2016         context_helper::build_all_paths();
2017         $newcontexts = $DB->get_records('context', array(), 'id');
2018         $this->assertEquals($oldcontexts, $newcontexts);
2019         unset($oldcontexts);
2020         unset($newcontexts);
2023         // ======= $context->reset_paths() ======================================
2025         $context = context_course::instance($testcourses[2]);
2026         $children = $context->get_child_contexts();
2027         $context->reset_paths(false);
2028         $this->assertSame($DB->get_field('context', 'path', array('id'=>$context->id)), NULL);
2029         $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), 0);
2030         foreach ($children as $child) {
2031             $this->assertSame($DB->get_field('context', 'path', array('id'=>$child->id)), NULL);
2032             $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$child->id)), 0);
2033         }
2034         $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0)));
2035         $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>NULL)));
2037         $context = context_course::instance($testcourses[2]);
2038         $context->reset_paths(true);
2039         $context = context_course::instance($testcourses[2]);
2040         $this->assertEquals($DB->get_field('context', 'path', array('id'=>$context->id)), $context->path);
2041         $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), $context->depth);
2042         $this->assertEquals(0, $DB->count_records('context', array('depth'=>0)));
2043         $this->assertEquals(0, $DB->count_records('context', array('path'=>NULL)));
2046         // ====== $context->update_moved(); ======================================
2048         accesslib_clear_all_caches(false);
2049         $DB->delete_records('cache_flags', array());
2050         $course = $DB->get_record('course', array('id'=>$testcourses[0]));
2051         $context = context_course::instance($course->id);
2052         $oldpath = $context->path;
2053         $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2054         $categorycontext = context_coursecat::instance($miscid);
2055         $course->category = $miscid;
2056         $DB->update_record('course', $course);
2057         $context->update_moved($categorycontext);
2059         $context = context_course::instance($course->id);
2060         $this->assertEquals($context->get_parent_context(), $categorycontext);
2061         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2062         $this->assertTrue(isset($dirty[$oldpath]));
2063         $this->assertTrue(isset($dirty[$context->path]));
2066         // ====== $context->delete_content() =====================================
2068         context_helper::reset_caches();
2069         $context = context_module::instance($testpages[3]);
2070         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2071         $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2072         $context->delete_content();
2073         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2074         $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2077         // ====== $context->delete() =============================
2079         context_helper::reset_caches();
2080         $context = context_module::instance($testpages[4]);
2081         $this->assertTrue($DB->record_exists('context', array('id'=>$context->id)));
2082         $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2083         $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id));
2084         $bicontext = context_block::instance($bi->id);
2085         $DB->delete_records('cache_flags', array());
2086         $context->delete(); // should delete also linked blocks
2087         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2088         $this->assertTrue(isset($dirty[$context->path]));
2089         $this->assertFalse($DB->record_exists('context', array('id'=>$context->id)));
2090         $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id)));
2091         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4])));
2092         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id)));
2093         $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id)));
2094         context_module::instance($testpages[4]);
2097         // ====== context_helper::delete_instance() =============================
2099         context_helper::reset_caches();
2100         $lastcourse = array_pop($testcourses);
2101         $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2102         $coursecontext = context_course::instance($lastcourse);
2103         $this->assertEquals(context_inspection::test_context_cache_size(), 1);
2104         $this->assertFalse($coursecontext->instanceid == CONTEXT_COURSE);
2105         $DB->delete_records('cache_flags', array());
2106         context_helper::delete_instance(CONTEXT_COURSE, $lastcourse);
2107         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2108         $this->assertTrue(isset($dirty[$coursecontext->path]));
2109         $this->assertEquals(context_inspection::test_context_cache_size(), 0);
2110         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse)));
2111         context_course::instance($lastcourse);
2114         // ======= context_helper::create_instances() ==========================
2116         $prevcount = $DB->count_records('context');
2117         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2118         context_helper::create_instances(null, true);
2119         $this->assertSame($DB->count_records('context'), $prevcount);
2120         $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0);
2121         $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0);
2123         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2124         $DB->delete_records('block_instances', array());
2125         $prevcount = $DB->count_records('context');
2126         $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM);
2127         context_helper::create_instances(null, true);
2128         $this->assertSame($DB->count_records('context'), $prevcount);
2129         $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0);
2130         $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0);
2133         // ======= context_helper::cleanup_instances() ==========================
2135         $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2136         $DB->delete_records('course', array('id'=>$lastcourse));
2137         $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2138         $DB->delete_records('course_categories', array('id'=>$lastcategory));
2139         $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2140         $DB->delete_records('user', array('id'=>$lastuser));
2141         $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2142         $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2143         context_helper::cleanup_instances();
2144         $count = 1; //system
2145         $count += $DB->count_records('user', array('deleted'=>0));
2146         $count += $DB->count_records('course_categories');
2147         $count += $DB->count_records('course');
2148         $count += $DB->count_records('course_modules');
2149         $count += $DB->count_records('block_instances');
2150         $this->assertEquals($DB->count_records('context'), $count);
2153         // ======= context cache size restrictions ==============================
2155         $testusers= array();
2156         for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2157             $user = $generator->create_user();
2158             $testusers[$i] = $user->id;
2159         }
2160         context_helper::create_instances(null, true);
2161         context_helper::reset_caches();
2162         for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) {
2163             context_user::instance($testusers[$i]);
2164             if ($i == CONTEXT_CACHE_MAX_SIZE - 1) {
2165                 $this->assertEquals(context_inspection::test_context_cache_size(), CONTEXT_CACHE_MAX_SIZE);
2166             } else if ($i == CONTEXT_CACHE_MAX_SIZE) {
2167                 // once the limit is reached roughly 1/3 of records should be removed from cache
2168                 $this->assertEquals(context_inspection::test_context_cache_size(), (int)(CONTEXT_CACHE_MAX_SIZE * (2/3) +102));
2169             }
2170         }
2171         // We keep the first 100 cached
2172         $prevsize = context_inspection::test_context_cache_size();
2173         for ($i=0; $i<100; $i++) {
2174             context_user::instance($testusers[$i]);
2175             $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize);
2176         }
2177         context_user::instance($testusers[102]);
2178         $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize+1);
2179         unset($testusers);
2183         // =================================================================
2184         // ======= basic test of legacy functions ==========================
2185         // =================================================================
2186         // note: watch out, the fake site might be pretty borked already
2188         $this->assertSame(get_system_context(), context_system::instance());
2190         foreach ($DB->get_records('context') as $contextid=>$record) {
2191             $context = context::instance_by_id($contextid);
2192             $this->assertSame(get_context_instance_by_id($contextid), $context);
2193             $this->assertSame(get_context_instance($record->contextlevel, $record->instanceid), $context);
2194             $this->assertSame(get_parent_contexts($context), $context->get_parent_context_ids());
2195             if ($context->id == SYSCONTEXTID) {
2196                 $this->assertSame(get_parent_contextid($context), false);
2197             } else {
2198                 $this->assertSame(get_parent_contextid($context), $context->get_parent_context()->id);
2199             }
2200         }
2202         $CFG->debug = 0;
2203         $children = get_child_contexts($systemcontext);
2204         $CFG->debug = DEBUG_DEVELOPER;
2205         $this->assertEquals(count($children), $DB->count_records('context')-1);
2206         unset($children);
2208         $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK));
2209         create_contexts();
2210         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK)));
2212         $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK));
2213         build_context_path();
2214         $this->assertFalse($DB->record_exists('context', array('depth'=>0)));
2216         $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}");
2217         $DB->delete_records('course', array('id'=>$lastcourse));
2218         $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}");
2219         $DB->delete_records('course_categories', array('id'=>$lastcategory));
2220         $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0");
2221         $DB->delete_records('user', array('id'=>$lastuser));
2222         $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id));
2223         $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid));
2224         cleanup_contexts();
2225         $count = 1; //system
2226         $count += $DB->count_records('user', array('deleted'=>0));
2227         $count += $DB->count_records('course_categories');
2228         $count += $DB->count_records('course');
2229         $count += $DB->count_records('course_modules');
2230         $count += $DB->count_records('block_instances');
2231         $this->assertEquals($DB->count_records('context'), $count);
2233         context_helper::reset_caches();
2234         preload_course_contexts($SITE->id);
2235         $this->assertEquals(1 + $DB->count_records('course_modules', array('course' => $SITE->id)),
2236                 context_inspection::test_context_cache_size());
2238         context_helper::reset_caches();
2239         list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx');
2240         $sql = "SELECT c.id $select FROM {course_categories} c $join";
2241         $records = $DB->get_records_sql($sql);
2242         foreach ($records as $record) {
2243             context_instance_preload($record);
2244             $record = (array)$record;
2245             $this->assertEquals(1, count($record)); // only id left
2246         }
2247         $this->assertEquals(count($records), context_inspection::test_context_cache_size());
2249         accesslib_clear_all_caches(true);
2250         $DB->delete_records('cache_flags', array());
2251         mark_context_dirty($systemcontext->path);
2252         $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2);
2253         $this->assertTrue(isset($dirty[$systemcontext->path]));
2255         accesslib_clear_all_caches(false);
2256         $DB->delete_records('cache_flags', array());
2257         $course = $DB->get_record('course', array('id'=>$testcourses[2]));
2258         $context = get_context_instance(CONTEXT_COURSE, $course->id);
2259         $oldpath = $context->path;
2260         $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
2261         $categorycontext = context_coursecat::instance($miscid);
2262         $course->category = $miscid;
2263         $DB->update_record('course', $course);
2264         context_moved($context, $categorycontext);
2265         $context = get_context_instance(CONTEXT_COURSE, $course->id);
2266         $this->assertEquals($context->get_parent_context(), $categorycontext);
2268         $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2269         delete_context(CONTEXT_COURSE, $testcourses[2]);
2270         $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2])));
2272         $name = get_contextlevel_name(CONTEXT_COURSE);
2273         $this->assertFalse(empty($name));
2275         $context = get_context_instance(CONTEXT_COURSE, $testcourses[2]);
2276         $name = print_context_name($context);
2277         $this->assertFalse(empty($name));
2279         $url = get_context_url($coursecontext);
2280         $this->assertFalse($url instanceof modole_url);
2282         $pagecm = get_coursemodule_from_instance('page', $testpages[7]);
2283         $context = get_context_instance(CONTEXT_MODULE, $pagecm->id);
2284         $coursecontext = get_course_context($context);
2285         $this->assertEquals($coursecontext->contextlevel, CONTEXT_COURSE);
2286         $this->assertEquals(get_courseid_from_context($context), $pagecm->course);
2288         $caps = fetch_context_capabilities($systemcontext);
2289         $this->assertTrue(is_array($caps));
2290         unset($caps);
2291     }
2293     /**
2294      * Test updating of role capabilities during upgrade
2295      * @return void
2296      */
2297     public function test_update_capabilities() {
2298         global $DB, $SITE;
2300         $this->resetAfterTest(true);
2302         $froncontext = context_course::instance($SITE->id);
2303         $student = $DB->get_record('role', array('archetype'=>'student'));
2304         $teacher = $DB->get_record('role', array('archetype'=>'teacher'));
2306         $existingcaps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2308         $this->assertFalse(isset($existingcaps['moodle/site:restore']));         // moved to new 'moodle/restore:restorecourse'
2309         $this->assertTrue(isset($existingcaps['moodle/restore:restorecourse'])); // new cap from 'moodle/site:restore'
2310         $this->assertTrue(isset($existingcaps['moodle/site:sendmessage']));      // new capability
2311         $this->assertTrue(isset($existingcaps['moodle/backup:backupcourse']));
2312         $this->assertTrue(isset($existingcaps['moodle/backup:backupsection']));  // cloned from 'moodle/backup:backupcourse'
2313         $this->assertTrue(isset($existingcaps['moodle/site:approvecourse']));    // updated bitmask
2314         $this->assertTrue(isset($existingcaps['moodle/course:manageactivities']));
2315         $this->assertTrue(isset($existingcaps['mod/page:addinstance']));         // cloned from core 'moodle/course:manageactivities'
2317         // fake state before upgrade
2318         $DB->set_field('capabilities', 'name', 'moodle/site:restore', array('name'=>'moodle/restore:restorecourse'));
2319         $DB->set_field('role_capabilities', 'capability', 'moodle/site:restore', array('capability'=>'moodle/restore:restorecourse'));
2320         assign_capability('moodle/site:restore', CAP_PROHIBIT, $teacher->id, $froncontext->id, true);
2321         $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/site:restore', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2323         $DB->delete_records('role_capabilities', array('capability'=>'moodle/site:sendmessage'));
2324         $DB->delete_records('capabilities', array('name'=>'moodle/site:sendmessage'));
2326         $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupsection'));
2327         $DB->delete_records('capabilities', array('name'=>'moodle/backup:backupsection'));
2328         assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2329         assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2331         $DB->set_field('capabilities', 'riskbitmask', 0, array('name'=>'moodle/site:approvecourse'));
2333         $DB->delete_records('role_capabilities', array('capability'=>'mod/page:addinstance'));
2334         $DB->delete_records('capabilities', array('name'=>'mod/page:addinstance'));
2335         assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $student->id, $froncontext->id, true);
2336         assign_capability('moodle/course:manageactivities', CAP_ALLOW, $teacher->id, $froncontext->id, true);
2338         // execute core
2339         update_capabilities('moodle');
2341         // only core should be upgraded
2342         $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2344         $this->assertFalse(isset($existingcaps['moodle/site:restore']));
2345         $this->assertTrue(isset($caps['moodle/restore:restorecourse']));
2346         $this->assertEquals($existingcaps['moodle/restore:restorecourse'], $caps['moodle/restore:restorecourse']);
2347         $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/restore:restorecourse', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission'));
2348         $this->assertEquals($perms1, $perms2);
2350         $this->assertTrue(isset($caps['moodle/site:sendmessage']));
2351         $this->assertEquals($existingcaps['moodle/site:sendmessage'], $caps['moodle/site:sendmessage']);
2353         $this->assertTrue(isset($caps['moodle/backup:backupsection']));
2354         $this->assertEquals($existingcaps['moodle/backup:backupsection'], $caps['moodle/backup:backupsection']);
2355         $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/backup:backupcourse', 'moodle/backup:backupsection'));
2356         foreach ($roles as $role) {
2357             $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2358             $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupsection', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2359             $this->assertEquals($perms1, $perms2);
2360         }
2362         $this->assertTrue(isset($caps['moodle/site:approvecourse']));
2363         $this->assertEquals($existingcaps['moodle/site:approvecourse'], $caps['moodle/site:approvecourse']);
2365         $this->assertFalse(isset($caps['mod/page:addinstance']));
2367         // execute plugin
2368         update_capabilities('mod_page');
2369         $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask');
2370         $this->assertTrue(isset($caps['mod/page:addinstance']));
2371         $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/course:manageactivities', 'mod/page:addinstance'));
2372         foreach ($roles as $role) {
2373             $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/course:manageactivities', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2374             $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'mod/page:addinstance', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission'));
2375         }
2376         $this->assertEquals($perms1, $perms2);
2377     }