Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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

   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   * Test for extensions manager.
  19   *
  20   * @package    core_contentbank
  21   * @category   test
  22   * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace core_contentbank;
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  
  30  use advanced_testcase;
  31  use context_course;
  32  use context_coursecat;
  33  use context_system;
  34  use Exception;
  35  
  36  global $CFG;
  37  require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
  38  require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
  39  
  40  /**
  41   * Test for extensions manager.
  42   *
  43   * @package    core_contentbank
  44   * @category   test
  45   * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
  46   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  47   * @coversDefaultClass \core_contentbank\contentbank
  48   */
  49  class core_contentbank_testcase extends advanced_testcase {
  50  
  51      /**
  52       * Setup to ensure that fixtures are loaded.
  53       */
  54      public static function setupBeforeClass(): void {
  55          global $CFG;
  56  
  57          require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
  58      }
  59  
  60      /**
  61       * Data provider for test_get_extension_supporter.
  62       *
  63       * @return  array
  64       */
  65      public function get_extension_provider() {
  66          return [
  67              'H5P file' => ['something.h5p', '.h5p'],
  68              'PDF file' => ['something.pdf', '.pdf']
  69          ];
  70      }
  71  
  72      /**
  73       * Tests for get_extension() function.
  74       *
  75       * @dataProvider    get_extension_provider
  76       * @param   string  $filename    The filename given
  77       * @param   string   $expected   The extension of the file
  78       *
  79       * @covers ::get_extension
  80       */
  81      public function test_get_extension(string $filename, string $expected) {
  82          $this->resetAfterTest();
  83  
  84          $cb = new contentbank();
  85  
  86          $extension = $cb->get_extension($filename);
  87          $this->assertEquals($expected, $extension);
  88      }
  89  
  90      /**
  91       * Data provider for test_load_context_supported_extensions.
  92       *
  93       * @return  array
  94       */
  95      public function get_extension_supporters_provider() {
  96          return [
  97              'H5P first' => [['.h5p' => ['h5p', 'testable']], '.h5p', 'h5p'],
  98              'Testable first (but upload not implemented)' => [['.h5p' => ['testable', 'h5p']], '.h5p', 'h5p'],
  99          ];
 100      }
 101  
 102      /**
 103       * Tests for get_extension_supporter() function with admin permissions.
 104       *
 105       * @dataProvider    get_extension_supporters_provider
 106       * @param   array   $supporters   The content type plugin supporters for each extension
 107       * @param   string  $extension    The extension of the file given
 108       * @param   string  $expected   The supporter contenttype of the file
 109       *
 110       * @covers ::load_context_supported_extensions
 111       */
 112      public function test_get_extension_supporter_for_admins(array $supporters, string $extension, string $expected) {
 113          $this->resetAfterTest();
 114  
 115          $cb = new contentbank();
 116  
 117          $systemcontext = context_system::instance();
 118  
 119          // All contexts allowed for admins.
 120          $this->setAdminUser();
 121          $contextsupporters = $cb->load_context_supported_extensions($systemcontext);
 122          $this->assertArrayHasKey($extension, $contextsupporters);
 123          $this->assertEquals($expected, $contextsupporters[$extension]);
 124      }
 125  
 126      /**
 127       * Tests for get_extension_supporter() function with user default permissions.
 128       *
 129       * @dataProvider    get_extension_supporters_provider
 130       * @param   array   $supporters   The content type plugin supporters for each extension
 131       * @param   string  $extension    The extension of the file given
 132       * @param   string  $expected   The supporter contenttype of the file
 133       *
 134       * @covers ::load_context_supported_extensions
 135       */
 136      public function test_get_extension_supporter_for_users(array $supporters, string $extension, string $expected) {
 137          $this->resetAfterTest();
 138  
 139          $cb = new contentbank();
 140          $systemcontext = context_system::instance();
 141  
 142          // Set a user with no permissions.
 143          $user = $this->getDataGenerator()->create_user();
 144          $this->setUser($user);
 145  
 146          // Users with no capabilities can't upload content.
 147          $contextsupporters = $cb->load_context_supported_extensions($systemcontext);
 148          $this->assertEquals([], $contextsupporters);
 149      }
 150  
 151      /**
 152       * Tests for get_extension_supporter() function with teacher defaul permissions.
 153       *
 154       * @dataProvider    get_extension_supporters_provider
 155       * @param   array   $supporters   The content type plugin supporters for each extension
 156       * @param   string  $extension    The extension of the file given
 157       * @param   string  $expected   The supporter contenttype of the file
 158       *
 159       * @covers ::load_context_supported_extensions
 160       */
 161      public function test_get_extension_supporter_for_teachers(array $supporters, string $extension, string $expected) {
 162          $this->resetAfterTest();
 163  
 164          $cb = new contentbank();
 165  
 166          $course = $this->getDataGenerator()->create_course();
 167          $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 168          $this->setUser($teacher);
 169          $coursecontext = context_course::instance($course->id);
 170  
 171          // Teachers has permission in their context to upload supported by H5P content type.
 172          $contextsupporters = $cb->load_context_supported_extensions($coursecontext);
 173          $this->assertArrayHasKey($extension, $contextsupporters);
 174          $this->assertEquals($expected, $contextsupporters[$extension]);
 175      }
 176  
 177      /**
 178       * Tests for get_extension_supporter() function.
 179       *
 180       * @dataProvider    get_extension_supporters_provider
 181       * @param   array   $supporters   The content type plugin supporters for each extension
 182       * @param   string  $extension    The extension of the file given
 183       * @param   string  $expected   The supporter contenttype of the file
 184       *
 185       * @covers ::get_extension_supporter
 186       */
 187      public function test_get_extension_supporter(array $supporters, string $extension, string $expected) {
 188          $this->resetAfterTest();
 189  
 190          $cb = new contentbank();
 191          $systemcontext = context_system::instance();
 192          $this->setAdminUser();
 193  
 194          $supporter = $cb->get_extension_supporter($extension, $systemcontext);
 195          $this->assertEquals($expected, $supporter);
 196      }
 197  
 198      /**
 199       * Test the behaviour of search_contents().
 200       *
 201       * @dataProvider search_contents_provider
 202       * @param  string $search String to search.
 203       * @param  string $where Context where to search.
 204       * @param  int $expectedresult Expected result.
 205       * @param  array $contexts List of contexts where to create content.
 206       */
 207      public function test_search_contents(?string $search, string $where, int $expectedresult, array $contexts = [],
 208              array $contenttypes = null): void {
 209          global $DB;
 210  
 211          $this->resetAfterTest();
 212  
 213          // Create users.
 214          $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
 215          $manager = $this->getDataGenerator()->create_user();
 216          $this->getDataGenerator()->role_assign($managerroleid, $manager->id);
 217  
 218          // Create a category and a course.
 219          $coursecat = $this->getDataGenerator()->create_category();
 220          $course = $this->getDataGenerator()->create_course();
 221          $existingcontexts = [];
 222          $existingcontexts['system'] = \context_system::instance();
 223          $existingcontexts['category'] = \context_coursecat::instance($coursecat->id);
 224          $existingcontexts['course'] = \context_course::instance($course->id);
 225  
 226          if (empty($where)) {
 227              $contextid = 0;
 228          } else {
 229              $contextid = $existingcontexts[$where]->id;
 230          }
 231  
 232          // Add some content to the content bank.
 233          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 234          foreach ($contexts as $context) {
 235              $contextinstance = $existingcontexts[$context];
 236              $records = $generator->generate_contentbank_data('contenttype_h5p', 3,
 237                  $manager->id, $contextinstance, false);
 238          }
 239  
 240          // Search for some content.
 241          $cb = new contentbank();
 242          $contents = $cb->search_contents($search, $contextid, $contenttypes);
 243  
 244          $this->assertCount($expectedresult, $contents);
 245          if (!empty($contents) && !empty($search)) {
 246              foreach ($contents as $content) {
 247                  $this->assertStringContainsString($search, $content->get_name());
 248              }
 249          }
 250      }
 251  
 252      /**
 253       * Data provider for test_search_contents().
 254       *
 255       * @return array
 256       */
 257      public function search_contents_provider(): array {
 258  
 259          return [
 260              'Search all content in all contexts' => [
 261                  null,
 262                  '',
 263                  9,
 264                  ['system', 'category', 'course']
 265              ],
 266              'Search in all contexts for existing string in all contents' => [
 267                  'content',
 268                  '',
 269                  9,
 270                  ['system', 'category', 'course']
 271              ],
 272              'Search in all contexts for unexisting string in all contents' => [
 273                  'chocolate',
 274                  '',
 275                  0,
 276                  ['system', 'category', 'course']
 277              ],
 278              'Search in all contexts for existing string in some contents' => [
 279                  '1',
 280                  '',
 281                  3,
 282                  ['system', 'category', 'course']
 283              ],
 284              'Search in all contexts for existing string in some contents (create only 1 context)' => [
 285                  '1',
 286                  '',
 287                  1,
 288                  ['system']
 289              ],
 290              'Search in system context for existing string in all contents' => [
 291                  'content',
 292                  'system',
 293                  3,
 294                  ['system', 'category', 'course']
 295              ],
 296              'Search in category context for unexisting string in all contents' => [
 297                  'chocolate',
 298                  'category',
 299                  0,
 300                  ['system', 'category', 'course']
 301              ],
 302              'Search in course context for existing string in some contents' => [
 303                  '1',
 304                  'course',
 305                  1,
 306                  ['system', 'category', 'course']
 307              ],
 308              'Search in system context' => [
 309                  null,
 310                  'system',
 311                  3,
 312                  ['system', 'category', 'course']
 313              ],
 314              'Search in course context with existing content' => [
 315                  null,
 316                  'course',
 317                  3,
 318                  ['system', 'category', 'course']
 319              ],
 320              'Search in course context without existing content' => [
 321                  null,
 322                  'course',
 323                  0,
 324                  ['system', 'category']
 325              ],
 326              'Search in an empty contentbank' => [
 327                  null,
 328                  '',
 329                  0,
 330                  []
 331              ],
 332              'Search in a context in an empty contentbank' => [
 333                  null,
 334                  'system',
 335                  0,
 336                  []
 337              ],
 338              'Search for a string in an empty contentbank' => [
 339                  'content',
 340                  '',
 341                  0,
 342                  []
 343              ],
 344              'Search with unexisting content-type' => [
 345                  null,
 346                  'course',
 347                  0,
 348                  ['system', 'category', 'course'],
 349                  ['contenttype_unexisting'],
 350              ],
 351          ];
 352      }
 353  
 354      /**
 355       * Test create_content_from_file function.
 356       *
 357       * @covers ::create_content_from_file
 358       */
 359      public function test_create_content_from_file() {
 360          global $USER;
 361  
 362          $this->resetAfterTest();
 363          $this->setAdminUser();
 364          $systemcontext = \context_system::instance();
 365          $name = 'dummy_h5p.h5p';
 366  
 367          // Create a dummy H5P file.
 368          $dummyh5p = array(
 369              'contextid' => $systemcontext->id,
 370              'component' => 'contentbank',
 371              'filearea' => 'public',
 372              'itemid' => 1,
 373              'filepath' => '/',
 374              'filename' => $name,
 375              'userid' => $USER->id
 376          );
 377          $fs = get_file_storage();
 378          $dummyh5pfile = $fs->create_file_from_string($dummyh5p, 'Dummy H5Pcontent');
 379  
 380          $cb = new contentbank();
 381          $content = $cb->create_content_from_file($systemcontext, $USER->id, $dummyh5pfile);
 382  
 383          $this->assertEquals('contenttype_h5p', $content->get_content_type());
 384          $this->assertInstanceOf('\\contenttype_h5p\\content', $content);
 385          $this->assertEquals($name, $content->get_name());
 386      }
 387  
 388      /**
 389       * Test the behaviour of delete_contents().
 390       *
 391       * @covers  ::delete_contents
 392       */
 393      public function test_delete_contents() {
 394          global $DB;
 395  
 396          $this->resetAfterTest();
 397          $cb = new \core_contentbank\contentbank();
 398  
 399          // Create a category and two courses.
 400          $systemcontext = context_system::instance();
 401          $coursecat = $this->getDataGenerator()->create_category();
 402          $coursecatcontext = context_coursecat::instance($coursecat->id);
 403          $course1 = $this->getDataGenerator()->create_course();
 404          $course1context = context_course::instance($course1->id);
 405          $course2 = $this->getDataGenerator()->create_course();
 406          $course2context = context_course::instance($course2->id);
 407  
 408          // Add some content to the content bank.
 409          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 410          $systemcontent = $generator->generate_contentbank_data(null, 3, 0, $systemcontext);
 411          $categorycontent = $generator->generate_contentbank_data(null, 3, 0, $coursecatcontext);
 412          $course1content = $generator->generate_contentbank_data(null, 3, 0, $course1context);
 413          $course2content = $generator->generate_contentbank_data(null, 3, 0, $course2context);
 414  
 415          // Check the content has been created as expected.
 416          $this->assertEquals(12, $DB->count_records('contentbank_content'));
 417  
 418          // Check the system content is deleted as expected and the rest of the content is not.
 419          $this->assertTrue($cb->delete_contents($systemcontext));
 420          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id]));
 421          // And the rest of the context content exists.
 422          $this->assertEquals(9, $DB->count_records('contentbank_content'));
 423  
 424          // Check the course category content is deleted as expected and the rest of the content is not.
 425          $this->assertTrue($cb->delete_contents($coursecatcontext));
 426          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $coursecatcontext->id]));
 427          // And the rest of the context content exists.
 428          $this->assertEquals(6, $DB->count_records('contentbank_content'));
 429  
 430          // Check the course content is deleted as expected and the rest of the content is not.
 431          $this->assertTrue($cb->delete_contents($course1context));
 432          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
 433          // And the rest of the context content exists.
 434          $this->assertEquals(3, $DB->count_records('contentbank_content'));
 435      }
 436  
 437      /**
 438       * Test the behaviour of delete_contents() for empty content bank.
 439       *
 440       * @covers  ::delete_contents
 441       */
 442      public function test_delete_contents_for_empty_contentbank() {
 443  
 444          $this->resetAfterTest();
 445          $cb = new \core_contentbank\contentbank();
 446  
 447          // Create a category and two courses.
 448          $systemcontext = \context_system::instance();
 449          $coursecat = $this->getDataGenerator()->create_category();
 450          $coursecatcontext = \context_coursecat::instance($coursecat->id);
 451          $course = $this->getDataGenerator()->create_course();
 452          $coursecontext = \context_course::instance($course->id);
 453  
 454          // Check there's no error when trying to delete content from an empty content bank.
 455          $this->assertTrue($cb->delete_contents($systemcontext));
 456          $this->assertTrue($cb->delete_contents($coursecatcontext));
 457          $this->assertTrue($cb->delete_contents($coursecontext));
 458      }
 459  
 460      /**
 461       * Test the behaviour of move_contents().
 462       *
 463       * @covers  ::move_contents
 464       */
 465      public function test_move_contents() {
 466          global $DB;
 467  
 468          $this->resetAfterTest();
 469          $cb = new \core_contentbank\contentbank();
 470  
 471          // Create a category and two courses.
 472          $course1 = $this->getDataGenerator()->create_course();
 473          $course1context = context_course::instance($course1->id);
 474          $course2 = $this->getDataGenerator()->create_course();
 475          $course2context = context_course::instance($course2->id);
 476  
 477          // Add some content to the content bank.
 478          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 479          $course1content = $generator->generate_contentbank_data(null, 3, 0, $course1context);
 480          $course2content = $generator->generate_contentbank_data(null, 3, 0, $course2context);
 481  
 482          // Check the content has been created as expected.
 483          $this->assertEquals(6, $DB->count_records('contentbank_content'));
 484          $this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
 485  
 486          // Check the content is moved to another context as expected and the rest of the content is not.
 487          $this->assertTrue($cb->move_contents($course1context, $course2context));
 488          $this->assertEquals(6, $DB->count_records('contentbank_content'));
 489          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
 490          $this->assertEquals(6, $DB->count_records('contentbank_content', ['contextid' => $course2context->id]));
 491      }
 492  
 493      /**
 494       * Test the behaviour of move_contents() for empty content bank.
 495       *
 496       * @covers  ::move_contents
 497       */
 498      public function test_move_contents_for_empty_contentbank() {
 499  
 500          $this->resetAfterTest();
 501          $cb = new \core_contentbank\contentbank();
 502  
 503          // Create a category and two courses.
 504          $systemcontext = \context_system::instance();
 505          $course = $this->getDataGenerator()->create_course();
 506          $coursecontext = \context_course::instance($course->id);
 507  
 508          // Check there's no error when trying to move content context from an empty content bank.
 509          $this->assertTrue($cb->delete_contents($systemcontext, $coursecontext));
 510      }
 511  
 512      /**
 513       * Data provider for get_contenttypes_with_capability_feature.
 514       *
 515       * @return  array
 516       */
 517      public function get_contenttypes_with_capability_feature_provider(): array {
 518          return [
 519              'no-contenttypes_enabled' => [
 520                  'contenttypesenabled' => [],
 521                  'contenttypescanfeature' => [],
 522              ],
 523              'contenttype_enabled_noeditable' => [
 524                  'contenttypesenabled' => ['testable'],
 525                  'contenttypescanfeature' => [],
 526              ],
 527              'contenttype_enabled_editable' => [
 528                  'contenttypesenabled' => ['testable'],
 529                  'contenttypescanfeature' => ['testable'],
 530              ],
 531              'no-contenttype_enabled_editable' => [
 532                  'contenttypesenabled' => [],
 533                  'contenttypescanfeature' => ['testable'],
 534              ],
 535          ];
 536      }
 537  
 538      /**
 539       * Tests for get_contenttypes_with_capability_feature() function.
 540       *
 541       * @dataProvider    get_contenttypes_with_capability_feature_provider
 542       * @param   array $contenttypesenabled Content types enabled.
 543       * @param   array $contenttypescanfeature Content types the user has the permission to use the feature.
 544       *
 545       * @covers ::get_contenttypes_with_capability_feature
 546       */
 547      public function test_get_contenttypes_with_capability_feature(array $contenttypesenabled, array $contenttypescanfeature): void {
 548          $this->resetAfterTest();
 549  
 550          $cb = new contentbank();
 551  
 552          $plugins = [];
 553  
 554          // Content types not enabled where the user has permission to use a feature.
 555          if (empty($contenttypesenabled) && !empty($contenttypescanfeature)) {
 556              $enabled = false;
 557  
 558              // Mock core_plugin_manager class and the method get_plugins_of_type.
 559              $pluginmanager = $this->getMockBuilder(\core_plugin_manager::class)
 560                  ->disableOriginalConstructor()
 561                  ->setMethods(['get_plugins_of_type'])
 562                  ->getMock();
 563  
 564              // Replace protected singletoninstance reference (core_plugin_manager property) with mock object.
 565              $ref = new \ReflectionProperty(\core_plugin_manager::class, 'singletoninstance');
 566              $ref->setAccessible(true);
 567              $ref->setValue(null, $pluginmanager);
 568  
 569              // Return values of get_plugins_of_type method.
 570              foreach ($contenttypescanfeature as $contenttypepluginname) {
 571                  $contenttypeplugin = new \stdClass();
 572                  $contenttypeplugin->name = $contenttypepluginname;
 573                  $contenttypeplugin->type = 'contenttype';
 574                  // Add the feature to the fake content type.
 575                  $classname = "\\contenttype_$contenttypepluginname\\contenttype";
 576                  $classname::$featurestotest = ['test2'];
 577                  $plugins[] = $contenttypeplugin;
 578              }
 579  
 580              // Set expectations and return values.
 581              $pluginmanager->expects($this->once())
 582                  ->method('get_plugins_of_type')
 583                  ->with('contenttype')
 584                  ->willReturn($plugins);
 585          } else {
 586              $enabled = true;
 587              // Get access to private property enabledcontenttypes.
 588              $rc = new \ReflectionClass(\core_contentbank\contentbank::class);
 589              $rcp = $rc->getProperty('enabledcontenttypes');
 590              $rcp->setAccessible(true);
 591  
 592              foreach ($contenttypesenabled as $contenttypename) {
 593                  $plugins["\\contenttype_$contenttypename\\contenttype"] = $contenttypename;
 594                  // Add to the testable contenttype the feature to test.
 595                  if (in_array($contenttypename, $contenttypescanfeature)) {
 596                      $classname = "\\contenttype_$contenttypename\\contenttype";
 597                      $classname::$featurestotest = ['test2'];
 598                  }
 599              }
 600              // Set as enabled content types only those in the test.
 601              $rcp->setValue($cb, $plugins);
 602          }
 603  
 604          $actual = $cb->get_contenttypes_with_capability_feature('test2', null, $enabled);
 605          $this->assertEquals($contenttypescanfeature, array_values($actual));
 606      }
 607  
 608      /**
 609       * Test the behaviour of get_content_from_id()
 610       *
 611       * @covers  ::get_content_from_id
 612       */
 613      public function test_get_content_from_id() {
 614  
 615          $this->resetAfterTest();
 616          $cb = new \core_contentbank\contentbank();
 617  
 618          // Create a category and two courses.
 619          $systemcontext = context_system::instance();
 620  
 621          // Add some content to the content bank.
 622          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 623          $contents = $generator->generate_contentbank_data(null, 3, 0, $systemcontext);
 624          $content = reset($contents);
 625  
 626          // Get the content instance form id.
 627          $newinstance = $cb->get_content_from_id($content->get_id());
 628          $this->assertEquals($content->get_id(), $newinstance->get_id());
 629  
 630          // Now produce and exception with an innexistent id.
 631          $this->expectException(Exception::class);
 632          $cb->get_content_from_id(0);
 633      }
 634  
 635      /**
 636       * Test the behaviour of is_context_allowed().
 637       *
 638       * @dataProvider context_provider
 639       * @param  \Closure $getcontext Get the context to check.
 640       * @param  bool $expectedresult Expected result.
 641       *
 642       * @covers ::is_context_allowed
 643       */
 644      public function test_is_context_allowed(\Closure $getcontext, bool $expectedresult): void {
 645          $this->resetAfterTest();
 646  
 647          $cb = new contentbank();
 648          $context = $getcontext();
 649          $this->assertEquals($expectedresult, $cb->is_context_allowed($context));
 650      }
 651  
 652      /**
 653       * Data provider for test_is_context_allowed().
 654       *
 655       * @return array
 656       */
 657      public function context_provider(): array {
 658  
 659          return [
 660              'System context' => [
 661                  function (): \context {
 662                      return \context_system::instance();
 663                  },
 664                  true,
 665              ],
 666              'User context' => [
 667                  function (): \context {
 668                      $user = $this->getDataGenerator()->create_user();
 669                      return \context_user::instance($user->id);
 670                  },
 671                  false,
 672              ],
 673              'Course category context' => [
 674                  function (): \context {
 675                      $coursecat = $this->getDataGenerator()->create_category();
 676                      return \context_coursecat::instance($coursecat->id);
 677                  },
 678                  true,
 679              ],
 680              'Course context' => [
 681                  function (): \context {
 682                      $course = $this->getDataGenerator()->create_course();
 683                      return \context_course::instance($course->id);
 684                  },
 685                  true,
 686              ],
 687              'Module context' => [
 688                  function (): \context {
 689                      $course = $this->getDataGenerator()->create_course();
 690                      $module = $this->getDataGenerator()->create_module('page', ['course' => $course->id]);
 691                      return \context_module::instance($module->cmid);
 692                  },
 693                  false,
 694              ],
 695              'Block context' => [
 696                  function (): \context {
 697                      $course = $this->getDataGenerator()->create_course();
 698                      $coursecontext = context_course::instance($course->id);
 699                      $block = $this->getDataGenerator()->create_block('online_users', ['parentcontextid' => $coursecontext->id]);
 700                      return \context_block::instance($block->id);
 701                  },
 702                  false,
 703              ],
 704          ];
 705      }
 706  }