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