See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401] [Versions 401 and 402] [Versions 401 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 declare(strict_types=1); 18 19 namespace core_course\reportbuilder\datasource; 20 21 use core_reportbuilder_testcase; 22 use core_reportbuilder_generator; 23 use core_reportbuilder\local\filters\boolean_select; 24 use core_reportbuilder\local\filters\date; 25 use core_reportbuilder\local\filters\select; 26 use core_reportbuilder\local\filters\tags; 27 use core_reportbuilder\local\filters\text; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php"); 33 34 /** 35 * Unit tests for courses datasources 36 * 37 * @package core_course 38 * @covers \core_course\reportbuilder\datasource\courses 39 * @copyright 2021 Paul Holden <paulh@moodle.com> 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 class courses_test extends core_reportbuilder_testcase { 43 44 /** 45 * Test default datasource 46 */ 47 public function test_datasource_default(): void { 48 $this->resetAfterTest(); 49 50 // Test subject. 51 $category = $this->getDataGenerator()->create_category(['name' => 'My cats']); 52 $course = $this->getDataGenerator()->create_course([ 53 'category' => $category->id, 54 'fullname' => 'All about cats', 55 'shortname' => 'C101', 56 'idnumber' => 'CAT101' 57 ]); 58 59 /** @var core_reportbuilder_generator $generator */ 60 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 61 $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 1]); 62 63 $content = $this->get_custom_report_content($report->get('id')); 64 $this->assertCount(1, $content); 65 66 $contentrow = array_values($content[0]); 67 68 $this->assertEquals([ 69 $category->get_formatted_name(), 70 $course->shortname, 71 $course->fullname, 72 $course->idnumber, 73 ], $contentrow); 74 } 75 76 /** 77 * Test datasource columns that aren't added by default 78 */ 79 public function test_datasource_non_default_columns(): void { 80 $this->resetAfterTest(); 81 82 $category = $this->getDataGenerator()->create_category([ 83 'name' => 'Animals', 84 'idnumber' => 'CAT101', 85 'description' => 'Category description', 86 ]); 87 $course = $this->getDataGenerator()->create_course([ 88 'category' => $category->id, 89 'fullname' => 'Cats', 90 'summary' => 'Course description', 91 'tags' => ['Horses'], 92 ]); 93 94 /** @var core_reportbuilder_generator $generator */ 95 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 96 $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]); 97 98 // Category. 99 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:namewithlink']); 100 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:path']); 101 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:idnumber']); 102 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:description']); 103 104 // Course. 105 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']); 106 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseshortnamewithlink']); 107 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseidnumberewithlink']); 108 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:summary']); 109 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:format']); 110 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:startdate']); 111 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enddate']); 112 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:visible']); 113 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmode']); 114 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmodeforce']); 115 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:lang']); 116 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:calendartype']); 117 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:theme']); 118 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enablecompletion']); 119 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:downloadcontent']); 120 121 // Tags. 122 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:name']); 123 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'tag:namewithlink']); 124 125 $content = $this->get_custom_report_content($report->get('id')); 126 $this->assertCount(1, $content); 127 128 $courserow = array_values($content[0]); 129 130 // Category. 131 $this->assertStringContainsString($category->get_formatted_name(), $courserow[0]); 132 $this->assertEquals($category->get_nested_name(false), $courserow[1]); 133 $this->assertEquals($category->idnumber, $courserow[2]); 134 $this->assertEquals(format_text($category->description, $category->descriptionformat), $courserow[3]); 135 136 // Course. 137 $this->assertStringContainsString($course->fullname, $courserow[4]); 138 $this->assertStringContainsString($course->shortname, $courserow[5]); 139 $this->assertStringContainsString($course->idnumber, $courserow[6]); 140 $this->assertEquals(format_text($course->summary, $course->summaryformat), $courserow[7]); 141 $this->assertEquals('Topics format', $courserow[8]); 142 $this->assertEquals(userdate($course->startdate), $courserow[9]); 143 $this->assertEmpty($courserow[10]); 144 $this->assertEquals('Yes', $courserow[11]); 145 $this->assertEquals('No groups', $courserow[12]); 146 $this->assertEquals('No', $courserow[13]); 147 $this->assertEmpty($courserow[14]); 148 $this->assertEmpty($courserow[15]); 149 $this->assertEmpty($courserow[16]); 150 $this->assertEquals('No', $courserow[17]); 151 $this->assertEmpty($courserow[18]); 152 153 // Tags. 154 $this->assertEquals('Horses', $courserow[19]); 155 $this->assertStringContainsString('Horses', $courserow[20]); 156 } 157 158 /** 159 * Tests courses datasource using multilang filters 160 */ 161 public function test_courses_datasource_multilang_filters(): void { 162 $this->resetAfterTest(); 163 164 filter_set_global_state('multilang', TEXTFILTER_ON); 165 filter_set_applies_to_strings('multilang', true); 166 167 // Test subject. 168 $category = $this->getDataGenerator()->create_category([ 169 'name' => '<span class="multilang" lang="en">Cat (en)</span><span class="multilang" lang="es">Cat (es)</span>', 170 ]); 171 $course = $this->getDataGenerator()->create_course([ 172 'category' => $category->id, 173 'fullname' => '<span class="multilang" lang="en">Crs (en)</span><span class="multilang" lang="es">Crs (es)</span>', 174 ]); 175 176 /** @var core_reportbuilder_generator $generator */ 177 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 178 179 // Create a report containing columns that support multilang content. 180 $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]); 181 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:name']); 182 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']); 183 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']); 184 185 $content = $this->get_custom_report_content($report->get('id')); 186 $this->assertCount(1, $content); 187 188 $contentrow = array_values(reset($content)); 189 $this->assertEquals([ 190 'Cat (en)', 191 'Crs (en)', 192 '<a href="' . (string) course_get_url($course->id) . '">Crs (en)</a>', 193 ], $contentrow); 194 } 195 196 /** 197 * Data provider for {@see test_datasource_filters} 198 * 199 * @return array[] 200 */ 201 public function datasource_filters_provider(): array { 202 return [ 203 // Category. 204 'Filter category' => ['course_category:name', [ 205 'course_category:name_value' => -1, 206 ], false], 207 'Filter category name' => ['course_category:text', [ 208 'course_category:text_operator' => text::IS_EQUAL_TO, 209 'course_category:text_value' => 'Animals', 210 ], true], 211 'Filter category name (no match)' => ['course_category:text', [ 212 'course_category:text_operator' => text::IS_EQUAL_TO, 213 'course_category:text_value' => 'Fruit', 214 ], false], 215 'Filter category idnumber' => ['course_category:idnumber', [ 216 'course_category:idnumber_operator' => text::IS_EQUAL_TO, 217 'course_category:idnumber_value' => 'CAT101', 218 ], true], 219 'Filter category idnumber (no match)' => ['course_category:idnumber', [ 220 'course_category:idnumber_operator' => text::CONTAINS, 221 'course_category:idnumber_value' => 'FRUIT', 222 ], false], 223 224 // Course. 225 'Filter course' => ['course:courseselector', [ 226 'course:courseselector_values' => [-1], 227 ], false], 228 'Filter course fullname' => ['course:fullname', [ 229 'course:fullname_operator' => text::IS_EQUAL_TO, 230 'course:fullname_value' => 'Equine', 231 ], true], 232 'Filter course fullname (no match)' => ['course:fullname', [ 233 'course:fullname_operator' => text::IS_EQUAL_TO, 234 'course:fullname_value' => 'Foxes', 235 ], false], 236 'Filter course shortname' => ['course:shortname', [ 237 'course:shortname_operator' => text::IS_EQUAL_TO, 238 'course:shortname_value' => 'EQ101', 239 ], true], 240 'Filter course shortname (no match)' => ['course:shortname', [ 241 'course:shortname_operator' => text::IS_EQUAL_TO, 242 'course:shortname_value' => 'FX101', 243 ], false], 244 'Filter course idnumber' => ['course:idnumber', [ 245 'course:idnumber_operator' => text::IS_EQUAL_TO, 246 'course:idnumber_value' => 'E-101AB', 247 ], true], 248 'Filter course idnumber (no match)' => ['course:idnumber', [ 249 'course:idnumber_operator' => text::IS_EQUAL_TO, 250 'course:idnumber_value' => 'F-101XT', 251 ], false], 252 'Filter course summary' => ['course:summary', [ 253 'course:summary_operator' => text::CONTAINS, 254 'course:summary_value' => 'Lorem ipsum', 255 ], true], 256 'Filter course summary (no match)' => ['course:summary', [ 257 'course:summary_operator' => text::IS_EQUAL_TO, 258 'course:summary_value' => 'Fiat', 259 ], false], 260 'Filter course format' => ['course:format', [ 261 'course:format_operator' => select::EQUAL_TO, 262 'course:format_value' => 'topics', 263 ], true], 264 'Filter course format (no match)' => ['course:format', [ 265 'course:format_operator' => select::EQUAL_TO, 266 'course:format_value' => 'weekly', 267 ], false], 268 'Filter course startdate' => ['course:startdate', [ 269 'course:startdate_operator' => date::DATE_RANGE, 270 'course:startdate_from' => 1622502000, 271 ], true], 272 'Filter course startdate (no match)' => ['course:startdate', [ 273 'course:startdate_operator' => date::DATE_RANGE, 274 'course:startdate_to' => 1622502000, 275 ], false], 276 'Filter course enddate' => ['course:enddate', [ 277 'course:enddate_operator' => date::DATE_EMPTY, 278 ], true], 279 'Filter course enddate (no match)' => ['course:enddate', [ 280 'course:enddate_operator' => date::DATE_NOT_EMPTY, 281 ], false], 282 'Filter course visible' => ['course:visible', [ 283 'course:visible_operator' => boolean_select::CHECKED, 284 ], true], 285 'Filter course visible (no match)' => ['course:visible', [ 286 'course:visible_operator' => boolean_select::NOT_CHECKED, 287 ], false], 288 'Filter course groupmode' => ['course:groupmode', [ 289 'course:groupmode_operator' => select::EQUAL_TO, 290 'course:groupmode_value' => 0, // No groups. 291 ], true], 292 'Filter course groupmode (no match)' => ['course:groupmode', [ 293 'course:groupmode_operator' => select::EQUAL_TO, 294 'course:groupmode_value' => 1, // Separate groups. 295 ], false], 296 'Filter course groupmodeforce' => ['course:groupmodeforce', [ 297 'course:groupmodeforce_operator' => boolean_select::NOT_CHECKED, 298 ], true], 299 'Filter course groupmodeforce (no match)' => ['course:groupmodeforce', [ 300 'course:groupmodeforce_operator' => boolean_select::CHECKED, 301 ], false], 302 'Filter course lang' => ['course:lang', [ 303 'course:lang_operator' => select::EQUAL_TO, 304 'course:lang_value' => 'en', 305 ], true], 306 'Filter course lang (no match)' => ['course:lang', [ 307 'course:lang_operator' => select::EQUAL_TO, 308 'course:lang_value' => 'de', 309 ], false], 310 'Filter course calendartype' => ['course:calendartype', [ 311 'course:calendartype_operator' => select::EQUAL_TO, 312 'course:calendartype_value' => 'gregorian', 313 ], true], 314 'Filter course calendartype (no match)' => ['course:calendartype', [ 315 'course:calendartype_operator' => select::EQUAL_TO, 316 'course:calendartype_value' => 'hijri', 317 ], false], 318 'Filter course theme' => ['course:theme', [ 319 'course:theme_operator' => select::EQUAL_TO, 320 'course:theme_value' => 'boost', 321 ], true], 322 'Filter course theme (no match)' => ['course:theme', [ 323 'course:theme_operator' => select::EQUAL_TO, 324 'course:theme_value' => 'classic', 325 ], false], 326 'Filter course enablecompletion' => ['course:enablecompletion', [ 327 'course:enablecompletion_operator' => boolean_select::NOT_CHECKED, 328 ], true], 329 'Filter course enablecompletion (no match)' => ['course:enablecompletion', [ 330 'course:enablecompletion_operator' => boolean_select::CHECKED, 331 ], false], 332 'Filter course downloadcontent' => ['course:downloadcontent', [ 333 'course:downloadcontent_operator' => boolean_select::CHECKED, 334 ], true], 335 'Filter course downloadcontent (no match)' => ['course:downloadcontent', [ 336 'course:downloadcontent_operator' => boolean_select::NOT_CHECKED, 337 ], false], 338 339 // Tags. 340 'Filter tag name' => ['tag:name', [ 341 'tag:name_operator' => tags::EQUAL_TO, 342 'tag:name_value' => [-1], 343 ], false], 344 'Filter tag name not empty' => ['tag:name', [ 345 'tag:name_operator' => tags::NOT_EMPTY, 346 ], true], 347 ]; 348 } 349 350 /** 351 * Test datasource filters 352 * 353 * @param string $filtername 354 * @param array $filtervalues 355 * @param bool $expectmatch 356 * 357 * @dataProvider datasource_filters_provider 358 */ 359 public function test_datasource_filters(string $filtername, array $filtervalues, bool $expectmatch): void { 360 $this->resetAfterTest(); 361 362 $category = $this->getDataGenerator()->create_category(['name' => 'Animals', 'idnumber' => 'CAT101']); 363 $course = $this->getDataGenerator()->create_course([ 364 'category' => $category->id, 365 'fullname' => 'Equine', 366 'shortname' => 'EQ101', 367 'idnumber' => 'E-101AB', 368 'lang' => 'en', 369 'calendartype' => 'gregorian', 370 'theme' => 'boost', 371 'downloadcontent' => 1, 372 'tags' => ['Horses'], 373 ]); 374 375 /** @var core_reportbuilder_generator $generator */ 376 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 377 378 // Create report containing single column, and given filter. 379 $report = $generator->create_report(['name' => 'Tasks', 'source' => courses::class, 'default' => 0]); 380 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']); 381 382 // Add filter, set it's values. 383 $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]); 384 $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues); 385 386 if ($expectmatch) { 387 $this->assertCount(1, $content); 388 $this->assertEquals($course->fullname, reset($content[0])); 389 } else { 390 $this->assertEmpty($content); 391 } 392 } 393 394 /** 395 * Stress test datasource 396 * 397 * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php 398 */ 399 public function test_stress_datasource(): void { 400 if (!PHPUNIT_LONGTEST) { 401 $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); 402 } 403 404 $this->resetAfterTest(); 405 406 $category = $this->getDataGenerator()->create_category(); 407 $course = $this->getDataGenerator()->create_course(['category' => $category->id]); 408 409 $this->datasource_stress_test_columns(courses::class); 410 $this->datasource_stress_test_columns_aggregation(courses::class); 411 $this->datasource_stress_test_conditions(courses::class, 'course:idnumber'); 412 } 413 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body