<?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 core_customfield_generator;
> 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;
< use core_reportbuilder\local\helpers\user_filter_manager;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
/**
< * Unit tests for component datasources
> * 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:path']);
> 'filepath' => '/',
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:idnumber']);
> 'filename' => 'HelloWorld.jpg',
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:description']);
> ], 'HelloWorld');
>
// Course.
> $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:namewithlink']);
$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.
$content = $this->get_custom_report_content($report->get('id'));
> $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:name']);
$this->assertCount(1, $content);
> $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:namewithlink']);
>
$courserow = array_values($content[0]);
> // File entity.
> $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:name']);
// Category.
>
< $this->assertEquals($category->get_nested_name(false), $courserow[0]);
< $this->assertEquals($category->idnumber, $courserow[1]);
< $this->assertEquals(format_text($category->description, $category->descriptionformat), $courserow[2]);
> $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[3]);
< $this->assertStringContainsString($course->shortname, $courserow[4]);
< $this->assertStringContainsString($course->idnumber, $courserow[5]);
< $this->assertEquals(format_text($course->summary, $course->summaryformat), $courserow[6]);
< $this->assertEquals('Topics format', $courserow[7]);
< $this->assertEquals(userdate($course->startdate), $courserow[8]);
< $this->assertEmpty($courserow[9]);
< $this->assertEquals('Yes', $courserow[10]);
< $this->assertEquals('No groups', $courserow[11]);
< $this->assertEquals('No', $courserow[12]);
< $this->assertEmpty($courserow[13]);
> $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->assertEquals('No', $courserow[16]);
< $this->assertEmpty($courserow[17]);
> $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' => select::EQUAL_TO,
> 'course_category:name_operator' => category::NOT_EQUAL_TO,
'course_category:name_value' => -1,
> ], true],
], false],
> 'Filter category (no match)' => ['course_category:name', [
'Filter category idnumber' => ['course_category:idnumber', [
> 'course_category:name_operator' => category::EQUAL_TO,
'course_category:idnumber_operator' => text::IS_EQUAL_TO,
> 'course_category:name_value' => -1,
'course_category:idnumber_value' => 'CAT101',
> ], false],
], true],
> 'Filter category name' => ['course_category:text', [
'Filter category idnumber (no match)' => ['course_category:idnumber', [
> 'course_category:text_operator' => text::IS_EQUAL_TO,
'course_category:idnumber_operator' => text::CONTAINS,
> 'course_category:text_value' => 'Animals',
'course_category:idnumber_value' => 'FRUIT',
> ], true],
], false],
> 'Filter category name (no match)' => ['course_category:text', [
> 'course_category:text_operator' => text::IS_EQUAL_TO,
// Course.
> 'course_category:text_value' => 'Fruit',
'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', [
'Filter course format' => ['course:format', [
> 'course:summary_operator' => text::CONTAINS,
'course:format_operator' => select::EQUAL_TO,
> 'course:summary_value' => 'Lorem ipsum',
'course:format_value' => 'topics',
> ], true],
], true],
> 'Filter course summary (no match)' => ['course:summary', [
'Filter course format (no match)' => ['course:format', [
> 'course:summary_operator' => text::IS_EQUAL_TO,
'course:format_operator' => select::EQUAL_TO,
> 'course:summary_value' => 'Fiat',
'course:format_value' => 'weekly',
> ], false],
], 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],
* Test datasource filters
> ], false],
*
> 'Filter tag name not empty' => ['tag:name', [
* @param string $filtername
> 'tag:name_operator' => tags::NOT_EMPTY,
* @param array $filtervalues
> ], true],
* @param bool $expectmatch
>
*
> // File.
* @dataProvider datasource_filters_provider
> 'Filter file name empty' => ['file:name', [
*/
> 'file:name_operator' => text::IS_EMPTY,
public function test_datasource_filters(string $filtername, array $filtervalues, bool $expectmatch): void {
> ], true],
$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]);
< user_filter_manager::set($report->get('id'), $filtervalues);
<
< $content = $this->get_custom_report_content($report->get('id'));
> $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();
< /** @var core_customfield_generator $generator */
< $generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
< $customfieldcategory = $generator->create_category();
< $generator->create_field(['categoryid' => $customfieldcategory->get('id'), 'shortname' => 'hi']);
<
$category = $this->getDataGenerator()->create_category();
< $course = $this->getDataGenerator()->create_course(['category' => $category->id, 'customfield_hi' => 'Hello']);
> $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');
}
}