Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]

   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   * A collection of tests for accesslib::has_capability().
  19   *
  20   * @package    core
  21   * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * Unit tests tests for has_capability.
  29   *
  30   * @package    core
  31   * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class accesslib_has_capability_testcase extends \advanced_testcase {
  35  
  36      /**
  37       * Unit tests to check the operation of locked contexts.
  38       *
  39       * Note: We only check the admin user here.
  40       * If the admin cannot do it, then no-one can.
  41       *
  42       * @dataProvider locked_context_provider
  43       * @param   string[]    $lockedcontexts The list of contexts, by name, to mark as locked
  44       * @param   string[]    $blocked The list of contexts which will be 'blocked' by has_capability
  45       */
  46      public function test_locked_contexts($lockedcontexts, $blocked) {
  47          global $DB;
  48  
  49          $this->resetAfterTest();
  50          set_config('contextlocking', 1);
  51  
  52          $generator = $this->getDataGenerator();
  53          $otheruser = $generator->create_user();
  54  
  55          // / (system)
  56          // /Cat1
  57          // /Cat1/Block
  58          // /Cat1/Course1
  59          // /Cat1/Course1/Block
  60          // /Cat1/Course2
  61          // /Cat1/Course2/Block
  62          // /Cat1/Cat1a
  63          // /Cat1/Cat1a/Block
  64          // /Cat1/Cat1a/Course1
  65          // /Cat1/Cat1a/Course1/Block
  66          // /Cat1/Cat1a/Course2
  67          // /Cat1/Cat1a/Course2/Block
  68          // /Cat1/Cat1b
  69          // /Cat1/Cat1b/Block
  70          // /Cat1/Cat1b/Course1
  71          // /Cat1/Cat1b/Course1/Block
  72          // /Cat1/Cat1b/Course2
  73          // /Cat1/Cat1b/Course2/Block
  74          // /Cat2
  75          // /Cat2/Block
  76          // /Cat2/Course1
  77          // /Cat2/Course1/Block
  78          // /Cat2/Course2
  79          // /Cat2/Course2/Block
  80          // /Cat2/Cat2a
  81          // /Cat2/Cat2a/Block
  82          // /Cat2/Cat2a/Course1
  83          // /Cat2/Cat2a/Course1/Block
  84          // /Cat2/Cat2a/Course2
  85          // /Cat2/Cat2a/Course2/Block
  86          // /Cat2/Cat2b
  87          // /Cat2/Cat2b/Block
  88          // /Cat2/Cat2b/Course1
  89          // /Cat2/Cat2b/Course1/Block
  90          // /Cat2/Cat2b/Course2
  91          // /Cat2/Cat2b/Course2/Block
  92  
  93          $adminuser = \core_user::get_user_by_username('admin');
  94          $contexts = (object) [
  95              'system' => \context_system::instance(),
  96              'adminuser' => \context_user::instance($adminuser->id),
  97          ];
  98  
  99          $cat1 = $generator->create_category();
 100          $cat1a = $generator->create_category(['parent' => $cat1->id]);
 101          $cat1b = $generator->create_category(['parent' => $cat1->id]);
 102  
 103          $contexts->cat1 = \context_coursecat::instance($cat1->id);
 104          $contexts->cat1a = \context_coursecat::instance($cat1a->id);
 105          $contexts->cat1b = \context_coursecat::instance($cat1b->id);
 106  
 107          $cat1course1 = $generator->create_course(['category' => $cat1->id]);
 108          $cat1course2 = $generator->create_course(['category' => $cat1->id]);
 109          $cat1acourse1 = $generator->create_course(['category' => $cat1a->id]);
 110          $cat1acourse2 = $generator->create_course(['category' => $cat1a->id]);
 111          $cat1bcourse1 = $generator->create_course(['category' => $cat1b->id]);
 112          $cat1bcourse2 = $generator->create_course(['category' => $cat1b->id]);
 113  
 114          $contexts->cat1course1 = \context_course::instance($cat1course1->id);
 115          $contexts->cat1acourse1 = \context_course::instance($cat1acourse1->id);
 116          $contexts->cat1bcourse1 = \context_course::instance($cat1bcourse1->id);
 117          $contexts->cat1course2 = \context_course::instance($cat1course2->id);
 118          $contexts->cat1acourse2 = \context_course::instance($cat1acourse2->id);
 119          $contexts->cat1bcourse2 = \context_course::instance($cat1bcourse2->id);
 120  
 121          $cat1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1->id]);
 122          $cat1ablock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1a->id]);
 123          $cat1bblock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1b->id]);
 124          $cat1course1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course1->id]);
 125          $cat1course2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course2->id]);
 126          $cat1acourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse1->id]);
 127          $cat1acourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse2->id]);
 128          $cat1bcourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse1->id]);
 129          $cat1bcourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse2->id]);
 130  
 131          $contexts->cat1block = \context_block::instance($cat1block->id);
 132          $contexts->cat1ablock = \context_block::instance($cat1ablock->id);
 133          $contexts->cat1bblock = \context_block::instance($cat1bblock->id);
 134          $contexts->cat1course1block = \context_block::instance($cat1course1block->id);
 135          $contexts->cat1course2block = \context_block::instance($cat1course2block->id);
 136          $contexts->cat1acourse1block = \context_block::instance($cat1acourse1block->id);
 137          $contexts->cat1acourse2block = \context_block::instance($cat1acourse2block->id);
 138          $contexts->cat1bcourse1block = \context_block::instance($cat1bcourse1block->id);
 139          $contexts->cat1bcourse2block = \context_block::instance($cat1bcourse2block->id);
 140  
 141          $writecapability = 'moodle/block:edit';
 142          $readcapability = 'moodle/block:view';
 143          $managecapability = 'moodle/site:managecontextlocks';
 144  
 145          $this->setAdminUser();
 146          $totest = (array) $contexts;
 147          foreach ($totest as $context) {
 148              $this->assertTrue(has_capability($writecapability, $context));
 149              $this->assertTrue(has_capability($readcapability, $context));
 150              $this->assertTrue(has_capability($managecapability, $context));
 151          }
 152  
 153          // Lock the specified contexts.
 154          foreach ($lockedcontexts as $contextname => $value) {
 155              $contexts->$contextname->set_locked($value);
 156          }
 157  
 158          // All read capabilities should remain.
 159          foreach ((array) $contexts as $context) {
 160              $this->assertTrue(has_capability($readcapability, $context));
 161              $this->assertTrue(has_capability($managecapability, $context));
 162          }
 163  
 164          // Check writes.
 165          foreach ((array) $contexts as $contextname => $context) {
 166              if (false !== array_search($contextname, $blocked)) {
 167                  $this->assertFalse(has_capability($writecapability, $context));
 168              } else {
 169                  $this->assertTrue(has_capability($writecapability, $context));
 170              }
 171          }
 172  
 173          $this->setUser($otheruser);
 174          // Check writes.
 175          foreach ((array) $contexts as $contextname => $context) {
 176              $this->assertFalse(has_capability($writecapability, $context));
 177          }
 178  
 179          // Disable the contextlocking experimental feature.
 180          set_config('contextlocking', 0);
 181  
 182          $this->setAdminUser();
 183          // All read capabilities should remain.
 184          foreach ((array) $contexts as $context) {
 185              $this->assertTrue(has_capability($readcapability, $context));
 186              $this->assertTrue(has_capability($managecapability, $context));
 187          }
 188  
 189          // All write capabilities should now be present again.
 190          foreach ((array) $contexts as $contextname => $context) {
 191              $this->assertTrue(has_capability($writecapability, $context));
 192          }
 193  
 194          $this->setUser($otheruser);
 195          // Check writes.
 196          foreach ((array) $contexts as $contextname => $context) {
 197              $this->assertFalse(has_capability($writecapability, $context));
 198          }
 199      }
 200  
 201      /**
 202       * Unit tests to check the operation of locked contexts.
 203       *
 204       * Note: We only check the admin user here.
 205       * If the admin cannot do it, then no-one can.
 206       *
 207       * @dataProvider locked_context_provider
 208       * @param   string[]    $lockedcontexts The list of contexts, by name, to mark as locked
 209       * @param   string[]    $blocked The list of contexts which will be 'blocked' by has_capability
 210       */
 211      public function test_locked_contexts_for_admin_with_config($lockedcontexts, $blocked) {
 212          global $DB;
 213  
 214          $this->resetAfterTest();
 215          set_config('contextlocking', 1);
 216          set_config('contextlockappliestoadmin', 0);
 217  
 218          $generator = $this->getDataGenerator();
 219          $otheruser = $generator->create_user();
 220  
 221          // / (system)
 222          // /Cat1
 223          // /Cat1/Block
 224          // /Cat1/Course1
 225          // /Cat1/Course1/Block
 226          // /Cat1/Course2
 227          // /Cat1/Course2/Block
 228          // /Cat1/Cat1a
 229          // /Cat1/Cat1a/Block
 230          // /Cat1/Cat1a/Course1
 231          // /Cat1/Cat1a/Course1/Block
 232          // /Cat1/Cat1a/Course2
 233          // /Cat1/Cat1a/Course2/Block
 234          // /Cat1/Cat1b
 235          // /Cat1/Cat1b/Block
 236          // /Cat1/Cat1b/Course1
 237          // /Cat1/Cat1b/Course1/Block
 238          // /Cat1/Cat1b/Course2
 239          // /Cat1/Cat1b/Course2/Block
 240          // /Cat2
 241          // /Cat2/Block
 242          // /Cat2/Course1
 243          // /Cat2/Course1/Block
 244          // /Cat2/Course2
 245          // /Cat2/Course2/Block
 246          // /Cat2/Cat2a
 247          // /Cat2/Cat2a/Block
 248          // /Cat2/Cat2a/Course1
 249          // /Cat2/Cat2a/Course1/Block
 250          // /Cat2/Cat2a/Course2
 251          // /Cat2/Cat2a/Course2/Block
 252          // /Cat2/Cat2b
 253          // /Cat2/Cat2b/Block
 254          // /Cat2/Cat2b/Course1
 255          // /Cat2/Cat2b/Course1/Block
 256          // /Cat2/Cat2b/Course2
 257          // /Cat2/Cat2b/Course2/Block
 258  
 259          $adminuser = \core_user::get_user_by_username('admin');
 260          $contexts = (object) [
 261              'system' => \context_system::instance(),
 262              'adminuser' => \context_user::instance($adminuser->id),
 263          ];
 264  
 265          $cat1 = $generator->create_category();
 266          $cat1a = $generator->create_category(['parent' => $cat1->id]);
 267          $cat1b = $generator->create_category(['parent' => $cat1->id]);
 268  
 269          $contexts->cat1 = \context_coursecat::instance($cat1->id);
 270          $contexts->cat1a = \context_coursecat::instance($cat1a->id);
 271          $contexts->cat1b = \context_coursecat::instance($cat1b->id);
 272  
 273          $cat1course1 = $generator->create_course(['category' => $cat1->id]);
 274          $cat1course2 = $generator->create_course(['category' => $cat1->id]);
 275          $cat1acourse1 = $generator->create_course(['category' => $cat1a->id]);
 276          $cat1acourse2 = $generator->create_course(['category' => $cat1a->id]);
 277          $cat1bcourse1 = $generator->create_course(['category' => $cat1b->id]);
 278          $cat1bcourse2 = $generator->create_course(['category' => $cat1b->id]);
 279  
 280          $contexts->cat1course1 = \context_course::instance($cat1course1->id);
 281          $contexts->cat1acourse1 = \context_course::instance($cat1acourse1->id);
 282          $contexts->cat1bcourse1 = \context_course::instance($cat1bcourse1->id);
 283          $contexts->cat1course2 = \context_course::instance($cat1course2->id);
 284          $contexts->cat1acourse2 = \context_course::instance($cat1acourse2->id);
 285          $contexts->cat1bcourse2 = \context_course::instance($cat1bcourse2->id);
 286  
 287          $cat1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1->id]);
 288          $cat1ablock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1a->id]);
 289          $cat1bblock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1b->id]);
 290          $cat1course1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course1->id]);
 291          $cat1course2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course2->id]);
 292          $cat1acourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse1->id]);
 293          $cat1acourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse2->id]);
 294          $cat1bcourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse1->id]);
 295          $cat1bcourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse2->id]);
 296  
 297          $contexts->cat1block = \context_block::instance($cat1block->id);
 298          $contexts->cat1ablock = \context_block::instance($cat1ablock->id);
 299          $contexts->cat1bblock = \context_block::instance($cat1bblock->id);
 300          $contexts->cat1course1block = \context_block::instance($cat1course1block->id);
 301          $contexts->cat1course2block = \context_block::instance($cat1course2block->id);
 302          $contexts->cat1acourse1block = \context_block::instance($cat1acourse1block->id);
 303          $contexts->cat1acourse2block = \context_block::instance($cat1acourse2block->id);
 304          $contexts->cat1bcourse1block = \context_block::instance($cat1bcourse1block->id);
 305          $contexts->cat1bcourse2block = \context_block::instance($cat1bcourse2block->id);
 306  
 307          $writecapability = 'moodle/block:edit';
 308          $readcapability = 'moodle/block:view';
 309          $managecapability = 'moodle/site:managecontextlocks';
 310  
 311          $this->setAdminUser();
 312          $totest = (array) $contexts;
 313          foreach ($totest as $context) {
 314              $this->assertTrue(has_capability($writecapability, $context));
 315              $this->assertTrue(has_capability($readcapability, $context));
 316              $this->assertTrue(has_capability($managecapability, $context));
 317          }
 318  
 319          // Lock the specified contexts.
 320          foreach ($lockedcontexts as $contextname => $value) {
 321              $contexts->$contextname->set_locked($value);
 322          }
 323  
 324          // All read capabilities should remain.
 325          foreach ((array) $contexts as $context) {
 326              $this->assertTrue(has_capability($readcapability, $context));
 327              $this->assertTrue(has_capability($managecapability, $context));
 328          }
 329  
 330          // Check writes.
 331          foreach ((array) $contexts as $contextname => $context) {
 332              $this->assertTrue(has_capability($writecapability, $context));
 333          }
 334  
 335          $this->setUser($otheruser);
 336          // Check writes.
 337          foreach ((array) $contexts as $contextname => $context) {
 338              $this->assertFalse(has_capability($writecapability, $context));
 339          }
 340  
 341          // Disable the contextlocking experimental feature.
 342          set_config('contextlocking', 0);
 343  
 344          $this->setAdminUser();
 345          // All read capabilities should remain.
 346          foreach ((array) $contexts as $context) {
 347              $this->assertTrue(has_capability($readcapability, $context));
 348              $this->assertTrue(has_capability($managecapability, $context));
 349          }
 350  
 351          // All write capabilities should now be present again.
 352          foreach ((array) $contexts as $contextname => $context) {
 353              $this->assertTrue(has_capability($writecapability, $context));
 354          }
 355  
 356          $this->setUser($otheruser);
 357          // Check writes.
 358          foreach ((array) $contexts as $contextname => $context) {
 359              $this->assertFalse(has_capability($writecapability, $context));
 360          }
 361      }
 362  
 363      /**
 364       * Data provider for testing that has_capability() deals with locked contexts.
 365       *
 366       * @return  array
 367       */
 368      public function locked_context_provider() {
 369          return [
 370              'All unlocked' => [
 371                  'locked' => [
 372                  ],
 373                  'blockedwrites' => [
 374                  ],
 375              ],
 376              'User is locked (yes, this is weird)' => [
 377                  'locked' => [
 378                      'adminuser' => true,
 379                  ],
 380                  'blockedwrites' => [
 381                      'adminuser',
 382                  ],
 383              ],
 384              'Cat1/Block locked' => [
 385                  'locked' => [
 386                      'cat1block' => true,
 387                  ],
 388                  'blockedwrites' => [
 389                      'cat1block',
 390                  ],
 391              ],
 392              'Cat1' => [
 393                  'locked' => [
 394                      'cat1' => true,
 395                  ],
 396                  'blockedwrites' => [
 397                      'cat1',
 398                      'cat1block',
 399                      'cat1a',
 400                      'cat1ablock',
 401                      'cat1b',
 402                      'cat1bblock',
 403                      'cat1course1',
 404                      'cat1course1block',
 405                      'cat1course2',
 406                      'cat1course2block',
 407                      'cat1acourse1',
 408                      'cat1acourse1block',
 409                      'cat1acourse2',
 410                      'cat1acourse2block',
 411                      'cat1bcourse1',
 412                      'cat1bcourse1block',
 413                      'cat1bcourse2',
 414                      'cat1bcourse2block',
 415                  ],
 416              ],
 417              'Cat1 locked and a child explicitly unlocked' => [
 418                  'locked' => [
 419                      'cat1' => true,
 420                      'cat1a' => false,
 421                  ],
 422                  'blockedwrites' => [
 423                      'cat1',
 424                      'cat1block',
 425                      'cat1a',
 426                      'cat1ablock',
 427                      'cat1b',
 428                      'cat1bblock',
 429                      'cat1course1',
 430                      'cat1course1block',
 431                      'cat1course2',
 432                      'cat1course2block',
 433                      'cat1acourse1',
 434                      'cat1acourse1block',
 435                      'cat1acourse2',
 436                      'cat1acourse2block',
 437                      'cat1bcourse1',
 438                      'cat1bcourse1block',
 439                      'cat1bcourse2',
 440                      'cat1bcourse2block',
 441                  ],
 442              ],
 443          ];
 444      }
 445  
 446      /**
 447       * Data provider for for has_capability tests when logged in as a different user.
 448       *
 449       * @return  array
 450       */
 451      public function login_as_provider(): array {
 452          return [
 453              [
 454                  'system',
 455                  [
 456                      'cat1course1block' => true,
 457                      'cat1course1' => true,
 458                      'cat1course2block' => true,
 459                      'cat1course2' => true,
 460                      'cat2course1block' => true,
 461                      'cat2course1' => true,
 462                      'cat2course2block' => true,
 463                      'cat2course2' => true,
 464                  ],
 465              ],
 466              [
 467                  'cat1',
 468                  [
 469                      'cat1course1block' => true,
 470                      'cat1course1' => true,
 471                      'cat1course2block' => true,
 472                      'cat1course2' => true,
 473  
 474                      'cat2course1block' => false,
 475                      'cat2course1' => false,
 476                      'cat2course2block' => false,
 477                      'cat2course2' => false,
 478                  ],
 479              ],
 480              [
 481                  'cat1course1',
 482                  [
 483                      'cat1course1block' => true,
 484                      'cat1course1' => true,
 485  
 486                      'cat1course2block' => false,
 487                      'cat1course2' => false,
 488                      'cat2course1block' => false,
 489                      'cat2course1' => false,
 490                      'cat2course2block' => false,
 491                      'cat2course2' => false,
 492                  ],
 493              ],
 494              [
 495                  'cat1course1block',
 496                  [
 497                      'cat1course1block' => true,
 498  
 499                      'cat1course1' => false,
 500                      'cat1course2block' => false,
 501                      'cat1course2' => false,
 502                      'cat2course1block' => false,
 503                      'cat2course1' => false,
 504                      'cat2course2block' => false,
 505                      'cat2course2' => false,
 506                  ],
 507              ],
 508          ];
 509      }
 510  
 511      /**
 512       * Test that the log in as functionality works as expected for an administrator.
 513       *
 514       * An administrator logged in as another user assumes all of their capabilities.
 515       *
 516       * @dataProvider    login_as_provider
 517       * @param   string $loginascontext
 518       * @param   string $testcontexts
 519       */
 520      public function test_login_as_admin(string $loginascontext, array $testcontexts): void {
 521          $this->resetAfterTest();
 522  
 523          $contexts = $this->get_test_data();
 524  
 525          $this->setAdminUser();
 526          $user = $this->getDataGenerator()->create_user();
 527  
 528          $testcontext = $contexts->$loginascontext;
 529          \core\session\manager::loginas($user->id, $testcontext);
 530  
 531          $capability = 'moodle/block:view';
 532          foreach ($testcontexts as $contextname => $hascapability) {
 533              $this->assertEquals($hascapability, has_capability($capability, $contexts->$contextname));
 534          }
 535      }
 536  
 537      /**
 538       * Test that the log in as functionality works as expected for a regulr user.
 539       *
 540       * @dataProvider    login_as_provider
 541       * @param   string $loginascontext
 542       * @param   string $testcontexts
 543       */
 544      public function test_login_as_user(string $loginascontext, array $testcontexts): void {
 545          $this->resetAfterTest();
 546  
 547          $contexts = $this->get_test_data();
 548  
 549          $initialuser = $this->getDataGenerator()->create_user();
 550          $user = $this->getDataGenerator()->create_user();
 551          $this->setUser($initialuser);
 552  
 553          $testcontext = $contexts->$loginascontext;
 554          \core\session\manager::loginas($user->id, $testcontext);
 555  
 556          $capability = 'moodle/block:view';
 557          foreach ($testcontexts as $contextname => $hascapability) {
 558              $this->assertEquals($hascapability, has_capability($capability, $contexts->$contextname));
 559          }
 560      }
 561  
 562      /**
 563       * Get the test data contexts.
 564       *
 565       * @return  stdClass
 566       */
 567      protected function get_test_data(): stdclass {
 568          $generator = $this->getDataGenerator();
 569          $otheruser = $generator->create_user();
 570  
 571          // / (system)
 572          // /Cat1
 573          // /Cat1/Block
 574          // /Cat1/Course1
 575          // /Cat1/Course1/Block
 576          // /Cat1/Course2
 577          // /Cat1/Course2/Block
 578          // /Cat1/Cat1a
 579          // /Cat1/Cat1a/Block
 580          // /Cat1/Cat1a/Course1
 581          // /Cat1/Cat1a/Course1/Block
 582          // /Cat1/Cat1a/Course2
 583          // /Cat1/Cat1a/Course2/Block
 584          // /Cat1/Cat1b
 585          // /Cat1/Cat1b/Block
 586          // /Cat1/Cat1b/Course1
 587          // /Cat1/Cat1b/Course1/Block
 588          // /Cat1/Cat1b/Course2
 589          // /Cat1/Cat1b/Course2/Block
 590          // /Cat2
 591          // /Cat2/Block
 592          // /Cat2/Course1
 593          // /Cat2/Course1/Block
 594          // /Cat2/Course2
 595          // /Cat2/Course2/Block
 596          // /Cat2/Cat2a
 597          // /Cat2/Cat2a/Block
 598          // /Cat2/Cat2a/Course1
 599          // /Cat2/Cat2a/Course1/Block
 600          // /Cat2/Cat2a/Course2
 601          // /Cat2/Cat2a/Course2/Block
 602          // /Cat2/Cat2b
 603          // /Cat2/Cat2b/Block
 604          // /Cat2/Cat2b/Course1
 605          // /Cat2/Cat2b/Course1/Block
 606          // /Cat2/Cat2b/Course2
 607          // /Cat2/Cat2b/Course2/Block
 608  
 609          $adminuser = \core_user::get_user_by_username('admin');
 610          $contexts = (object) [
 611              'system' => \context_system::instance(),
 612              'adminuser' => \context_user::instance($adminuser->id),
 613          ];
 614  
 615          $cat1 = $generator->create_category();
 616          $cat1a = $generator->create_category(['parent' => $cat1->id]);
 617          $cat1b = $generator->create_category(['parent' => $cat1->id]);
 618  
 619          $contexts->cat1 = \context_coursecat::instance($cat1->id);
 620          $contexts->cat1a = \context_coursecat::instance($cat1a->id);
 621          $contexts->cat1b = \context_coursecat::instance($cat1b->id);
 622  
 623          $cat1course1 = $generator->create_course(['category' => $cat1->id]);
 624          $cat1course2 = $generator->create_course(['category' => $cat1->id]);
 625          $cat1acourse1 = $generator->create_course(['category' => $cat1a->id]);
 626          $cat1acourse2 = $generator->create_course(['category' => $cat1a->id]);
 627          $cat1bcourse1 = $generator->create_course(['category' => $cat1b->id]);
 628          $cat1bcourse2 = $generator->create_course(['category' => $cat1b->id]);
 629  
 630          $contexts->cat1course1 = \context_course::instance($cat1course1->id);
 631          $contexts->cat1acourse1 = \context_course::instance($cat1acourse1->id);
 632          $contexts->cat1bcourse1 = \context_course::instance($cat1bcourse1->id);
 633          $contexts->cat1course2 = \context_course::instance($cat1course2->id);
 634          $contexts->cat1acourse2 = \context_course::instance($cat1acourse2->id);
 635          $contexts->cat1bcourse2 = \context_course::instance($cat1bcourse2->id);
 636  
 637          $cat1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1->id]);
 638          $cat1ablock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1a->id]);
 639          $cat1bblock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1b->id]);
 640          $cat1course1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course1->id]);
 641          $cat1course2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course2->id]);
 642          $cat1acourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse1->id]);
 643          $cat1acourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse2->id]);
 644          $cat1bcourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse1->id]);
 645          $cat1bcourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse2->id]);
 646  
 647          $contexts->cat1block = \context_block::instance($cat1block->id);
 648          $contexts->cat1ablock = \context_block::instance($cat1ablock->id);
 649          $contexts->cat1bblock = \context_block::instance($cat1bblock->id);
 650          $contexts->cat1course1block = \context_block::instance($cat1course1block->id);
 651          $contexts->cat1course2block = \context_block::instance($cat1course2block->id);
 652          $contexts->cat1acourse1block = \context_block::instance($cat1acourse1block->id);
 653          $contexts->cat1acourse2block = \context_block::instance($cat1acourse2block->id);
 654          $contexts->cat1bcourse1block = \context_block::instance($cat1bcourse1block->id);
 655          $contexts->cat1bcourse2block = \context_block::instance($cat1bcourse2block->id);
 656  
 657          $cat2 = $generator->create_category();
 658          $cat2a = $generator->create_category(['parent' => $cat2->id]);
 659          $cat2b = $generator->create_category(['parent' => $cat2->id]);
 660  
 661          $contexts->cat2 = \context_coursecat::instance($cat2->id);
 662          $contexts->cat2a = \context_coursecat::instance($cat2a->id);
 663          $contexts->cat2b = \context_coursecat::instance($cat2b->id);
 664  
 665          $cat2course1 = $generator->create_course(['category' => $cat2->id]);
 666          $cat2course2 = $generator->create_course(['category' => $cat2->id]);
 667          $cat2acourse1 = $generator->create_course(['category' => $cat2a->id]);
 668          $cat2acourse2 = $generator->create_course(['category' => $cat2a->id]);
 669          $cat2bcourse1 = $generator->create_course(['category' => $cat2b->id]);
 670          $cat2bcourse2 = $generator->create_course(['category' => $cat2b->id]);
 671  
 672          $contexts->cat2course1 = \context_course::instance($cat2course1->id);
 673          $contexts->cat2acourse1 = \context_course::instance($cat2acourse1->id);
 674          $contexts->cat2bcourse1 = \context_course::instance($cat2bcourse1->id);
 675          $contexts->cat2course2 = \context_course::instance($cat2course2->id);
 676          $contexts->cat2acourse2 = \context_course::instance($cat2acourse2->id);
 677          $contexts->cat2bcourse2 = \context_course::instance($cat2bcourse2->id);
 678  
 679          $cat2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2->id]);
 680          $cat2ablock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2a->id]);
 681          $cat2bblock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2b->id]);
 682          $cat2course1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2course1->id]);
 683          $cat2course2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2course2->id]);
 684          $cat2acourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2acourse1->id]);
 685          $cat2acourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2acourse2->id]);
 686          $cat2bcourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2bcourse1->id]);
 687          $cat2bcourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat2bcourse2->id]);
 688  
 689          $contexts->cat2block = \context_block::instance($cat2block->id);
 690          $contexts->cat2ablock = \context_block::instance($cat2ablock->id);
 691          $contexts->cat2bblock = \context_block::instance($cat2bblock->id);
 692          $contexts->cat2course1block = \context_block::instance($cat2course1block->id);
 693          $contexts->cat2course2block = \context_block::instance($cat2course2block->id);
 694          $contexts->cat2acourse1block = \context_block::instance($cat2acourse1block->id);
 695          $contexts->cat2acourse2block = \context_block::instance($cat2acourse2block->id);
 696          $contexts->cat2bcourse1block = \context_block::instance($cat2bcourse1block->id);
 697          $contexts->cat2bcourse2block = \context_block::instance($cat2bcourse2block->id);
 698  
 699          return $contexts;
 700      }
 701  }