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