Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is 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/>.

declare(strict_types=1);

namespace core_course\reportbuilder\datasource;

> use context_course;
use core_reportbuilder_testcase; use core_reportbuilder_generator; use core_reportbuilder\local\filters\boolean_select;
> use core_reportbuilder\local\filters\category;
use core_reportbuilder\local\filters\date; use core_reportbuilder\local\filters\select; use core_reportbuilder\local\filters\tags; use core_reportbuilder\local\filters\text; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php"); /** * Unit tests for courses datasources * * @package core_course * @covers \core_course\reportbuilder\datasource\courses * @copyright 2021 Paul Holden <paulh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class courses_test extends core_reportbuilder_testcase { /** * Test default datasource */ public function test_datasource_default(): void { $this->resetAfterTest(); // Test subject. $category = $this->getDataGenerator()->create_category(['name' => 'My cats']);
< $course = $this->getDataGenerator()->create_course([
> $courseone = $this->getDataGenerator()->create_course([ > 'category' => $category->id, > 'fullname' => 'Feline fine', > 'shortname' => 'C102', > 'idnumber' => 'CAT102' > ]); > $coursetwo = $this->getDataGenerator()->create_course([
'category' => $category->id, 'fullname' => 'All about cats', 'shortname' => 'C101', 'idnumber' => 'CAT101' ]); /** @var core_reportbuilder_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 1]); $content = $this->get_custom_report_content($report->get('id'));
< $this->assertCount(1, $content); < < $contentrow = array_values($content[0]);
> // Default columns are category, shortname, fullname, idnumber. Sorted by category, shortname, fullname.
$this->assertEquals([
< $category->get_formatted_name(), < $course->shortname, < $course->fullname, < $course->idnumber, < ], $contentrow);
> [$category->name, $coursetwo->shortname, $coursetwo->fullname, $coursetwo->idnumber], > [$category->name, $courseone->shortname, $courseone->fullname, $courseone->idnumber], > ], array_map('array_values', $content));
} /** * Test datasource columns that aren't added by default */ public function test_datasource_non_default_columns(): void { $this->resetAfterTest(); $category = $this->getDataGenerator()->create_category([ 'name' => 'Animals', 'idnumber' => 'CAT101', 'description' => 'Category description', ]); $course = $this->getDataGenerator()->create_course([ 'category' => $category->id, 'fullname' => 'Cats', 'summary' => 'Course description', 'tags' => ['Horses'], ]);
> // Add a course image. /** @var core_reportbuilder_generator $generator */ > get_file_storage()->create_file_from_string([ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); > 'contextid' => context_course::instance($course->id)->id, $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]); > 'component' => 'course', > 'filearea' => 'overviewfiles', // Category. > 'itemid' => 0, $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:namewithlink']); > 'filepath' => '/', $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:path']); > 'filename' => 'HelloWorld.jpg', $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:idnumber']); > ], 'HelloWorld'); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:description']); >
// Course. $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseshortnamewithlink']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseidnumberewithlink']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:summary']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:format']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:startdate']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enddate']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:visible']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmode']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmodeforce']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:lang']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:calendartype']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:theme']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enablecompletion']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:downloadcontent']); // Tags. $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:name']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:namewithlink']);
> // File entity. $content = $this->get_custom_report_content($report->get('id')); > $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:name']); $this->assertCount(1, $content); >
$courserow = array_values($content[0]); // Category. $this->assertStringContainsString($category->get_formatted_name(), $courserow[0]); $this->assertEquals($category->get_nested_name(false), $courserow[1]); $this->assertEquals($category->idnumber, $courserow[2]); $this->assertEquals(format_text($category->description, $category->descriptionformat), $courserow[3]); // Course. $this->assertStringContainsString($course->fullname, $courserow[4]); $this->assertStringContainsString($course->shortname, $courserow[5]); $this->assertStringContainsString($course->idnumber, $courserow[6]); $this->assertEquals(format_text($course->summary, $course->summaryformat), $courserow[7]); $this->assertEquals('Topics format', $courserow[8]); $this->assertEquals(userdate($course->startdate), $courserow[9]); $this->assertEmpty($courserow[10]); $this->assertEquals('Yes', $courserow[11]); $this->assertEquals('No groups', $courserow[12]); $this->assertEquals('No', $courserow[13]); $this->assertEmpty($courserow[14]); $this->assertEmpty($courserow[15]); $this->assertEmpty($courserow[16]); $this->assertEquals('No', $courserow[17]); $this->assertEmpty($courserow[18]); // Tags. $this->assertEquals('Horses', $courserow[19]); $this->assertStringContainsString('Horses', $courserow[20]);
> } > // File. > $this->assertEquals('HelloWorld.jpg', $courserow[21]);
/** * Tests courses datasource using multilang filters */ public function test_courses_datasource_multilang_filters(): void { $this->resetAfterTest(); filter_set_global_state('multilang', TEXTFILTER_ON); filter_set_applies_to_strings('multilang', true); // Test subject. $category = $this->getDataGenerator()->create_category([ 'name' => '<span class="multilang" lang="en">Cat (en)</span><span class="multilang" lang="es">Cat (es)</span>', ]); $course = $this->getDataGenerator()->create_course([ 'category' => $category->id, 'fullname' => '<span class="multilang" lang="en">Crs (en)</span><span class="multilang" lang="es">Crs (es)</span>', ]); /** @var core_reportbuilder_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); // Create a report containing columns that support multilang content. $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:name']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']); $content = $this->get_custom_report_content($report->get('id')); $this->assertCount(1, $content); $contentrow = array_values(reset($content)); $this->assertEquals([ 'Cat (en)', 'Crs (en)', '<a href="' . (string) course_get_url($course->id) . '">Crs (en)</a>', ], $contentrow); } /** * Data provider for {@see test_datasource_filters} * * @return array[] */ public function datasource_filters_provider(): array { return [ // Category. 'Filter category' => ['course_category:name', [
> 'course_category:name_operator' => category::NOT_EQUAL_TO, 'course_category:name_value' => -1, > 'course_category:name_value' => -1, ], false], > ], true], 'Filter category name' => ['course_category:text', [ > 'Filter category (no match)' => ['course_category:name', [ 'course_category:text_operator' => text::IS_EQUAL_TO, > 'course_category:name_operator' => category::EQUAL_TO,
'course_category:text_value' => 'Animals', ], true], 'Filter category name (no match)' => ['course_category:text', [ 'course_category:text_operator' => text::IS_EQUAL_TO, 'course_category:text_value' => 'Fruit', ], false], 'Filter category idnumber' => ['course_category:idnumber', [ 'course_category:idnumber_operator' => text::IS_EQUAL_TO, 'course_category:idnumber_value' => 'CAT101', ], true], 'Filter category idnumber (no match)' => ['course_category:idnumber', [ 'course_category:idnumber_operator' => text::CONTAINS, 'course_category:idnumber_value' => 'FRUIT', ], false], // Course. 'Filter course' => ['course:courseselector', [ 'course:courseselector_values' => [-1], ], false], 'Filter course fullname' => ['course:fullname', [ 'course:fullname_operator' => text::IS_EQUAL_TO, 'course:fullname_value' => 'Equine', ], true], 'Filter course fullname (no match)' => ['course:fullname', [ 'course:fullname_operator' => text::IS_EQUAL_TO, 'course:fullname_value' => 'Foxes', ], false], 'Filter course shortname' => ['course:shortname', [ 'course:shortname_operator' => text::IS_EQUAL_TO, 'course:shortname_value' => 'EQ101', ], true], 'Filter course shortname (no match)' => ['course:shortname', [ 'course:shortname_operator' => text::IS_EQUAL_TO, 'course:shortname_value' => 'FX101', ], false], 'Filter course idnumber' => ['course:idnumber', [ 'course:idnumber_operator' => text::IS_EQUAL_TO, 'course:idnumber_value' => 'E-101AB', ], true], 'Filter course idnumber (no match)' => ['course:idnumber', [ 'course:idnumber_operator' => text::IS_EQUAL_TO, 'course:idnumber_value' => 'F-101XT', ], false], 'Filter course summary' => ['course:summary', [ 'course:summary_operator' => text::CONTAINS, 'course:summary_value' => 'Lorem ipsum', ], true], 'Filter course summary (no match)' => ['course:summary', [ 'course:summary_operator' => text::IS_EQUAL_TO, 'course:summary_value' => 'Fiat', ], false], 'Filter course format' => ['course:format', [ 'course:format_operator' => select::EQUAL_TO, 'course:format_value' => 'topics', ], true], 'Filter course format (no match)' => ['course:format', [ 'course:format_operator' => select::EQUAL_TO, 'course:format_value' => 'weekly', ], false], 'Filter course startdate' => ['course:startdate', [ 'course:startdate_operator' => date::DATE_RANGE, 'course:startdate_from' => 1622502000, ], true], 'Filter course startdate (no match)' => ['course:startdate', [ 'course:startdate_operator' => date::DATE_RANGE, 'course:startdate_to' => 1622502000, ], false], 'Filter course enddate' => ['course:enddate', [ 'course:enddate_operator' => date::DATE_EMPTY, ], true], 'Filter course enddate (no match)' => ['course:enddate', [ 'course:enddate_operator' => date::DATE_NOT_EMPTY, ], false], 'Filter course visible' => ['course:visible', [ 'course:visible_operator' => boolean_select::CHECKED, ], true], 'Filter course visible (no match)' => ['course:visible', [ 'course:visible_operator' => boolean_select::NOT_CHECKED, ], false], 'Filter course groupmode' => ['course:groupmode', [ 'course:groupmode_operator' => select::EQUAL_TO, 'course:groupmode_value' => 0, // No groups. ], true], 'Filter course groupmode (no match)' => ['course:groupmode', [ 'course:groupmode_operator' => select::EQUAL_TO, 'course:groupmode_value' => 1, // Separate groups. ], false], 'Filter course groupmodeforce' => ['course:groupmodeforce', [ 'course:groupmodeforce_operator' => boolean_select::NOT_CHECKED, ], true], 'Filter course groupmodeforce (no match)' => ['course:groupmodeforce', [ 'course:groupmodeforce_operator' => boolean_select::CHECKED, ], false], 'Filter course lang' => ['course:lang', [ 'course:lang_operator' => select::EQUAL_TO, 'course:lang_value' => 'en', ], true], 'Filter course lang (no match)' => ['course:lang', [ 'course:lang_operator' => select::EQUAL_TO, 'course:lang_value' => 'de', ], false], 'Filter course calendartype' => ['course:calendartype', [ 'course:calendartype_operator' => select::EQUAL_TO, 'course:calendartype_value' => 'gregorian', ], true], 'Filter course calendartype (no match)' => ['course:calendartype', [ 'course:calendartype_operator' => select::EQUAL_TO, 'course:calendartype_value' => 'hijri', ], false], 'Filter course theme' => ['course:theme', [ 'course:theme_operator' => select::EQUAL_TO, 'course:theme_value' => 'boost', ], true], 'Filter course theme (no match)' => ['course:theme', [ 'course:theme_operator' => select::EQUAL_TO, 'course:theme_value' => 'classic', ], false], 'Filter course enablecompletion' => ['course:enablecompletion', [ 'course:enablecompletion_operator' => boolean_select::NOT_CHECKED, ], true], 'Filter course enablecompletion (no match)' => ['course:enablecompletion', [ 'course:enablecompletion_operator' => boolean_select::CHECKED, ], false], 'Filter course downloadcontent' => ['course:downloadcontent', [ 'course:downloadcontent_operator' => boolean_select::CHECKED, ], true], 'Filter course downloadcontent (no match)' => ['course:downloadcontent', [ 'course:downloadcontent_operator' => boolean_select::NOT_CHECKED, ], false], // Tags. 'Filter tag name' => ['tag:name', [ 'tag:name_operator' => tags::EQUAL_TO, 'tag:name_value' => [-1], ], false], 'Filter tag name not empty' => ['tag:name', [ 'tag:name_operator' => tags::NOT_EMPTY,
> ], true], ], true], > ]; > // File. } > 'Filter file name empty' => ['file:name', [ > 'file:name_operator' => text::IS_EMPTY,
/** * Test datasource filters * * @param string $filtername * @param array $filtervalues * @param bool $expectmatch * * @dataProvider datasource_filters_provider */ public function test_datasource_filters(string $filtername, array $filtervalues, bool $expectmatch): void { $this->resetAfterTest(); $category = $this->getDataGenerator()->create_category(['name' => 'Animals', 'idnumber' => 'CAT101']); $course = $this->getDataGenerator()->create_course([ 'category' => $category->id, 'fullname' => 'Equine', 'shortname' => 'EQ101', 'idnumber' => 'E-101AB', 'lang' => 'en', 'calendartype' => 'gregorian', 'theme' => 'boost', 'downloadcontent' => 1, 'tags' => ['Horses'], ]); /** @var core_reportbuilder_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); // Create report containing single column, and given filter. $report = $generator->create_report(['name' => 'Tasks', 'source' => courses::class, 'default' => 0]); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']); // Add filter, set it's values. $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]); $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues); if ($expectmatch) { $this->assertCount(1, $content); $this->assertEquals($course->fullname, reset($content[0])); } else { $this->assertEmpty($content); } } /** * Stress test datasource * * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php */ public function test_stress_datasource(): void { if (!PHPUNIT_LONGTEST) { $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); } $this->resetAfterTest(); $category = $this->getDataGenerator()->create_category(); $course = $this->getDataGenerator()->create_course(['category' => $category->id]); $this->datasource_stress_test_columns(courses::class); $this->datasource_stress_test_columns_aggregation(courses::class); $this->datasource_stress_test_conditions(courses::class, 'course:idnumber'); } }