Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 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 namespace core_contentbank; 18 19 use stdClass; 20 use context_system; 21 use context_user; 22 use Exception; 23 use contenttype_testable\contenttype as contenttype; 24 /** 25 * Test for content bank contenttype class. 26 * 27 * @package core_contentbank 28 * @category test 29 * @copyright 2020 Amaia Anabitarte <amaia@moodle.com> 30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 * @coversDefaultClass \core_contentbank\contenttype 32 * 33 */ 34 class contenttype_test extends \advanced_testcase { 35 36 /** @var int Identifier for the manager role. */ 37 protected $managerroleid; 38 39 /** @var stdClass Manager user. */ 40 protected $manager1; 41 42 /** @var stdClass Manager user. */ 43 protected $manager2; 44 45 /** @var stdClass User. */ 46 protected $user; 47 48 /** @var array List of contents created (every user has a key with contents created by her). */ 49 protected $contents = []; 50 51 /** @var contenttype The contenttype instance. */ 52 protected $contenttype; 53 54 /** 55 * Setup to ensure that fixtures are loaded. 56 */ 57 public static function setupBeforeClass(): void { 58 global $CFG; 59 60 require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php'); 61 require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php'); 62 } 63 64 /** 65 * Tests get_contenttype_name result. 66 * 67 * @covers ::get_contenttype_name 68 */ 69 public function test_get_contenttype_name() { 70 $this->resetAfterTest(); 71 72 $systemcontext = \context_system::instance(); 73 $testable = new contenttype($systemcontext); 74 75 $this->assertEquals('contenttype_testable', $testable->get_contenttype_name()); 76 } 77 78 /** 79 * Tests get_plugin_name result. 80 * 81 * @covers ::get_plugin_name 82 */ 83 public function test_get_plugin_name() { 84 $this->resetAfterTest(); 85 86 $systemcontext = \context_system::instance(); 87 $testable = new contenttype($systemcontext); 88 89 $this->assertEquals('testable', $testable->get_plugin_name()); 90 } 91 92 /** 93 * Tests get_icon result. 94 * 95 * @covers ::get_icon 96 */ 97 public function test_get_icon() { 98 global $CFG; 99 100 $this->resetAfterTest(); 101 102 $systemcontext = \context_system::instance(); 103 $testable = new contenttype($systemcontext); 104 $record = new stdClass(); 105 $record->name = 'New content'; 106 $content = $testable->create_content($record); 107 $this->assertEquals( 108 "{$CFG->wwwroot}/theme/image.php/boost/core/1/f/unknown", 109 $testable->get_icon($content), 110 ); 111 } 112 113 /** 114 * Tests is_feature_supported behavior . 115 * 116 * @covers ::is_feature_supported 117 */ 118 public function test_is_feature_supported() { 119 $this->resetAfterTest(); 120 121 $systemcontext = \context_system::instance(); 122 $testable = new contenttype($systemcontext); 123 124 $this->assertTrue($testable->is_feature_supported(contenttype::CAN_TEST)); 125 $this->assertFalse($testable->is_feature_supported(contenttype::CAN_UPLOAD)); 126 } 127 128 /** 129 * Tests can_upload behavior with no implemented upload feature. 130 * 131 * @covers ::can_upload 132 */ 133 public function test_no_upload_feature_supported() { 134 $this->resetAfterTest(); 135 136 $systemcontext = \context_system::instance(); 137 $testable = new contenttype($systemcontext); 138 139 $this->setAdminUser(); 140 $this->assertFalse($testable->is_feature_supported(contenttype::CAN_UPLOAD)); 141 $this->assertFalse($testable->can_upload()); 142 } 143 144 /** 145 * Test create_content() with empty data. 146 * 147 * @covers ::create_content 148 */ 149 public function test_create_empty_content() { 150 $this->resetAfterTest(); 151 152 // Create empty content. 153 $record = new stdClass(); 154 155 $contenttype = new contenttype(context_system::instance()); 156 $content = $contenttype->create_content($record); 157 158 $this->assertEquals('contenttype_testable', $content->get_content_type()); 159 $this->assertInstanceOf('\\contenttype_testable\\content', $content); 160 } 161 162 /** 163 * Tests for behaviour of create_content() with data. 164 * 165 * @covers ::create_content 166 */ 167 public function test_create_content() { 168 $this->resetAfterTest(); 169 170 // Create content. 171 $record = new stdClass(); 172 $record->name = 'Test content'; 173 $record->configdata = ''; 174 $record->contenttype = ''; 175 176 $contenttype = new contenttype(context_system::instance()); 177 $content = $contenttype->create_content($record); 178 179 $this->assertEquals('contenttype_testable', $content->get_content_type()); 180 $this->assertInstanceOf('\\contenttype_testable\\content', $content); 181 } 182 183 /** 184 * Tests for behaviour of upload_content() with a file and a record. 185 * 186 * @dataProvider upload_content_provider 187 * @param bool $userecord if a predefined record has to be used. 188 * 189 * @covers ::upload_content 190 */ 191 public function test_upload_content(bool $userecord): void { 192 global $USER; 193 194 $this->resetAfterTest(); 195 $this->setAdminUser(); 196 197 $dummy = [ 198 'contextid' => context_user::instance($USER->id)->id, 199 'component' => 'user', 200 'filearea' => 'draft', 201 'itemid' => 1, 202 'filepath' => '/', 203 'filename' => 'file.h5p', 204 'userid' => $USER->id, 205 ]; 206 $fs = get_file_storage(); 207 $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); 208 209 // Create content. 210 if ($userecord) { 211 $record = new stdClass(); 212 $record->name = 'Test content'; 213 $record->configdata = ''; 214 $record->contenttype = ''; 215 $checkname = $record->name; 216 } else { 217 $record = null; 218 $checkname = $dummyfile->get_filename(); 219 } 220 221 $contenttype = new contenttype(context_system::instance()); 222 $content = $contenttype->upload_content($dummyfile, $record); 223 224 $this->assertEquals('contenttype_testable', $content->get_content_type()); 225 $this->assertEquals($checkname, $content->get_name()); 226 $this->assertInstanceOf('\\contenttype_testable\\content', $content); 227 228 $file = $content->get_file(); 229 $this->assertEquals($dummyfile->get_filename(), $file->get_filename()); 230 $this->assertEquals($dummyfile->get_userid(), $file->get_userid()); 231 $this->assertEquals($dummyfile->get_mimetype(), $file->get_mimetype()); 232 $this->assertEquals($dummyfile->get_contenthash(), $file->get_contenthash()); 233 $this->assertEquals('contentbank', $file->get_component()); 234 $this->assertEquals('public', $file->get_filearea()); 235 $this->assertEquals('/', $file->get_filepath()); 236 } 237 238 /** 239 * Data provider for test_rename_content. 240 * 241 * @return array 242 */ 243 public function upload_content_provider() { 244 return [ 245 'With record' => [true], 246 'Without record' => [false], 247 ]; 248 } 249 250 /** 251 * Tests for behaviour of upload_content() with a file wrong file. 252 * 253 * @covers ::upload_content 254 */ 255 public function test_upload_content_exception(): void { 256 global $USER, $DB; 257 258 $this->resetAfterTest(); 259 $this->setAdminUser(); 260 261 // The testing contenttype thows exception if filename is "error.*". 262 $dummy = [ 263 'contextid' => context_user::instance($USER->id)->id, 264 'component' => 'user', 265 'filearea' => 'draft', 266 'itemid' => 1, 267 'filepath' => '/', 268 'filename' => 'error.txt', 269 'userid' => $USER->id, 270 ]; 271 $fs = get_file_storage(); 272 $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); 273 274 $contenttype = new contenttype(context_system::instance()); 275 $cbcontents = $DB->count_records('contentbank_content'); 276 277 // We need to capture the exception to check no content is created. 278 try { 279 $content = $contenttype->upload_content($dummyfile); 280 $this->assertTrue(false); 281 } catch (Exception $e) { 282 $this->assertTrue(true); 283 } 284 $this->assertEquals($cbcontents, $DB->count_records('contentbank_content')); 285 $this->assertEquals(1, $DB->count_records('files', ['contenthash' => $dummyfile->get_contenthash()])); 286 } 287 288 /** 289 * Tests for behaviour of replace_content() using a dummy file. 290 * 291 * @covers ::replace_content 292 */ 293 public function test_replace_content(): void { 294 global $USER; 295 296 $this->resetAfterTest(); 297 $this->setAdminUser(); 298 $context = context_system::instance(); 299 300 // Add some content to the content bank. 301 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 302 $contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context); 303 $content = reset($contents); 304 305 $dummy = [ 306 'contextid' => context_user::instance($USER->id)->id, 307 'component' => 'user', 308 'filearea' => 'draft', 309 'itemid' => 1, 310 'filepath' => '/', 311 'filename' => 'file.h5p', 312 'userid' => $USER->id, 313 ]; 314 $fs = get_file_storage(); 315 $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); 316 317 $contenttype = new contenttype(context_system::instance()); 318 $content = $contenttype->replace_content($dummyfile, $content); 319 320 $this->assertEquals('contenttype_testable', $content->get_content_type()); 321 $this->assertInstanceOf('\\contenttype_testable\\content', $content); 322 323 $file = $content->get_file(); 324 $this->assertEquals($dummyfile->get_userid(), $file->get_userid()); 325 $this->assertEquals($dummyfile->get_contenthash(), $file->get_contenthash()); 326 $this->assertEquals('contentbank', $file->get_component()); 327 $this->assertEquals('public', $file->get_filearea()); 328 $this->assertEquals('/', $file->get_filepath()); 329 } 330 331 /** 332 * Tests for behaviour of replace_content() using an error file. 333 * 334 * @covers ::replace_content 335 */ 336 public function test_replace_content_exception(): void { 337 global $USER; 338 339 $this->resetAfterTest(); 340 $this->setAdminUser(); 341 $context = context_system::instance(); 342 343 // Add some content to the content bank. 344 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 345 $contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context); 346 $content = reset($contents); 347 348 $dummy = [ 349 'contextid' => context_user::instance($USER->id)->id, 350 'component' => 'user', 351 'filearea' => 'draft', 352 'itemid' => 1, 353 'filepath' => '/', 354 'filename' => 'error.txt', 355 'userid' => $USER->id, 356 ]; 357 $fs = get_file_storage(); 358 $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); 359 360 $contenttype = new contenttype(context_system::instance()); 361 362 $this->expectException(Exception::class); 363 $content = $contenttype->replace_content($dummyfile, $content); 364 } 365 366 /** 367 * Test the behaviour of can_delete(). 368 */ 369 public function test_can_delete() { 370 global $DB; 371 372 $this->resetAfterTest(); 373 $this->contenttype_setup_scenario_data(); 374 375 $managercontent = array_shift($this->contents[$this->manager1->id]); 376 $usercontent = array_shift($this->contents[$this->user->id]); 377 378 // Check the content has been created as expected. 379 $records = $DB->count_records('contentbank_content'); 380 $this->assertEquals(4, $records); 381 382 // Check user can only delete records created by her. 383 $this->setUser($this->user); 384 $this->assertFalse($this->contenttype->can_delete($managercontent)); 385 $this->assertTrue($this->contenttype->can_delete($usercontent)); 386 387 // Check manager can delete records all the records created. 388 $this->setUser($this->manager1); 389 $this->assertTrue($this->contenttype->can_delete($managercontent)); 390 $this->assertTrue($this->contenttype->can_delete($usercontent)); 391 392 // Unassign capability to manager role and check not can only delete their own records. 393 unassign_capability('moodle/contentbank:deleteanycontent', $this->managerroleid); 394 $this->assertTrue($this->contenttype->can_delete($managercontent)); 395 $this->assertFalse($this->contenttype->can_delete($usercontent)); 396 $this->setUser($this->manager2); 397 $this->assertFalse($this->contenttype->can_delete($managercontent)); 398 $this->assertFalse($this->contenttype->can_delete($usercontent)); 399 } 400 401 /** 402 * Test the behaviour of delete_content(). 403 */ 404 public function test_delete_content() { 405 global $DB; 406 407 $this->resetAfterTest(); 408 $this->contenttype_setup_scenario_data(); 409 410 // Check the content has been created as expected. 411 $this->assertEquals(4, $DB->count_records('contentbank_content')); 412 413 // Check the content is deleted as expected. 414 $this->setUser($this->manager1); 415 $content = array_shift($this->contents[$this->manager1->id]); 416 $deleted = $this->contenttype->delete_content($content); 417 $this->assertTrue($deleted); 418 $this->assertEquals(3, $DB->count_records('contentbank_content')); 419 } 420 421 /** 422 * Helper function to setup 3 users (manager1, manager2 and user) and 4 contents (3 created by manager1 and 1 by user). 423 */ 424 protected function contenttype_setup_scenario_data(string $contenttype = 'contenttype_testable'): void { 425 global $DB; 426 $systemcontext = context_system::instance(); 427 428 // Create users. 429 $this->manager1 = $this->getDataGenerator()->create_user(); 430 $this->manager2 = $this->getDataGenerator()->create_user(); 431 $this->managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 432 $this->getDataGenerator()->role_assign($this->managerroleid, $this->manager1->id); 433 $this->getDataGenerator()->role_assign($this->managerroleid, $this->manager2->id); 434 $editingteacherrolerid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']); 435 $this->user = $this->getDataGenerator()->create_user(); 436 $this->getDataGenerator()->role_assign($editingteacherrolerid, $this->user->id); 437 438 // Add some content to the content bank. 439 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 440 $this->contents[$this->manager1->id] = $generator->generate_contentbank_data($contenttype, 3, $this->manager1->id); 441 $this->contents[$this->user->id] = $generator->generate_contentbank_data($contenttype, 1, $this->user->id); 442 443 $contenttypeclass = "\\$contenttype\\contenttype"; 444 $this->contenttype = new $contenttypeclass($systemcontext); 445 } 446 447 /** 448 * Data provider for test_rename_content. 449 * 450 * @return array 451 */ 452 public function rename_content_provider() { 453 return [ 454 'Standard name' => ['New name', 'New name', true], 455 'Name with digits' => ['Today is 17/04/2017', 'Today is 17/04/2017', true], 456 'Name with symbols' => ['Follow us: @moodle', 'Follow us: @moodle', true], 457 'Name with tags' => ['This is <b>bold</b>', 'This is bold', true], 458 'Long name' => [str_repeat('a', 100), str_repeat('a', 100), true], 459 'Too long name' => [str_repeat('a', 300), str_repeat('a', 255), true], 460 'Empty name' => ['', 'Test content ', false], 461 'Blanks only' => [' ', 'Test content ', false], 462 'Zero name' => ['0', '0', true], 463 ]; 464 } 465 466 /** 467 * Test the behaviour of rename_content(). 468 * 469 * @dataProvider rename_content_provider 470 * @param string $newname The name to set 471 * @param string $expected The name result 472 * @param bool $result The bolean result expected when renaming 473 * 474 * @covers ::rename_content 475 */ 476 public function test_rename_content(string $newname, string $expected, bool $result) { 477 global $DB; 478 479 $this->resetAfterTest(); 480 481 // Create course and teacher user. 482 $course = $this->getDataGenerator()->create_course(); 483 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 484 $coursecontext = \context_course::instance($course->id); 485 $contenttype = new contenttype($coursecontext); 486 487 // Add some content to the content bank as teacher. 488 $this->setUser($teacher); 489 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 490 $contents = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id); 491 $content = array_shift($contents); 492 493 $oldname = $content->get_name(); 494 495 // Check the content is renamed as expected by a user with permission. 496 $renamed = $contenttype->rename_content($content, $newname); 497 $this->assertEquals($result, $renamed); 498 $record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]); 499 $this->assertEquals($expected, $record->name); 500 } 501 502 /** 503 * Test the behaviour of move_content(). 504 */ 505 public function test_move_content() { 506 global $DB; 507 508 $this->resetAfterTest(); 509 $systemcontext = context_system::instance(); 510 $course = $this->getDataGenerator()->create_course(); 511 $coursecontext = \context_course::instance($course->id); 512 513 // Add some content to the content bank. 514 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 515 $systemcontents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $systemcontext); 516 $generator->generate_contentbank_data('contenttype_testable', 3, 0, $coursecontext); 517 $systemcontent = reset($systemcontents); 518 519 // Check the content has been created as expected. 520 $this->assertEquals(6, $DB->count_records('contentbank_content')); 521 $this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id])); 522 $this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $coursecontext->id])); 523 524 // Check the content files has been created as expected. 525 $this->assertEquals(12, $DB->count_records('files', ['component' => 'contentbank'])); 526 $this->assertEquals(6, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $systemcontext->id])); 527 $this->assertEquals(6, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $coursecontext->id])); 528 529 // Check the content is moved as expected. 530 $contenttype = new contenttype($systemcontext); 531 $this->assertTrue($contenttype->move_content($systemcontent, $coursecontext)); 532 $this->assertEquals(6, $DB->count_records('contentbank_content')); 533 $this->assertEquals(2, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id])); 534 $this->assertEquals(4, $DB->count_records('contentbank_content', ['contextid' => $coursecontext->id])); 535 536 // Check the content files were moved as expected. 537 $this->assertEquals(12, $DB->count_records('files', ['component' => 'contentbank'])); 538 $this->assertEquals(4, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $systemcontext->id])); 539 $this->assertEquals(8, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $coursecontext->id])); 540 } 541 542 /** 543 * Test the behaviour of can_manage(). 544 * 545 * @covers ::can_manage 546 */ 547 public function test_can_manage() { 548 global $DB, $USER; 549 550 $this->resetAfterTest(); 551 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 552 553 // Create course and teacher user. 554 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']); 555 $course = $this->getDataGenerator()->create_course(); 556 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 557 $manager = $this->getDataGenerator()->create_and_enrol($course, 'manager'); 558 $coursecontext = \context_course::instance($course->id); 559 560 $contenttype = new contenttype($coursecontext); 561 562 // Add some content to the content bank as admin. 563 $this->setAdminUser(); 564 $contentsbyadmin = $generator->generate_contentbank_data('contenttype_testable', 1, $USER->id, $coursecontext); 565 $contentbyadmin = array_shift($contentsbyadmin); 566 567 // Add some content to the content bank as teacher. 568 $contentsbyteacher = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id, $coursecontext); 569 $contentbyteacher = array_shift($contentsbyteacher); 570 571 // Check the content has been created as expected. 572 $records = $DB->count_records('contentbank_content'); 573 $this->assertEquals(2, $records); 574 575 // Check manager can manage by default all the contents created. 576 $this->setUser($manager); 577 $this->assertTrue($contenttype->can_manage($contentbyteacher)); 578 $this->assertTrue($contenttype->can_manage($contentbyadmin)); 579 580 // Check teacher can only edit their own content. 581 $this->setUser($teacher); 582 $this->assertTrue($contenttype->can_manage($contentbyteacher)); 583 $this->assertFalse($contenttype->can_manage($contentbyadmin)); 584 585 // Unassign capability to teacher role and check they not can not edit any content. 586 unassign_capability('moodle/contentbank:manageowncontent', $teacherroleid); 587 $this->assertFalse($contenttype->can_manage($contentbyteacher)); 588 $this->assertFalse($contenttype->can_manage($contentbyadmin)); 589 } 590 591 /** 592 * Test the behaviour of can_download(). 593 * 594 * @covers ::can_download 595 */ 596 public function test_can_download() { 597 global $DB; 598 599 $this->resetAfterTest(); 600 $this->contenttype_setup_scenario_data('contenttype_h5p'); 601 602 $managercontent = array_shift($this->contents[$this->manager1->id]); 603 $usercontent = array_shift($this->contents[$this->user->id]); 604 605 // Check the content has been created as expected. 606 $records = $DB->count_records('contentbank_content'); 607 $this->assertEquals(4, $records); 608 609 // Check user can download content created by anybody. 610 $this->setUser($this->user); 611 $this->assertTrue($this->contenttype->can_download($usercontent)); 612 $this->assertTrue($this->contenttype->can_download($managercontent)); 613 614 // Check manager can download all the content too. 615 $this->setUser($this->manager1); 616 $this->assertTrue($this->contenttype->can_download($managercontent)); 617 $this->assertTrue($this->contenttype->can_download($usercontent)); 618 619 // Unassign capability to manager role and check she cannot download content anymore. 620 unassign_capability('moodle/contentbank:downloadcontent', $this->managerroleid); 621 $this->assertFalse($this->contenttype->can_download($managercontent)); 622 $this->assertFalse($this->contenttype->can_download($usercontent)); 623 } 624 625 /** 626 * Tests get_download_url result. 627 * 628 * @covers ::get_download_url 629 */ 630 public function test_get_download_url() { 631 global $CFG; 632 633 $this->resetAfterTest(); 634 $this->setAdminUser(); 635 $systemcontext = context_system::instance(); 636 637 // Add some content to the content bank. 638 $filename = 'filltheblanks.h5p'; 639 $filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename; 640 $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); 641 $contents = $generator->generate_contentbank_data('contenttype_testable', 1, 0, $systemcontext, true, $filepath); 642 $content = array_shift($contents); 643 644 // Check the URL is returned OK for a content with file. 645 $contenttype = new contenttype($systemcontext); 646 $url = $contenttype->get_download_url($content); 647 $this->assertNotEmpty($url); 648 $this->assertStringContainsString($filename, $url); 649 650 // Check the URL is empty when the content hasn't any file. 651 $record = new stdClass(); 652 $content = $contenttype->create_content($record); 653 $url = $contenttype->get_download_url($content); 654 $this->assertEmpty($url); 655 } 656 657 /** 658 * Tests pluginfile result. 659 * 660 * @covers ::pluginfile 661 */ 662 public function test_pluginfile() { 663 $this->resetAfterTest(); 664 $this->setAdminUser(); 665 $systemcontext = context_system::instance(); 666 $contenttype = new contenttype($systemcontext); 667 $this->assertIsCallable([$contenttype, 'pluginfile']); 668 } 669 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body