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 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * 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 contentbank_test 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, $CFG;
 210  
 211          $this->resetAfterTest();
 212          $this->setAdminUser();
 213  
 214          // Create users.
 215          $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
 216          $manager = $this->getDataGenerator()->create_user();
 217          $this->getDataGenerator()->role_assign($managerroleid, $manager->id);
 218  
 219          // Create a category and a course.
 220          $coursecat = $this->getDataGenerator()->create_category();
 221          $course = $this->getDataGenerator()->create_course();
 222          $existingcontexts = [];
 223          $existingcontexts['system'] = \context_system::instance();
 224          $existingcontexts['category'] = \context_coursecat::instance($coursecat->id);
 225          $existingcontexts['course'] = \context_course::instance($course->id);
 226  
 227          if (empty($where)) {
 228              $contextid = 0;
 229          } else {
 230              $contextid = $existingcontexts[$where]->id;
 231          }
 232  
 233          // Add some content to the content bank.
 234          $filepath = $CFG->dirroot . '/h5p/tests/fixtures/filltheblanks.h5p';
 235          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 236          foreach ($contexts as $context) {
 237              $contextinstance = $existingcontexts[$context];
 238              $records = $generator->generate_contentbank_data('contenttype_h5p', 3,
 239                  $manager->id, $contextinstance, false, $filepath);
 240          }
 241  
 242          // Search for some content.
 243          $cb = new contentbank();
 244          $contents = $cb->search_contents($search, $contextid, $contenttypes);
 245  
 246          $this->assertCount($expectedresult, $contents);
 247          if (!empty($contents) && !empty($search)) {
 248              foreach ($contents as $content) {
 249                  $this->assertStringContainsString($search, $content->get_name());
 250              }
 251          }
 252      }
 253  
 254      /**
 255       * Data provider for test_search_contents().
 256       *
 257       * @return array
 258       */
 259      public function search_contents_provider(): array {
 260  
 261          return [
 262              'Search all content in all contexts' => [
 263                  null,
 264                  '',
 265                  9,
 266                  ['system', 'category', 'course']
 267              ],
 268              'Search in all contexts for existing string in all contents' => [
 269                  'content',
 270                  '',
 271                  9,
 272                  ['system', 'category', 'course']
 273              ],
 274              'Search in all contexts for unexisting string in all contents' => [
 275                  'chocolate',
 276                  '',
 277                  0,
 278                  ['system', 'category', 'course']
 279              ],
 280              'Search in all contexts for existing string in some contents' => [
 281                  '1',
 282                  '',
 283                  3,
 284                  ['system', 'category', 'course']
 285              ],
 286              'Search in all contexts for existing string in some contents (create only 1 context)' => [
 287                  '1',
 288                  '',
 289                  1,
 290                  ['system']
 291              ],
 292              'Search in system context for existing string in all contents' => [
 293                  'content',
 294                  'system',
 295                  3,
 296                  ['system', 'category', 'course']
 297              ],
 298              'Search in category context for unexisting string in all contents' => [
 299                  'chocolate',
 300                  'category',
 301                  0,
 302                  ['system', 'category', 'course']
 303              ],
 304              'Search in course context for existing string in some contents' => [
 305                  '1',
 306                  'course',
 307                  1,
 308                  ['system', 'category', 'course']
 309              ],
 310              'Search in system context' => [
 311                  null,
 312                  'system',
 313                  3,
 314                  ['system', 'category', 'course']
 315              ],
 316              'Search in course context with existing content' => [
 317                  null,
 318                  'course',
 319                  3,
 320                  ['system', 'category', 'course']
 321              ],
 322              'Search in course context without existing content' => [
 323                  null,
 324                  'course',
 325                  0,
 326                  ['system', 'category']
 327              ],
 328              'Search in an empty contentbank' => [
 329                  null,
 330                  '',
 331                  0,
 332                  []
 333              ],
 334              'Search in a context in an empty contentbank' => [
 335                  null,
 336                  'system',
 337                  0,
 338                  []
 339              ],
 340              'Search for a string in an empty contentbank' => [
 341                  'content',
 342                  '',
 343                  0,
 344                  []
 345              ],
 346              'Search with unexisting content-type' => [
 347                  null,
 348                  'course',
 349                  0,
 350                  ['system', 'category', 'course'],
 351                  ['contenttype_unexisting'],
 352              ],
 353          ];
 354      }
 355  
 356      /**
 357       * Test create_content_from_file function.
 358       *
 359       * @covers ::create_content_from_file
 360       */
 361      public function test_create_content_from_file() {
 362          global $USER, $CFG;
 363  
 364          $this->resetAfterTest();
 365          $this->setAdminUser();
 366          $systemcontext = \context_system::instance();
 367          $name = 'greeting-card-887.h5p';
 368  
 369          // Create a dummy H5P file.
 370          $dummyh5p = array(
 371              'contextid' => $systemcontext->id,
 372              'component' => 'contentbank',
 373              'filearea' => 'public',
 374              'itemid' => 1,
 375              'filepath' => '/',
 376              'filename' => $name,
 377              'userid' => $USER->id
 378          );
 379          $path = $CFG->dirroot . '/h5p/tests/fixtures/' . $name;
 380          $dummyh5pfile = \core_h5p\helper::create_fake_stored_file_from_path($path);
 381  
 382          $cb = new contentbank();
 383          $content = $cb->create_content_from_file($systemcontext, $USER->id, $dummyh5pfile);
 384  
 385          $this->assertEquals('contenttype_h5p', $content->get_content_type());
 386          $this->assertInstanceOf('\\contenttype_h5p\\content', $content);
 387          $this->assertEquals($name, $content->get_name());
 388      }
 389  
 390      /**
 391       * Test the behaviour of delete_contents().
 392       *
 393       * @covers  ::delete_contents
 394       */
 395      public function test_delete_contents() {
 396          global $DB;
 397  
 398          $this->resetAfterTest();
 399          $cb = new \core_contentbank\contentbank();
 400  
 401          // Create a category and two courses.
 402          $systemcontext = context_system::instance();
 403          $coursecat = $this->getDataGenerator()->create_category();
 404          $coursecatcontext = context_coursecat::instance($coursecat->id);
 405          $course1 = $this->getDataGenerator()->create_course();
 406          $course1context = context_course::instance($course1->id);
 407          $course2 = $this->getDataGenerator()->create_course();
 408          $course2context = context_course::instance($course2->id);
 409  
 410          // Add some content to the content bank.
 411          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 412          $systemcontent = $generator->generate_contentbank_data(null, 3, 0, $systemcontext);
 413          $categorycontent = $generator->generate_contentbank_data(null, 3, 0, $coursecatcontext);
 414          $course1content = $generator->generate_contentbank_data(null, 3, 0, $course1context);
 415          $course2content = $generator->generate_contentbank_data(null, 3, 0, $course2context);
 416  
 417          // Check the content has been created as expected.
 418          $this->assertEquals(12, $DB->count_records('contentbank_content'));
 419  
 420          // Check the system content is deleted as expected and the rest of the content is not.
 421          $this->assertTrue($cb->delete_contents($systemcontext));
 422          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id]));
 423          // And the rest of the context content exists.
 424          $this->assertEquals(9, $DB->count_records('contentbank_content'));
 425  
 426          // Check the course category content is deleted as expected and the rest of the content is not.
 427          $this->assertTrue($cb->delete_contents($coursecatcontext));
 428          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $coursecatcontext->id]));
 429          // And the rest of the context content exists.
 430          $this->assertEquals(6, $DB->count_records('contentbank_content'));
 431  
 432          // Check the course content is deleted as expected and the rest of the content is not.
 433          $this->assertTrue($cb->delete_contents($course1context));
 434          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
 435          // And the rest of the context content exists.
 436          $this->assertEquals(3, $DB->count_records('contentbank_content'));
 437      }
 438  
 439      /**
 440       * Test the behaviour of delete_contents() for empty content bank.
 441       *
 442       * @covers  ::delete_contents
 443       */
 444      public function test_delete_contents_for_empty_contentbank() {
 445  
 446          $this->resetAfterTest();
 447          $cb = new \core_contentbank\contentbank();
 448  
 449          // Create a category and two courses.
 450          $systemcontext = \context_system::instance();
 451          $coursecat = $this->getDataGenerator()->create_category();
 452          $coursecatcontext = \context_coursecat::instance($coursecat->id);
 453          $course = $this->getDataGenerator()->create_course();
 454          $coursecontext = \context_course::instance($course->id);
 455  
 456          // Check there's no error when trying to delete content from an empty content bank.
 457          $this->assertTrue($cb->delete_contents($systemcontext));
 458          $this->assertTrue($cb->delete_contents($coursecatcontext));
 459          $this->assertTrue($cb->delete_contents($coursecontext));
 460      }
 461  
 462      /**
 463       * Test the behaviour of move_contents().
 464       *
 465       * @covers  ::move_contents
 466       */
 467      public function test_move_contents() {
 468          global $DB;
 469  
 470          $this->resetAfterTest();
 471          $cb = new \core_contentbank\contentbank();
 472  
 473          // Create a category and two courses.
 474          $course1 = $this->getDataGenerator()->create_course();
 475          $course1context = context_course::instance($course1->id);
 476          $course2 = $this->getDataGenerator()->create_course();
 477          $course2context = context_course::instance($course2->id);
 478  
 479          // Add some content to the content bank.
 480          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 481          $course1content = $generator->generate_contentbank_data(null, 3, 0, $course1context);
 482          $course2content = $generator->generate_contentbank_data(null, 3, 0, $course2context);
 483  
 484          // Check the content has been created as expected.
 485          $this->assertEquals(6, $DB->count_records('contentbank_content'));
 486          $this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
 487  
 488          // Check the content is moved to another context as expected and the rest of the content is not.
 489          $this->assertTrue($cb->move_contents($course1context, $course2context));
 490          $this->assertEquals(6, $DB->count_records('contentbank_content'));
 491          $this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
 492          $this->assertEquals(6, $DB->count_records('contentbank_content', ['contextid' => $course2context->id]));
 493      }
 494  
 495      /**
 496       * Test the behaviour of move_contents() for empty content bank.
 497       *
 498       * @covers  ::move_contents
 499       */
 500      public function test_move_contents_for_empty_contentbank() {
 501  
 502          $this->resetAfterTest();
 503          $cb = new \core_contentbank\contentbank();
 504  
 505          // Create a category and two courses.
 506          $systemcontext = \context_system::instance();
 507          $course = $this->getDataGenerator()->create_course();
 508          $coursecontext = \context_course::instance($course->id);
 509  
 510          // Check there's no error when trying to move content context from an empty content bank.
 511          $this->assertTrue($cb->delete_contents($systemcontext, $coursecontext));
 512      }
 513  
 514      /**
 515       * Data provider for get_contenttypes_with_capability_feature.
 516       *
 517       * @return  array
 518       */
 519      public function get_contenttypes_with_capability_feature_provider(): array {
 520          return [
 521              'no-contenttypes_enabled' => [
 522                  'contenttypesenabled' => [],
 523                  'contenttypescanfeature' => [],
 524              ],
 525              'contenttype_enabled_noeditable' => [
 526                  'contenttypesenabled' => ['testable'],
 527                  'contenttypescanfeature' => [],
 528              ],
 529              'contenttype_enabled_editable' => [
 530                  'contenttypesenabled' => ['testable'],
 531                  'contenttypescanfeature' => ['testable'],
 532              ],
 533              'no-contenttype_enabled_editable' => [
 534                  'contenttypesenabled' => [],
 535                  'contenttypescanfeature' => ['testable'],
 536              ],
 537          ];
 538      }
 539  
 540      /**
 541       * Tests for get_contenttypes_with_capability_feature() function.
 542       *
 543       * @dataProvider    get_contenttypes_with_capability_feature_provider
 544       * @param   array $contenttypesenabled Content types enabled.
 545       * @param   array $contenttypescanfeature Content types the user has the permission to use the feature.
 546       *
 547       * @covers ::get_contenttypes_with_capability_feature
 548       */
 549      public function test_get_contenttypes_with_capability_feature(array $contenttypesenabled, array $contenttypescanfeature): void {
 550          $this->resetAfterTest();
 551  
 552          $cb = new contentbank();
 553  
 554          $plugins = [];
 555  
 556          // Content types not enabled where the user has permission to use a feature.
 557          if (empty($contenttypesenabled) && !empty($contenttypescanfeature)) {
 558              $enabled = false;
 559  
 560              // Mock core_plugin_manager class and the method get_plugins_of_type.
 561              $pluginmanager = $this->getMockBuilder(\core_plugin_manager::class)
 562                  ->disableOriginalConstructor()
 563                  ->onlyMethods(['get_plugins_of_type'])
 564                  ->getMock();
 565  
 566              // Replace protected singletoninstance reference (core_plugin_manager property) with mock object.
 567              $ref = new \ReflectionProperty(\core_plugin_manager::class, 'singletoninstance');
 568              $ref->setAccessible(true);
 569              $ref->setValue(null, $pluginmanager);
 570  
 571              // Return values of get_plugins_of_type method.
 572              foreach ($contenttypescanfeature as $contenttypepluginname) {
 573                  $contenttypeplugin = new \stdClass();
 574                  $contenttypeplugin->name = $contenttypepluginname;
 575                  $contenttypeplugin->type = 'contenttype';
 576                  // Add the feature to the fake content type.
 577                  $classname = "\\contenttype_$contenttypepluginname\\contenttype";
 578                  $classname::$featurestotest = ['test2'];
 579                  $plugins[] = $contenttypeplugin;
 580              }
 581  
 582              // Set expectations and return values.
 583              $pluginmanager->expects($this->once())
 584                  ->method('get_plugins_of_type')
 585                  ->with('contenttype')
 586                  ->willReturn($plugins);
 587          } else {
 588              $enabled = true;
 589              // Get access to private property enabledcontenttypes.
 590              $rc = new \ReflectionClass(\core_contentbank\contentbank::class);
 591              $rcp = $rc->getProperty('enabledcontenttypes');
 592              $rcp->setAccessible(true);
 593  
 594              foreach ($contenttypesenabled as $contenttypename) {
 595                  $plugins["\\contenttype_$contenttypename\\contenttype"] = $contenttypename;
 596                  // Add to the testable contenttype the feature to test.
 597                  if (in_array($contenttypename, $contenttypescanfeature)) {
 598                      $classname = "\\contenttype_$contenttypename\\contenttype";
 599                      $classname::$featurestotest = ['test2'];
 600                  }
 601              }
 602              // Set as enabled content types only those in the test.
 603              $rcp->setValue($cb, $plugins);
 604          }
 605  
 606          $actual = $cb->get_contenttypes_with_capability_feature('test2', null, $enabled);
 607          $this->assertEquals($contenttypescanfeature, array_values($actual));
 608      }
 609  
 610      /**
 611       * Test the behaviour of get_content_from_id()
 612       *
 613       * @covers  ::get_content_from_id
 614       */
 615      public function test_get_content_from_id() {
 616  
 617          $this->resetAfterTest();
 618          $cb = new \core_contentbank\contentbank();
 619  
 620          // Create a category and two courses.
 621          $systemcontext = context_system::instance();
 622  
 623          // Add some content to the content bank.
 624          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 625          $contents = $generator->generate_contentbank_data(null, 3, 0, $systemcontext);
 626          $content = reset($contents);
 627  
 628          // Get the content instance form id.
 629          $newinstance = $cb->get_content_from_id($content->get_id());
 630          $this->assertEquals($content->get_id(), $newinstance->get_id());
 631  
 632          // Now produce and exception with an innexistent id.
 633          $this->expectException(Exception::class);
 634          $cb->get_content_from_id(0);
 635      }
 636  
 637      /**
 638       * Test the behaviour of is_context_allowed().
 639       *
 640       * @dataProvider context_provider
 641       * @param  \Closure $getcontext Get the context to check.
 642       * @param  bool $expectedresult Expected result.
 643       *
 644       * @covers ::is_context_allowed
 645       */
 646      public function test_is_context_allowed(\Closure $getcontext, bool $expectedresult): void {
 647          $this->resetAfterTest();
 648  
 649          $cb = new contentbank();
 650          $context = $getcontext();
 651          $this->assertEquals($expectedresult, $cb->is_context_allowed($context));
 652      }
 653  
 654      /**
 655       * Data provider for test_is_context_allowed().
 656       *
 657       * @return array
 658       */
 659      public function context_provider(): array {
 660  
 661          return [
 662              'System context' => [
 663                  function (): \context {
 664                      return \context_system::instance();
 665                  },
 666                  true,
 667              ],
 668              'User context' => [
 669                  function (): \context {
 670                      $user = $this->getDataGenerator()->create_user();
 671                      return \context_user::instance($user->id);
 672                  },
 673                  false,
 674              ],
 675              'Course category context' => [
 676                  function (): \context {
 677                      $coursecat = $this->getDataGenerator()->create_category();
 678                      return \context_coursecat::instance($coursecat->id);
 679                  },
 680                  true,
 681              ],
 682              'Course context' => [
 683                  function (): \context {
 684                      $course = $this->getDataGenerator()->create_course();
 685                      return \context_course::instance($course->id);
 686                  },
 687                  true,
 688              ],
 689              'Module context' => [
 690                  function (): \context {
 691                      $course = $this->getDataGenerator()->create_course();
 692                      $module = $this->getDataGenerator()->create_module('page', ['course' => $course->id]);
 693                      return \context_module::instance($module->cmid);
 694                  },
 695                  false,
 696              ],
 697              'Block context' => [
 698                  function (): \context {
 699                      $course = $this->getDataGenerator()->create_course();
 700                      $coursecontext = context_course::instance($course->id);
 701                      $block = $this->getDataGenerator()->create_block('online_users', ['parentcontextid' => $coursecontext->id]);
 702                      return \context_block::instance($block->id);
 703                  },
 704                  false,
 705              ],
 706          ];
 707      }
 708  }