[ Index ]

PHP Cross Reference of Unnamed Project

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1