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