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