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.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Test for content bank contenttype class.
 *
 * @package    core_contentbank
 * @category   test
 * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace core_contentbank;

use stdClass;
use context_system;
use context_user;
use Exception;
use contenttype_testable\contenttype as contenttype;
/**
 * Test for content bank contenttype class.
 *
 * @package    core_contentbank
 * @category   test
 * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @coversDefaultClass \core_contentbank\contenttype
 *
 */
class core_contenttype_contenttype_testcase extends \advanced_testcase {

    /** @var int Identifier for the manager role. */
    protected $managerroleid;

    /** @var stdClass Manager user. */
    protected $manager1;

    /** @var stdClass Manager user. */
    protected $manager2;

    /** @var stdClass User. */
    protected $user;

    /** @var array List of contents created (every user has a key with contents created by her). */
    protected $contents = [];

    /** @var contenttype The contenttype instance. */
    protected $contenttype;

    /**
     * Setup to ensure that fixtures are loaded.
     */
    public static function setupBeforeClass(): void {
        global $CFG;

        require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
        require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
    }

    /**
     * Tests get_contenttype_name result.
     *
     * @covers ::get_contenttype_name
     */
    public function test_get_contenttype_name() {
        $this->resetAfterTest();

        $systemcontext = \context_system::instance();
        $testable = new contenttype($systemcontext);

        $this->assertEquals('contenttype_testable', $testable->get_contenttype_name());
    }

    /**
     * Tests get_plugin_name result.
     *
     * @covers ::get_plugin_name
     */
    public function test_get_plugin_name() {
        $this->resetAfterTest();

        $systemcontext = \context_system::instance();
        $testable = new contenttype($systemcontext);

        $this->assertEquals('testable', $testable->get_plugin_name());
    }

    /**
     * Tests get_icon result.
     *
     * @covers ::get_icon
     */
    public function test_get_icon() {
        $this->resetAfterTest();

        $systemcontext = \context_system::instance();
        $testable = new contenttype($systemcontext);
        $record = new stdClass();
        $record->name = 'New content';
        $content = $testable->create_content($record);
        $icon = $testable->get_icon($content);
< $this->assertContains('archive', $icon);
> $this->assertStringContainsString('archive', $icon);
} /** * Tests is_feature_supported behavior . * * @covers ::is_feature_supported */ public function test_is_feature_supported() { $this->resetAfterTest(); $systemcontext = \context_system::instance(); $testable = new contenttype($systemcontext); $this->assertTrue($testable->is_feature_supported(contenttype::CAN_TEST)); $this->assertFalse($testable->is_feature_supported(contenttype::CAN_UPLOAD)); } /** * Tests can_upload behavior with no implemented upload feature. * * @covers ::can_upload */ public function test_no_upload_feature_supported() { $this->resetAfterTest(); $systemcontext = \context_system::instance(); $testable = new contenttype($systemcontext); $this->setAdminUser(); $this->assertFalse($testable->is_feature_supported(contenttype::CAN_UPLOAD)); $this->assertFalse($testable->can_upload()); } /** * Test create_content() with empty data. * * @covers ::create_content */ public function test_create_empty_content() { $this->resetAfterTest(); // Create empty content. $record = new stdClass(); $contenttype = new contenttype(context_system::instance()); $content = $contenttype->create_content($record); $this->assertEquals('contenttype_testable', $content->get_content_type()); $this->assertInstanceOf('\\contenttype_testable\\content', $content); } /** * Tests for behaviour of create_content() with data. * * @covers ::create_content */ public function test_create_content() { $this->resetAfterTest(); // Create content. $record = new stdClass(); $record->name = 'Test content'; $record->configdata = ''; $record->contenttype = ''; $contenttype = new contenttype(context_system::instance()); $content = $contenttype->create_content($record); $this->assertEquals('contenttype_testable', $content->get_content_type()); $this->assertInstanceOf('\\contenttype_testable\\content', $content); } /** * Tests for behaviour of upload_content() with a file and a record. * * @dataProvider upload_content_provider * @param bool $userecord if a predefined record has to be used. * * @covers ::upload_content */ public function test_upload_content(bool $userecord): void { global $USER; $this->resetAfterTest(); $this->setAdminUser(); $dummy = [ 'contextid' => context_user::instance($USER->id)->id, 'component' => 'user', 'filearea' => 'draft', 'itemid' => 1, 'filepath' => '/', 'filename' => 'file.h5p', 'userid' => $USER->id, ]; $fs = get_file_storage(); $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); // Create content. if ($userecord) { $record = new stdClass(); $record->name = 'Test content'; $record->configdata = ''; $record->contenttype = ''; $checkname = $record->name; } else { $record = null; $checkname = $dummyfile->get_filename(); } $contenttype = new contenttype(context_system::instance()); $content = $contenttype->upload_content($dummyfile, $record); $this->assertEquals('contenttype_testable', $content->get_content_type()); $this->assertEquals($checkname, $content->get_name()); $this->assertInstanceOf('\\contenttype_testable\\content', $content); $file = $content->get_file(); $this->assertEquals($dummyfile->get_filename(), $file->get_filename()); $this->assertEquals($dummyfile->get_userid(), $file->get_userid()); $this->assertEquals($dummyfile->get_mimetype(), $file->get_mimetype()); $this->assertEquals($dummyfile->get_contenthash(), $file->get_contenthash()); $this->assertEquals('contentbank', $file->get_component()); $this->assertEquals('public', $file->get_filearea()); $this->assertEquals('/', $file->get_filepath()); } /** * Data provider for test_rename_content. * * @return array */ public function upload_content_provider() { return [ 'With record' => [true], 'Without record' => [false], ]; } /** * Tests for behaviour of upload_content() with a file wrong file. * * @covers ::upload_content */ public function test_upload_content_exception(): void { global $USER, $DB; $this->resetAfterTest(); $this->setAdminUser(); // The testing contenttype thows exception if filename is "error.*". $dummy = [ 'contextid' => context_user::instance($USER->id)->id, 'component' => 'user', 'filearea' => 'draft', 'itemid' => 1, 'filepath' => '/', 'filename' => 'error.txt', 'userid' => $USER->id, ]; $fs = get_file_storage(); $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); $contenttype = new contenttype(context_system::instance()); $cbcontents = $DB->count_records('contentbank_content'); // We need to capture the exception to check no content is created. try { $content = $contenttype->upload_content($dummyfile); $this->assertTrue(false); } catch (Exception $e) { $this->assertTrue(true); } $this->assertEquals($cbcontents, $DB->count_records('contentbank_content')); $this->assertEquals(1, $DB->count_records('files', ['contenthash' => $dummyfile->get_contenthash()])); } /**
> * Tests for behaviour of replace_content() using a dummy file. * Test the behaviour of can_delete(). > * */ > * @covers ::replace_content public function test_can_delete() { > */ global $DB; > public function test_replace_content(): void { > global $USER; $this->resetAfterTest(); > $this->contenttype_setup_scenario_data(); > $this->resetAfterTest(); > $this->setAdminUser(); $managercontent = array_shift($this->contents[$this->manager1->id]); > $context = context_system::instance(); $usercontent = array_shift($this->contents[$this->user->id]); > > // Add some content to the content bank. // Check the content has been created as expected. > $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); $records = $DB->count_records('contentbank_content'); > $contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context); $this->assertEquals(4, $records); > $content = reset($contents); > // Check user can only delete records created by her. > $dummy = [ $this->setUser($this->user); > 'contextid' => context_user::instance($USER->id)->id, $this->assertFalse($this->contenttype->can_delete($managercontent)); > 'component' => 'user', $this->assertTrue($this->contenttype->can_delete($usercontent)); > 'filearea' => 'draft', > 'itemid' => 1, // Check manager can delete records all the records created. > 'filepath' => '/', $this->setUser($this->manager1); > 'filename' => 'file.h5p', $this->assertTrue($this->contenttype->can_delete($managercontent)); > 'userid' => $USER->id, $this->assertTrue($this->contenttype->can_delete($usercontent)); > ]; > $fs = get_file_storage(); // Unassign capability to manager role and check not can only delete their own records. > $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); unassign_capability('moodle/contentbank:deleteanycontent', $this->managerroleid); > $this->assertTrue($this->contenttype->can_delete($managercontent)); > $contenttype = new contenttype(context_system::instance()); $this->assertFalse($this->contenttype->can_delete($usercontent)); > $content = $contenttype->replace_content($dummyfile, $content); $this->setUser($this->manager2); > $this->assertFalse($this->contenttype->can_delete($managercontent)); > $this->assertEquals('contenttype_testable', $content->get_content_type()); $this->assertFalse($this->contenttype->can_delete($usercontent)); > $this->assertInstanceOf('\\contenttype_testable\\content', $content); } > > $file = $content->get_file(); /** > $this->assertEquals($dummyfile->get_userid(), $file->get_userid()); * Test the behaviour of delete_content(). > $this->assertEquals($dummyfile->get_contenthash(), $file->get_contenthash()); */ > $this->assertEquals('contentbank', $file->get_component()); public function test_delete_content() { > $this->assertEquals('public', $file->get_filearea()); global $DB; > $this->assertEquals('/', $file->get_filepath()); > } $this->resetAfterTest(); > $this->contenttype_setup_scenario_data(); > /** > * Tests for behaviour of replace_content() using an error file. // Check the content has been created as expected. > * $this->assertEquals(4, $DB->count_records('contentbank_content')); > * @covers ::replace_content > */ // Check the content is deleted as expected. > public function test_replace_content_exception(): void { $this->setUser($this->manager1); > global $USER; $content = array_shift($this->contents[$this->manager1->id]); > $deleted = $this->contenttype->delete_content($content); > $this->resetAfterTest(); $this->assertTrue($deleted); > $this->setAdminUser(); $this->assertEquals(3, $DB->count_records('contentbank_content')); > $context = context_system::instance(); } > > // Add some content to the content bank. /** > $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); * Helper function to setup 3 users (manager1, manager2 and user) and 4 contents (3 created by manager1 and 1 by user). > $contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context); */ > $content = reset($contents); protected function contenttype_setup_scenario_data(): void { > global $DB; > $dummy = [ $systemcontext = context_system::instance(); > 'contextid' => context_user::instance($USER->id)->id, > 'component' => 'user', // Create users. > 'filearea' => 'draft', $this->manager1 = $this->getDataGenerator()->create_user(); > 'itemid' => 1, $this->manager2 = $this->getDataGenerator()->create_user(); > 'filepath' => '/', $this->managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); > 'filename' => 'error.txt', $this->getDataGenerator()->role_assign($this->managerroleid, $this->manager1->id); > 'userid' => $USER->id, $this->getDataGenerator()->role_assign($this->managerroleid, $this->manager2->id); > ]; $this->user = $this->getDataGenerator()->create_user(); > $fs = get_file_storage(); > $dummyfile = $fs->create_file_from_string($dummy, 'Dummy content'); // Add some content to the content bank. > $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); > $contenttype = new contenttype(context_system::instance()); $this->contents[$this->manager1->id] = $generator->generate_contentbank_data(null, 3, $this->manager1->id); > $this->contents[$this->user->id] = $generator->generate_contentbank_data(null, 1, $this->user->id); > $this->expectException(Exception::class); > $content = $contenttype->replace_content($dummyfile, $content); $this->contenttype = new \contenttype_testable\contenttype($systemcontext); > } } > > /**
< protected function contenttype_setup_scenario_data(): void {
> protected function contenttype_setup_scenario_data(string $contenttype = 'contenttype_testable'): void {
* Data provider for test_rename_content.
> $editingteacherrolerid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
*
> $this->getDataGenerator()->role_assign($editingteacherrolerid, $this->user->id);
< $this->contents[$this->manager1->id] = $generator->generate_contentbank_data(null, 3, $this->manager1->id); < $this->contents[$this->user->id] = $generator->generate_contentbank_data(null, 1, $this->user->id);
> $this->contents[$this->manager1->id] = $generator->generate_contentbank_data($contenttype, 3, $this->manager1->id); > $this->contents[$this->user->id] = $generator->generate_contentbank_data($contenttype, 1, $this->user->id);
< $this->contenttype = new \contenttype_testable\contenttype($systemcontext);
> $contenttypeclass = "\\$contenttype\\contenttype"; > $this->contenttype = new $contenttypeclass($systemcontext);
return [ 'Standard name' => ['New name', 'New name', true], 'Name with digits' => ['Today is 17/04/2017', 'Today is 17/04/2017', true], 'Name with symbols' => ['Follow us: @moodle', 'Follow us: @moodle', true], 'Name with tags' => ['This is <b>bold</b>', 'This is bold', true], 'Long name' => [str_repeat('a', 100), str_repeat('a', 100), true], 'Too long name' => [str_repeat('a', 300), str_repeat('a', 255), true], 'Empty name' => ['', 'Test content ', false], 'Blanks only' => [' ', 'Test content ', false], 'Zero name' => ['0', '0', true], ]; } /** * Test the behaviour of rename_content(). * * @dataProvider rename_content_provider * @param string $newname The name to set * @param string $expected The name result * @param bool $result The bolean result expected when renaming * * @covers ::rename_content */ public function test_rename_content(string $newname, string $expected, bool $result) { global $DB; $this->resetAfterTest(); // Create course and teacher user. $course = $this->getDataGenerator()->create_course(); $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); $coursecontext = \context_course::instance($course->id); $contenttype = new contenttype($coursecontext); // Add some content to the content bank as teacher. $this->setUser($teacher); $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); $contents = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id); $content = array_shift($contents); $oldname = $content->get_name(); // Check the content is renamed as expected by a user with permission. $renamed = $contenttype->rename_content($content, $newname); $this->assertEquals($result, $renamed); $record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]); $this->assertEquals($expected, $record->name); } /** * Test the behaviour of move_content(). */ public function test_move_content() { global $DB; $this->resetAfterTest(); $systemcontext = context_system::instance(); $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); // Add some content to the content bank. $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); $systemcontents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $systemcontext); $generator->generate_contentbank_data('contenttype_testable', 3, 0, $coursecontext); $systemcontent = reset($systemcontents); // Check the content has been created as expected. $this->assertEquals(6, $DB->count_records('contentbank_content')); $this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id])); $this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $coursecontext->id])); // Check the content files has been created as expected. $this->assertEquals(12, $DB->count_records('files', ['component' => 'contentbank'])); $this->assertEquals(6, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $systemcontext->id])); $this->assertEquals(6, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $coursecontext->id])); // Check the content is moved as expected. $contenttype = new contenttype($systemcontext); $this->assertTrue($contenttype->move_content($systemcontent, $coursecontext)); $this->assertEquals(6, $DB->count_records('contentbank_content')); $this->assertEquals(2, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id])); $this->assertEquals(4, $DB->count_records('contentbank_content', ['contextid' => $coursecontext->id])); // Check the content files were moved as expected. $this->assertEquals(12, $DB->count_records('files', ['component' => 'contentbank'])); $this->assertEquals(4, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $systemcontext->id])); $this->assertEquals(8, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $coursecontext->id])); } /** * Test the behaviour of can_manage(). * * @covers ::can_manage */ public function test_can_manage() { global $DB, $USER; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); // Create course and teacher user. $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']); $course = $this->getDataGenerator()->create_course(); $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); $manager = $this->getDataGenerator()->create_and_enrol($course, 'manager'); $coursecontext = \context_course::instance($course->id); $contenttype = new contenttype($coursecontext); // Add some content to the content bank as admin. $this->setAdminUser(); $contentsbyadmin = $generator->generate_contentbank_data('contenttype_testable', 1, $USER->id, $coursecontext); $contentbyadmin = array_shift($contentsbyadmin); // Add some content to the content bank as teacher. $contentsbyteacher = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id, $coursecontext); $contentbyteacher = array_shift($contentsbyteacher); // Check the content has been created as expected. $records = $DB->count_records('contentbank_content'); $this->assertEquals(2, $records); // Check manager can manage by default all the contents created. $this->setUser($manager); $this->assertTrue($contenttype->can_manage($contentbyteacher)); $this->assertTrue($contenttype->can_manage($contentbyadmin)); // Check teacher can only edit their own content. $this->setUser($teacher); $this->assertTrue($contenttype->can_manage($contentbyteacher)); $this->assertFalse($contenttype->can_manage($contentbyadmin)); // Unassign capability to teacher role and check they not can not edit any content. unassign_capability('moodle/contentbank:manageowncontent', $teacherroleid); $this->assertFalse($contenttype->can_manage($contentbyteacher)); $this->assertFalse($contenttype->can_manage($contentbyadmin));
> } } > } > /** > * Test the behaviour of can_download(). > * > * @covers ::can_download > */ > public function test_can_download() { > global $DB; > > $this->resetAfterTest(); > $this->contenttype_setup_scenario_data('contenttype_h5p'); > > $managercontent = array_shift($this->contents[$this->manager1->id]); > $usercontent = array_shift($this->contents[$this->user->id]); > > // Check the content has been created as expected. > $records = $DB->count_records('contentbank_content'); > $this->assertEquals(4, $records); > > // Check user can download content created by anybody. > $this->setUser($this->user); > $this->assertTrue($this->contenttype->can_download($usercontent)); > $this->assertTrue($this->contenttype->can_download($managercontent)); > > // Check manager can download all the content too. > $this->setUser($this->manager1); > $this->assertTrue($this->contenttype->can_download($managercontent)); > $this->assertTrue($this->contenttype->can_download($usercontent)); > > // Unassign capability to manager role and check she cannot download content anymore. > unassign_capability('moodle/contentbank:downloadcontent', $this->managerroleid); > $this->assertFalse($this->contenttype->can_download($managercontent)); > $this->assertFalse($this->contenttype->can_download($usercontent)); > } > > /** > * Tests get_download_url result. > * > * @covers ::get_download_url > */ > public function test_get_download_url() { > global $CFG; > > $this->resetAfterTest(); > $this->setAdminUser(); > $systemcontext = context_system::instance(); > > // Add some content to the content bank. > $filename = 'filltheblanks.h5p'; > $filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename; > $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank'); > $contents = $generator->generate_contentbank_data('contenttype_testable', 1, 0, $systemcontext, true, $filepath); > $content = array_shift($contents); > > // Check the URL is returned OK for a content with file. > $contenttype = new contenttype($systemcontext); > $url = $contenttype->get_download_url($content); > $this->assertNotEmpty($url); > $this->assertStringContainsString($filename, $url); > > // Check the URL is empty when the content hasn't any file. > $record = new stdClass(); > $content = $contenttype->create_content($record); > $url = $contenttype->get_download_url($content); > $this->assertEmpty($url);