[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/tests/ -> accesslib_test.php (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1