Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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_reportbuilder\local\filters;
  20  
  21  use advanced_testcase;
  22  use lang_string;
  23  use core_reportbuilder\local\report\filter;
  24  
  25  /**
  26   * Unit tests for date report filter
  27   *
  28   * @package     core_reportbuilder
  29   * @covers      \core_reportbuilder\local\filters\base
  30   * @covers      \core_reportbuilder\local\filters\date
  31   * @copyright   2021 Paul Holden <paulh@moodle.com>
  32   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class date_test extends advanced_testcase {
  35  
  36      /**
  37       * Data provider for {@see test_get_sql_filter_simple}
  38       *
  39       * @return array
  40       */
  41      public function get_sql_filter_simple_provider(): array {
  42          return [
  43              [date::DATE_ANY, true],
  44              [date::DATE_NOT_EMPTY, true],
  45              [date::DATE_EMPTY, false],
  46          ];
  47      }
  48  
  49      /**
  50       * Test getting filter SQL
  51       *
  52       * @param int $operator
  53       * @param bool $expectuser
  54       *
  55       * @dataProvider get_sql_filter_simple_provider
  56       */
  57      public function test_get_sql_filter_simple(int $operator, bool $expectuser): void {
  58          global $DB;
  59  
  60          $this->resetAfterTest();
  61  
  62          $user = $this->getDataGenerator()->create_user([
  63              'timecreated' => 12345,
  64          ]);
  65  
  66          $filter = new filter(
  67              date::class,
  68              'test',
  69              new lang_string('yes'),
  70              'testentity',
  71              'timecreated'
  72          );
  73  
  74          // Create instance of our filter, passing given operator.
  75          [$select, $params] = date::create($filter)->get_sql_filter([
  76              $filter->get_unique_identifier() . '_operator' => $operator,
  77          ]);
  78  
  79          $usernames = $DB->get_fieldset_select('user', 'username', $select, $params);
  80          if ($expectuser) {
  81              $this->assertContains($user->username, $usernames);
  82          } else {
  83              $this->assertNotContains($user->username, $usernames);
  84          }
  85      }
  86  
  87      /**
  88       * Test getting filter SQL while specifying a date range
  89       */
  90      public function test_get_sql_filter_date_range(): void {
  91          global $DB;
  92  
  93          $this->resetAfterTest();
  94  
  95          $userone = $this->getDataGenerator()->create_user(['timecreated' => 50]);
  96          $usertwo = $this->getDataGenerator()->create_user(['timecreated' => 100]);
  97  
  98          $filter = new filter(
  99              date::class,
 100              'test',
 101              new lang_string('yes'),
 102              'testentity',
 103              'timecreated'
 104          );
 105  
 106          // Create instance of our date range filter.
 107          [$select, $params] = date::create($filter)->get_sql_filter([
 108              $filter->get_unique_identifier() . '_operator' => date::DATE_RANGE,
 109              $filter->get_unique_identifier() . '_from' => 80,
 110              $filter->get_unique_identifier() . '_to' => 120,
 111          ]);
 112  
 113          // The only matching user should be our first test user.
 114          $usernames = $DB->get_fieldset_select('user', 'username', $select, $params);
 115          $this->assertEquals([$usertwo->username], $usernames);
 116      }
 117  
 118      /**
 119       * Data provider for {@see test_get_sql_filter_current_week}
 120       *
 121       * @return array
 122       */
 123      public function get_sql_filter_current_week_provider(): array {
 124          return array_map(static function(int $day): array {
 125              return [$day];
 126          }, range(0, 6));
 127      }
 128  
 129      /**
 130       * Test getting filter SQL for the current week. Note that relative dates are hard to test, here we are asserting that
 131       * the current time is always within the current week regardless of calendar configuration/preferences
 132       *
 133       * @param int $startweekday
 134       *
 135       * @dataProvider get_sql_filter_current_week_provider
 136       */
 137      public function test_get_sql_filter_current_week(int $startweekday): void {
 138          global $DB;
 139  
 140          $this->resetAfterTest();
 141  
 142          set_config('calendar_startwday', $startweekday);
 143  
 144          $user = $this->getDataGenerator()->create_user(['timecreated' => time()]);
 145  
 146          $filter = new filter(
 147              date::class,
 148              'test',
 149              new lang_string('yes'),
 150              'testentity',
 151              'timecreated'
 152          );
 153  
 154          [$select, $params] = date::create($filter)->get_sql_filter([
 155              $filter->get_unique_identifier() . '_operator' => date::DATE_CURRENT,
 156              $filter->get_unique_identifier() . '_unit' => date::DATE_UNIT_WEEK,
 157          ]);
 158  
 159          $matchingusers = $DB->get_fieldset_select('user', 'username', $select, $params);
 160          $this->assertContains($user->username, $matchingusers);
 161      }
 162  
 163      /**
 164       * Data provider for {@see test_get_sql_filter_current_week_no_match}
 165       *
 166       * @return array
 167       */
 168      public function get_sql_filter_current_week_no_match_provider(): array {
 169          $data = [];
 170  
 171          // For each day, create provider data for -/+ 8 days.
 172          foreach (range(0, 6) as $day) {
 173              $data = array_merge($data, [
 174                  [$day, '-8 day'],
 175                  [$day, '+8 day'],
 176              ]);
 177          }
 178  
 179          return $data;
 180      }
 181  
 182      /**
 183       * Test getting filter SQL for the current week excludes dates that don't match (outside week time range)
 184       *
 185       * @param int $startweekday
 186       * @param string $timecreated Relative time suitable for passing to {@see strtotime}
 187       *
 188       * @dataProvider get_sql_filter_current_week_no_match_provider
 189       */
 190      public function test_get_sql_filter_current_week_no_match(int $startweekday, string $timecreated): void {
 191          global $DB;
 192  
 193          $this->resetAfterTest();
 194  
 195          set_config('calendar_startwday', $startweekday);
 196  
 197          $usertimecreated = strtotime($timecreated);
 198          $user = $this->getDataGenerator()->create_user(['timecreated' => $usertimecreated]);
 199  
 200          $filter = new filter(
 201              date::class,
 202              'test',
 203              new lang_string('yes'),
 204              'testentity',
 205              'timecreated'
 206          );
 207  
 208          [$select, $params] = date::create($filter)->get_sql_filter([
 209              $filter->get_unique_identifier() . '_operator' => date::DATE_CURRENT,
 210              $filter->get_unique_identifier() . '_unit' => date::DATE_UNIT_WEEK,
 211          ]);
 212  
 213          $matchingusers = $DB->get_fieldset_select('user', 'username', $select, $params);
 214          $this->assertNotContains($user->username, $matchingusers);
 215      }
 216  
 217      /**
 218       * Data provider for {@see test_get_sql_filter_relative}
 219       *
 220       * @return array
 221       */
 222      public function get_sql_filter_relative_provider(): array {
 223          return [
 224              'Last day' => [date::DATE_LAST, 1, date::DATE_UNIT_DAY, '-6 hour'],
 225              'Last week' => [date::DATE_LAST, 1, date::DATE_UNIT_WEEK, '-3 day'],
 226              'Last month' => [date::DATE_LAST, 1, date::DATE_UNIT_MONTH, '-3 week'],
 227              'Last year' => [date::DATE_LAST, 1, date::DATE_UNIT_YEAR, '-6 month'],
 228              'Last two days' => [date::DATE_LAST, 2, date::DATE_UNIT_DAY, '-25 hour'],
 229              'Last two weeks' => [date::DATE_LAST, 2, date::DATE_UNIT_WEEK, '-10 day'],
 230              'Last two months' => [date::DATE_LAST, 2, date::DATE_UNIT_MONTH, '-7 week'],
 231              'Last two years' => [date::DATE_LAST, 2, date::DATE_UNIT_YEAR, '-15 month'],
 232  
 233              // Current week is tested separately.
 234              'Current day' => [date::DATE_CURRENT, null, date::DATE_UNIT_DAY],
 235              'Current month' => [date::DATE_CURRENT, null, date::DATE_UNIT_MONTH],
 236              'Current year' => [date::DATE_CURRENT, null, date::DATE_UNIT_YEAR],
 237  
 238              'Next day' => [date::DATE_NEXT, 1, date::DATE_UNIT_DAY, '+6 hour'],
 239              'Next week' => [date::DATE_NEXT, 1, date::DATE_UNIT_WEEK, '+3 day'],
 240              'Next month' => [date::DATE_NEXT, 1, date::DATE_UNIT_MONTH, '+3 week'],
 241              'Next year' => [date::DATE_NEXT, 1, date::DATE_UNIT_YEAR, '+6 month'],
 242              'Next two days' => [date::DATE_NEXT, 2, date::DATE_UNIT_DAY, '+25 hour'],
 243              'Next two weeks' => [date::DATE_NEXT, 2, date::DATE_UNIT_WEEK, '+10 day'],
 244              'Next two months' => [date::DATE_NEXT, 2, date::DATE_UNIT_MONTH, '+7 week'],
 245              'Next two years' => [date::DATE_NEXT, 2, date::DATE_UNIT_YEAR, '+15 month'],
 246          ];
 247      }
 248  
 249      /**
 250       * Unit tests for filtering relative dates
 251       *
 252       * @param int $operator
 253       * @param int|null $unitvalue
 254       * @param int $unit
 255       * @param string|null $timecreated Relative time suitable for passing to {@see strtotime} (or null for current time)
 256       *
 257       * @dataProvider get_sql_filter_relative_provider
 258       */
 259      public function test_get_sql_filter_relative(int $operator, ?int $unitvalue, int $unit, ?string $timecreated = null): void {
 260          global $DB;
 261  
 262          $this->resetAfterTest();
 263  
 264          $usertimecreated = ($timecreated !== null ? strtotime($timecreated) : time());
 265          $user = $this->getDataGenerator()->create_user(['timecreated' => $usertimecreated]);
 266  
 267          $filter = new filter(
 268              date::class,
 269              'test',
 270              new lang_string('yes'),
 271              'testentity',
 272              'timecreated'
 273          );
 274  
 275          [$select, $params] = date::create($filter)->get_sql_filter([
 276              $filter->get_unique_identifier() . '_operator' => $operator,
 277              $filter->get_unique_identifier() . '_value' => $unitvalue,
 278              $filter->get_unique_identifier() . '_unit' => $unit,
 279          ]);
 280  
 281          $matchingusers = $DB->get_fieldset_select('user', 'username', $select, $params);
 282          $this->assertContains($user->username, $matchingusers);
 283      }
 284  }