Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [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_group\reportbuilder\datasource;
  20  
  21  use core_reportbuilder_generator;
  22  use core_reportbuilder_testcase;
  23  use core_reportbuilder\local\filters\{boolean_select, date, select, text};
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  global $CFG;
  28  require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
  29  
  30  /**
  31   * Unit tests for groups datasource
  32   *
  33   * @package     core_group
  34   * @covers      \core_group\reportbuilder\datasource\groups
  35   * @copyright   2022 Paul Holden <paulh@moodle.com>
  36   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class groups_test extends core_reportbuilder_testcase {
  39  
  40      /**
  41       * Test default datasource
  42       */
  43      public function test_datasource_default(): void {
  44          $this->resetAfterTest();
  45  
  46          $course = $this->getDataGenerator()->create_course();
  47          $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
  48  
  49          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
  50          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
  51  
  52          /** @var core_reportbuilder_generator $generator */
  53          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
  54          $report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 1]);
  55  
  56          $content = $this->get_custom_report_content($report->get('id'));
  57          $this->assertCount(1, $content);
  58  
  59          $contentrow = array_values(reset($content));
  60          $this->assertEquals([
  61              "<a href=\"https://www.example.com/moodle/course/view.php?id={$course->id}\">{$course->fullname}</a>", // Course.
  62              $group->name, // Group.
  63              fullname($user), // User.
  64          ], $contentrow);
  65      }
  66  
  67      /**
  68       * Test datasource groupings reports
  69       */
  70      public function test_datasource_groupings(): void {
  71          $this->resetAfterTest();
  72  
  73          $course = $this->getDataGenerator()->create_course();
  74  
  75          // Create group, add to grouping.
  76          $groupone = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'Group A']);
  77          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id]);
  78          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $groupone->id]);
  79  
  80          // Create second group, no grouping.
  81          $grouptwo = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'Group B']);
  82  
  83          /** @var core_reportbuilder_generator $generator */
  84          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
  85          $report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 0]);
  86  
  87          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
  88          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:name']);
  89          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:name', 'sortenabled' => 1]);
  90  
  91          $content = $this->get_custom_report_content($report->get('id'));
  92          $this->assertCount(2, $content);
  93  
  94          $this->assertEquals([
  95              [
  96                  $course->fullname,
  97                  $grouping->name,
  98                  $groupone->name,
  99              ],
 100              [
 101                  $course->fullname,
 102                  null,
 103                  $grouptwo->name,
 104              ],
 105          ], array_map('array_values', $content));
 106      }
 107  
 108      /**
 109       * Test datasource columns that aren't added by default
 110       */
 111      public function test_datasource_non_default_columns(): void {
 112          $this->resetAfterTest();
 113  
 114          $course = $this->getDataGenerator()->create_course();
 115          $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
 116  
 117          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'idnumber' => 'G101', 'enrolmentkey' => 'S',
 118              'description' => 'My group']);
 119          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 120  
 121          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id, 'idnumber' => 'GR101',
 122              'description' => 'My grouping']);
 123          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $group->id]);
 124  
 125          /** @var core_reportbuilder_generator $generator */
 126          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 127          $report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 0]);
 128  
 129          // Course (just to test join).
 130          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:shortname']);
 131  
 132          // Group.
 133          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:idnumber']);
 134          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:description']);
 135          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:enrolmentkey']);
 136          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:visibility']);
 137          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:participation']);
 138          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:picture']);
 139          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:timecreated']);
 140          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:timemodified']);
 141  
 142          // Grouping.
 143          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:name']);
 144          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:idnumber']);
 145          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:description']);
 146          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:timecreated']);
 147          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:timemodified']);
 148  
 149          // Group member.
 150          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group_member:timeadded']);
 151          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group_member:component']);
 152  
 153          // User (just to test join).
 154          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:username']);
 155  
 156          $content = $this->get_custom_report_content($report->get('id'));
 157          $this->assertCount(1, $content);
 158  
 159          [
 160              $courseshortname,
 161              $groupidnumber,
 162              $groupdescription,
 163              $groupenrolmentkey,
 164              $groupvisibility,
 165              $groupparticipation,
 166              $grouppicture,
 167              $grouptimecreated,
 168              $grouptimemodified,
 169              $groupingname,
 170              $groupingidnumber,
 171              $groupingdescription,
 172              $groupingtimecreated,
 173              $groupingtimemodified,
 174              $groupmembertimeadded,
 175              $groupmemebercomponent,
 176              $userusername,
 177          ] = array_values($content[0]);
 178  
 179          $this->assertEquals($course->shortname, $courseshortname);
 180          $this->assertEquals('G101', $groupidnumber);
 181          $this->assertEquals(format_text($group->description), $groupdescription);
 182          $this->assertEquals('S', $groupenrolmentkey);
 183          $this->assertEquals('Visible', $groupvisibility);
 184          $this->assertEquals('Yes', $groupparticipation);
 185          $this->assertEmpty($grouppicture);
 186          $this->assertNotEmpty($grouptimecreated);
 187          $this->assertNotEmpty($grouptimemodified);
 188          $this->assertEquals($grouping->name, $groupingname);
 189          $this->assertEquals('GR101', $groupingidnumber);
 190          $this->assertEquals(format_text($grouping->description), $groupingdescription);
 191          $this->assertNotEmpty($groupingtimecreated);
 192          $this->assertNotEmpty($groupingtimemodified);
 193          $this->assertNotEmpty($groupmembertimeadded);
 194          $this->assertEmpty($groupmemebercomponent);
 195          $this->assertEquals($user->username, $userusername);
 196      }
 197  
 198      /**
 199       * Data provider for {@see test_datasource_filters}
 200       *
 201       * @return array[]
 202       */
 203      public function datasource_filters_provider(): array {
 204          return [
 205              // Course (just to test join).
 206              'Filter course name' => ['course:fullname', [
 207                  'course:fullname_operator' => text::IS_EQUAL_TO,
 208                  'course:fullname_value' => 'Test course',
 209              ], true],
 210              'Filter course name (no match)' => ['course:fullname', [
 211                  'course:fullname_operator' => text::IS_NOT_EQUAL_TO,
 212                  'course:fullname_value' => 'Test course',
 213              ], false],
 214  
 215              // Group.
 216              'Filter group name' => ['group:name', [
 217                  'group:name_operator' => text::IS_EQUAL_TO,
 218                  'group:name_value' => 'Test group',
 219              ], true],
 220              'Filter group name (no match)' => ['group:name', [
 221                  'group:name_operator' => text::IS_NOT_EQUAL_TO,
 222                  'group:name_value' => 'Test group',
 223              ], false],
 224              'Filter group idnumber' => ['group:idnumber', [
 225                  'group:idnumber_operator' => text::IS_EQUAL_TO,
 226                  'group:idnumber_value' => 'G101',
 227              ], true],
 228              'Filter group idnumber (no match)' => ['group:idnumber', [
 229                  'group:idnumber_operator' => text::IS_NOT_EQUAL_TO,
 230                  'group:idnumber_value' => 'G101',
 231              ], false],
 232              'Filter group visibility' => ['group:visibility', [
 233                  'group:visibility_operator' => select::EQUAL_TO,
 234                  'group:visibility_value' => 0, // Visible to everyone.
 235              ], true],
 236              'Filter group visibility (no match)' => ['group:visibility', [
 237                  'group:visibility_operator' => select::EQUAL_TO,
 238                  'group:visibility_value' => 1, // Visible to members only.
 239              ], false],
 240              'Filter group participation' => ['group:participation', [
 241                  'group:participation_operator' => boolean_select::CHECKED,
 242              ], true],
 243              'Filter group participation (no match)' => ['group:participation', [
 244                  'group:participation_operator' => boolean_select::NOT_CHECKED,
 245              ], false],
 246              'Filter group time created' => ['group:timecreated', [
 247                  'group:timecreated_operator' => date::DATE_RANGE,
 248                  'group:timecreated_from' => 1622502000,
 249              ], true],
 250              'Filter group time created (no match)' => ['group:timecreated', [
 251                  'group:timecreated_operator' => date::DATE_RANGE,
 252                  'group:timecreated_to' => 1622502000,
 253              ], false],
 254  
 255              // Grouping.
 256              'Filter grouping name' => ['grouping:name', [
 257                  'grouping:name_operator' => text::IS_EQUAL_TO,
 258                  'grouping:name_value' => 'Test grouping',
 259              ], true],
 260              'Filter grouping name (no match)' => ['grouping:name', [
 261                  'grouping:name_operator' => text::IS_NOT_EQUAL_TO,
 262                  'grouping:name_value' => 'Test grouping',
 263              ], false],
 264              'Filter grouping idnumber' => ['grouping:idnumber', [
 265                  'grouping:idnumber_operator' => text::IS_EQUAL_TO,
 266                  'grouping:idnumber_value' => 'GR101',
 267              ], true],
 268              'Filter grouping idnumber (no match)' => ['grouping:idnumber', [
 269                  'grouping:idnumber_operator' => text::IS_NOT_EQUAL_TO,
 270                  'grouping:idnumber_value' => 'GR101',
 271              ], false],
 272              'Filter grouping time created' => ['grouping:timecreated', [
 273                  'grouping:timecreated_operator' => date::DATE_RANGE,
 274                  'grouping:timecreated_from' => 1622502000,
 275              ], true],
 276              'Filter grouping time created (no match)' => ['grouping:timecreated', [
 277                  'grouping:timecreated_operator' => date::DATE_RANGE,
 278                  'grouping:timecreated_to' => 1622502000,
 279              ], false],
 280  
 281              // Group member.
 282              'Filter group member time added' => ['group_member:timeadded', [
 283                  'group_member:timeadded_operator' => date::DATE_RANGE,
 284                  'group_member:timeadded_from' => 1622502000,
 285              ], true],
 286              'Filter group member time added (no match)' => ['group_member:timeadded', [
 287                  'group_member:timeadded_operator' => date::DATE_RANGE,
 288                  'group_member:timeadded_to' => 1622502000,
 289              ], false],
 290  
 291              // User (just to test join).
 292              'Filter user username' => ['user:username', [
 293                  'user:username_operator' => text::IS_EQUAL_TO,
 294                  'user:username_value' => 'testuser',
 295              ], true],
 296              'Filter user username (no match)' => ['user:username', [
 297                  'user:username_operator' => text::IS_NOT_EQUAL_TO,
 298                  'user:username_value' => 'testuser',
 299              ], false],
 300          ];
 301      }
 302  
 303      /**
 304       * Test datasource filters
 305       *
 306       * @param string $filtername
 307       * @param array $filtervalues
 308       * @param bool $expectmatch
 309       *
 310       * @dataProvider datasource_filters_provider
 311       */
 312      public function test_datasource_filters(
 313          string $filtername,
 314          array $filtervalues,
 315          bool $expectmatch
 316      ): void {
 317          $this->resetAfterTest();
 318  
 319          $course = $this->getDataGenerator()->create_course(['fullname' => 'Test course']);
 320          $user = $this->getDataGenerator()->create_and_enrol($course, 'student', ['username' => 'testuser']);
 321  
 322          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'idnumber' => 'G101', 'name' => 'Test group']);
 323          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 324  
 325          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id, 'idnumber' => 'GR101',
 326              'name' => 'Test grouping']);
 327          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $group->id]);
 328  
 329          /** @var core_reportbuilder_generator $generator */
 330          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 331  
 332          // Create report containing single column, and given filter.
 333          $report = $generator->create_report(['name' => 'Tasks', 'source' => groups::class, 'default' => 0]);
 334          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:idnumber']);
 335  
 336          // Add filter, set it's values.
 337          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
 338          $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
 339  
 340          if ($expectmatch) {
 341              $this->assertCount(1, $content);
 342              $this->assertEquals('G101', reset($content[0]));
 343          } else {
 344              $this->assertEmpty($content);
 345          }
 346      }
 347  
 348      /**
 349       * Stress test datasource
 350       *
 351       * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
 352       */
 353      public function test_stress_datasource(): void {
 354          if (!PHPUNIT_LONGTEST) {
 355              $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
 356          }
 357  
 358          $this->resetAfterTest();
 359  
 360          $course = $this->getDataGenerator()->create_course(['fullname' => 'Test course']);
 361          $user = $this->getDataGenerator()->create_and_enrol($course, 'student', ['username' => 'testuser']);
 362  
 363          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'idnumber' => 'G101', 'name' => 'Test group']);
 364          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 365  
 366          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id, 'idnumber' => 'GR101',
 367              'name' => 'Test grouping']);
 368          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $group->id]);
 369  
 370          $this->datasource_stress_test_columns(groups::class);
 371          $this->datasource_stress_test_columns_aggregation(groups::class);
 372          $this->datasource_stress_test_conditions(groups::class, 'group:idnumber');
 373      }
 374  }