Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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  /**
  18   * Unit tests for the date condition.
  19   *
  20   * @package availability_date
  21   * @copyright 2014 The Open University
  22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  use availability_date\condition;
  28  use core_availability\tree;
  29  
  30  /**
  31   * Unit tests for the date condition.
  32   *
  33   * @package availability_date
  34   * @copyright 2014 The Open University
  35   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class availability_date_condition_testcase extends advanced_testcase {
  38      /**
  39       * Load required classes.
  40       */
  41      public function setUp(): void {
  42          // Load the mock info class so that it can be used.
  43          global $CFG;
  44          require_once($CFG->dirroot . '/availability/tests/fixtures/mock_info.php');
  45      }
  46  
  47      /**
  48       * Tests constructing and using date condition as part of tree.
  49       */
  50      public function test_in_tree() {
  51          global $SITE, $USER, $CFG;
  52          $this->resetAfterTest();
  53          $this->setAdminUser();
  54  
  55          // Set server timezone for test. (Important as otherwise the timezone
  56          // could be anything - this is modified by other unit tests, too.)
  57          $this->setTimezone('UTC');
  58  
  59          // SEt user to GMT+5.
  60          $USER->timezone = 5;
  61  
  62          // Construct tree with date condition.
  63          $time = strtotime('2014-02-18 14:20:00 GMT');
  64          $structure = (object)array('op' => '|', 'show' => true, 'c' => array(
  65                  (object)array('type' => 'date', 'd' => '>=', 't' => $time)));
  66          $tree = new \core_availability\tree($structure);
  67          $info = new \core_availability\mock_info();
  68  
  69          // Check if available (when not available).
  70          condition::set_current_time_for_test($time - 1);
  71          $information = '';
  72          $result = $tree->check_available(false, $info, true, $USER->id);
  73          $this->assertFalse($result->is_available());
  74          $information = $tree->get_result_information($info, $result);
  75  
  76          // Note: PM is normally upper-case, but an issue with PHP on Mac means
  77          // that on that platform, it is reported lower-case.
  78          $this->assertRegExp('~from.*18 February 2014, 7:20 (PM|pm)~', $information);
  79  
  80          // Check if available (when available).
  81          condition::set_current_time_for_test($time);
  82          $result = $tree->check_available(false, $info, true, $USER->id);
  83          $this->assertTrue($result->is_available());
  84          $information = $tree->get_result_information($info, $result);
  85          $this->assertEquals('', $information);
  86      }
  87  
  88      /**
  89       * Tests the constructor including error conditions. Also tests the
  90       * string conversion feature (intended for debugging only).
  91       */
  92      public function test_constructor() {
  93          // No parameters.
  94          $structure = (object)array();
  95          try {
  96              $date = new condition($structure);
  97              $this->fail();
  98          } catch (coding_exception $e) {
  99              $this->assertStringContainsString('Missing or invalid ->d', $e->getMessage());
 100          }
 101  
 102          // Invalid ->d.
 103          $structure->d = 'woo hah!!';
 104          try {
 105              $date = new condition($structure);
 106              $this->fail();
 107          } catch (coding_exception $e) {
 108              $this->assertStringContainsString('Missing or invalid ->d', $e->getMessage());
 109          }
 110  
 111          // Missing ->t.
 112          $structure->d = '>=';
 113          try {
 114              $date = new condition($structure);
 115              $this->fail();
 116          } catch (coding_exception $e) {
 117              $this->assertStringContainsString('Missing or invalid ->t', $e->getMessage());
 118          }
 119  
 120          // Invalid ->t.
 121          $structure->t = 'got you all in check';
 122          try {
 123              $date = new condition($structure);
 124              $this->fail();
 125          } catch (coding_exception $e) {
 126              $this->assertStringContainsString('Missing or invalid ->t', $e->getMessage());
 127          }
 128  
 129          // Valid conditions of both types.
 130          $structure = (object)array('d' => '>=', 't' => strtotime('2014-02-18 14:43:17 GMT'));
 131          $date = new condition($structure);
 132          $this->assertEquals('{date:>= 2014-02-18 14:43:17}', (string)$date);
 133          $structure->d = '<';
 134          $date = new condition($structure);
 135          $this->assertEquals('{date:< 2014-02-18 14:43:17}', (string)$date);
 136      }
 137  
 138      /**
 139       * Tests the save() function.
 140       */
 141      public function test_save() {
 142          $structure = (object)array('d' => '>=', 't' => 12345);
 143          $cond = new condition($structure);
 144          $structure->type = 'date';
 145          $this->assertEquals($structure, $cond->save());
 146      }
 147  
 148      /**
 149       * Tests the is_available() and is_available_to_all() functions.
 150       */
 151      public function test_is_available() {
 152          global $SITE, $USER;
 153  
 154          $time = strtotime('2014-02-18 14:50:10 GMT');
 155          $info = new \core_availability\mock_info();
 156  
 157          // Test with >=.
 158          $date = new condition((object)array('d' => '>=', 't' => $time));
 159          condition::set_current_time_for_test($time - 1);
 160          $this->assertFalse($date->is_available(false, $info, true, $USER->id));
 161          condition::set_current_time_for_test($time);
 162          $this->assertTrue($date->is_available(false, $info, true, $USER->id));
 163  
 164          // Test with <.
 165          $date = new condition((object)array('d' => '<', 't' => $time));
 166          condition::set_current_time_for_test($time);
 167          $this->assertFalse($date->is_available(false, $info, true, $USER->id));
 168          condition::set_current_time_for_test($time - 1);
 169          $this->assertTrue($date->is_available(false, $info, true, $USER->id));
 170  
 171          // Repeat this test with is_available_to_all() - it should be the same.
 172          $date = new condition((object)array('d' => '<', 't' => $time));
 173          condition::set_current_time_for_test($time);
 174          $this->assertFalse($date->is_available_for_all(false));
 175          condition::set_current_time_for_test($time - 1);
 176          $this->assertTrue($date->is_available_for_all(false));
 177      }
 178  
 179      /**
 180       * Tests the get_description and get_standalone_description functions.
 181       */
 182      public function test_get_description() {
 183          global $SITE, $CFG;
 184  
 185          $this->resetAfterTest();
 186          $this->setTimezone('UTC');
 187  
 188          $modinfo = get_fast_modinfo($SITE);
 189          $info = new \core_availability\mock_info();
 190          $time = strtotime('2014-02-18 14:55:01 GMT');
 191  
 192          // Test with >=.
 193          $date = new condition((object)array('d' => '>=', 't' => $time));
 194          $information = $date->get_description(true, false, $info);
 195          $this->assertRegExp('~after.*18 February 2014, 2:55 (PM|pm)~', $information);
 196          $information = $date->get_description(true, true, $info);
 197          $this->assertRegExp('~before.*18 February 2014, 2:55 (PM|pm)~', $information);
 198          $information = $date->get_standalone_description(true, false, $info);
 199          $this->assertRegExp('~from.*18 February 2014, 2:55 (PM|pm)~', $information);
 200          $information = $date->get_standalone_description(true, true, $info);
 201          $this->assertRegExp('~until.*18 February 2014, 2:55 (PM|pm)~', $information);
 202  
 203          // Test with <.
 204          $date = new condition((object)array('d' => '<', 't' => $time));
 205          $information = $date->get_description(true, false, $info);
 206          $this->assertRegExp('~before.*18 February 2014, 2:55 (PM|pm)~', $information);
 207          $information = $date->get_description(true, true, $info);
 208          $this->assertRegExp('~after.*18 February 2014, 2:55 (PM|pm)~', $information);
 209          $information = $date->get_standalone_description(true, false, $info);
 210          $this->assertRegExp('~until.*18 February 2014, 2:55 (PM|pm)~', $information);
 211          $information = $date->get_standalone_description(true, true, $info);
 212          $this->assertRegExp('~from.*18 February 2014, 2:55 (PM|pm)~', $information);
 213  
 214          // Test special case for dates that are midnight.
 215          $date = new condition((object)array('d' => '>=',
 216                  't' => strtotime('2014-03-05 00:00 GMT')));
 217          $information = $date->get_description(true, false, $info);
 218          $this->assertRegExp('~on or after.*5 March 2014([^0-9]*)$~', $information);
 219          $information = $date->get_description(true, true, $info);
 220          $this->assertRegExp('~before.*end of.*4 March 2014([^0-9]*)$~', $information);
 221          $information = $date->get_standalone_description(true, false, $info);
 222          $this->assertRegExp('~from.*5 March 2014([^0-9]*)$~', $information);
 223          $information = $date->get_standalone_description(true, true, $info);
 224          $this->assertRegExp('~until end of.*4 March 2014([^0-9]*)$~', $information);
 225  
 226          // In the 'until' case for midnight, it shows the previous day. (I.e.
 227          // if the date is 5 March 00:00, then we show it as available until 4
 228          // March, implying 'the end of'.)
 229          $date = new condition((object)array('d' => '<',
 230                  't' => strtotime('2014-03-05 00:00 GMT')));
 231          $information = $date->get_description(true, false, $info);
 232          $this->assertRegExp('~before end of.*4 March 2014([^0-9]*)$~', $information);
 233          $information = $date->get_description(true, true, $info);
 234          $this->assertRegExp('~on or after.*5 March 2014([^0-9]*)$~', $information);
 235          $information = $date->get_standalone_description(true, false, $info);
 236          $this->assertRegExp('~until end of.*4 March 2014([^0-9]*)$~', $information);
 237          $information = $date->get_standalone_description(true, true, $info);
 238          $this->assertRegExp('~from.*5 March 2014([^0-9]*)$~', $information);
 239      }
 240  
 241      /**
 242       * Tests the update_all_dates function.
 243       */
 244      public function test_update_all_dates() {
 245          global $DB;
 246          $this->resetAfterTest();
 247  
 248          // Create a course with 3 pages.
 249          $generator = $this->getDataGenerator();
 250          $course = $generator->create_course();
 251          $rec = array('course' => $course);
 252          $page1 = $generator->get_plugin_generator('mod_page')->create_instance($rec);
 253          $page2 = $generator->get_plugin_generator('mod_page')->create_instance($rec);
 254          $page3 = $generator->get_plugin_generator('mod_page')->create_instance($rec);
 255  
 256          // Set the availability page 2 to a simple date condition. You can access
 257          // it from 1337 onwards.
 258          $simplecondition = tree::get_root_json(array(
 259                  condition::get_json(condition::DIRECTION_FROM, 1337)));
 260          $DB->set_field('course_modules', 'availability',
 261                  json_encode($simplecondition), array('id' => $page2->cmid));
 262  
 263          // Set page 3 to a complex set of conditions including a nested date condition.
 264          // You can access it until 1459, *or* after 2810 if you belong to a group.
 265          $complexcondition = tree::get_root_json(array(
 266                  condition::get_json(condition::DIRECTION_UNTIL, 1459),
 267                  tree::get_nested_json(array(
 268                      condition::get_json(condition::DIRECTION_FROM, 2810),
 269                      \availability_group\condition::get_json()))),
 270                  tree::OP_OR);
 271          $DB->set_field('course_modules', 'availability',
 272                  json_encode($complexcondition), array('id' => $page3->cmid));
 273  
 274          // Now use the update_all_dates function to move date forward 100000.
 275          condition::update_all_dates($course->id, 100000);
 276  
 277          // Get the expected conditions after adjusting time, and compare to database.
 278          $simplecondition->c[0]->t = 101337;
 279          $complexcondition->c[0]->t = 101459;
 280          $complexcondition->c[1]->c[0]->t = 102810;
 281          $this->assertEquals($simplecondition, json_decode(
 282                  $DB->get_field('course_modules', 'availability', array('id' => $page2->cmid))));
 283          $this->assertEquals($complexcondition, json_decode(
 284                  $DB->get_field('course_modules', 'availability', array('id' => $page3->cmid))));
 285  
 286          // The one without availability conditions should still be null.
 287          $this->assertNull($DB->get_field('course_modules', 'availability', array('id' => $page1->cmid)));
 288      }
 289  }