Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 9 May 2022 (12 months).
  • Bug fixes for security issues in 3.11.x will end 14 November 2022 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 310 and 311] [Versions 35 and 311] [Versions 36 and 311] [Versions 37 and 311] [Versions 38 and 311] [Versions 39 and 311]

       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->accessdatabyuser);
      61          accesslib_clear_all_caches_for_unit_testing();
      62          $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts);
      63          $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser);
      64      }
      65  
      66      /**
      67       * Check modifying capability record is not exposed to other code.
      68       */
      69      public function test_capabilities_mutation() {
      70          $oldcap = get_capability_info('moodle/site:config');
      71          $cap = get_capability_info('moodle/site:config');
      72          unset($cap->name);
      73          $newcap = get_capability_info('moodle/site:config');
      74  
      75          $this->assertFalse(isset($cap->name));
      76          $this->assertTrue(isset($newcap->name));
      77          $this->assertTrue(isset($oldcap->name));
      78      }
      79  
      80      /**
      81       * Test getting of role access
      82       */
      83      public function test_get_role_access() {
      84          global $DB;
      85  
      86          $roles = $DB->get_records('role');
      87          foreach ($roles as $role) {
      88              $access = get_role_access($role->id);
      89  
      90              $this->assertTrue(is_array($access));
      91              $this->assertTrue(is_array($access['ra']));
      92              $this->assertFalse(isset($access['rdef']));
      93              $this->assertFalse(isset($access['rdef_count']));
      94              $this->assertFalse(isset($access['loaded']));
      95              $this->assertTrue(isset($access['time']));
      96              $this->assertTrue(is_array($access['rsw']));
      97          }
      98  
      99          // Note: the data is validated in the functional permission evaluation test at the end of this testcase.
     100      }
     101  
     102      /**
     103       * Test getting of guest role.
     104       */
     105      public function test_get_guest_role() {
     106          global $CFG;
     107  
     108          $guest = get_guest_role();
     109          $this->assertEquals('guest', $guest->archetype);
     110          $this->assertEquals('guest', $guest->shortname);
     111  
     112          $this->assertEquals($CFG->guestroleid, $guest->id);
     113      }
     114  
     115      /**
     116       * Test if user is admin.
     117       */
     118      public function test_is_siteadmin() {
     119          global $DB, $CFG;
     120  
     121          $this->resetAfterTest();
     122  
     123          $users = $DB->get_records('user');
     124  
     125          foreach ($users as $user) {
     126              $this->setUser(0);
     127              if ($user->username === 'admin') {
     128                  $this->assertTrue(is_siteadmin($user));
     129                  $this->assertTrue(is_siteadmin($user->id));
     130                  $this->setUser($user);
     131                  $this->assertTrue(is_siteadmin());
     132                  $this->assertTrue(is_siteadmin(null));
     133              } else {
     134                  $this->assertFalse(is_siteadmin($user));
     135                  $this->assertFalse(is_siteadmin($user->id));
     136                  $this->setUser($user);
     137                  $this->assertFalse(is_siteadmin());
     138                  $this->assertFalse(is_siteadmin(null));
     139              }
     140          }
     141  
     142          // Change the site admin list and check that it still works with
     143          // multiple admins. We do this with userids only (not real user
     144          // accounts) because it makes the test simpler.
     145          $before = $CFG->siteadmins;
     146          set_config('siteadmins', '666,667,668');
     147          $this->assertTrue(is_siteadmin(666));
     148          $this->assertTrue(is_siteadmin(667));
     149          $this->assertTrue(is_siteadmin(668));
     150          $this->assertFalse(is_siteadmin(669));
     151          set_config('siteadmins', '13');
     152          $this->assertTrue(is_siteadmin(13));
     153          $this->assertFalse(is_siteadmin(666));
     154          set_config('siteadmins', $before);
     155      }
     156  
     157      /**
     158       * Test if user is enrolled in a course
     159       */
     160      public function test_is_enrolled() {
     161          global $DB;
     162  
     163          $this->resetAfterTest();
     164  
     165          // Generate data.
     166          $user = $this->getDataGenerator()->create_user();
     167          $course = $this->getDataGenerator()->create_course();
     168          $coursecontext = context_course::instance($course->id);
     169          $role = $DB->get_record('role', array('shortname'=>'student'));
     170  
     171          // There should be a manual enrolment as part of the default install.
     172          $plugin = enrol_get_plugin('manual');
     173          $instance = $DB->get_record('enrol', array(
     174              'courseid' => $course->id,
     175              'enrol' => 'manual',
     176          ));
     177          $this->assertNotSame(false, $instance);
     178  
     179          // Enrol the user in the course.
     180          $plugin->enrol_user($instance, $user->id, $role->id);
     181  
     182          // We'll test with the mod/assign:submit capability.
     183          $capability= 'mod/assign:submit';
     184          $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
     185  
     186          // Switch to our user.
     187          $this->setUser($user);
     188  
     189          // Ensure that the user has the capability first.
     190          $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
     191  
     192          // We first test whether the user is enrolled on the course as this
     193          // seeds the cache, then we test for the capability.
     194          $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
     195          $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
     196  
     197          // Prevent the capability for this user role.
     198          assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
     199          $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
     200  
     201          // Again, we seed the cache first by checking initial enrolment,
     202          // and then we test the actual capability.
     203          $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
     204          $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
     205      }
     206  
     207      /**
     208       * Test logged in test.
     209       */
     210      public function test_isloggedin() {
     211          global $USER;
     212  
     213          $this->resetAfterTest();
     214  
     215          $USER->id = 0;
     216          $this->assertFalse(isloggedin());
     217          $USER->id = 1;
     218          $this->assertTrue(isloggedin());
     219      }
     220  
     221      /**
     222       * Test guest user test.
     223       */
     224      public function test_isguestuser() {
     225          global $DB;
     226  
     227          $this->resetAfterTest();
     228  
     229          $guest = $DB->get_record('user', array('username'=>'guest'));
     230          $this->setUser(0);
     231          $this->assertFalse(isguestuser());
     232          $this->setAdminUser();
     233          $this->assertFalse(isguestuser());
     234          $this->assertTrue(isguestuser($guest));
     235          $this->assertTrue(isguestuser($guest->id));
     236          $this->setUser($guest);
     237          $this->assertTrue(isguestuser());
     238  
     239          $users = $DB->get_records('user');
     240          foreach ($users as $user) {
     241              if ($user->username === 'guest') {
     242                  continue;
     243              }
     244              $this->assertFalse(isguestuser($user));
     245          }
     246      }
     247  
     248      /**
     249       * Test capability riskiness.
     250       */
     251      public function test_is_safe_capability() {
     252          global $DB;
     253          // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap.
     254          $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST);
     255          $this->assertFalse(is_safe_capability($capability));
     256      }
     257  
     258      /**
     259       * Test context fetching.
     260       */
     261      public function test_get_context_info_array() {
     262          $this->resetAfterTest();
     263  
     264          $syscontext = context_system::instance();
     265          $user = $this->getDataGenerator()->create_user();
     266          $usercontext = context_user::instance($user->id);
     267          $course = $this->getDataGenerator()->create_course();
     268          $catcontext = context_coursecat::instance($course->category);
     269          $coursecontext = context_course::instance($course->id);
     270          $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
     271          $modcontext = context_module::instance($page->cmid);
     272          $cm = get_coursemodule_from_instance('page', $page->id);
     273          $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id));
     274          $block1context = context_block::instance($block1->id);
     275          $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id));
     276          $block2context = context_block::instance($block2->id);
     277  
     278          $result = get_context_info_array($syscontext->id);
     279          $this->assertCount(3, $result);
     280          $this->assertEquals($syscontext, $result[0]);
     281          $this->assertNull($result[1]);
     282          $this->assertNull($result[2]);
     283  
     284          $result = get_context_info_array($usercontext->id);
     285          $this->assertCount(3, $result);
     286          $this->assertEquals($usercontext, $result[0]);
     287          $this->assertNull($result[1]);
     288          $this->assertNull($result[2]);
     289  
     290          $result = get_context_info_array($catcontext->id);
     291          $this->assertCount(3, $result);
     292          $this->assertEquals($catcontext, $result[0]);
     293          $this->assertNull($result[1]);
     294          $this->assertNull($result[2]);
     295  
     296          $result = get_context_info_array($coursecontext->id);
     297          $this->assertCount(3, $result);
     298          $this->assertEquals($coursecontext, $result[0]);
     299          $this->assertEquals($course->id, $result[1]->id);
     300          $this->assertSame($course->shortname, $result[1]->shortname);
     301          $this->assertNull($result[2]);
     302  
     303          $result = get_context_info_array($block1context->id);
     304          $this->assertCount(3, $result);
     305          $this->assertEquals($block1context, $result[0]);
     306          $this->assertEquals($course->id, $result[1]->id);
     307          $this->assertEquals($course->shortname, $result[1]->shortname);
     308          $this->assertNull($result[2]);
     309  
     310          $result = get_context_info_array($modcontext->id);
     311          $this->assertCount(3, $result);
     312          $this->assertEquals($modcontext, $result[0]);
     313          $this->assertEquals($course->id, $result[1]->id);
     314          $this->assertSame($course->shortname, $result[1]->shortname);
     315          $this->assertEquals($cm->id, $result[2]->id);
     316  
     317          $result = get_context_info_array($block2context->id);
     318          $this->assertCount(3, $result);
     319          $this->assertEquals($block2context, $result[0]);
     320          $this->assertEquals($course->id, $result[1]->id);
     321          $this->assertSame($course->shortname, $result[1]->shortname);
     322          $this->assertEquals($cm->id, $result[2]->id);
     323      }
     324  
     325      /**
     326       * Test looking for course contacts.
     327       */
     328      public function test_has_coursecontact_role() {
     329          global $DB, $CFG;
     330  
     331          $this->resetAfterTest();
     332  
     333          $users = $DB->get_records('user');
     334  
     335          // Nobody is expected to have any course level roles.
     336          $this->assertNotEmpty($CFG->coursecontact);
     337          foreach ($users as $user) {
     338              $this->assertFalse(has_coursecontact_role($user->id));
     339          }
     340  
     341          $user = $this->getDataGenerator()->create_user();
     342          $course = $this->getDataGenerator()->create_course();
     343          $contactroles = preg_split('/,/', $CFG->coursecontact);
     344          $roleid = reset($contactroles);
     345          role_assign($roleid, $user->id, context_course::instance($course->id));
     346          $this->assertTrue(has_coursecontact_role($user->id));
     347      }
     348  
     349      /**
     350       * Test creation of roles.
     351       */
     352      public function test_create_role() {
     353          global $DB;
     354  
     355          $this->resetAfterTest();
     356  
     357          $id = create_role('New student role', 'student2', 'New student description', 'student');
     358          $role = $DB->get_record('role', array('id'=>$id));
     359  
     360          $this->assertNotEmpty($role);
     361          $this->assertSame('New student role', $role->name);
     362          $this->assertSame('student2', $role->shortname);
     363          $this->assertSame('New student description', $role->description);
     364          $this->assertSame('student', $role->archetype);
     365      }
     366  
     367      /**
     368       * Test adding of capabilities to roles.
     369       */
     370      public function test_assign_capability() {
     371          global $DB, $USER;
     372  
     373          $this->resetAfterTest();
     374  
     375          $user = $this->getDataGenerator()->create_user();
     376          $syscontext = context_system::instance();
     377          $frontcontext = context_course::instance(SITEID);
     378          $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
     379          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to student by default.
     380          $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
     381          $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')));
     382  
     383          $this->setUser($user);
     384          $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id);
     385          $this->assertTrue($result);
     386          $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
     387          $this->assertNotEmpty($permission);
     388          $this->assertEquals(CAP_ALLOW, $permission->permission);
     389          $this->assertEquals($user->id, $permission->modifierid);
     390  
     391          $this->setUser(0);
     392          $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false);
     393          $this->assertTrue($result);
     394          $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
     395          $this->assertNotEmpty($permission);
     396          $this->assertEquals(CAP_ALLOW, $permission->permission);
     397          $this->assertEquals($user->id, $permission->modifierid);
     398  
     399          $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true);
     400          $this->assertTrue($result);
     401          $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
     402          $this->assertNotEmpty($permission);
     403          $this->assertEquals(CAP_PROHIBIT, $permission->permission);
     404          $this->assertEquals(0, $permission->modifierid);
     405  
     406          $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id);
     407          $this->assertTrue($result);
     408          $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
     409          $this->assertEmpty($permission);
     410  
     411          // Test event triggered.
     412          $sink = $this->redirectEvents();
     413          $capability = 'moodle/backup:backupcourse';
     414          assign_capability($capability, CAP_ALLOW, $student->id, $syscontext);
     415          $events = $sink->get_events();
     416          $sink->close();
     417          $this->assertCount(1, $events);
     418          $event = $events[0];
     419          $this->assertInstanceOf('\core\event\capability_assigned', $event);
     420          $this->assertSame('role_capabilities', $event->objecttable);
     421          $this->assertEquals($student->id, $event->objectid);
     422          $this->assertEquals($syscontext->id, $event->contextid);
     423          $other = ['capability' => $capability, 'oldpermission' => CAP_INHERIT, 'permission' => CAP_ALLOW];
     424          $this->assertEquals($other, $event->other);
     425          $description = "The user id '$USER->id' assigned the '$capability' capability for " .
     426              "role '$student->id' with 'Allow' permission";
     427          $this->assertEquals($description, $event->get_description());
     428  
     429          // Test if the event has different description when updating the capability permission.
     430          $sink = $this->redirectEvents();
     431          assign_capability($capability, CAP_PROHIBIT, $student->id, $syscontext, true);
     432          $events = $sink->get_events();
     433          $sink->close();
     434          $event = $events[0];
     435          $description = "The user id '$USER->id' changed the '$capability' capability permission for " .
     436              "role '$student->id' from 'Allow' to 'Prohibit'";
     437          $this->assertEquals($description, $event->get_description());
     438      }
     439  
     440      /**
     441       * Test removing of capabilities from roles.
     442       */
     443      public function test_unassign_capability() {
     444          global $DB, $USER;
     445  
     446          $this->resetAfterTest();
     447  
     448          $syscontext = context_system::instance();
     449          $frontcontext = context_course::instance(SITEID);
     450          $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
     451          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to manager by default.
     452          assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
     453  
     454          $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     455          $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     456  
     457          $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id);
     458          $this->assertTrue($result);
     459          $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     460          $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     461          unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext);
     462          $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     463  
     464          assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
     465          assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id);
     466          $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     467  
     468          $result = unassign_capability('moodle/backup:backupcourse', $manager->id);
     469          $this->assertTrue($result);
     470          $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     471          $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse')));
     472  
     473          // Test event triggered.
     474          $sink = $this->redirectEvents();
     475          $capability = 'moodle/backup:backupcourse';
     476          unassign_capability($capability, CAP_ALLOW, $manager->id);
     477          $events = $sink->get_events();
     478          $sink->close();
     479          $this->assertCount(1, $events);
     480          $event = $events[0];
     481          $this->assertInstanceOf('\core\event\capability_unassigned', $event);
     482          $this->assertSame('role_capabilities', $event->objecttable);
     483          $this->assertEquals($manager->id, $event->objectid);
     484          $this->assertEquals($syscontext->id, $event->contextid);
     485          $this->assertEquals($capability, $event->other['capability']);
     486          $description = "The user id id '$USER->id' has unassigned the '$capability' capability for role '$manager->id'";
     487          $this->assertEquals($description, $event->get_description());
     488      }
     489  
     490      /**
     491       * Test role assigning.
     492       */
     493      public function test_role_assign() {
     494          global $DB, $USER;
     495  
     496          $this->resetAfterTest();
     497  
     498          $user = $this->getDataGenerator()->create_user();
     499          $course = $this->getDataGenerator()->create_course();
     500          $role = $DB->get_record('role', array('shortname'=>'student'));
     501  
     502          $this->setUser(0);
     503          $context = context_system::instance();
     504          $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
     505          role_assign($role->id, $user->id, $context->id);
     506          $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
     507          $this->assertNotEmpty($ras);
     508          $this->assertSame('', $ras->component);
     509          $this->assertSame('0', $ras->itemid);
     510          $this->assertEquals($USER->id, $ras->modifierid);
     511  
     512          $this->setAdminUser();
     513          $context = context_course::instance($course->id);
     514          $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
     515          role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666);
     516          $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id));
     517          $this->assertNotEmpty($ras);
     518          $this->assertSame('enrol_self', $ras->component);
     519          $this->assertSame('1', $ras->itemid);
     520          $this->assertEquals($USER->id, $ras->modifierid);
     521          $this->assertEquals(666, $ras->timemodified);
     522  
     523          // Test event triggered.
     524  
     525          $user2 = $this->getDataGenerator()->create_user();
     526          $sink = $this->redirectEvents();
     527          $raid = role_assign($role->id, $user2->id, $context->id);
     528          $events = $sink->get_events();
     529          $sink->close();
     530          $this->assertCount(1, $events);
     531          $event = $events[0];
     532          $this->assertInstanceOf('\core\event\role_assigned', $event);
     533          $this->assertSame('role', $event->target);
     534          $this->assertSame('role', $event->objecttable);
     535          $this->assertEquals($role->id, $event->objectid);
     536          $this->assertEquals($context->id, $event->contextid);
     537          $this->assertEquals($user2->id, $event->relateduserid);
     538          $this->assertCount(3, $event->other);
     539          $this->assertEquals($raid, $event->other['id']);
     540          $this->assertSame('', $event->other['component']);
     541          $this->assertEquals(0, $event->other['itemid']);
     542          $this->assertInstanceOf('moodle_url', $event->get_url());
     543          $this->assertSame('role_assigned', $event::get_legacy_eventname());
     544          $roles = get_all_roles();
     545          $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
     546          $expectedlegacylog = array($course->id, 'role', 'assign',
     547              'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
     548          $this->assertEventLegacyLogData($expectedlegacylog, $event);
     549      }
     550  
     551      /**
     552       * Test role unassigning.
     553       */
     554      public function test_role_unassign() {
     555          global $DB, $USER;
     556  
     557          $this->resetAfterTest();
     558  
     559          $user = $this->getDataGenerator()->create_user();
     560          $course = $this->getDataGenerator()->create_course();
     561          $role = $DB->get_record('role', array('shortname'=>'student'));
     562  
     563          $context = context_course::instance($course->id);
     564          role_assign($role->id, $user->id, $context->id);
     565          $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
     566          role_unassign($role->id, $user->id, $context->id);
     567          $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
     568  
     569          role_assign($role->id, $user->id, $context->id, 'enrol_self', 1);
     570          $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
     571          role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1);
     572          $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)));
     573  
     574          // Test event triggered.
     575  
     576          role_assign($role->id, $user->id, $context->id);
     577          $sink = $this->redirectEvents();
     578          role_unassign($role->id, $user->id, $context->id);
     579          $events = $sink->get_events();
     580          $sink->close();
     581          $this->assertCount(1, $events);
     582          $event = $events[0];
     583          $this->assertInstanceOf('\core\event\role_unassigned', $event);
     584          $this->assertSame('role', $event->target);
     585          $this->assertSame('role', $event->objecttable);
     586          $this->assertEquals($role->id, $event->objectid);
     587          $this->assertEquals($context->id, $event->contextid);
     588          $this->assertEquals($user->id, $event->relateduserid);
     589          $this->assertCount(3, $event->other);
     590          $this->assertSame('', $event->other['component']);
     591          $this->assertEquals(0, $event->other['itemid']);
     592          $this->assertInstanceOf('moodle_url', $event->get_url());
     593          $roles = get_all_roles();
     594          $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true);
     595          $expectedlegacylog = array($course->id, 'role', 'unassign',
     596              'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id);
     597          $this->assertEventLegacyLogData($expectedlegacylog, $event);
     598      }
     599  
     600      /**
     601       * Test role unassigning.
     602       */
     603      public function test_role_unassign_all() {
     604          global $DB;
     605  
     606          $this->resetAfterTest();
     607  
     608          $user = $this->getDataGenerator()->create_user();
     609          $course = $this->getDataGenerator()->create_course();
     610          $role = $DB->get_record('role', array('shortname'=>'student'));
     611          $role2 = $DB->get_record('role', array('shortname'=>'teacher'));
     612          $syscontext = context_system::instance();
     613          $coursecontext = context_course::instance($course->id);
     614          $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
     615          $modcontext = context_module::instance($page->cmid);
     616  
     617          role_assign($role->id, $user->id, $syscontext->id);
     618          role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
     619          $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     620          role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id));
     621          $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     622  
     623          role_assign($role->id, $user->id, $syscontext->id);
     624          role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
     625          role_assign($role->id, $user->id, $modcontext->id);
     626          $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     627          role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false);
     628          $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     629          role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true);
     630          $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     631          role_unassign_all(array('userid'=>$user->id));
     632          $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     633  
     634          role_assign($role->id, $user->id, $syscontext->id);
     635          role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1);
     636          role_assign($role->id, $user->id, $coursecontext->id);
     637          role_assign($role->id, $user->id, $modcontext->id);
     638          $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     639          role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true);
     640          $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id)));
     641  
     642          // Test events triggered.
     643  
     644          role_assign($role2->id, $user->id, $coursecontext->id);
     645          role_assign($role2->id, $user->id, $modcontext->id);
     646          $sink = $this->redirectEvents();
     647          role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role2->id));
     648          $events = $sink->get_events();
     649          $sink->close();
     650          $this->assertCount(2, $events);
     651          $this->assertInstanceOf('\core\event\role_unassigned', $events[0]);
     652          $this->assertInstanceOf('\core\event\role_unassigned', $events[1]);
     653      }
     654  
     655      /**
     656       * Test role queries.
     657       */
     658      public function test_get_roles_with_capability() {
     659          global $DB;
     660  
     661          $this->resetAfterTest();
     662  
     663          $syscontext = context_system::instance();
     664          $frontcontext = context_course::instance(SITEID);
     665          $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
     666          $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
     667  
     668          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
     669          $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse'));
     670  
     671          $roles = get_roles_with_capability('moodle/backup:backupcourse');
     672          $this->assertEquals(array(), $roles);
     673  
     674          assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id);
     675          assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id);
     676          assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id);
     677  
     678          $roles = get_roles_with_capability('moodle/backup:backupcourse');
     679          $this->assertEqualsCanonicalizing(array($teacher->id, $manager->id), array_keys($roles), true);
     680  
     681          $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW);
     682          $this->assertEqualsCanonicalizing(array($manager->id), array_keys($roles), true);
     683  
     684          $roles = get_roles_with_capability('moodle/backup:backupcourse', null, $syscontext);
     685          $this->assertEqualsCanonicalizing(array($manager->id), array_keys($roles), true);
     686      }
     687  
     688      /**
     689       * Test deleting of roles.
     690       */
     691      public function test_delete_role() {
     692          global $DB;
     693  
     694          $this->resetAfterTest();
     695  
     696          $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
     697          $user = $this->getDataGenerator()->create_user();
     698          role_assign($role->id, $user->id, context_system::instance());
     699          $course = $this->getDataGenerator()->create_course();
     700          $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id);
     701          $DB->insert_record('role_names', $rolename);
     702  
     703          $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
     704          $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
     705          $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id)));
     706          $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
     707          $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
     708          $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
     709          $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
     710          $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
     711  
     712          // Delete role and get event.
     713          $sink = $this->redirectEvents();
     714          $result = delete_role($role->id);
     715          $events = $sink->get_events();
     716          $sink->close();
     717          $event = array_pop($events);
     718  
     719          $this->assertTrue($result);
     720          $this->assertFalse($DB->record_exists('role', array('id'=>$role->id)));
     721          $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id)));
     722          $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id)));
     723          $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id)));
     724          $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id)));
     725          $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id)));
     726          $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id)));
     727          $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id)));
     728          $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id)));
     729  
     730          // Test triggered event.
     731          $this->assertInstanceOf('\core\event\role_deleted', $event);
     732          $this->assertSame('role', $event->target);
     733          $this->assertSame('role', $event->objecttable);
     734          $this->assertSame($role->id, $event->objectid);
     735          $this->assertEquals(context_system::instance(), $event->get_context());
     736          $this->assertSame($role->shortname, $event->other['shortname']);
     737          $this->assertSame($role->description, $event->other['description']);
     738          $this->assertSame($role->archetype, $event->other['archetype']);
     739  
     740          $expectedlegacylog = array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$role->id,
     741                                     $role->shortname, '');
     742          $this->assertEventLegacyLogData($expectedlegacylog, $event);
     743      }
     744  
     745      /**
     746       * Test fetching of all roles.
     747       */
     748      public function test_get_all_roles() {
     749          global $DB;
     750  
     751          $this->resetAfterTest();
     752  
     753          $allroles = get_all_roles();
     754          $this->assertIsArray($allroles);
     755          $initialrolescount = count($allroles);
     756          $this->assertTrue($initialrolescount >= 8); // There are 8 roles is standard install.
     757          $rolenames = array_column($allroles, 'shortname');
     758          foreach (get_role_archetypes() as $archetype) {
     759              $this->assertContains($archetype, $rolenames);
     760          }
     761  
     762          $role = reset($allroles);
     763          $role = (array)$role;
     764  
     765          $this->assertEqualsCanonicalizing(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'),
     766              array_keys($role));
     767  
     768          foreach ($allroles as $roleid => $role) {
     769              $this->assertEquals($role->id, $roleid);
     770          }
     771  
     772          $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
     773          $course = $this->getDataGenerator()->create_course();
     774          $coursecontext = context_course::instance($course->id);
     775          $otherid = create_role('Other role', 'other', 'Some other role', '');
     776          $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
     777          $DB->insert_record('role_names', $teacherename);
     778          $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
     779          $DB->insert_record('role_names', $otherrename);
     780          $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
     781  
     782          $allroles = get_all_roles($coursecontext);
     783          $this->assertIsArray($allroles);
     784          $this->assertCount($initialrolescount + 1, $allroles);
     785          $role = reset($allroles);
     786          $role = (array)$role;
     787  
     788          $this->assertEqualsCanonicalizing(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role));
     789  
     790          foreach ($allroles as $roleid => $role) {
     791              $this->assertEquals($role->id, $roleid);
     792              if (isset($renames[$roleid])) {
     793                  $this->assertSame($renames[$roleid], $role->coursealias);
     794              } else {
     795                  $this->assertNull($role->coursealias);
     796              }
     797          }
     798      }
     799  
     800      /**
     801       * Test getting of all archetypes.
     802       */
     803      public function test_get_role_archetypes() {
     804          $archetypes = get_role_archetypes();
     805          $this->assertCount(8, $archetypes); // There are 8 archetypes in standard install.
     806          foreach ($archetypes as $k => $v) {
     807              $this->assertSame($k, $v);
     808          }
     809      }
     810  
     811      /**
     812       * Test getting of roles with given archetype.
     813       */
     814      public function test_get_archetype_roles() {
     815          $this->resetAfterTest();
     816  
     817          // New install should have at least 1 role for each archetype.
     818          $archetypes = get_role_archetypes();
     819          foreach ($archetypes as $archetype) {
     820              $roles = get_archetype_roles($archetype);
     821              $this->assertGreaterThanOrEqual(1, count($roles));
     822              $role = reset($roles);
     823              $this->assertSame($archetype, $role->archetype);
     824          }
     825  
     826          create_role('New student role', 'student2', 'New student description', 'student');
     827          $roles = get_archetype_roles('student');
     828          $this->assertGreaterThanOrEqual(2, count($roles));
     829      }
     830  
     831      /**
     832       * Test aliased role names.
     833       */
     834      public function test_role_get_name() {
     835          global $DB;
     836  
     837          $this->resetAfterTest();
     838  
     839          $allroles = $DB->get_records('role');
     840          $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
     841          $course = $this->getDataGenerator()->create_course();
     842          $coursecontext = context_course::instance($course->id);
     843          $otherid = create_role('Other role', 'other', 'Some other role', '');
     844          $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
     845          $DB->insert_record('role_names', $teacherename);
     846          $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
     847          $DB->insert_record('role_names', $otherrename);
     848          $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
     849  
     850          foreach ($allroles as $role) {
     851              if (in_array($role->shortname, get_role_archetypes())) {
     852                  // Standard roles do not have a set name.
     853                  $this->assertSame('', $role->name);
     854              }
     855              // Get localised name from lang pack.
     856              $name = role_get_name($role, null, ROLENAME_ORIGINAL);
     857              $this->assertNotEmpty($name);
     858              $this->assertNotEquals($role->shortname, $name);
     859  
     860              if (isset($renames[$role->id])) {
     861                  $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext));
     862                  $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS));
     863                  $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
     864                  $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH));
     865              } else {
     866                  $this->assertSame($name, role_get_name($role, $coursecontext));
     867                  $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS));
     868                  $this->assertNull(role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW));
     869                  $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH));
     870              }
     871              $this->assertSame($name, role_get_name($role));
     872              $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL));
     873              $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL));
     874              $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT));
     875              $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT));
     876              $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT));
     877              $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT));
     878              $this->assertNull(role_get_name($role, null, ROLENAME_ALIAS_RAW));
     879          }
     880      }
     881  
     882      /**
     883       * Test tweaking of role name arrays.
     884       */
     885      public function test_role_fix_names() {
     886          global $DB;
     887  
     888          $this->resetAfterTest();
     889  
     890          $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST);
     891          $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
     892          $otherid = create_role('Other role', 'other', 'Some other role', '');
     893          $anotherid = create_role('Another role', 'another', 'Yet another other role', '');
     894          $allroles = $DB->get_records('role');
     895  
     896          $syscontext = context_system::instance();
     897          $frontcontext = context_course::instance(SITEID);
     898          $course = $this->getDataGenerator()->create_course();
     899          $coursecontext = context_course::instance($course->id);
     900          $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST);
     901          $categorycontext = context_coursecat::instance($category->id);
     902  
     903          $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
     904          $DB->insert_record('role_names', $teacherename);
     905          $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
     906          $DB->insert_record('role_names', $otherrename);
     907          $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name');
     908  
     909          // Make sure all localname contain proper values for each ROLENAME_ constant,
     910          // note role_get_name() on frontpage is used to get the original name for future compatibility.
     911          $roles = $allroles;
     912          unset($roles[$student->id]); // Remove one role to make sure no role is added or removed.
     913          $rolenames = array();
     914          foreach ($roles as $role) {
     915              $rolenames[$role->id] = $role->name;
     916          }
     917  
     918          $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
     919          foreach ($alltypes as $type) {
     920              $fixed = role_fix_names($roles, $coursecontext, $type);
     921              $this->assertCount(count($roles), $fixed);
     922              foreach ($fixed as $roleid => $rolename) {
     923                  $this->assertInstanceOf('stdClass', $rolename);
     924                  $role = $allroles[$roleid];
     925                  $name = role_get_name($role, $coursecontext, $type);
     926                  $this->assertSame($name, $rolename->localname);
     927              }
     928              $fixed = role_fix_names($rolenames, $coursecontext, $type);
     929              $this->assertCount(count($rolenames), $fixed);
     930              foreach ($fixed as $roleid => $rolename) {
     931                  $role = $allroles[$roleid];
     932                  $name = role_get_name($role, $coursecontext, $type);
     933                  $this->assertSame($name, $rolename);
     934              }
     935          }
     936      }
     937  
     938      /**
     939       * Test role default allows.
     940       */
     941      public function test_get_default_role_archetype_allows() {
     942          $archetypes = get_role_archetypes();
     943          foreach ($archetypes as $archetype) {
     944  
     945              $result = get_default_role_archetype_allows('assign', $archetype);
     946              $this->assertIsArray($result);
     947  
     948              $result = get_default_role_archetype_allows('override', $archetype);
     949              $this->assertIsArray($result);
     950  
     951              $result = get_default_role_archetype_allows('switch', $archetype);
     952              $this->assertIsArray($result);
     953  
     954              $result = get_default_role_archetype_allows('view', $archetype);
     955              $this->assertIsArray($result);
     956          }
     957  
     958          $result = get_default_role_archetype_allows('assign', '');
     959          $this->assertSame(array(), $result);
     960  
     961          $result = get_default_role_archetype_allows('override', '');
     962          $this->assertSame(array(), $result);
     963  
     964          $result = get_default_role_archetype_allows('switch', '');
     965          $this->assertSame(array(), $result);
     966  
     967          $result = get_default_role_archetype_allows('view', '');
     968          $this->assertSame(array(), $result);
     969  
     970          $result = get_default_role_archetype_allows('assign', 'wrongarchetype');
     971          $this->assertSame(array(), $result);
     972          $this->assertDebuggingCalled();
     973  
     974          $result = get_default_role_archetype_allows('override', 'wrongarchetype');
     975          $this->assertSame(array(), $result);
     976          $this->assertDebuggingCalled();
     977  
     978          $result = get_default_role_archetype_allows('switch', 'wrongarchetype');
     979          $this->assertSame(array(), $result);
     980          $this->assertDebuggingCalled();
     981  
     982          $result = get_default_role_archetype_allows('view', 'wrongarchetype');
     983          $this->assertSame(array(), $result);
     984          $this->assertDebuggingCalled();
     985      }
     986  
     987      /**
     988       * Test allowing of role assignments.
     989       */
     990      public function test_core_role_set_assign_allowed() {
     991          global $DB, $CFG;
     992  
     993          $this->resetAfterTest();
     994  
     995          $otherid = create_role('Other role', 'other', 'Some other role', '');
     996          $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
     997  
     998          $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
     999          core_role_set_assign_allowed($otherid, $student->id);
    1000          $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id)));
    1001  
    1002          // Test event trigger.
    1003          $allowroleassignevent = \core\event\role_allow_assign_updated::create([
    1004              'context' => context_system::instance(),
    1005              'objectid' => $otherid,
    1006              'other' => ['targetroleid' => $student->id]
    1007          ]);
    1008          $sink = $this->redirectEvents();
    1009          $allowroleassignevent->trigger();
    1010          $events = $sink->get_events();
    1011          $sink->close();
    1012          $event = array_pop($events);
    1013          $this->assertInstanceOf('\core\event\role_allow_assign_updated', $event);
    1014          $mode = 'assign';
    1015          $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
    1016          $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
    1017          $this->assertEventLegacyLogData($expectedlegacylog, $event);
    1018      }
    1019  
    1020      /**
    1021       * Test allowing of role overrides.
    1022       */
    1023      public function test_core_role_set_override_allowed() {
    1024          global $DB, $CFG;
    1025  
    1026          $this->resetAfterTest();
    1027  
    1028          $otherid = create_role('Other role', 'other', 'Some other role', '');
    1029          $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1030  
    1031          $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
    1032          core_role_set_override_allowed($otherid, $student->id);
    1033          $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id)));
    1034  
    1035          // Test event trigger.
    1036          $allowroleassignevent = \core\event\role_allow_override_updated::create([
    1037              'context' => context_system::instance(),
    1038              'objectid' => $otherid,
    1039              'other' => ['targetroleid' => $student->id]
    1040          ]);
    1041          $sink = $this->redirectEvents();
    1042          $allowroleassignevent->trigger();
    1043          $events = $sink->get_events();
    1044          $sink->close();
    1045          $event = array_pop($events);
    1046          $this->assertInstanceOf('\core\event\role_allow_override_updated', $event);
    1047          $mode = 'override';
    1048          $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
    1049          $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
    1050          $this->assertEventLegacyLogData($expectedlegacylog, $event);
    1051      }
    1052  
    1053      /**
    1054       * Test allowing of role switching.
    1055       */
    1056      public function test_core_role_set_switch_allowed() {
    1057          global $DB, $CFG;
    1058  
    1059          $this->resetAfterTest();
    1060  
    1061          $otherid = create_role('Other role', 'other', 'Some other role', '');
    1062          $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1063  
    1064          $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
    1065          core_role_set_switch_allowed($otherid, $student->id);
    1066          $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id)));
    1067  
    1068          // Test event trigger.
    1069          $allowroleassignevent = \core\event\role_allow_switch_updated::create([
    1070              'context' => context_system::instance(),
    1071              'objectid' => $otherid,
    1072              'other' => ['targetroleid' => $student->id]
    1073          ]);
    1074          $sink = $this->redirectEvents();
    1075          $allowroleassignevent->trigger();
    1076          $events = $sink->get_events();
    1077          $sink->close();
    1078          $event = array_pop($events);
    1079          $this->assertInstanceOf('\core\event\role_allow_switch_updated', $event);
    1080          $mode = 'switch';
    1081          $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
    1082          $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
    1083          $this->assertEventLegacyLogData($expectedlegacylog, $event);
    1084      }
    1085  
    1086      /**
    1087       * Test allowing of role switching.
    1088       */
    1089      public function test_core_role_set_view_allowed() {
    1090          global $DB, $CFG;
    1091  
    1092          $this->resetAfterTest();
    1093  
    1094          $otherid = create_role('Other role', 'other', 'Some other role', '');
    1095          $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
    1096  
    1097          $this->assertFalse($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id)));
    1098          core_role_set_view_allowed($otherid, $student->id);
    1099          $this->assertTrue($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id)));
    1100  
    1101          // Test event trigger.
    1102          $allowroleassignevent = \core\event\role_allow_view_updated::create([
    1103              'context' => context_system::instance(),
    1104              'objectid' => $otherid,
    1105              'other' => ['targetroleid' => $student->id]
    1106          ]);
    1107          $sink = $this->redirectEvents();
    1108          $allowroleassignevent->trigger();
    1109          $events = $sink->get_events();
    1110          $sink->close();
    1111          $event = array_pop($events);
    1112          $this->assertInstanceOf('\core\event\role_allow_view_updated', $event);
    1113          $mode = 'view';
    1114          $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode));
    1115          $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl));
    1116          $this->assertEventLegacyLogData($expectedlegacylog, $event);
    1117      }
    1118  
    1119      /**
    1120       * Test returning of assignable roles in context.
    1121       */
    1122      public function test_get_assignable_roles() {
    1123          global $DB;
    1124  
    1125          $this->resetAfterTest();
    1126  
    1127          $course = $this->getDataGenerator()->create_course();
    1128          $coursecontext = context_course::instance($course->id);
    1129  
    1130          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1131          $teacher = $this->getDataGenerator()->create_user();
    1132          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1133          $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1134          $DB->insert_record('role_names', $teacherename);
    1135  
    1136          $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1137          $student = $this->getDataGenerator()->create_user();
    1138          role_assign($studentrole->id, $student->id, $coursecontext);
    1139  
    1140          $contexts = $DB->get_records('context');
    1141          $users = $DB->get_records('user');
    1142          $allroles = $DB->get_records('role');
    1143  
    1144          // Evaluate all results for all users in all contexts.
    1145          foreach ($users as $user) {
    1146              $this->setUser($user);
    1147              foreach ($contexts as $contextid => $unused) {
    1148                  $context = context_helper::instance_by_id($contextid);
    1149                  $roles = get_assignable_roles($context, ROLENAME_SHORT);
    1150                  foreach ($allroles as $roleid => $role) {
    1151                      if (isset($roles[$roleid])) {
    1152                          if (is_siteadmin()) {
    1153                              $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)));
    1154                          } else {
    1155                              $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid");
    1156                          }
    1157                          $this->assertEquals($role->shortname, $roles[$roleid]);
    1158                      } else {
    1159                          $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid));
    1160                          if (is_siteadmin()) {
    1161                              $this->assertFalse($allowed);
    1162                          } else {
    1163                              $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel");
    1164                          }
    1165                      }
    1166                  }
    1167              }
    1168          }
    1169  
    1170          // Not-logged-in user.
    1171          $this->setUser(0);
    1172          foreach ($contexts as $contextid => $unused) {
    1173              $context = context_helper::instance_by_id($contextid);
    1174              $roles = get_assignable_roles($context, ROLENAME_SHORT);
    1175              $this->assertSame(array(), $roles);
    1176          }
    1177  
    1178          // Test current user.
    1179          $this->setUser(0);
    1180          $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST);
    1181          $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin);
    1182          $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id);
    1183          $this->setAdminUser();
    1184          $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT);
    1185          $this->assertSame($roles1, $roles3);
    1186          $this->assertSame($roles2, $roles3);
    1187  
    1188          // Test parameter defaults.
    1189          $this->setAdminUser();
    1190          $roles1 = get_assignable_roles($coursecontext);
    1191          $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin);
    1192          $this->assertEquals($roles2, $roles1);
    1193  
    1194          // Verify returned names - let's allow all roles everywhere to simplify this a bit.
    1195          $alllevels = context_helper::get_all_levels();
    1196          $alllevels = array_keys($alllevels);
    1197          foreach ($allroles as $roleid => $role) {
    1198              set_role_contextlevels($roleid, $alllevels);
    1199          }
    1200          $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
    1201          foreach ($alltypes as $type) {
    1202              $rolenames = role_fix_names($allroles, $coursecontext, $type);
    1203              $roles = get_assignable_roles($coursecontext, $type, false, $admin);
    1204              foreach ($roles as $roleid => $rolename) {
    1205                  $this->assertSame($rolenames[$roleid]->localname, $rolename);
    1206              }
    1207          }
    1208  
    1209          // Verify counts.
    1210          $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
    1211          foreach ($alltypes as $type) {
    1212              $roles = get_assignable_roles($coursecontext, $type, false, $admin);
    1213              list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin);
    1214              $this->assertEquals($roles, $rolenames);
    1215              foreach ($rolenames as $roleid => $name) {
    1216                  if ($roleid == $teacherrole->id or $roleid == $studentrole->id) {
    1217                      $this->assertEquals(1, $rolecounts[$roleid]);
    1218                  } else {
    1219                      $this->assertEquals(0, $rolecounts[$roleid]);
    1220                  }
    1221                  $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
    1222              }
    1223          }
    1224      }
    1225  
    1226      /**
    1227       * Test user count of assignable roles in context where users are assigned the role via different components.
    1228       */
    1229      public function test_get_assignable_roles_distinct_usercount() {
    1230          global $DB;
    1231  
    1232          $this->resetAfterTest(true);
    1233  
    1234          $this->setAdminUser();
    1235  
    1236          $course = $this->getDataGenerator()->create_course();
    1237          $context = \context_course::instance($course->id);
    1238  
    1239          $user1 = $this->getDataGenerator()->create_user();
    1240          $user2 = $this->getDataGenerator()->create_user();
    1241  
    1242          $studentrole = $DB->get_record('role', ['shortname' => 'student']);
    1243  
    1244          // Assign each user the student role in course.
    1245          role_assign($studentrole->id, $user1->id, $context->id);
    1246          role_assign($studentrole->id, $user2->id, $context->id);
    1247  
    1248          list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true);
    1249          $this->assertEquals(2, $rolecounts[$studentrole->id]);
    1250  
    1251          // Assign first user the student role in course again (this time via 'enrol_self' component).
    1252          role_assign($studentrole->id, $user1->id, $context->id, 'enrol_self', 1);
    1253  
    1254          // There are still only two distinct users.
    1255          list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true);
    1256          $this->assertEquals(2, $rolecounts[$studentrole->id]);
    1257      }
    1258  
    1259      /**
    1260       * Test getting of all switchable roles.
    1261       */
    1262      public function test_get_switchable_roles() {
    1263          global $DB;
    1264  
    1265          $this->resetAfterTest();
    1266  
    1267          $course = $this->getDataGenerator()->create_course();
    1268          $coursecontext = context_course::instance($course->id);
    1269  
    1270          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1271          $teacher = $this->getDataGenerator()->create_user();
    1272          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1273          $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1274          $DB->insert_record('role_names', $teacherename);
    1275  
    1276          $contexts = $DB->get_records('context');
    1277          $users = $DB->get_records('user');
    1278          $allroles = $DB->get_records('role');
    1279  
    1280          // Evaluate all results for all users in all contexts.
    1281          foreach ($users as $user) {
    1282              $this->setUser($user);
    1283              foreach ($contexts as $contextid => $unused) {
    1284                  $context = context_helper::instance_by_id($contextid);
    1285                  $roles = get_switchable_roles($context);
    1286                  foreach ($allroles as $roleid => $role) {
    1287                      if (is_siteadmin()) {
    1288                          $this->assertTrue(isset($roles[$roleid]));
    1289                      } else {
    1290                          $parents = $context->get_parent_context_ids(true);
    1291                          $pcontexts = implode(',' , $parents);
    1292                          $allowed = $DB->record_exists_sql(
    1293                              "SELECT r.id
    1294                                 FROM {role} r
    1295                                 JOIN {role_allow_switch} ras ON ras.allowswitch = r.id
    1296                                 JOIN {role_assignments} ra ON ra.roleid = ras.roleid
    1297                                WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
    1298                              ",
    1299                              array('userid'=>$user->id, 'roleid'=>$roleid)
    1300                          );
    1301                          if (isset($roles[$roleid])) {
    1302                              $this->assertTrue($allowed);
    1303                          } else {
    1304                              $this->assertFalse($allowed);
    1305                          }
    1306                      }
    1307  
    1308                      if (isset($roles[$roleid])) {
    1309                          $coursecontext = $context->get_course_context(false);
    1310                          $this->assertSame(role_get_name($role, $coursecontext), $roles[$roleid]);
    1311                      }
    1312                  }
    1313              }
    1314          }
    1315      }
    1316  
    1317      /**
    1318       * Test getting of all overridable roles.
    1319       */
    1320      public function test_get_overridable_roles() {
    1321          global $DB;
    1322  
    1323          $this->resetAfterTest();
    1324  
    1325          $course = $this->getDataGenerator()->create_course();
    1326          $coursecontext = context_course::instance($course->id);
    1327  
    1328          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1329          $teacher = $this->getDataGenerator()->create_user();
    1330          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1331          $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1332          $DB->insert_record('role_names', $teacherename);
    1333          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok.
    1334          assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
    1335  
    1336          $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1337          $student = $this->getDataGenerator()->create_user();
    1338          role_assign($studentrole->id, $student->id, $coursecontext);
    1339  
    1340          $contexts = $DB->get_records('context');
    1341          $users = $DB->get_records('user');
    1342          $allroles = $DB->get_records('role');
    1343  
    1344          // Evaluate all results for all users in all contexts.
    1345          foreach ($users as $user) {
    1346              $this->setUser($user);
    1347              foreach ($contexts as $contextid => $unused) {
    1348                  $context = context_helper::instance_by_id($contextid);
    1349                  $roles = get_overridable_roles($context, ROLENAME_SHORT);
    1350                  foreach ($allroles as $roleid => $role) {
    1351                      $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context);
    1352                      if (is_siteadmin()) {
    1353                          $this->assertTrue(isset($roles[$roleid]));
    1354                      } else {
    1355                          $parents = $context->get_parent_context_ids(true);
    1356                          $pcontexts = implode(',' , $parents);
    1357                          $allowed = $DB->record_exists_sql(
    1358                              "SELECT r.id
    1359                                 FROM {role} r
    1360                                 JOIN {role_allow_override} rao ON r.id = rao.allowoverride
    1361                                 JOIN {role_assignments} ra ON rao.roleid = ra.roleid
    1362                                WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid
    1363                              ",
    1364                              array('userid'=>$user->id, 'roleid'=>$roleid)
    1365                          );
    1366                          if (isset($roles[$roleid])) {
    1367                              $this->assertTrue($hascap);
    1368                              $this->assertTrue($allowed);
    1369                          } else {
    1370                              $this->assertFalse($hascap and $allowed);
    1371                          }
    1372                      }
    1373  
    1374                      if (isset($roles[$roleid])) {
    1375                          $this->assertEquals($role->shortname, $roles[$roleid]);
    1376                      }
    1377                  }
    1378              }
    1379          }
    1380  
    1381          // Test parameter defaults.
    1382          $this->setAdminUser();
    1383          $roles1 = get_overridable_roles($coursecontext);
    1384          $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
    1385          $this->assertEquals($roles2, $roles1);
    1386  
    1387          $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT);
    1388          foreach ($alltypes as $type) {
    1389              $rolenames = role_fix_names($allroles, $coursecontext, $type);
    1390              $roles = get_overridable_roles($coursecontext, $type, false);
    1391              foreach ($roles as $roleid => $rolename) {
    1392                  $this->assertSame($rolenames[$roleid]->localname, $rolename);
    1393              }
    1394          }
    1395  
    1396          // Verify counts.
    1397          $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false);
    1398          list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true);
    1399          $this->assertEquals($roles, $rolenames);
    1400          foreach ($rolenames as $roleid => $name) {
    1401              if ($roleid == $teacherrole->id) {
    1402                  $this->assertEquals(1, $rolecounts[$roleid]);
    1403              } else {
    1404                  $this->assertEquals(0, $rolecounts[$roleid]);
    1405              }
    1406              $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]);
    1407          }
    1408      }
    1409  
    1410      /**
    1411       * Test getting of all overridable roles.
    1412       */
    1413      public function test_get_viewable_roles_course() {
    1414          global $DB;
    1415  
    1416          $this->resetAfterTest();
    1417  
    1418          $course = $this->getDataGenerator()->create_course();
    1419          $coursecontext = context_course::instance($course->id);
    1420  
    1421          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
    1422          $teacher = $this->getDataGenerator()->create_user();
    1423          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1424  
    1425          $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
    1426          $studentrolerename = (object) array('roleid' => $studentrole->id, 'name' => 'Učitel', 'contextid' => $coursecontext->id);
    1427          $DB->insert_record('role_names', $studentrolerename);
    1428  
    1429          // By default teacher can see student.
    1430          $this->setUser($teacher);
    1431          $viewableroles = get_viewable_roles($coursecontext);
    1432          $this->assertContains($studentrolerename->name, array_values($viewableroles));
    1433          // Remove view permission.
    1434          $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id));
    1435          $viewableroles = get_viewable_roles($coursecontext);
    1436          // Teacher can no longer see student role.
    1437          $this->assertNotContains($studentrolerename->name, array_values($viewableroles));
    1438          // Allow again teacher to view student.
    1439          core_role_set_view_allowed($teacherrole->id, $studentrole->id);
    1440          // Teacher can now see student role.
    1441          $viewableroles = get_viewable_roles($coursecontext);
    1442          $this->assertContains($studentrolerename->name, array_values($viewableroles));
    1443      }
    1444  
    1445      /**
    1446       * Test getting of all overridable roles.
    1447       */
    1448      public function test_get_viewable_roles_system() {
    1449          global $DB;
    1450  
    1451          $this->resetAfterTest();
    1452  
    1453          $context = context_system::instance();
    1454  
    1455          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
    1456          $teacher = $this->getDataGenerator()->create_user();
    1457          role_assign($teacherrole->id, $teacher->id, $context);
    1458  
    1459          $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
    1460          $studentrolename = role_get_name($studentrole, $context);
    1461  
    1462          // By default teacher can see student.
    1463          $this->setUser($teacher);
    1464          $viewableroles = get_viewable_roles($context);
    1465          $this->assertContains($studentrolename, array_values($viewableroles));
    1466          // Remove view permission.
    1467          $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id));
    1468          $viewableroles = get_viewable_roles($context);
    1469          // Teacher can no longer see student role.
    1470          $this->assertNotContains($studentrolename, array_values($viewableroles));
    1471          // Allow again teacher to view student.
    1472          core_role_set_view_allowed($teacherrole->id, $studentrole->id);
    1473          // Teacher can now see student role.
    1474          $viewableroles = get_viewable_roles($context);
    1475          $this->assertContains($studentrolename, array_values($viewableroles));
    1476      }
    1477  
    1478      /**
    1479       * Test we have context level defaults.
    1480       */
    1481      public function test_get_default_contextlevels() {
    1482          $archetypes = get_role_archetypes();
    1483          $alllevels = context_helper::get_all_levels();
    1484          foreach ($archetypes as $archetype) {
    1485              $defaults = get_default_contextlevels($archetype);
    1486              $this->assertIsArray($defaults);
    1487              foreach ($defaults as $level) {
    1488                  $this->assertTrue(isset($alllevels[$level]));
    1489              }
    1490          }
    1491      }
    1492  
    1493      /**
    1494       * Test role context level setup.
    1495       */
    1496      public function test_set_role_contextlevels() {
    1497          global $DB;
    1498  
    1499          $this->resetAfterTest();
    1500  
    1501          $roleid = create_role('New student role', 'student2', 'New student description', 'student');
    1502  
    1503          $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid)));
    1504  
    1505          set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE));
    1506          $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
    1507          $this->assertCount(2, $levels);
    1508          $this->assertTrue(isset($levels[CONTEXT_COURSE]));
    1509          $this->assertTrue(isset($levels[CONTEXT_MODULE]));
    1510  
    1511          set_role_contextlevels($roleid, array(CONTEXT_COURSE));
    1512          $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel');
    1513          $this->assertCount(1, $levels);
    1514          $this->assertTrue(isset($levels[CONTEXT_COURSE]));
    1515      }
    1516  
    1517      /**
    1518       * Test getting of role context levels
    1519       */
    1520      public function test_get_roles_for_contextlevels() {
    1521          global $DB;
    1522  
    1523          $allroles = get_all_roles();
    1524          foreach (context_helper::get_all_levels() as $level => $unused) {
    1525              $roles = get_roles_for_contextlevels($level);
    1526              foreach ($allroles as $roleid => $unused) {
    1527                  $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid));
    1528                  if (in_array($roleid, $roles)) {
    1529                      $this->assertTrue($exists);
    1530                  } else {
    1531                      $this->assertFalse($exists);
    1532                  }
    1533              }
    1534          }
    1535      }
    1536  
    1537      /**
    1538       * Test default enrol roles.
    1539       */
    1540      public function test_get_default_enrol_roles() {
    1541          $this->resetAfterTest();
    1542  
    1543          $course = $this->getDataGenerator()->create_course();
    1544          $coursecontext = context_course::instance($course->id);
    1545  
    1546          $id2 = create_role('New student role', 'student2', 'New student description', 'student');
    1547          set_role_contextlevels($id2, array(CONTEXT_COURSE));
    1548  
    1549          $allroles = get_all_roles();
    1550          $expected = array($id2=>$allroles[$id2]);
    1551  
    1552          foreach (get_roles_for_contextlevels(CONTEXT_COURSE) as $roleid) {
    1553              $expected[$roleid] = $roleid;
    1554          }
    1555  
    1556          $roles = get_default_enrol_roles($coursecontext);
    1557          foreach ($allroles as $role) {
    1558              $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id]));
    1559              if (isset($roles[$role->id])) {
    1560                  $this->assertSame(role_get_name($role, $coursecontext), $roles[$role->id]);
    1561              }
    1562          }
    1563      }
    1564  
    1565      /**
    1566       * Test getting of role users.
    1567       */
    1568      public function test_get_role_users() {
    1569          global $DB;
    1570  
    1571          $this->resetAfterTest();
    1572  
    1573          $systemcontext = context_system::instance();
    1574          $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1575          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1576          $noeditteacherrole = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
    1577          $course = $this->getDataGenerator()->create_course();
    1578          $coursecontext = context_course::instance($course->id);
    1579          $otherid = create_role('Other role', 'other', 'Some other role', '');
    1580          $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1581          $DB->insert_record('role_names', $teacherrename);
    1582          $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
    1583          $DB->insert_record('role_names', $otherrename);
    1584  
    1585          $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith'));
    1586          role_assign($teacherrole->id, $user1->id, $coursecontext->id);
    1587          $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar'));
    1588          role_assign($teacherrole->id, $user2->id, $systemcontext->id);
    1589          $user3 = $this->getDataGenerator()->create_user();
    1590          $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id);
    1591          $user4 = $this->getDataGenerator()->create_user();
    1592          $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id);
    1593          $this->getDataGenerator()->enrol_user($user4->id, $course->id, $noeditteacherrole->id);
    1594  
    1595          $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id));
    1596          groups_add_member($group, $user3);
    1597  
    1598          $users = get_role_users($teacherrole->id, $coursecontext);
    1599          $this->assertCount(2, $users);
    1600          $this->assertArrayHasKey($user1->id, $users);
    1601          $this->assertEquals($users[$user1->id]->id, $user1->id);
    1602          $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id);
    1603          $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name);
    1604          $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname);
    1605          $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name);
    1606          $this->assertArrayHasKey($user3->id, $users);
    1607          $this->assertEquals($users[$user3->id]->id, $user3->id);
    1608          $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id);
    1609          $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name);
    1610          $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname);
    1611          $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name);
    1612  
    1613          $users = get_role_users($teacherrole->id, $coursecontext, true);
    1614          $this->assertCount(3, $users);
    1615  
    1616          $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1);
    1617          $this->assertCount(1, $users);
    1618  
    1619          $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber');
    1620          $this->assertCount(2, $users);
    1621          $this->assertArrayHasKey($user1->id, $users);
    1622          $this->assertArrayHasKey($user3->id, $users);
    1623  
    1624          $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email');
    1625          $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields');
    1626          $this->assertCount(2, $users);
    1627          $this->assertArrayHasKey($user1->id, $users);
    1628          $this->assertObjectHasAttribute('lastname', $users[$user1->id]);
    1629          $this->assertObjectHasAttribute('firstname', $users[$user1->id]);
    1630          $this->assertArrayHasKey($user3->id, $users);
    1631          $this->assertObjectHasAttribute('lastname', $users[$user3->id]);
    1632          $this->assertObjectHasAttribute('firstname', $users[$user3->id]);
    1633  
    1634          $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id AS id_alias');
    1635          $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields');
    1636          $this->assertCount(2, $users);
    1637          $this->assertArrayHasKey($user1->id, $users);
    1638          $this->assertObjectHasAttribute('id_alias', $users[$user1->id]);
    1639          $this->assertObjectHasAttribute('lastname', $users[$user1->id]);
    1640          $this->assertObjectHasAttribute('firstname', $users[$user1->id]);
    1641          $this->assertArrayHasKey($user3->id, $users);
    1642          $this->assertObjectHasAttribute('id_alias', $users[$user3->id]);
    1643          $this->assertObjectHasAttribute('lastname', $users[$user3->id]);
    1644          $this->assertObjectHasAttribute('firstname', $users[$user3->id]);
    1645  
    1646          $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id);
    1647          $this->assertCount(1, $users);
    1648          $this->assertArrayHasKey($user3->id, $users);
    1649  
    1650          $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'));
    1651          $this->assertCount(1, $users);
    1652          $this->assertArrayHasKey($user1->id, $users);
    1653  
    1654          $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.id', 'ra.id');
    1655          $this->assertDebuggingNotCalled();
    1656          $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.userid', 'ra.userid');
    1657          $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' .
    1658              'role assignments id (ra.id) as unique field, you can use $fields param for it.');
    1659          $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false);
    1660          $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' .
    1661              'role assignments id (ra.id) as unique field, you can use $fields param for it.');
    1662          $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext,
    1663              false, 'u.id, u.firstname', 'u.id, u.firstname');
    1664          $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' .
    1665              'role assignments id (ra.id) as unique field, you can use $fields param for it.');
    1666      }
    1667  
    1668      /**
    1669       * Test used role query.
    1670       */
    1671      public function test_get_roles_used_in_context() {
    1672          global $DB;
    1673  
    1674          $this->resetAfterTest();
    1675  
    1676          $systemcontext = context_system::instance();
    1677          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1678          $course = $this->getDataGenerator()->create_course();
    1679          $coursecontext = context_course::instance($course->id);
    1680          $otherid = create_role('Other role', 'other', 'Some other role', '');
    1681          $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1682          $DB->insert_record('role_names', $teacherrename);
    1683          $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id);
    1684          $DB->insert_record('role_names', $otherrename);
    1685  
    1686          $user1 = $this->getDataGenerator()->create_user();
    1687          role_assign($teacherrole->id, $user1->id, $coursecontext->id);
    1688  
    1689          $roles = get_roles_used_in_context($coursecontext);
    1690          $this->assertCount(1, $roles);
    1691          $role = reset($roles);
    1692          $roleid = key($roles);
    1693          $this->assertEquals($roleid, $role->id);
    1694          $this->assertEquals($teacherrole->id, $role->id);
    1695          $this->assertSame($teacherrole->name, $role->name);
    1696          $this->assertSame($teacherrole->shortname, $role->shortname);
    1697          $this->assertEquals($teacherrole->sortorder, $role->sortorder);
    1698          $this->assertSame($teacherrename->name, $role->coursealias);
    1699  
    1700          $user2 = $this->getDataGenerator()->create_user();
    1701          role_assign($teacherrole->id, $user2->id, $systemcontext->id);
    1702          role_assign($otherid, $user2->id, $systemcontext->id);
    1703  
    1704          $roles = get_roles_used_in_context($systemcontext);
    1705          $this->assertCount(2, $roles);
    1706      }
    1707  
    1708      /**
    1709       * Test roles used in course.
    1710       */
    1711      public function test_get_user_roles_in_course() {
    1712          global $DB, $CFG;
    1713  
    1714          $this->resetAfterTest();
    1715  
    1716          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1717          $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1718          $managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
    1719          $course = $this->getDataGenerator()->create_course();
    1720          $coursecontext = context_course::instance($course->id);
    1721          $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1722          $DB->insert_record('role_names', $teacherrename);
    1723  
    1724          $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
    1725          $this->assertTrue(in_array($teacherrole->id, $roleids));
    1726          $this->assertTrue(in_array($studentrole->id, $roleids));
    1727          $this->assertFalse(in_array($managerrole->id, $roleids));
    1728  
    1729          $user1 = $this->getDataGenerator()->create_user();
    1730          role_assign($teacherrole->id, $user1->id, $coursecontext->id);
    1731          role_assign($studentrole->id, $user1->id, $coursecontext->id);
    1732          $user2 = $this->getDataGenerator()->create_user();
    1733          role_assign($studentrole->id, $user2->id, $coursecontext->id);
    1734          $user3 = $this->getDataGenerator()->create_user();
    1735          $user4 = $this->getDataGenerator()->create_user();
    1736          role_assign($managerrole->id, $user4->id, $coursecontext->id);
    1737  
    1738          $this->setAdminUser();
    1739  
    1740          $roles = get_user_roles_in_course($user1->id, $course->id);
    1741          $this->assertEquals([
    1742              role_get_name($teacherrole, $coursecontext),
    1743              role_get_name($studentrole, $coursecontext),
    1744          ], array_map('strip_tags', explode(', ', $roles)));
    1745  
    1746          $roles = get_user_roles_in_course($user2->id, $course->id);
    1747          $this->assertEquals([
    1748              role_get_name($studentrole, $coursecontext),
    1749          ], array_map('strip_tags', explode(', ', $roles)));
    1750  
    1751          $roles = get_user_roles_in_course($user3->id, $course->id);
    1752          $this->assertEmpty($roles);
    1753  
    1754          // Managers should be able to see a link to their own role type, given they can assign it in the context.
    1755          $this->setUser($user4);
    1756          $roles = get_user_roles_in_course($user4->id, $course->id);
    1757          $this->assertEquals([
    1758              role_get_name($managerrole, $coursecontext),
    1759          ], array_map('strip_tags', explode(', ', $roles)));
    1760  
    1761          // Managers should see 2 roles if viewing a user who has been enrolled as a student and a teacher in the course.
    1762          $roles = get_user_roles_in_course($user1->id, $course->id);
    1763          $this->assertEquals([
    1764              role_get_name($teacherrole, $coursecontext),
    1765              role_get_name($studentrole, $coursecontext),
    1766          ], array_map('strip_tags', explode(', ', $roles)));
    1767  
    1768          // Students should not see the manager role if viewing a manager's profile.
    1769          $this->setUser($user2);
    1770          $roles = get_user_roles_in_course($user4->id, $course->id);
    1771          $this->assertEmpty($roles); // Should see 0 roles on the manager's profile.
    1772      }
    1773  
    1774      /**
    1775       * Test get_user_roles and get_users_roles
    1776       */
    1777      public function test_get_user_roles() {
    1778          global $DB, $CFG;
    1779  
    1780          $this->resetAfterTest();
    1781  
    1782          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1783          $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    1784          $course = $this->getDataGenerator()->create_course();
    1785          $coursecontext = context_course::instance($course->id);
    1786          $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
    1787          $DB->insert_record('role_names', $teacherrename);
    1788  
    1789          $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
    1790  
    1791          $user1 = $this->getDataGenerator()->create_user();
    1792          role_assign($teacherrole->id, $user1->id, $coursecontext->id);
    1793          role_assign($studentrole->id, $user1->id, $coursecontext->id);
    1794          $user2 = $this->getDataGenerator()->create_user();
    1795          role_assign($studentrole->id, $user2->id, $coursecontext->id);
    1796          $user3 = $this->getDataGenerator()->create_user();
    1797  
    1798          $u1roles = get_user_roles($coursecontext, $user1->id);
    1799  
    1800          $u2roles = get_user_roles($coursecontext, $user2->id);
    1801  
    1802          $allroles = get_users_roles($coursecontext, [], false);
    1803          $specificuserroles = get_users_roles($coursecontext, [$user1->id, $user2->id]);
    1804          $this->assertEquals($u1roles, $allroles[$user1->id]);
    1805          $this->assertEquals($u1roles, $specificuserroles[$user1->id]);
    1806          $this->assertEquals($u2roles, $allroles[$user2->id]);
    1807          $this->assertEquals($u2roles, $specificuserroles[$user2->id]);
    1808      }
    1809  
    1810      /**
    1811       * Test has_capability(), has_any_capability() and has_all_capabilities().
    1812       */
    1813      public function test_has_capability_and_friends() {
    1814          global $DB;
    1815  
    1816          $this->resetAfterTest();
    1817  
    1818          $course = $this->getDataGenerator()->create_course();
    1819          $coursecontext = context_course::instance($course->id);
    1820          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    1821          $teacher = $this->getDataGenerator()->create_user();
    1822          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1823          $admin = $DB->get_record('user', array('username'=>'admin'));
    1824  
    1825          // Note: Here are used default capabilities, the full test is in permission evaluation bellow,
    1826          // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user.
    1827  
    1828          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection')));
    1829          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse')));
    1830          $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse')));
    1831  
    1832          $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse');
    1833          $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse');
    1834  
    1835          $this->setUser(0);
    1836          $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext));
    1837          $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext));
    1838          $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
    1839          $this->assertFalse(has_any_capability($sca, $coursecontext));
    1840          $this->assertFalse(has_all_capabilities($sca, $coursecontext));
    1841  
    1842          $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher));
    1843          $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher));
    1844          $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher));
    1845          $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher));
    1846          $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher));
    1847          $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher));
    1848  
    1849          $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin));
    1850          $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin));
    1851          $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin));
    1852          $this->assertTrue(has_any_capability($sca, $coursecontext, $admin));
    1853          $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin));
    1854          $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin));
    1855  
    1856          $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false));
    1857          $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false));
    1858          $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false));
    1859          $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false));
    1860          $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false));
    1861          $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false));
    1862  
    1863          $this->setUser($teacher);
    1864          $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
    1865          $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
    1866          $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext));
    1867          $this->assertTrue(has_any_capability($sca, $coursecontext));
    1868          $this->assertTrue(has_all_capabilities($sc, $coursecontext));
    1869          $this->assertFalse(has_all_capabilities($sca, $coursecontext));
    1870  
    1871          $this->setAdminUser();
    1872          $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext));
    1873          $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext));
    1874          $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext));
    1875          $this->assertTrue(has_any_capability($sca, $coursecontext));
    1876          $this->assertTrue(has_all_capabilities($sc, $coursecontext));
    1877          $this->assertTrue(has_all_capabilities($sca, $coursecontext));
    1878  
    1879          $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0));
    1880          $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0));
    1881          $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0));
    1882          $this->assertFalse(has_any_capability($sca, $coursecontext, 0));
    1883          $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0));
    1884      }
    1885  
    1886      /**
    1887       * Test that assigning a fake cap does not return.
    1888       */
    1889      public function test_fake_capability() {
    1890          global $DB;
    1891  
    1892          $this->resetAfterTest();
    1893  
    1894          $course = $this->getDataGenerator()->create_course();
    1895          $coursecontext = context_course::instance($course->id);
    1896          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
    1897          $teacher = $this->getDataGenerator()->create_user();
    1898  
    1899          $fakecapname = 'moodle/fake:capability';
    1900  
    1901          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1902          $admin = $DB->get_record('user', array('username' => 'admin'));
    1903  
    1904          // Test a capability which does not exist.
    1905          // Note: Do not use assign_capability because it will not allow fake caps.
    1906          $DB->insert_record('role_capabilities', (object) [
    1907              'contextid' => $coursecontext->id,
    1908              'roleid' => $teacherrole->id,
    1909              'capability' => $fakecapname,
    1910              'permission' => CAP_ALLOW,
    1911              'timemodified' => time(),
    1912              'modifierid' => 0,
    1913          ]);
    1914  
    1915          // Check `has_capability`.
    1916          $this->assertFalse(has_capability($fakecapname, $coursecontext, $teacher));
    1917          $this->assertDebuggingCalled("Capability \"{$fakecapname}\" was not found! This has to be fixed in code.");
    1918          $this->assertFalse(has_capability($fakecapname, $coursecontext, $admin));
    1919          $this->assertDebuggingCalled("Capability \"{$fakecapname}\" was not found! This has to be fixed in code.");
    1920  
    1921          // Check `get_with_capability_sql` (with uses `get_with_capability_join`).
    1922          list($sql, $params) = get_with_capability_sql($coursecontext, $fakecapname);
    1923          $users = $DB->get_records_sql($sql, $params);
    1924  
    1925          $this->assertFalse(array_key_exists($teacher->id, $users));
    1926          $this->assertFalse(array_key_exists($admin->id, $users));
    1927  
    1928          // Check `get_users_by_capability`.
    1929          $users = get_users_by_capability($coursecontext, $fakecapname);
    1930  
    1931          $this->assertFalse(array_key_exists($teacher->id, $users));
    1932          $this->assertFalse(array_key_exists($admin->id, $users));
    1933      }
    1934  
    1935      /**
    1936       * Test that assigning a fake cap does not return.
    1937       */
    1938      public function test_fake_capability_assign() {
    1939          global $DB;
    1940  
    1941          $this->resetAfterTest();
    1942  
    1943          $course = $this->getDataGenerator()->create_course();
    1944          $coursecontext = context_course::instance($course->id);
    1945          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
    1946          $teacher = $this->getDataGenerator()->create_user();
    1947  
    1948          $capability = 'moodle/fake:capability';
    1949  
    1950          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1951          $admin = $DB->get_record('user', array('username' => 'admin'));
    1952  
    1953          $this->expectException('coding_exception');
    1954          $this->expectExceptionMessage("Capability '{$capability}' was not found! This has to be fixed in code.");
    1955          assign_capability($capability, CAP_ALLOW, $teacherrole->id, $coursecontext);
    1956      }
    1957  
    1958      /**
    1959       * Test that assigning a fake cap does not return.
    1960       */
    1961      public function test_fake_capability_unassign() {
    1962          global $DB;
    1963  
    1964          $this->resetAfterTest();
    1965  
    1966          $course = $this->getDataGenerator()->create_course();
    1967          $coursecontext = context_course::instance($course->id);
    1968          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
    1969          $teacher = $this->getDataGenerator()->create_user();
    1970  
    1971          $capability = 'moodle/fake:capability';
    1972  
    1973          role_assign($teacherrole->id, $teacher->id, $coursecontext);
    1974          $admin = $DB->get_record('user', array('username' => 'admin'));
    1975  
    1976          $this->expectException('coding_exception');
    1977          $this->expectExceptionMessage("Capability '{$capability}' was not found! This has to be fixed in code.");
    1978          unassign_capability($capability, CAP_ALLOW, $teacherrole->id, $coursecontext);
    1979      }
    1980  
    1981      /**
    1982       * Test that the caching in get_role_definitions() and get_role_definitions_uncached()
    1983       * works as intended.
    1984       */
    1985      public function test_role_definition_caching() {
    1986          global $DB;
    1987  
    1988          $this->resetAfterTest();
    1989  
    1990          // Get some role ids.
    1991          $authenticatedrole = $DB->get_record('role', array('shortname' => 'user'), '*', MUST_EXIST);
    1992          $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
    1993          $emptyroleid = create_role('No capabilities', 'empty', 'A role with no capabilties');
    1994          $course = $this->getDataGenerator()->create_course();
    1995          $coursecontext = context_course::instance($course->id);
    1996  
    1997          // Instantiate the cache instance, since that does DB queries (get_config)
    1998          // and we don't care about those.
    1999          cache::make('core', 'roledefs');
    2000  
    2001          // One database query is not necessarily one database read, it seems. Find out how many.
    2002          $startdbreads = $DB->perf_get_reads();
    2003          $rs = $DB->get_recordset('user');
    2004          $rs->close();
    2005          $readsperquery = $DB->perf_get_reads() - $startdbreads;
    2006  
    2007          // Now load some role definitions, and check when it queries the database.
    2008  
    2009          // Load the capabilities for two roles. Should be one query.
    2010          $startdbreads = $DB->perf_get_reads();
    2011          get_role_definitions([$authenticatedrole->id, $studentrole->id]);
    2012          $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
    2013  
    2014          // Load the capabilities for same two roles. Should not query the DB.
    2015          $startdbreads = $DB->perf_get_reads();
    2016          get_role_definitions([$authenticatedrole->id, $studentrole->id]);
    2017          $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
    2018  
    2019          // Include a third role. Should do one DB query.
    2020          $startdbreads = $DB->perf_get_reads();
    2021          get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]);
    2022          $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
    2023  
    2024          // Repeat call. No DB queries.
    2025          $startdbreads = $DB->perf_get_reads();
    2026          get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]);
    2027          $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
    2028  
    2029          // Alter a role.
    2030          role_change_permission($studentrole->id, $coursecontext, 'moodle/course:tag', CAP_ALLOW);
    2031  
    2032          // Should now know to do one query.
    2033          $startdbreads = $DB->perf_get_reads();
    2034          get_role_definitions([$authenticatedrole->id, $studentrole->id]);
    2035          $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
    2036  
    2037          // Now clear the in-memory cache, and verify that it does not query the DB.
    2038          // Cannot use accesslib_clear_all_caches_for_unit_testing since that also
    2039          // clears the MUC cache.
    2040          global $ACCESSLIB_PRIVATE;
    2041          $ACCESSLIB_PRIVATE->cacheroledefs = array();
    2042  
    2043          // Get all roles. Should not need the DB.
    2044          $startdbreads = $DB->perf_get_reads();
    2045          get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]);
    2046          $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads);
    2047      }
    2048  
    2049      /**
    2050       * Tests get_user_capability_course() which checks a capability across all courses.
    2051       */
    2052      public function test_get_user_capability_course() {
    2053          global $CFG, $USER;
    2054  
    2055          $this->resetAfterTest();
    2056  
    2057          $generator = $this->getDataGenerator();
    2058          $cap = 'moodle/course:view';
    2059  
    2060          // The structure being created here is this:
    2061          //
    2062          // All tests work with the single capability 'moodle/course:view'.
    2063          //
    2064          //             ROLE DEF/OVERRIDE                        ROLE ASSIGNS
    2065          //    Role:  Allow    Prohib    Empty   Def user      u1  u2  u3  u4   u5  u6  u7  u8
    2066          // System    ALLOW    PROHIBIT                            A   E   A+E
    2067          //   cat1                       ALLOW
    2068          //     C1                               (ALLOW)                            P
    2069          //     C2             ALLOW                                                    E   P
    2070          //     cat2                     PREVENT
    2071          //       C3                     ALLOW                                      E
    2072          //       C4
    2073          //   Misc.                                                             A
    2074          //     C5    PREVENT                                                       A
    2075          //     C6                       PROHIBIT
    2076          //
    2077          // Front-page and guest role stuff from the end of this test not included in the diagram.
    2078  
    2079          // Create a role which allows course:view and one that prohibits it, and one neither.
    2080          $allowroleid = $generator->create_role();
    2081          $prohibitroleid = $generator->create_role();
    2082          $emptyroleid = $generator->create_role();
    2083          $systemcontext = context_system::instance();
    2084          assign_capability($cap, CAP_ALLOW, $allowroleid, $systemcontext->id);
    2085          assign_capability($cap, CAP_PROHIBIT, $prohibitroleid, $systemcontext->id);
    2086  
    2087          // Create two categories (nested).
    2088          $cat1 = $generator->create_category();
    2089          $cat2 = $generator->create_category(['parent' => $cat1->id]);
    2090  
    2091          // Create six courses - two in cat1, two in cat2, and two in default category.
    2092          // Shortnames are used for a sorting test. Otherwise they are not significant.
    2093          $c1 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Z']);
    2094          $c2 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Y']);
    2095          $c3 = $generator->create_course(['category' => $cat2->id, 'shortname' => 'X']);
    2096          $c4 = $generator->create_course(['category' => $cat2->id]);
    2097          $c5 = $generator->create_course();
    2098          $c6 = $generator->create_course();
    2099  
    2100          // Category overrides: in cat 1, empty role is allowed; in cat 2, empty role is prevented.
    2101          assign_capability($cap, CAP_ALLOW, $emptyroleid,
    2102                  context_coursecat::instance($cat1->id)->id);
    2103          assign_capability($cap, CAP_PREVENT, $emptyroleid,
    2104                  context_coursecat::instance($cat2->id)->id);
    2105  
    2106          // Course overrides: in C5, allow role is prevented; in C6, empty role is prohibited; in
    2107          // C3, empty role is allowed.
    2108          assign_capability($cap, CAP_PREVENT, $allowroleid,
    2109                  context_course::instance($c5->id)->id);
    2110          assign_capability($cap, CAP_PROHIBIT, $emptyroleid,
    2111                  context_course::instance($c6->id)->id);
    2112          assign_capability($cap, CAP_ALLOW, $emptyroleid,
    2113                  context_course::instance($c3->id)->id);
    2114          assign_capability($cap, CAP_ALLOW, $prohibitroleid,
    2115                  context_course::instance($c2->id)->id);
    2116  
    2117          // User 1 has no roles except default user role.
    2118          $u1 = $generator->create_user();
    2119  
    2120          // It returns false (annoyingly) if there are no courses.
    2121          $this->assertFalse(get_user_capability_course($cap, $u1->id, true, '', 'id'));
    2122  
    2123          // Final override: in C1, default user role is allowed.
    2124          assign_capability($cap, CAP_ALLOW, $CFG->defaultuserroleid,
    2125                  context_course::instance($c1->id)->id);
    2126  
    2127          // Should now get C1 only.
    2128          $courses = get_user_capability_course($cap, $u1->id, true, '', 'id');
    2129          $this->assert_course_ids([$c1->id], $courses);
    2130  
    2131          // User 2 has allow role (system wide).
    2132          $u2 = $generator->create_user();
    2133          role_assign($allowroleid, $u2->id, $systemcontext->id);
    2134  
    2135          // Should get everything except C5.
    2136          $courses = get_user_capability_course($cap, $u2->id, true, '', 'id');
    2137          $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c6->id], $courses);
    2138  
    2139          // User 3 has empty role (system wide).
    2140          $u3 = $generator->create_user();
    2141          role_assign($emptyroleid, $u3->id, $systemcontext->id);
    2142  
    2143          // Should get cat 1 courses but not cat2, except C3.
    2144          $courses = get_user_capability_course($cap, $u3->id, true, '', 'id');
    2145          $this->assert_course_ids([$c1->id, $c2->id, $c3->id], $courses);
    2146  
    2147          // User 4 has allow and empty role (system wide).
    2148          $u4 = $generator->create_user();
    2149          role_assign($allowroleid, $u4->id, $systemcontext->id);
    2150          role_assign($emptyroleid, $u4->id, $systemcontext->id);
    2151  
    2152          // Should get everything except C5 and C6.
    2153          $courses = get_user_capability_course($cap, $u4->id, true, '', 'id');
    2154          $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id], $courses);
    2155  
    2156          // User 5 has allow role in default category only.
    2157          $u5 = $generator->create_user();
    2158          role_assign($allowroleid, $u5->id, context_coursecat::instance($c5->category)->id);
    2159  
    2160          // Should get C1 and the default category courses but not C5.
    2161          $courses = get_user_capability_course($cap, $u5->id, true, '', 'id');
    2162          $this->assert_course_ids([$c1->id, $c6->id], $courses);
    2163  
    2164          // User 6 has a bunch of course roles: prohibit role in C1, empty role in C3, allow role in
    2165          // C6.
    2166          $u6 = $generator->create_user();
    2167          role_assign($prohibitroleid, $u6->id, context_course::instance($c1->id)->id);
    2168          role_assign($emptyroleid, $u6->id, context_course::instance($c3->id)->id);
    2169          role_assign($allowroleid, $u6->id, context_course::instance($c5->id)->id);
    2170  
    2171          // Should get C3 only because the allow role is prevented in C5.
    2172          $courses = get_user_capability_course($cap, $u6->id, true, '', 'id');
    2173          $this->assert_course_ids([$c3->id], $courses);
    2174  
    2175          // User 7 has empty role in C2.
    2176          $u7 = $generator->create_user();
    2177          role_assign($emptyroleid, $u7->id, context_course::instance($c2->id)->id);
    2178  
    2179          // Should get C1 by the default user role override, and C2 by the cat1 level override.
    2180          $courses = get_user_capability_course($cap, $u7->id, true, '', 'id');
    2181          $this->assert_course_ids([$c1->id, $c2->id], $courses);
    2182  
    2183          // User 8 has prohibit role as system context, to verify that prohibits can't be overridden.
    2184          $u8 = $generator->create_user();
    2185          role_assign($prohibitroleid, $u8->id, context_course::instance($c2->id)->id);
    2186  
    2187          // Should get C1 by the default user role override, no other courses because the prohibit cannot be overridden.
    2188          $courses = get_user_capability_course($cap, $u8->id, true, '', 'id');
    2189          $this->assert_course_ids([$c1->id], $courses);
    2190  
    2191          // Admin user gets everything....
    2192          $courses = get_user_capability_course($cap, get_admin()->id, true, '', 'id');
    2193          $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c6->id],
    2194                  $courses);
    2195  
    2196          // Unless you turn off doanything, when it only has the things a user with no role does.
    2197          $courses = get_user_capability_course($cap, get_admin()->id, false, '', 'id');
    2198          $this->assert_course_ids([$c1->id], $courses);
    2199  
    2200          // Using u3 as an example, test the limit feature.
    2201          $courses = get_user_capability_course($cap, $u3->id, true, '', 'id', 2);
    2202          $this->assert_course_ids([$c1->id, $c2->id], $courses);
    2203  
    2204          // Check sorting.
    2205          $courses = get_user_capability_course($cap, $u3->id, true, '', 'shortname');
    2206          $this->assert_course_ids([$c3->id, $c2->id, $c1->id], $courses);
    2207  
    2208          // Check returned fields - default.
    2209          $courses = get_user_capability_course($cap, $u3->id, true, '', 'id');
    2210          $this->assertEquals((object)['id' => $c1->id], $courses[0]);
    2211  
    2212          // Add a selection of fields, including the context ones with special handling.
    2213          $courses = get_user_capability_course($cap, $u3->id, true, 'shortname, ctxlevel, ctxdepth, ctxinstance', 'id');
    2214          $this->assertEquals((object)['id' => $c1->id, 'shortname' => 'Z', 'ctxlevel' => 50,
    2215                  'ctxdepth' => 3, 'ctxinstance' => $c1->id], $courses[0]);
    2216  
    2217          // Test front page role - user 1 has no roles, but if we change the front page role
    2218          // definition so that it has our capability, then they should see the front page course.
    2219          // as well as C1.
    2220          assign_capability($cap, CAP_ALLOW, $CFG->defaultfrontpageroleid, $systemcontext->id);
    2221          $courses = get_user_capability_course($cap, $u1->id, true, '', 'id');
    2222          $this->assert_course_ids([SITEID, $c1->id], $courses);
    2223  
    2224          // Check that temporary guest access (in this case, given on course 2 for user 1)
    2225          // also is included, if it has this capability.
    2226          assign_capability($cap, CAP_ALLOW, $CFG->guestroleid, $systemcontext->id);
    2227          $this->setUser($u1);
    2228          load_temp_course_role(context_course::instance($c2->id), $CFG->guestroleid);
    2229          $courses = get_user_capability_course($cap, $USER->id, true, '', 'id');
    2230          $this->assert_course_ids([SITEID, $c1->id, $c2->id], $courses);
    2231      }
    2232  
    2233      /**
    2234       * Extracts an array of course ids to make the above test script shorter.
    2235       *
    2236       * @param int[] $expected Array of expected course ids
    2237       * @param stdClass[] $courses Array of course objects
    2238       */
    2239      protected function assert_course_ids(array $expected, array $courses) {
    2240          $courseids = array_map(function($c) {
    2241              return $c->id;
    2242          }, $courses);
    2243          $this->assertEquals($expected, $courseids);
    2244      }
    2245  
    2246      /**
    2247       * Test if course creator future capability lookup works.
    2248       */
    2249      public function test_guess_if_creator_will_have_course_capability() {
    2250          global $DB, $CFG, $USER;
    2251  
    2252          $this->resetAfterTest();
    2253  
    2254          $category = $this->getDataGenerator()->create_category();
    2255          $course = $this->getDataGenerator()->create_course(array('category'=>$category->id));
    2256  
    2257          $syscontext = context_system::instance();
    2258          $categorycontext = context_coursecat::instance($category->id);
    2259          $coursecontext = context_course::instance($course->id);
    2260          $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
    2261          $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
    2262          $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST);
    2263          $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST);
    2264  
    2265          $this->assertEquals($teacherrole->id, $CFG->creatornewroleid);
    2266  
    2267          $creator = $this->getDataGenerator()->create_user();
    2268          $manager = $this->getDataGenerator()->create_user();
    2269          role_assign($managerrole->id, $manager->id, $categorycontext);
    2270  
    2271          $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator));
    2272          $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator));
    2273          $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator));
    2274          $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator));
    2275          $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator));
    2276          $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator));
    2277  
    2278          $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager));
    2279          $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager));
    2280          $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager));
    2281          $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id));
    2282          $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id));
    2283  
    2284          $this->assertEquals(0, $USER->id);
    2285          $this->assertFalse(has_capability('moodle/course:view', $categorycontext));
    2286          $this->assertFalse(has_capability('moodle/role:assign', $categorycontext));
    2287          $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext));
    2288          $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext));
    2289          $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
    2290          $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
    2291  
    2292          $this->setUser($manager);
    2293          $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
    2294          $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
    2295          $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
    2296          $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
    2297          $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
    2298  
    2299          $this->setAdminUser();
    2300          $this->assertTrue(has_capability('moodle/role:assign', $categorycontext));
    2301          $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext));
    2302          $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext));
    2303          $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext));
    2304          $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext));
    2305          $this->setUser(0);
    2306  
    2307          role_assign($creatorrole->id, $creator->