Search moodle.org's
Developer Documentation

Long Term Support Release

  • Bug fixes for general core bugs in 3.5.x ended May 2019 (12 months).
  • Bug fixes for security issues in 3.5.x will end 10 May 2021 (36 months) - Support has ended.
  • minimum PHP 7.0.0 Note: minimum PHP version has increased since Moodle 3.3. PHP 7.1.x and 7.2.x are supported too. PHP 7.x could have some engine limitations.
  • Differences Between: [Versions 35 and 310] [Versions 35 and 311] [Versions 35 and 36] [Versions 35 and 37] [Versions 35 and 38] [Versions 35 and 39]

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