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