[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/tests/ -> moodlelib_test.php (source)

   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 (some of) ../moodlelib.php.
  19   *
  20   * @package    core
  21   * @category   phpunit
  22   * @copyright  &copy; 2006 The Open University
  23   * @author     [email protected]
  24   * @author     [email protected]
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  class core_moodlelib_testcase extends advanced_testcase {
  30  
  31      public static $includecoverage = array('lib/moodlelib.php');
  32  
  33      /**
  34       * Define a local decimal separator.
  35       *
  36       * It is not possible to directly change the result of get_string in
  37       * a unit test. Instead, we create a language pack for language 'xx' in
  38       * dataroot and make langconfig.php with the string we need to change.
  39       * The example separator used here is 'X'; on PHP 5.3 and before this
  40       * must be a single byte character due to PHP bug/limitation in
  41       * number_format, so you can't use UTF-8 characters.
  42       */
  43      protected function define_local_decimal_separator() {
  44          global $SESSION, $CFG;
  45  
  46          $SESSION->lang = 'xx';
  47          $langconfig = "<?php\n\$string['decsep'] = 'X';";
  48          $langfolder = $CFG->dataroot . '/lang/xx';
  49          check_dir_exists($langfolder);
  50          file_put_contents($langfolder . '/langconfig.php', $langconfig);
  51      }
  52  
  53      public function test_cleanremoteaddr() {
  54          // IPv4.
  55          $this->assertNull(cleanremoteaddr('1023.121.234.1'));
  56          $this->assertSame('123.121.234.1', cleanremoteaddr('123.121.234.01 '));
  57  
  58          // IPv6.
  59          $this->assertNull(cleanremoteaddr('0:0:0:0:0:0:0:0:0'));
  60          $this->assertNull(cleanremoteaddr('0:0:0:0:0:0:0:abh'));
  61          $this->assertNull(cleanremoteaddr('0:0:0:::0:0:1'));
  62          $this->assertSame('::', cleanremoteaddr('0:0:0:0:0:0:0:0', true));
  63          $this->assertSame('::1:1', cleanremoteaddr('0:0:0:0:0:0:1:1', true));
  64          $this->assertSame('abcd:ef::', cleanremoteaddr('abcd:00ef:0:0:0:0:0:0', true));
  65          $this->assertSame('1::1', cleanremoteaddr('1:0:0:0:0:0:0:1', true));
  66          $this->assertSame('0:0:0:0:0:0:10:1', cleanremoteaddr('::10:1', false));
  67          $this->assertSame('1:1:0:0:0:0:0:0', cleanremoteaddr('01:1::', false));
  68          $this->assertSame('10:0:0:0:0:0:0:10', cleanremoteaddr('10::10', false));
  69          $this->assertSame('::ffff:c0a8:11', cleanremoteaddr('::ffff:192.168.1.1', true));
  70      }
  71  
  72      public function test_address_in_subnet() {
  73          // 1: xxx.xxx.xxx.xxx/nn or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/nnn (number of bits in net mask).
  74          $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.1/32'));
  75          $this->assertFalse(address_in_subnet('123.121.23.1', '123.121.23.0/32'));
  76          $this->assertTrue(address_in_subnet('10.10.10.100',  '123.121.23.45/0'));
  77          $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/24'));
  78          $this->assertFalse(address_in_subnet('123.121.34.1', '123.121.234.0/24'));
  79          $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/30'));
  80          $this->assertFalse(address_in_subnet('123.121.23.8', '123.121.23.0/30'));
  81          $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128'));
  82          $this->assertFalse(address_in_subnet('bab:baba::baba', 'bab:baba::cece/128'));
  83          $this->assertTrue(address_in_subnet('baba:baba::baba', 'cece:cece::cece/0'));
  84          $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128'));
  85          $this->assertTrue(address_in_subnet('baba:baba::00ba', 'baba:baba::/120'));
  86          $this->assertFalse(address_in_subnet('baba:baba::aba', 'baba:baba::/120'));
  87          $this->assertTrue(address_in_subnet('baba::baba:00ba', 'baba::baba:0/112'));
  88          $this->assertFalse(address_in_subnet('baba::aba:00ba', 'baba::baba:0/112'));
  89          $this->assertFalse(address_in_subnet('aba::baba:0000', 'baba::baba:0/112'));
  90  
  91          // Fixed input.
  92          $this->assertTrue(address_in_subnet('123.121.23.1   ', ' 123.121.23.0 / 24'));
  93          $this->assertTrue(address_in_subnet('::ffff:10.1.1.1', ' 0:0:0:000:0:ffff:a1:10 / 126'));
  94  
  95          // Incorrect input.
  96          $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/-2'));
  97          $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/64'));
  98          $this->assertFalse(address_in_subnet('123.121.234.x', '123.121.234.1/24'));
  99          $this->assertFalse(address_in_subnet('123.121.234.0', '123.121.234.xx/24'));
 100          $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/xx0'));
 101          $this->assertFalse(address_in_subnet('::1', '::aa:0/xx0'));
 102          $this->assertFalse(address_in_subnet('::1', '::aa:0/-5'));
 103          $this->assertFalse(address_in_subnet('::1', '::aa:0/130'));
 104          $this->assertFalse(address_in_subnet('x:1', '::aa:0/130'));
 105          $this->assertFalse(address_in_subnet('::1', '::ax:0/130'));
 106  
 107          // 2: xxx.xxx.xxx.xxx-yyy or  xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::xxxx-yyyy (a range of IP addresses in the last group).
 108          $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12-14'));
 109          $this->assertTrue(address_in_subnet('123.121.234.13', '123.121.234.12-14'));
 110          $this->assertTrue(address_in_subnet('123.121.234.14', '123.121.234.12-14'));
 111          $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.12-14'));
 112          $this->assertFalse(address_in_subnet('123.121.234.20', '123.121.234.12-14'));
 113          $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.234.12-14'));
 114          $this->assertFalse(address_in_subnet('123.12.234.12', '123.121.234.12-14'));
 115          $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba-babe'));
 116          $this->assertTrue(address_in_subnet('baba:baba::babc', 'baba:baba::baba-babe'));
 117          $this->assertTrue(address_in_subnet('baba:baba::babe', 'baba:baba::baba-babe'));
 118          $this->assertFalse(address_in_subnet('bab:baba::bab0', 'bab:baba::baba-babe'));
 119          $this->assertFalse(address_in_subnet('bab:baba::babf', 'bab:baba::baba-babe'));
 120          $this->assertFalse(address_in_subnet('bab:baba::bfbe', 'bab:baba::baba-babe'));
 121          $this->assertFalse(address_in_subnet('bfb:baba::babe', 'bab:baba::baba-babe'));
 122  
 123          // Fixed input.
 124          $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12 - 14 '));
 125          $this->assertTrue(address_in_subnet('bab:baba::babe', 'bab:baba::baba - babe  '));
 126  
 127          // Incorrect input.
 128          $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-234.14'));
 129          $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-256'));
 130          $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12--256'));
 131  
 132          // 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx. (incomplete address, a bit non-technical ;-).
 133          $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12'));
 134          $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.23.13'));
 135          $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.'));
 136          $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234'));
 137          $this->assertTrue(address_in_subnet('123.121.234.12', '123.121'));
 138          $this->assertTrue(address_in_subnet('123.121.234.12', '123'));
 139          $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234.'));
 140          $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234'));
 141          $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba::bab'));
 142          $this->assertFalse(address_in_subnet('baba:baba::ba', 'baba:baba::bc'));
 143          $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba'));
 144          $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:'));
 145          $this->assertFalse(address_in_subnet('bab:baba::bab', 'baba:'));
 146  
 147          // Multiple subnets.
 148          $this->assertTrue(address_in_subnet('123.121.234.12', '::1/64, 124., 123.121.234.10-30'));
 149          $this->assertTrue(address_in_subnet('124.121.234.12', '::1/64, 124., 123.121.234.10-30'));
 150          $this->assertTrue(address_in_subnet('::2',            '::1/64, 124., 123.121.234.10-30'));
 151          $this->assertFalse(address_in_subnet('12.121.234.12', '::1/64, 124., 123.121.234.10-30'));
 152  
 153          // Other incorrect input.
 154          $this->assertFalse(address_in_subnet('123.123.123.123', ''));
 155      }
 156  
 157      public function test_fix_utf8() {
 158          // Make sure valid data including other types is not changed.
 159          $this->assertSame(null, fix_utf8(null));
 160          $this->assertSame(1, fix_utf8(1));
 161          $this->assertSame(1.1, fix_utf8(1.1));
 162          $this->assertSame(true, fix_utf8(true));
 163          $this->assertSame('', fix_utf8(''));
 164          $this->assertSame('abc', fix_utf8('abc'));
 165          $array = array('do', 're', 'mi');
 166          $this->assertSame($array, fix_utf8($array));
 167          $object = new stdClass();
 168          $object->a = 'aa';
 169          $object->b = 'bb';
 170          $this->assertEquals($object, fix_utf8($object));
 171  
 172          // valid utf8 string
 173          $this->assertSame("žlutý koníček přeskočil potůček \n\t\r", fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
 174  
 175          // Invalid utf8 string.
 176          $this->assertSame('aš', fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
 177      }
 178  
 179      public function test_optional_param() {
 180          global $CFG;
 181  
 182          $_POST['username'] = 'post_user';
 183          $_GET['username'] = 'get_user';
 184          $this->assertSame($_POST['username'], optional_param('username', 'default_user', PARAM_RAW));
 185  
 186          unset($_POST['username']);
 187          $this->assertSame($_GET['username'], optional_param('username', 'default_user', PARAM_RAW));
 188  
 189          unset($_GET['username']);
 190          $this->assertSame('default_user', optional_param('username', 'default_user', PARAM_RAW));
 191  
 192          // Make sure exception is triggered when some params are missing, hide error notices here - new in 2.2.
 193          $_POST['username'] = 'post_user';
 194          try {
 195              optional_param('username', 'default_user', null);
 196              $this->fail('coding_exception expected');
 197          } catch (moodle_exception $ex) {
 198              $this->assertInstanceOf('coding_exception', $ex);
 199          }
 200          try {
 201              @optional_param('username', 'default_user');
 202              $this->fail('coding_exception expected');
 203          } catch (moodle_exception $ex) {
 204              $this->assertInstanceOf('coding_exception', $ex);
 205          }
 206          try {
 207              @optional_param('username');
 208              $this->fail('coding_exception expected');
 209          } catch (moodle_exception $ex) {
 210              $this->assertInstanceOf('coding_exception', $ex);
 211          }
 212          try {
 213              optional_param('', 'default_user', PARAM_RAW);
 214              $this->fail('coding_exception expected');
 215          } catch (moodle_exception $ex) {
 216              $this->assertInstanceOf('coding_exception', $ex);
 217          }
 218  
 219          // Make sure warning is displayed if array submitted - TODO: throw exception in Moodle 2.3.
 220          $_POST['username'] = array('a'=>'a');
 221          $this->assertSame($_POST['username'], optional_param('username', 'default_user', PARAM_RAW));
 222          $this->assertDebuggingCalled();
 223      }
 224  
 225      public function test_optional_param_array() {
 226          global $CFG;
 227  
 228          $_POST['username'] = array('a'=>'post_user');
 229          $_GET['username'] = array('a'=>'get_user');
 230          $this->assertSame($_POST['username'], optional_param_array('username', array('a'=>'default_user'), PARAM_RAW));
 231  
 232          unset($_POST['username']);
 233          $this->assertSame($_GET['username'], optional_param_array('username', array('a'=>'default_user'), PARAM_RAW));
 234  
 235          unset($_GET['username']);
 236          $this->assertSame(array('a'=>'default_user'), optional_param_array('username', array('a'=>'default_user'), PARAM_RAW));
 237  
 238          // Make sure exception is triggered when some params are missing, hide error notices here - new in 2.2.
 239          $_POST['username'] = array('a'=>'post_user');
 240          try {
 241              optional_param_array('username', array('a'=>'default_user'), null);
 242              $this->fail('coding_exception expected');
 243          } catch (moodle_exception $ex) {
 244              $this->assertInstanceOf('coding_exception', $ex);
 245          }
 246          try {
 247              @optional_param_array('username', array('a'=>'default_user'));
 248              $this->fail('coding_exception expected');
 249          } catch (moodle_exception $ex) {
 250              $this->assertInstanceOf('coding_exception', $ex);
 251          }
 252          try {
 253              @optional_param_array('username');
 254              $this->fail('coding_exception expected');
 255          } catch (moodle_exception $ex) {
 256              $this->assertInstanceOf('coding_exception', $ex);
 257          }
 258          try {
 259              optional_param_array('', array('a'=>'default_user'), PARAM_RAW);
 260              $this->fail('coding_exception expected');
 261          } catch (moodle_exception $ex) {
 262              $this->assertInstanceOf('coding_exception', $ex);
 263          }
 264  
 265          // Do not allow nested arrays.
 266          try {
 267              $_POST['username'] = array('a'=>array('b'=>'post_user'));
 268              optional_param_array('username', array('a'=>'default_user'), PARAM_RAW);
 269              $this->fail('coding_exception expected');
 270          } catch (coding_exception $ex) {
 271              $this->assertTrue(true);
 272          }
 273  
 274          // Do not allow non-arrays.
 275          $_POST['username'] = 'post_user';
 276          $this->assertSame(array('a'=>'default_user'), optional_param_array('username', array('a'=>'default_user'), PARAM_RAW));
 277          $this->assertDebuggingCalled();
 278  
 279          // Make sure array keys are sanitised.
 280          $_POST['username'] = array('abc123_;-/*-+ '=>'arrggh', 'a1_-'=>'post_user');
 281          $this->assertSame(array('a1_-'=>'post_user'), optional_param_array('username', array(), PARAM_RAW));
 282          $this->assertDebuggingCalled();
 283      }
 284  
 285      public function test_required_param() {
 286          $_POST['username'] = 'post_user';
 287          $_GET['username'] = 'get_user';
 288          $this->assertSame('post_user', required_param('username', PARAM_RAW));
 289  
 290          unset($_POST['username']);
 291          $this->assertSame('get_user', required_param('username', PARAM_RAW));
 292  
 293          unset($_GET['username']);
 294          try {
 295              $this->assertSame('default_user', required_param('username', PARAM_RAW));
 296              $this->fail('moodle_exception expected');
 297          } catch (moodle_exception $ex) {
 298              $this->assertInstanceOf('moodle_exception', $ex);
 299          }
 300  
 301          // Make sure exception is triggered when some params are missing, hide error notices here - new in 2.2.
 302          $_POST['username'] = 'post_user';
 303          try {
 304              @required_param('username');
 305              $this->fail('coding_exception expected');
 306          } catch (moodle_exception $ex) {
 307              $this->assertInstanceOf('coding_exception', $ex);
 308          }
 309          try {
 310              required_param('username', '');
 311              $this->fail('coding_exception expected');
 312          } catch (moodle_exception $ex) {
 313              $this->assertInstanceOf('coding_exception', $ex);
 314          }
 315          try {
 316              required_param('', PARAM_RAW);
 317              $this->fail('coding_exception expected');
 318          } catch (moodle_exception $ex) {
 319              $this->assertInstanceOf('coding_exception', $ex);
 320          }
 321  
 322          // Make sure warning is displayed if array submitted - TODO: throw exception in Moodle 2.3.
 323          $_POST['username'] = array('a'=>'a');
 324          $this->assertSame($_POST['username'], required_param('username', PARAM_RAW));
 325          $this->assertDebuggingCalled();
 326      }
 327  
 328      public function test_required_param_array() {
 329          global $CFG;
 330  
 331          $_POST['username'] = array('a'=>'post_user');
 332          $_GET['username'] = array('a'=>'get_user');
 333          $this->assertSame($_POST['username'], required_param_array('username', PARAM_RAW));
 334  
 335          unset($_POST['username']);
 336          $this->assertSame($_GET['username'], required_param_array('username', PARAM_RAW));
 337  
 338          // Make sure exception is triggered when some params are missing, hide error notices here - new in 2.2.
 339          $_POST['username'] = array('a'=>'post_user');
 340          try {
 341              required_param_array('username', null);
 342              $this->fail('coding_exception expected');
 343          } catch (moodle_exception $ex) {
 344              $this->assertInstanceOf('coding_exception', $ex);
 345          }
 346          try {
 347              @required_param_array('username');
 348              $this->fail('coding_exception expected');
 349          } catch (moodle_exception $ex) {
 350              $this->assertInstanceOf('coding_exception', $ex);
 351          }
 352          try {
 353              required_param_array('', PARAM_RAW);
 354              $this->fail('coding_exception expected');
 355          } catch (moodle_exception $ex) {
 356              $this->assertInstanceOf('coding_exception', $ex);
 357          }
 358  
 359          // Do not allow nested arrays.
 360          try {
 361              $_POST['username'] = array('a'=>array('b'=>'post_user'));
 362              required_param_array('username', PARAM_RAW);
 363              $this->fail('coding_exception expected');
 364          } catch (moodle_exception $ex) {
 365              $this->assertInstanceOf('coding_exception', $ex);
 366          }
 367  
 368          // Do not allow non-arrays.
 369          try {
 370              $_POST['username'] = 'post_user';
 371              required_param_array('username', PARAM_RAW);
 372              $this->fail('moodle_exception expected');
 373          } catch (moodle_exception $ex) {
 374              $this->assertInstanceOf('moodle_exception', $ex);
 375          }
 376  
 377          // Make sure array keys are sanitised.
 378          $_POST['username'] = array('abc123_;-/*-+ '=>'arrggh', 'a1_-'=>'post_user');
 379          $this->assertSame(array('a1_-'=>'post_user'), required_param_array('username', PARAM_RAW));
 380          $this->assertDebuggingCalled();
 381      }
 382  
 383      public function test_clean_param() {
 384          // Forbid objects and arrays.
 385          try {
 386              clean_param(array('x', 'y'), PARAM_RAW);
 387              $this->fail('coding_exception expected');
 388          } catch (moodle_exception $ex) {
 389              $this->assertInstanceOf('coding_exception', $ex);
 390          }
 391          try {
 392              $param = new stdClass();
 393              $param->id = 1;
 394              clean_param($param, PARAM_RAW);
 395              $this->fail('coding_exception expected');
 396          } catch (moodle_exception $ex) {
 397              $this->assertInstanceOf('coding_exception', $ex);
 398          }
 399  
 400          // Require correct type.
 401          try {
 402              clean_param('x', 'xxxxxx');
 403              $this->fail('moodle_exception expected');
 404          } catch (moodle_exception $ex) {
 405              $this->assertInstanceOf('moodle_exception', $ex);
 406          }
 407          try {
 408              @clean_param('x');
 409              $this->fail('moodle_exception expected');
 410          } catch (moodle_exception $ex) {
 411              $this->assertInstanceOf('moodle_exception', $ex);
 412          }
 413      }
 414  
 415      public function test_clean_param_array() {
 416          $this->assertSame(array(), clean_param_array(null, PARAM_RAW));
 417          $this->assertSame(array('a', 'b'), clean_param_array(array('a', 'b'), PARAM_RAW));
 418          $this->assertSame(array('a', array('b')), clean_param_array(array('a', array('b')), PARAM_RAW, true));
 419  
 420          // Require correct type.
 421          try {
 422              clean_param_array(array('x'), 'xxxxxx');
 423              $this->fail('moodle_exception expected');
 424          } catch (moodle_exception $ex) {
 425              $this->assertInstanceOf('moodle_exception', $ex);
 426          }
 427          try {
 428              @clean_param_array(array('x'));
 429              $this->fail('moodle_exception expected');
 430          } catch (moodle_exception $ex) {
 431              $this->assertInstanceOf('moodle_exception', $ex);
 432          }
 433  
 434          try {
 435              clean_param_array(array('x', array('y')), PARAM_RAW);
 436              $this->fail('coding_exception expected');
 437          } catch (moodle_exception $ex) {
 438              $this->assertInstanceOf('coding_exception', $ex);
 439          }
 440  
 441          // Test recursive.
 442      }
 443  
 444      public function test_clean_param_raw() {
 445          $this->assertSame(
 446              '#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)',
 447              clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_RAW));
 448      }
 449  
 450      public function test_clean_param_trim() {
 451          $this->assertSame('Frog toad', clean_param("   Frog toad   \r\n  ", PARAM_RAW_TRIMMED));
 452      }
 453  
 454      public function test_clean_param_clean() {
 455          // PARAM_CLEAN is an ugly hack, do not use in new code (skodak),
 456          // instead use more specific type, or submit sothing that can be verified properly.
 457          $this->assertSame('xx', clean_param('xx<script>', PARAM_CLEAN));
 458      }
 459  
 460      public function test_clean_param_alpha() {
 461          $this->assertSame('DSFMOSDJ', clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHA));
 462      }
 463  
 464      public function test_clean_param_alphanum() {
 465          $this->assertSame('978942897DSFMOSDJ', clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHANUM));
 466      }
 467  
 468      public function test_clean_param_alphaext() {
 469          $this->assertSame('DSFMOSDJ', clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHAEXT));
 470      }
 471  
 472      public function test_clean_param_sequence() {
 473          $this->assertSame(',9789,42897', clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_SEQUENCE));
 474      }
 475  
 476      public function test_clean_param_component() {
 477          // Please note the cleaning of component names is very strict, no guessing here.
 478          $this->assertSame('mod_forum', clean_param('mod_forum', PARAM_COMPONENT));
 479          $this->assertSame('block_online_users', clean_param('block_online_users', PARAM_COMPONENT));
 480          $this->assertSame('block_blond_online_users', clean_param('block_blond_online_users', PARAM_COMPONENT));
 481          $this->assertSame('mod_something2', clean_param('mod_something2', PARAM_COMPONENT));
 482          $this->assertSame('forum', clean_param('forum', PARAM_COMPONENT));
 483          $this->assertSame('user', clean_param('user', PARAM_COMPONENT));
 484          $this->assertSame('rating', clean_param('rating', PARAM_COMPONENT));
 485          $this->assertSame('feedback360', clean_param('feedback360', PARAM_COMPONENT));
 486          $this->assertSame('mod_feedback360', clean_param('mod_feedback360', PARAM_COMPONENT));
 487          $this->assertSame('', clean_param('mod_2something', PARAM_COMPONENT));
 488          $this->assertSame('', clean_param('2mod_something', PARAM_COMPONENT));
 489          $this->assertSame('', clean_param('mod_something_xx', PARAM_COMPONENT));
 490          $this->assertSame('', clean_param('auth_something__xx', PARAM_COMPONENT));
 491          $this->assertSame('', clean_param('mod_Something', PARAM_COMPONENT));
 492          $this->assertSame('', clean_param('mod_somethíng', PARAM_COMPONENT));
 493          $this->assertSame('', clean_param('mod__something', PARAM_COMPONENT));
 494          $this->assertSame('', clean_param('auth_xx-yy', PARAM_COMPONENT));
 495          $this->assertSame('', clean_param('_auth_xx', PARAM_COMPONENT));
 496          $this->assertSame('', clean_param('a2uth_xx', PARAM_COMPONENT));
 497          $this->assertSame('', clean_param('auth_xx_', PARAM_COMPONENT));
 498          $this->assertSame('', clean_param('auth_xx.old', PARAM_COMPONENT));
 499          $this->assertSame('', clean_param('_user', PARAM_COMPONENT));
 500          $this->assertSame('', clean_param('2rating', PARAM_COMPONENT));
 501          $this->assertSame('', clean_param('user_', PARAM_COMPONENT));
 502      }
 503  
 504      public function test_is_valid_plugin_name() {
 505          $this->assertTrue(is_valid_plugin_name('forum'));
 506          $this->assertTrue(is_valid_plugin_name('forum2'));
 507          $this->assertTrue(is_valid_plugin_name('feedback360'));
 508          $this->assertTrue(is_valid_plugin_name('online_users'));
 509          $this->assertTrue(is_valid_plugin_name('blond_online_users'));
 510          $this->assertFalse(is_valid_plugin_name('online__users'));
 511          $this->assertFalse(is_valid_plugin_name('forum '));
 512          $this->assertFalse(is_valid_plugin_name('forum.old'));
 513          $this->assertFalse(is_valid_plugin_name('xx-yy'));
 514          $this->assertFalse(is_valid_plugin_name('2xx'));
 515          $this->assertFalse(is_valid_plugin_name('Xx'));
 516          $this->assertFalse(is_valid_plugin_name('_xx'));
 517          $this->assertFalse(is_valid_plugin_name('xx_'));
 518      }
 519  
 520      public function test_clean_param_plugin() {
 521          // Please note the cleaning of plugin names is very strict, no guessing here.
 522          $this->assertSame('forum', clean_param('forum', PARAM_PLUGIN));
 523          $this->assertSame('forum2', clean_param('forum2', PARAM_PLUGIN));
 524          $this->assertSame('feedback360', clean_param('feedback360', PARAM_PLUGIN));
 525          $this->assertSame('online_users', clean_param('online_users', PARAM_PLUGIN));
 526          $this->assertSame('blond_online_users', clean_param('blond_online_users', PARAM_PLUGIN));
 527          $this->assertSame('', clean_param('online__users', PARAM_PLUGIN));
 528          $this->assertSame('', clean_param('forum ', PARAM_PLUGIN));
 529          $this->assertSame('', clean_param('forum.old', PARAM_PLUGIN));
 530          $this->assertSame('', clean_param('xx-yy', PARAM_PLUGIN));
 531          $this->assertSame('', clean_param('2xx', PARAM_PLUGIN));
 532          $this->assertSame('', clean_param('Xx', PARAM_PLUGIN));
 533          $this->assertSame('', clean_param('_xx', PARAM_PLUGIN));
 534          $this->assertSame('', clean_param('xx_', PARAM_PLUGIN));
 535      }
 536  
 537      public function test_clean_param_area() {
 538          // Please note the cleaning of area names is very strict, no guessing here.
 539          $this->assertSame('something', clean_param('something', PARAM_AREA));
 540          $this->assertSame('something2', clean_param('something2', PARAM_AREA));
 541          $this->assertSame('some_thing', clean_param('some_thing', PARAM_AREA));
 542          $this->assertSame('some_thing_xx', clean_param('some_thing_xx', PARAM_AREA));
 543          $this->assertSame('feedback360', clean_param('feedback360', PARAM_AREA));
 544          $this->assertSame('', clean_param('_something', PARAM_AREA));
 545          $this->assertSame('', clean_param('something_', PARAM_AREA));
 546          $this->assertSame('', clean_param('2something', PARAM_AREA));
 547          $this->assertSame('', clean_param('Something', PARAM_AREA));
 548          $this->assertSame('', clean_param('some-thing', PARAM_AREA));
 549          $this->assertSame('', clean_param('somethííng', PARAM_AREA));
 550          $this->assertSame('', clean_param('something.x', PARAM_AREA));
 551      }
 552  
 553      public function test_clean_param_text() {
 554          $this->assertSame(PARAM_TEXT, PARAM_MULTILANG);
 555          // Standard.
 556          $this->assertSame('xx<lang lang="en">aa</lang><lang lang="yy">pp</lang>', clean_param('xx<lang lang="en">aa</lang><lang lang="yy">pp</lang>', PARAM_TEXT));
 557          $this->assertSame('<span lang="en" class="multilang">aa</span><span lang="xy" class="multilang">bb</span>', clean_param('<span lang="en" class="multilang">aa</span><span lang="xy" class="multilang">bb</span>', PARAM_TEXT));
 558          $this->assertSame('xx<lang lang="en">aa'."\n".'</lang><lang lang="yy">pp</lang>', clean_param('xx<lang lang="en">aa'."\n".'</lang><lang lang="yy">pp</lang>', PARAM_TEXT));
 559          // Malformed.
 560          $this->assertSame('<span lang="en" class="multilang">aa</span>', clean_param('<span lang="en" class="multilang">aa</span>', PARAM_TEXT));
 561          $this->assertSame('aa', clean_param('<span lang="en" class="nothing" class="multilang">aa</span>', PARAM_TEXT));
 562          $this->assertSame('aa', clean_param('<lang lang="en" class="multilang">aa</lang>', PARAM_TEXT));
 563          $this->assertSame('aa', clean_param('<lang lang="en!!">aa</lang>', PARAM_TEXT));
 564          $this->assertSame('aa', clean_param('<span lang="en==" class="multilang">aa</span>', PARAM_TEXT));
 565          $this->assertSame('abc', clean_param('a<em>b</em>c', PARAM_TEXT));
 566          $this->assertSame('a>c>', clean_param('a><xx >c>', PARAM_TEXT)); // Standard strip_tags() behaviour.
 567          $this->assertSame('a', clean_param('a<b', PARAM_TEXT));
 568          $this->assertSame('a>b', clean_param('a>b', PARAM_TEXT));
 569          $this->assertSame('<lang lang="en">a>a</lang>', clean_param('<lang lang="en">a>a</lang>', PARAM_TEXT)); // Standard strip_tags() behaviour.
 570          $this->assertSame('a', clean_param('<lang lang="en">a<a</lang>', PARAM_TEXT));
 571          $this->assertSame('<lang lang="en">aa</lang>', clean_param('<lang lang="en">a<br>a</lang>', PARAM_TEXT));
 572      }
 573  
 574      public function test_clean_param_url() {
 575          // Test PARAM_URL and PARAM_LOCALURL a bit.
 576          $this->assertSame('http://google.com/', clean_param('http://google.com/', PARAM_URL));
 577          $this->assertSame('http://some.very.long.and.silly.domain/with/a/path/', clean_param('http://some.very.long.and.silly.domain/with/a/path/', PARAM_URL));
 578          $this->assertSame('http://localhost/', clean_param('http://localhost/', PARAM_URL));
 579          $this->assertSame('http://0.255.1.1/numericip.php', clean_param('http://0.255.1.1/numericip.php', PARAM_URL));
 580          $this->assertSame('/just/a/path', clean_param('/just/a/path', PARAM_URL));
 581          $this->assertSame('', clean_param('funny:thing', PARAM_URL));
 582      }
 583  
 584      public function test_clean_param_localurl() {
 585          global $CFG;
 586          $this->assertSame('', clean_param('http://google.com/', PARAM_LOCALURL));
 587          $this->assertSame('', clean_param('http://some.very.long.and.silly.domain/with/a/path/', PARAM_LOCALURL));
 588          $this->assertSame(clean_param($CFG->wwwroot, PARAM_LOCALURL), $CFG->wwwroot);
 589          $this->assertSame('/just/a/path', clean_param('/just/a/path', PARAM_LOCALURL));
 590          $this->assertSame('', clean_param('funny:thing', PARAM_LOCALURL));
 591          $this->assertSame('course/view.php?id=3', clean_param('course/view.php?id=3', PARAM_LOCALURL));
 592      }
 593  
 594      public function test_clean_param_file() {
 595          $this->assertSame('correctfile.txt', clean_param('correctfile.txt', PARAM_FILE));
 596          $this->assertSame('badfile.txt', clean_param('b\'a<d`\\/fi:l>e.t"x|t', PARAM_FILE));
 597          $this->assertSame('..parentdirfile.txt', clean_param('../parentdirfile.txt', PARAM_FILE));
 598          $this->assertSame('....grandparentdirfile.txt', clean_param('../../grandparentdirfile.txt', PARAM_FILE));
 599          $this->assertSame('..winparentdirfile.txt', clean_param('..\winparentdirfile.txt', PARAM_FILE));
 600          $this->assertSame('....wingrandparentdir.txt', clean_param('..\..\wingrandparentdir.txt', PARAM_FILE));
 601          $this->assertSame('myfile.a.b.txt', clean_param('myfile.a.b.txt', PARAM_FILE));
 602          $this->assertSame('myfile..a..b.txt', clean_param('myfile..a..b.txt', PARAM_FILE));
 603          $this->assertSame('myfile.a..b...txt', clean_param('myfile.a..b...txt', PARAM_FILE));
 604          $this->assertSame('myfile.a.txt', clean_param('myfile.a.txt', PARAM_FILE));
 605          $this->assertSame('myfile...txt', clean_param('myfile...txt', PARAM_FILE));
 606          $this->assertSame('...jpg', clean_param('...jpg', PARAM_FILE));
 607          $this->assertSame('.a.b.', clean_param('.a.b.', PARAM_FILE));
 608          $this->assertSame('', clean_param('.', PARAM_FILE));
 609          $this->assertSame('', clean_param('..', PARAM_FILE));
 610          $this->assertSame('...', clean_param('...', PARAM_FILE));
 611          $this->assertSame('. . . .', clean_param('. . . .', PARAM_FILE));
 612          $this->assertSame('dontrtrim.me. .. .. . ', clean_param('dontrtrim.me. .. .. . ', PARAM_FILE));
 613          $this->assertSame(' . .dontltrim.me', clean_param(' . .dontltrim.me', PARAM_FILE));
 614          $this->assertSame('here is a tab.txt', clean_param("here is a tab\t.txt", PARAM_FILE));
 615          $this->assertSame('here is a linebreak.txt', clean_param("here is a line\r\nbreak.txt", PARAM_FILE));
 616  
 617          // The following behaviours have been maintained although they seem a little odd.
 618          $this->assertSame('funnything', clean_param('funny:thing', PARAM_FILE));
 619          $this->assertSame('.currentdirfile.txt', clean_param('./currentdirfile.txt', PARAM_FILE));
 620          $this->assertSame('ctempwindowsfile.txt', clean_param('c:\temp\windowsfile.txt', PARAM_FILE));
 621          $this->assertSame('homeuserlinuxfile.txt', clean_param('/home/user/linuxfile.txt', PARAM_FILE));
 622          $this->assertSame('~myfile.txt', clean_param('~/myfile.txt', PARAM_FILE));
 623      }
 624  
 625      public function test_clean_param_path() {
 626          $this->assertSame('correctfile.txt', clean_param('correctfile.txt', PARAM_PATH));
 627          $this->assertSame('bad/file.txt', clean_param('b\'a<d`\\/fi:l>e.t"x|t', PARAM_PATH));
 628          $this->assertSame('/parentdirfile.txt', clean_param('../parentdirfile.txt', PARAM_PATH));
 629          $this->assertSame('/grandparentdirfile.txt', clean_param('../../grandparentdirfile.txt', PARAM_PATH));
 630          $this->assertSame('/winparentdirfile.txt', clean_param('..\winparentdirfile.txt', PARAM_PATH));
 631          $this->assertSame('/wingrandparentdir.txt', clean_param('..\..\wingrandparentdir.txt', PARAM_PATH));
 632          $this->assertSame('funnything', clean_param('funny:thing', PARAM_PATH));
 633          $this->assertSame('./here', clean_param('./././here', PARAM_PATH));
 634          $this->assertSame('./currentdirfile.txt', clean_param('./currentdirfile.txt', PARAM_PATH));
 635          $this->assertSame('c/temp/windowsfile.txt', clean_param('c:\temp\windowsfile.txt', PARAM_PATH));
 636          $this->assertSame('/home/user/linuxfile.txt', clean_param('/home/user/linuxfile.txt', PARAM_PATH));
 637          $this->assertSame('/home../user ./.linuxfile.txt', clean_param('/home../user ./.linuxfile.txt', PARAM_PATH));
 638          $this->assertSame('~/myfile.txt', clean_param('~/myfile.txt', PARAM_PATH));
 639          $this->assertSame('~/myfile.txt', clean_param('~/../myfile.txt', PARAM_PATH));
 640          $this->assertSame('/..b../.../myfile.txt', clean_param('/..b../.../myfile.txt', PARAM_PATH));
 641          $this->assertSame('..b../.../myfile.txt', clean_param('..b../.../myfile.txt', PARAM_PATH));
 642          $this->assertSame('/super/slashes/', clean_param('/super//slashes///', PARAM_PATH));
 643      }
 644  
 645      public function test_clean_param_username() {
 646          global $CFG;
 647          $currentstatus =  $CFG->extendedusernamechars;
 648  
 649          // Run tests with extended character == false;.
 650          $CFG->extendedusernamechars = false;
 651          $this->assertSame('johndoe123', clean_param('johndoe123', PARAM_USERNAME) );
 652          $this->assertSame('john.doe', clean_param('john.doe', PARAM_USERNAME));
 653          $this->assertSame('john-doe', clean_param('john-doe', PARAM_USERNAME));
 654          $this->assertSame('john-doe', clean_param('john- doe', PARAM_USERNAME));
 655          $this->assertSame('john_doe', clean_param('john_doe', PARAM_USERNAME));
 656          $this->assertSame('john@doe', clean_param('john@doe', PARAM_USERNAME));
 657          $this->assertSame('johndoe', clean_param('john~doe', PARAM_USERNAME));
 658          $this->assertSame('johndoe', clean_param('john´doe', PARAM_USERNAME));
 659          $this->assertSame(clean_param('john# $%&()+_^', PARAM_USERNAME), 'john_');
 660          $this->assertSame(clean_param(' john# $%&()+_^ ', PARAM_USERNAME), 'john_');
 661          $this->assertSame(clean_param('john#$%&() ', PARAM_USERNAME), 'john');
 662          $this->assertSame('johnd', clean_param('JOHNdóé ', PARAM_USERNAME));
 663          $this->assertSame(clean_param('john.,:;-_/|\ñÑ[]A_X-,D {} ~!@#$%^&*()_+ ?><[] ščřžžý ?ýáž?žý??šdoe ', PARAM_USERNAME), 'john.-_a_x-d@_doe');
 664  
 665          // Test success condition, if extendedusernamechars == ENABLE;.
 666          $CFG->extendedusernamechars = true;
 667          $this->assertSame('john_doe', clean_param('john_doe', PARAM_USERNAME));
 668          $this->assertSame('john@doe', clean_param('john@doe', PARAM_USERNAME));
 669          $this->assertSame(clean_param('john# $%&()+_^', PARAM_USERNAME), 'john# $%&()+_^');
 670          $this->assertSame(clean_param(' john# $%&()+_^ ', PARAM_USERNAME), 'john# $%&()+_^');
 671          $this->assertSame('john~doe', clean_param('john~doe', PARAM_USERNAME));
 672          $this->assertSame('john´doe', clean_param('joHN´doe', PARAM_USERNAME));
 673          $this->assertSame('johndoe', clean_param('johnDOE', PARAM_USERNAME));
 674          $this->assertSame('johndóé', clean_param('johndóé ', PARAM_USERNAME));
 675  
 676          $CFG->extendedusernamechars = $currentstatus;
 677      }
 678  
 679      public function test_clean_param_stringid() {
 680          // Test string identifiers validation.
 681          // Valid strings.
 682          $this->assertSame('validstring', clean_param('validstring', PARAM_STRINGID));
 683          $this->assertSame('mod/foobar:valid_capability', clean_param('mod/foobar:valid_capability', PARAM_STRINGID));
 684          $this->assertSame('CZ', clean_param('CZ', PARAM_STRINGID));
 685          $this->assertSame('application/vnd.ms-powerpoint', clean_param('application/vnd.ms-powerpoint', PARAM_STRINGID));
 686          $this->assertSame('grade2', clean_param('grade2', PARAM_STRINGID));
 687          // Invalid strings.
 688          $this->assertSame('', clean_param('trailing ', PARAM_STRINGID));
 689          $this->assertSame('', clean_param('space bar', PARAM_STRINGID));
 690          $this->assertSame('', clean_param('0numeric', PARAM_STRINGID));
 691          $this->assertSame('', clean_param('*', PARAM_STRINGID));
 692          $this->assertSame('', clean_param(' ', PARAM_STRINGID));
 693      }
 694  
 695      public function test_clean_param_timezone() {
 696          // Test timezone validation.
 697          $testvalues = array (
 698              'America/Jamaica'                => 'America/Jamaica',
 699              'America/Argentina/Cordoba'      => 'America/Argentina/Cordoba',
 700              'America/Port-au-Prince'         => 'America/Port-au-Prince',
 701              'America/Argentina/Buenos_Aires' => 'America/Argentina/Buenos_Aires',
 702              'PST8PDT'                        => 'PST8PDT',
 703              'Wrong.Value'                    => '',
 704              'Wrong/.Value'                   => '',
 705              'Wrong(Value)'                   => '',
 706              '0'                              => '0',
 707              '0.0'                            => '0.0',
 708              '0.5'                            => '0.5',
 709              '9.0'                            => '9.0',
 710              '-9.0'                           => '-9.0',
 711              '+9.0'                           => '+9.0',
 712              '9.5'                            => '9.5',
 713              '-9.5'                           => '-9.5',
 714              '+9.5'                           => '+9.5',
 715              '12.0'                           => '12.0',
 716              '-12.0'                          => '-12.0',
 717              '+12.0'                          => '+12.0',
 718              '12.5'                           => '12.5',
 719              '-12.5'                          => '-12.5',
 720              '+12.5'                          => '+12.5',
 721              '13.0'                           => '13.0',
 722              '-13.0'                          => '-13.0',
 723              '+13.0'                          => '+13.0',
 724              '13.5'                           => '',
 725              '+13.5'                          => '',
 726              '-13.5'                          => '',
 727              '0.2'                            => '');
 728  
 729          foreach ($testvalues as $testvalue => $expectedvalue) {
 730              $actualvalue = clean_param($testvalue, PARAM_TIMEZONE);
 731              $this->assertEquals($expectedvalue, $actualvalue);
 732          }
 733      }
 734  
 735      public function test_validate_param() {
 736          try {
 737              $param = validate_param('11a', PARAM_INT);
 738              $this->fail('invalid_parameter_exception expected');
 739          } catch (moodle_exception $ex) {
 740              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 741          }
 742  
 743          $param = validate_param('11', PARAM_INT);
 744          $this->assertSame(11, $param);
 745  
 746          try {
 747              $param = validate_param(null, PARAM_INT, false);
 748              $this->fail('invalid_parameter_exception expected');
 749          } catch (moodle_exception $ex) {
 750              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 751          }
 752  
 753          $param = validate_param(null, PARAM_INT, true);
 754          $this->assertSame(null, $param);
 755  
 756          try {
 757              $param = validate_param(array(), PARAM_INT);
 758              $this->fail('invalid_parameter_exception expected');
 759          } catch (moodle_exception $ex) {
 760              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 761          }
 762          try {
 763              $param = validate_param(new stdClass, PARAM_INT);
 764              $this->fail('invalid_parameter_exception expected');
 765          } catch (moodle_exception $ex) {
 766              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 767          }
 768  
 769          $param = validate_param('1.0', PARAM_FLOAT);
 770          $this->assertSame(1.0, $param);
 771  
 772          // Make sure valid floats do not cause exception.
 773          validate_param(1.0, PARAM_FLOAT);
 774          validate_param(10, PARAM_FLOAT);
 775          validate_param('0', PARAM_FLOAT);
 776          validate_param('119813454.545464564564546564545646556564465465456465465465645645465645645645', PARAM_FLOAT);
 777          validate_param('011.1', PARAM_FLOAT);
 778          validate_param('11', PARAM_FLOAT);
 779          validate_param('+.1', PARAM_FLOAT);
 780          validate_param('-.1', PARAM_FLOAT);
 781          validate_param('1e10', PARAM_FLOAT);
 782          validate_param('.1e+10', PARAM_FLOAT);
 783          validate_param('1E-1', PARAM_FLOAT);
 784  
 785          try {
 786              $param = validate_param('1,2', PARAM_FLOAT);
 787              $this->fail('invalid_parameter_exception expected');
 788          } catch (moodle_exception $ex) {
 789              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 790          }
 791          try {
 792              $param = validate_param('', PARAM_FLOAT);
 793              $this->fail('invalid_parameter_exception expected');
 794          } catch (moodle_exception $ex) {
 795              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 796          }
 797          try {
 798              $param = validate_param('.', PARAM_FLOAT);
 799              $this->fail('invalid_parameter_exception expected');
 800          } catch (moodle_exception $ex) {
 801              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 802          }
 803          try {
 804              $param = validate_param('e10', PARAM_FLOAT);
 805              $this->fail('invalid_parameter_exception expected');
 806          } catch (moodle_exception $ex) {
 807              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 808          }
 809          try {
 810              $param = validate_param('abc', PARAM_FLOAT);
 811              $this->fail('invalid_parameter_exception expected');
 812          } catch (moodle_exception $ex) {
 813              $this->assertInstanceOf('invalid_parameter_exception', $ex);
 814          }
 815      }
 816  
 817      public function test_shorten_text_no_tags_already_short_enough() {
 818          // ......12345678901234567890123456.
 819          $text = "short text already no tags";
 820          $this->assertSame($text, shorten_text($text));
 821      }
 822  
 823      public function test_shorten_text_with_tags_already_short_enough() {
 824          // .........123456...7890....12345678.......901234567.
 825          $text = "<p>short <b>text</b> already</p><p>with tags</p>";
 826          $this->assertSame($text, shorten_text($text));
 827      }
 828  
 829      public function test_shorten_text_no_tags_needs_shortening() {
 830          // Default truncation is after 30 chars, but allowing 3 for the final '...'.
 831          // ......12345678901234567890123456789023456789012345678901234.
 832          $text = "long text without any tags blah de blah blah blah what";
 833          $this->assertSame('long text without any tags ...', shorten_text($text));
 834      }
 835  
 836      public function test_shorten_text_with_tags_needs_shortening() {
 837          // .......................................123456789012345678901234567890...
 838          $text = "<div class='frog'><p><blockquote>Long text with tags that will ".
 839              "be chopped off but <b>should be added back again</b></blockquote></p></div>";
 840          $this->assertEquals("<div class='frog'><p><blockquote>Long text with " .
 841              "tags that ...</blockquote></p></div>", shorten_text($text));
 842      }
 843  
 844      public function test_shorten_text_with_entities() {
 845          // Remember to allow 3 chars for the final '...'.
 846          // ......123456789012345678901234567_____890...
 847          $text = "some text which shouldn't &nbsp; break there";
 848          $this->assertSame("some text which shouldn't &nbsp; ...", shorten_text($text, 31));
 849          $this->assertSame("some text which shouldn't &nbsp;...", shorten_text($text, 30));
 850          $this->assertSame("some text which shouldn't ...", shorten_text($text, 29));
 851      }
 852  
 853      public function test_shorten_text_known_tricky_case() {
 854          // This case caused a bug up to 1.9.5
 855          // ..........123456789012345678901234567890123456789.....0_____1___2___...
 856          $text = "<h3>standard 'break-out' sub groups in TGs?</h3>&nbsp;&lt;&lt;There are several";
 857          $this->assertSame("<h3>standard 'break-out' sub groups in ...</h3>",
 858              shorten_text($text, 41));
 859          $this->assertSame("<h3>standard 'break-out' sub groups in TGs?...</h3>",
 860              shorten_text($text, 42));
 861          $this->assertSame("<h3>standard 'break-out' sub groups in TGs?</h3>&nbsp;...",
 862              shorten_text($text, 43));
 863      }
 864  
 865      public function test_shorten_text_no_spaces() {
 866          // ..........123456789.
 867          $text = "<h1>123456789</h1>"; // A string with no convenient breaks.
 868          $this->assertSame("<h1>12345...</h1>", shorten_text($text, 8));
 869      }
 870  
 871      public function test_shorten_text_utf8_european() {
 872          // Text without tags.
 873          // ......123456789012345678901234567.
 874          $text = "Žluťoučký koníček přeskočil";
 875          $this->assertSame($text, shorten_text($text)); // 30 chars by default.
 876          $this->assertSame("Žluťoučký koníče...", shorten_text($text, 19, true));
 877          $this->assertSame("Žluťoučký ...", shorten_text($text, 19, false));
 878          // And try it with 2-less (that are, in bytes, the middle of a sequence).
 879          $this->assertSame("Žluťoučký koní...", shorten_text($text, 17, true));
 880          $this->assertSame("Žluťoučký ...", shorten_text($text, 17, false));
 881  
 882          // .........123456789012345678...901234567....89012345.
 883          $text = "<p>Žluťoučký koníček <b>přeskočil</b> potůček</p>";
 884          $this->assertSame($text, shorten_text($text, 60));
 885          $this->assertSame("<p>Žluťoučký koníček ...</p>", shorten_text($text, 21));
 886          $this->assertSame("<p>Žluťoučký koníče...</p>", shorten_text($text, 19, true));
 887          $this->assertSame("<p>Žluťoučký ...</p>", shorten_text($text, 19, false));
 888          // And try it with 2 fewer (that are, in bytes, the middle of a sequence).
 889          $this->assertSame("<p>Žluťoučký koní...</p>", shorten_text($text, 17, true));
 890          $this->assertSame("<p>Žluťoučký ...</p>", shorten_text($text, 17, false));
 891          // And try over one tag (start/end), it does proper text len.
 892          $this->assertSame("<p>Žluťoučký koníček <b>př...</b></p>", shorten_text($text, 23, true));
 893          $this->assertSame("<p>Žluťoučký koníček <b>přeskočil</b> pot...</p>", shorten_text($text, 34, true));
 894          // And in the middle of one tag.
 895          $this->assertSame("<p>Žluťoučký koníček <b>přeskočil...</b></p>", shorten_text($text, 30, true));
 896      }
 897  
 898      public function test_shorten_text_utf8_oriental() {
 899          // Japanese
 900          // text without tags
 901          // ......123456789012345678901234.
 902          $text = '言語設定言語設定abcdefghijkl';
 903          $this->assertSame($text, shorten_text($text)); // 30 chars by default.
 904          $this->assertSame("言語設定言語...", shorten_text($text, 9, true));
 905          $this->assertSame("言語設定言語...", shorten_text($text, 9, false));
 906          $this->assertSame("言語設定言語設定ab...", shorten_text($text, 13, true));
 907          $this->assertSame("言語設定言語設定...", shorten_text($text, 13, false));
 908  
 909          // Chinese
 910          // text without tags
 911          // ......123456789012345678901234.
 912          $text = '简体中文简体中文abcdefghijkl';
 913          $this->assertSame($text, shorten_text($text)); // 30 chars by default.
 914          $this->assertSame("简体中文简体...", shorten_text($text, 9, true));
 915          $this->assertSame("简体中文简体...", shorten_text($text, 9, false));
 916          $this->assertSame("简体中文简体中文ab...", shorten_text($text, 13, true));
 917          $this->assertSame("简体中文简体中文...", shorten_text($text, 13, false));
 918      }
 919  
 920      public function test_shorten_text_multilang() {
 921          // This is not necessaryily specific to multilang. The issue is really
 922          // tags with attributes, where before we were generating invalid HTML
 923          // output like shorten_text('<span id="x" class="y">A</span> B', 1)
 924          // returning '<span id="x" ...</span>'. It is just that multilang
 925          // requires the sort of HTML that is quite likely to trigger this.
 926          // ........................................1...
 927          $text = '<span lang="en" class="multilang">A</span>' .
 928                  '<span lang="fr" class="multilang">B</span>';
 929          $this->assertSame('<span lang="en" class="multilang">...</span>',
 930                  shorten_text($text, 1));
 931      }
 932  
 933      public function test_usergetdate() {
 934          global $USER, $CFG, $DB;
 935          $this->resetAfterTest();
 936  
 937          // Check if forcetimezone is set then save it and set it to use user timezone.
 938          $cfgforcetimezone = null;
 939          if (isset($CFG->forcetimezone)) {
 940              $cfgforcetimezone = $CFG->forcetimezone;
 941              $CFG->forcetimezone = 99; // Get user default timezone.
 942          }
 943  
 944          $this->setAdminUser();
 945  
 946          $userstimezone = $USER->timezone;
 947          $USER->timezone = 2;// Set the timezone to a known state.
 948  
 949          // The string version of date comes from server locale setting and does
 950          // not respect user language, so it is necessary to reset that.
 951          $oldlocale = setlocale(LC_TIME, '0');
 952          setlocale(LC_TIME, 'en_AU.UTF-8');
 953  
 954          $ts = 1261540267; // The time this function was created.
 955  
 956          $arr = usergetdate($ts, 1); // Specify the timezone as an argument.
 957          $arr = array_values($arr);
 958  
 959          list($seconds, $minutes, $hours, $mday, $wday, $mon, $year, $yday, $weekday, $month) = $arr;
 960          $this->assertSame(7, $seconds);
 961          $this->assertSame(51, $minutes);
 962          $this->assertSame(4, $hours);
 963          $this->assertSame(23, $mday);
 964          $this->assertSame(3, $wday);
 965          $this->assertSame(12, $mon);
 966          $this->assertSame(2009, $year);
 967          $this->assertSame(356, $yday);
 968          $this->assertSame('Wednesday', $weekday);
 969          $this->assertSame('December', $month);
 970          $arr = usergetdate($ts); // Gets the timezone from the $USER object.
 971          $arr = array_values($arr);
 972  
 973          list($seconds, $minutes, $hours, $mday, $wday, $mon, $year, $yday, $weekday, $month) = $arr;
 974          $this->assertSame(7, $seconds);
 975          $this->assertSame(51, $minutes);
 976          $this->assertSame(5, $hours);
 977          $this->assertSame(23, $mday);
 978          $this->assertSame(3, $wday);
 979          $this->assertSame(12, $mon);
 980          $this->assertSame(2009, $year);
 981          $this->assertSame(356, $yday);
 982          $this->assertSame('Wednesday', $weekday);
 983          $this->assertSame('December', $month);
 984          // Set the timezone back to what it was.
 985          $USER->timezone = $userstimezone;
 986  
 987          // Restore forcetimezone if changed.
 988          if (!is_null($cfgforcetimezone)) {
 989              $CFG->forcetimezone = $cfgforcetimezone;
 990          }
 991  
 992          setlocale(LC_TIME, $oldlocale);
 993      }
 994  
 995      public function test_mark_user_preferences_changed() {
 996          $this->resetAfterTest();
 997          $otheruser = $this->getDataGenerator()->create_user();
 998          $otheruserid = $otheruser->id;
 999  
1000          set_cache_flag('userpreferenceschanged', $otheruserid, null);
1001          mark_user_preferences_changed($otheruserid);
1002  
1003          $this->assertEquals(get_cache_flag('userpreferenceschanged', $otheruserid, time()-10), 1);
1004          set_cache_flag('userpreferenceschanged', $otheruserid, null);
1005      }
1006  
1007      public function test_check_user_preferences_loaded() {
1008          global $DB;
1009          $this->resetAfterTest();
1010  
1011          $otheruser = $this->getDataGenerator()->create_user();
1012          $otheruserid = $otheruser->id;
1013  
1014          $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
1015          set_cache_flag('userpreferenceschanged', $otheruserid, null);
1016  
1017          $user = new stdClass();
1018          $user->id = $otheruserid;
1019  
1020          // Load.
1021          check_user_preferences_loaded($user);
1022          $this->assertTrue(isset($user->preference));
1023          $this->assertTrue(is_array($user->preference));
1024          $this->assertArrayHasKey('_lastloaded', $user->preference);
1025          $this->assertCount(1, $user->preference);
1026  
1027          // Add preference via direct call.
1028          $DB->insert_record('user_preferences', array('name'=>'xxx', 'value'=>'yyy', 'userid'=>$user->id));
1029  
1030          // No cache reload yet.
1031          check_user_preferences_loaded($user);
1032          $this->assertCount(1, $user->preference);
1033  
1034          // Forced reloading of cache.
1035          unset($user->preference);
1036          check_user_preferences_loaded($user);
1037          $this->assertCount(2, $user->preference);
1038          $this->assertSame('yyy', $user->preference['xxx']);
1039  
1040          // Add preference via direct call.
1041          $DB->insert_record('user_preferences', array('name'=>'aaa', 'value'=>'bbb', 'userid'=>$user->id));
1042  
1043          // Test timeouts and modifications from different session.
1044          set_cache_flag('userpreferenceschanged', $user->id, 1, time() + 1000);
1045          $user->preference['_lastloaded'] = $user->preference['_lastloaded'] - 20;
1046          check_user_preferences_loaded($user);
1047          $this->assertCount(2, $user->preference);
1048          check_user_preferences_loaded($user, 10);
1049          $this->assertCount(3, $user->preference);
1050          $this->assertSame('bbb', $user->preference['aaa']);
1051          set_cache_flag('userpreferenceschanged', $user->id, null);
1052      }
1053  
1054      public function test_set_user_preference() {
1055          global $DB, $USER;
1056          $this->resetAfterTest();
1057  
1058          $this->setAdminUser();
1059  
1060          $otheruser = $this->getDataGenerator()->create_user();
1061          $otheruserid = $otheruser->id;
1062  
1063          $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
1064          set_cache_flag('userpreferenceschanged', $otheruserid, null);
1065  
1066          $user = new stdClass();
1067          $user->id = $otheruserid;
1068  
1069          set_user_preference('aaa', 'bbb', $otheruserid);
1070          $this->assertSame('bbb', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'aaa')));
1071          $this->assertSame('bbb', get_user_preferences('aaa', null, $otheruserid));
1072  
1073          set_user_preference('xxx', 'yyy', $user);
1074          $this->assertSame('yyy', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx')));
1075          $this->assertSame('yyy', get_user_preferences('xxx', null, $otheruserid));
1076          $this->assertTrue(is_array($user->preference));
1077          $this->assertSame('bbb', $user->preference['aaa']);
1078          $this->assertSame('yyy', $user->preference['xxx']);
1079  
1080          set_user_preference('xxx', null, $user);
1081          $this->assertFalse($DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx')));
1082          $this->assertNull(get_user_preferences('xxx', null, $otheruserid));
1083  
1084          set_user_preference('ooo', true, $user);
1085          $prefs = get_user_preferences(null, null, $otheruserid);
1086          $this->assertSame($user->preference['aaa'], $prefs['aaa']);
1087          $this->assertSame($user->preference['ooo'], $prefs['ooo']);
1088          $this->assertSame('1', $prefs['ooo']);
1089  
1090          set_user_preference('null', 0, $user);
1091          $this->assertSame('0', get_user_preferences('null', null, $otheruserid));
1092  
1093          $this->assertSame('lala', get_user_preferences('undefined', 'lala', $otheruserid));
1094  
1095          $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
1096          set_cache_flag('userpreferenceschanged', $otheruserid, null);
1097  
1098          // Test $USER default.
1099          set_user_preference('_test_user_preferences_pref', 'ok');
1100          $this->assertSame('ok', $USER->preference['_test_user_preferences_pref']);
1101          unset_user_preference('_test_user_preferences_pref');
1102          $this->assertTrue(!isset($USER->preference['_test_user_preferences_pref']));
1103  
1104          // Test 1333 char values (no need for unicode, there are already tests for that in DB tests).
1105          $longvalue = str_repeat('a', 1333);
1106          set_user_preference('_test_long_user_preference', $longvalue);
1107          $this->assertEquals($longvalue, get_user_preferences('_test_long_user_preference'));
1108          $this->assertEquals($longvalue,
1109              $DB->get_field('user_preferences', 'value', array('userid' => $USER->id, 'name' => '_test_long_user_preference')));
1110  
1111          // Test > 1333 char values, coding_exception expected.
1112          $longvalue = str_repeat('a', 1334);
1113          try {
1114              set_user_preference('_test_long_user_preference', $longvalue);
1115              $this->fail('Exception expected - longer than 1333 chars not allowed as preference value');
1116          } catch (moodle_exception $ex) {
1117              $this->assertInstanceOf('coding_exception', $ex);
1118          }
1119  
1120          // Test invalid params.
1121          try {
1122              set_user_preference('_test_user_preferences_pref', array());
1123              $this->fail('Exception expected - array not valid preference value');
1124          } catch (moodle_exception $ex) {
1125              $this->assertInstanceOf('coding_exception', $ex);
1126          }
1127          try {
1128              set_user_preference('_test_user_preferences_pref', new stdClass);
1129              $this->fail('Exception expected - class not valid preference value');
1130          } catch (moodle_exception $ex) {
1131              $this->assertInstanceOf('coding_exception', $ex);
1132          }
1133          try {
1134              set_user_preference('_test_user_preferences_pref', 1, array('xx' => 1));
1135              $this->fail('Exception expected - user instance expected');
1136          } catch (moodle_exception $ex) {
1137              $this->assertInstanceOf('coding_exception', $ex);
1138          }
1139          try {
1140              set_user_preference('_test_user_preferences_pref', 1, 'abc');
1141              $this->fail('Exception expected - user instance expected');
1142          } catch (moodle_exception $ex) {
1143              $this->assertInstanceOf('coding_exception', $ex);
1144          }
1145          try {
1146              set_user_preference('', 1);
1147              $this->fail('Exception expected - invalid name accepted');
1148          } catch (moodle_exception $ex) {
1149              $this->assertInstanceOf('coding_exception', $ex);
1150          }
1151          try {
1152              set_user_preference('1', 1);
1153              $this->fail('Exception expected - invalid name accepted');
1154          } catch (moodle_exception $ex) {
1155              $this->assertInstanceOf('coding_exception', $ex);
1156          }
1157      }
1158  
1159      public function test_get_extra_user_fields() {
1160          global $CFG, $USER, $DB;
1161          $this->resetAfterTest();
1162  
1163          $this->setAdminUser();
1164  
1165          // It would be really nice if there were a way to 'mock' has_capability
1166          // checks (either to return true or false) but as there is not, this
1167          // test doesn't test the capability check. Presumably, anyone running
1168          // unit tests will have the capability.
1169          $context = context_system::instance();
1170  
1171          // No fields.
1172          $CFG->showuseridentity = '';
1173          $this->assertEquals(array(), get_extra_user_fields($context));
1174  
1175          // One field.
1176          $CFG->showuseridentity = 'frog';
1177          $this->assertEquals(array('frog'), get_extra_user_fields($context));
1178  
1179          // Two fields.
1180          $CFG->showuseridentity = 'frog,zombie';
1181          $this->assertEquals(array('frog', 'zombie'), get_extra_user_fields($context));
1182  
1183          // No fields, except.
1184          $CFG->showuseridentity = '';
1185          $this->assertEquals(array(), get_extra_user_fields($context, array('frog')));
1186  
1187          // One field.
1188          $CFG->showuseridentity = 'frog';
1189          $this->assertEquals(array(), get_extra_user_fields($context, array('frog')));
1190  
1191          // Two fields.
1192          $CFG->showuseridentity = 'frog,zombie';
1193          $this->assertEquals(array('zombie'), get_extra_user_fields($context, array('frog')));
1194      }
1195  
1196      public function test_get_extra_user_fields_sql() {
1197          global $CFG, $USER, $DB;
1198          $this->resetAfterTest();
1199  
1200          $this->setAdminUser();
1201  
1202          $context = context_system::instance();
1203  
1204          // No fields.
1205          $CFG->showuseridentity = '';
1206          $this->assertSame('', get_extra_user_fields_sql($context));
1207  
1208          // One field.
1209          $CFG->showuseridentity = 'frog';
1210          $this->assertSame(', frog', get_extra_user_fields_sql($context));
1211  
1212          // Two fields with table prefix.
1213          $CFG->showuseridentity = 'frog,zombie';
1214          $this->assertSame(', u1.frog, u1.zombie', get_extra_user_fields_sql($context, 'u1'));
1215  
1216          // Two fields with field prefix.
1217          $CFG->showuseridentity = 'frog,zombie';
1218          $this->assertSame(', frog AS u_frog, zombie AS u_zombie',
1219              get_extra_user_fields_sql($context, '', 'u_'));
1220  
1221          // One field excluded.
1222          $CFG->showuseridentity = 'frog';
1223          $this->assertSame('', get_extra_user_fields_sql($context, '', '', array('frog')));
1224  
1225          // Two fields, one excluded, table+field prefix.
1226          $CFG->showuseridentity = 'frog,zombie';
1227          $this->assertEquals(', u1.zombie AS u_zombie',
1228              get_extra_user_fields_sql($context, 'u1', 'u_', array('frog')));
1229      }
1230  
1231      /**
1232       * Test some critical TZ/DST.
1233       *
1234       * This method tests some special TZ/DST combinations that were fixed
1235       * by MDL-38999. The tests are done by comparing the results of the
1236       * output using Moodle TZ/DST support and PHP native one.
1237       *
1238       * Note: If you don't trust PHP TZ/DST support, can verify the
1239       * harcoded expectations below with:
1240       * http://www.tools4noobs.com/online_tools/unix_timestamp_to_datetime/
1241       */
1242      public function test_some_moodle_special_dst() {
1243          $stamp = 1365386400; // 2013/04/08 02:00:00 GMT/UTC.
1244  
1245          // In Europe/Tallinn it was 2013/04/08 05:00:00.
1246          $expectation = '2013/04/08 05:00:00';
1247          $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
1248          $phpdt->setTimezone(new DateTimeZone('Europe/Tallinn'));
1249          $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
1250          $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'Europe/Tallinn', false); // Moodle result.
1251          $this->assertSame($expectation, $phpres);
1252          $this->assertSame($expectation, $moodleres);
1253  
1254          // In St. Johns it was 2013/04/07 23:30:00.
1255          $expectation = '2013/04/07 23:30:00';
1256          $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
1257          $phpdt->setTimezone(new DateTimeZone('America/St_Johns'));
1258          $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
1259          $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'America/St_Johns', false); // Moodle result.
1260          $this->assertSame($expectation, $phpres);
1261          $this->assertSame($expectation, $moodleres);
1262  
1263          $stamp = 1383876000; // 2013/11/08 02:00:00 GMT/UTC.
1264  
1265          // In Europe/Tallinn it was 2013/11/08 04:00:00.
1266          $expectation = '2013/11/08 04:00:00';
1267          $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
1268          $phpdt->setTimezone(new DateTimeZone('Europe/Tallinn'));
1269          $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
1270          $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'Europe/Tallinn', false); // Moodle result.
1271          $this->assertSame($expectation, $phpres);
1272          $this->assertSame($expectation, $moodleres);
1273  
1274          // In St. Johns it was 2013/11/07 22:30:00.
1275          $expectation = '2013/11/07 22:30:00';
1276          $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
1277          $phpdt->setTimezone(new DateTimeZone('America/St_Johns'));
1278          $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
1279          $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'America/St_Johns', false); // Moodle result.
1280          $this->assertSame($expectation, $phpres);
1281          $this->assertSame($expectation, $moodleres);
1282      }
1283  
1284      public function test_userdate() {
1285          global $USER, $CFG, $DB;
1286          $this->resetAfterTest();
1287  
1288          $this->setAdminUser();
1289  
1290          $testvalues = array(
1291              array(
1292                  'time' => '1309514400',
1293                  'usertimezone' => 'America/Moncton',
1294                  'timezone' => '0.0', // No dst offset.
1295                  'expectedoutput' => 'Friday, 1 July 2011, 10:00 AM'
1296              ),
1297              array(
1298                  'time' => '1309514400',
1299                  'usertimezone' => 'America/Moncton',
1300                  'timezone' => '99', // Dst offset and timezone offset.
1301                  'expectedoutput' => 'Friday, 1 July 2011, 7:00 AM'
1302              ),
1303              array(
1304                  'time' => '1309514400',
1305                  'usertimezone' => 'America/Moncton',
1306                  'timezone' => 'America/Moncton', // Dst offset and timezone offset.
1307                  'expectedoutput' => 'Friday, 1 July 2011, 7:00 AM'
1308              ),
1309              array(
1310                  'time' => '1293876000 ',
1311                  'usertimezone' => 'America/Moncton',
1312                  'timezone' => '0.0', // No dst offset.
1313                  'expectedoutput' => 'Saturday, 1 January 2011, 10:00 AM'
1314              ),
1315              array(
1316                  'time' => '1293876000 ',
1317                  'usertimezone' => 'America/Moncton',
1318                  'timezone' => '99', // No dst offset in jan, so just timezone offset.
1319                  'expectedoutput' => 'Saturday, 1 January 2011, 6:00 AM'
1320              ),
1321              array(
1322                  'time' => '1293876000 ',
1323                  'usertimezone' => 'America/Moncton',
1324                  'timezone' => 'America/Moncton', // No dst offset in jan.
1325                  'expectedoutput' => 'Saturday, 1 January 2011, 6:00 AM'
1326              ),
1327              array(
1328                  'time' => '1293876000 ',
1329                  'usertimezone' => '2',
1330                  'timezone' => '99', // Take user timezone.
1331                  'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
1332              ),
1333              array(
1334                  'time' => '1293876000 ',
1335                  'usertimezone' => '-2',
1336                  'timezone' => '99', // Take user timezone.
1337                  'expectedoutput' => 'Saturday, 1 January 2011, 8:00 AM'
1338              ),
1339              array(
1340                  'time' => '1293876000 ',
1341                  'usertimezone' => '-10',
1342                  'timezone' => '2', // Take this timezone.
1343                  'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
1344              ),
1345              array(
1346                  'time' => '1293876000 ',
1347                  'usertimezone' => '-10',
1348                  'timezone' => '-2', // Take this timezone.
1349                  'expectedoutput' => 'Saturday, 1 January 2011, 8:00 AM'
1350              ),
1351              array(
1352                  'time' => '1293876000 ',
1353                  'usertimezone' => '-10',
1354                  'timezone' => 'random/time', // This should show server time.
1355                  'expectedoutput' => 'Saturday, 1 January 2011, 6:00 PM'
1356              ),
1357              array(
1358                  'time' => '1293876000 ',
1359                  'usertimezone' => '14', // Server time zone.
1360                  'timezone' => '99',     // This should show user time.
1361                  'expectedoutput' => 'Saturday, 1 January 2011, 6:00 PM'
1362              ),
1363          );
1364  
1365          // Check if forcetimezone is set then save it and set it to use user timezone.
1366          $cfgforcetimezone = null;
1367          if (isset($CFG->forcetimezone)) {
1368              $cfgforcetimezone = $CFG->forcetimezone;
1369              $CFG->forcetimezone = 99; // Get user default timezone.
1370          }
1371          // Store user default timezone to restore later.
1372          $userstimezone = $USER->timezone;
1373  
1374          // The string version of date comes from server locale setting and does
1375          // not respect user language, so it is necessary to reset that.
1376          $oldlocale = setlocale(LC_TIME, '0');
1377          setlocale(LC_TIME, 'en_AU.UTF-8');
1378  
1379          // Set default timezone to Australia/Perth, else time calculated
1380          // will not match expected values. Before that save system defaults.
1381          $systemdefaulttimezone = date_default_timezone_get();
1382          date_default_timezone_set('Australia/Perth');
1383  
1384          foreach ($testvalues as $vals) {
1385              $USER->timezone = $vals['usertimezone'];
1386              $actualoutput = userdate($vals['time'], '%A, %d %B %Y, %I:%M %p', $vals['timezone']);
1387  
1388              // On different systems case of AM PM changes so compare case insensitive.
1389              $vals['expectedoutput'] = core_text::strtolower($vals['expectedoutput']);
1390              $actualoutput = core_text::strtolower($actualoutput);
1391  
1392              $this->assertSame($vals['expectedoutput'], $actualoutput,
1393                  "Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
1394                  Please check if timezones are updated (Site adminstration -> location -> update timezone)");
1395          }
1396  
1397          // Restore user timezone back to what it was.
1398          $USER->timezone = $userstimezone;
1399  
1400          // Restore forcetimezone.
1401          if (!is_null($cfgforcetimezone)) {
1402              $CFG->forcetimezone = $cfgforcetimezone;
1403          }
1404  
1405          // Restore system default values.
1406          date_default_timezone_set($systemdefaulttimezone);
1407          setlocale(LC_TIME, $oldlocale);
1408      }
1409  
1410      public function test_make_timestamp() {
1411          global $USER, $CFG, $DB;
1412          $this->resetAfterTest();
1413  
1414          $this->setAdminUser();
1415  
1416          $testvalues = array(
1417              array(
1418                  'usertimezone' => 'America/Moncton',
1419                  'year' => '2011',
1420                  'month' => '7',
1421                  'day' => '1',
1422                  'hour' => '10',
1423                  'minutes' => '00',
1424                  'seconds' => '00',
1425                  'timezone' => '0.0',
1426                  'applydst' => false, // No dst offset.
1427                  'expectedoutput' => '1309514400' // 6pm at UTC+0.
1428              ),
1429              array(
1430                  'usertimezone' => 'America/Moncton',
1431                  'year' => '2011',
1432                  'month' => '7',
1433                  'day' => '1',
1434                  'hour' => '10',
1435                  'minutes' => '00',
1436                  'seconds' => '00',
1437                  'timezone' => '99',  // User default timezone.
1438                  'applydst' => false, // Don't apply dst.
1439                  'expectedoutput' => '1309528800'
1440              ),
1441              array(
1442                  'usertimezone' => 'America/Moncton',
1443                  'year' => '2011',
1444                  'month' => '7',
1445                  'day' => '1',
1446                  'hour' => '10',
1447                  'minutes' => '00',
1448                  'seconds' => '00',
1449                  'timezone' => '99', // User default timezone.
1450                  'applydst' => true, // Apply dst.
1451                  'expectedoutput' => '1309525200'
1452              ),
1453              array(
1454                  'usertimezone' => 'America/Moncton',
1455                  'year' => '2011',
1456                  'month' => '7',
1457                  'day' => '1',
1458                  'hour' => '10',
1459                  'minutes' => '00',
1460                  'seconds' => '00',
1461                  'timezone' => 'America/Moncton', // String timezone.
1462                  'applydst' => true, // Apply dst.
1463                  'expectedoutput' => '1309525200'
1464              ),
1465              array(
1466                  'usertimezone' => '2', // No dst applyed.
1467                  'year' => '2011',
1468                  'month' => '7',
1469                  'day' => '1',
1470                  'hour' => '10',
1471                  'minutes' => '00',
1472                  'seconds' => '00',
1473                  'timezone' => '99', // Take user timezone.
1474                  'applydst' => true, // Apply dst.
1475                  'expectedoutput' => '1309507200'
1476              ),
1477              array(
1478                  'usertimezone' => '-2', // No dst applyed.
1479                  'year' => '2011',
1480                  'month' => '7',
1481                  'day' => '1',
1482                  'hour' => '10',
1483                  'minutes' => '00',
1484                  'seconds' => '00',
1485                  'timezone' => '99', // Take usertimezone.
1486                  'applydst' => true, // Apply dst.
1487                  'expectedoutput' => '1309521600'
1488              ),
1489              array(
1490                  'usertimezone' => '-10', // No dst applyed.
1491                  'year' => '2011',
1492                  'month' => '7',
1493                  'day' => '1',
1494                  'hour' => '10',
1495                  'minutes' => '00',
1496                  'seconds' => '00',
1497                  'timezone' => '2',  // Take this timezone.
1498                  'applydst' => true, // Apply dst.
1499                  'expectedoutput' => '1309507200'
1500              ),
1501              array(
1502                  'usertimezone' => '-10', // No dst applyed.
1503                  'year' => '2011',
1504                  'month' => '7',
1505                  'day' => '1',
1506                  'hour' => '10',
1507                  'minutes' => '00',
1508                  'seconds' => '00',
1509                  'timezone' => '-2', // Take this timezone.
1510                  'applydst' => true, // Apply dst.
1511                  'expectedoutput' => '1309521600'
1512              ),
1513              array(
1514                  'usertimezone' => '-10', // No dst applyed.
1515                  'year' => '2011',
1516                  'month' => '7',
1517                  'day' => '1',
1518                  'hour' => '10',
1519                  'minutes' => '00',
1520                  'seconds' => '00',
1521                  'timezone' => 'random/time', // This should show server time.
1522                  'applydst' => true,          // Apply dst.
1523                  'expectedoutput' => '1309485600'
1524              ),
1525              array(
1526                  'usertimezone' => '14', // Server time.
1527                  'year' => '2011',
1528                  'month' => '7',
1529                  'day' => '1',
1530                  'hour' => '10',
1531                  'minutes' => '00',
1532                  'seconds' => '00',
1533                  'timezone' => '99', // Get user time.
1534                  'applydst' => true, // Apply dst.
1535                  'expectedoutput' => '1309485600'
1536              )
1537          );
1538  
1539          // Check if forcetimezone is set then save it and set it to use user timezone.
1540          $cfgforcetimezone = null;
1541          if (isset($CFG->forcetimezone)) {
1542              $cfgforcetimezone = $CFG->forcetimezone;
1543              $CFG->forcetimezone = 99; // Get user default timezone.
1544          }
1545  
1546          // Store user default timezone to restore later.
1547          $userstimezone = $USER->timezone;
1548  
1549          // The string version of date comes from server locale setting and does
1550          // not respect user language, so it is necessary to reset that.
1551          $oldlocale = setlocale(LC_TIME, '0');
1552          setlocale(LC_TIME, 'en_AU.UTF-8');
1553  
1554          // Set default timezone to Australia/Perth, else time calculated
1555          // Will not match expected values. Before that save system defaults.
1556          $systemdefaulttimezone = date_default_timezone_get();
1557          date_default_timezone_set('Australia/Perth');
1558  
1559          // Test make_timestamp with all testvals and assert if anything wrong.
1560          foreach ($testvalues as $vals) {
1561              $USER->timezone = $vals['usertimezone'];
1562              $actualoutput = make_timestamp(
1563                  $vals['year'],
1564                  $vals['month'],
1565                  $vals['day'],
1566                  $vals['hour'],
1567                  $vals['minutes'],
1568                  $vals['seconds'],
1569                  $vals['timezone'],
1570                  $vals['applydst']
1571              );
1572  
1573              // On different systems case of AM PM changes so compare case insensitive.
1574              $vals['expectedoutput'] = core_text::strtolower($vals['expectedoutput']);
1575              $actualoutput = core_text::strtolower($actualoutput);
1576  
1577              $this->assertSame($vals['expectedoutput'], $actualoutput,
1578                  "Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
1579                  Please check if timezones are updated (Site adminstration -> location -> update timezone)");
1580          }
1581  
1582          // Restore user timezone back to what it was.
1583          $USER->timezone = $userstimezone;
1584  
1585          // Restore forcetimezone.
1586          if (!is_null($cfgforcetimezone)) {
1587              $CFG->forcetimezone = $cfgforcetimezone;
1588          }
1589  
1590          // Restore system default values.
1591          date_default_timezone_set($systemdefaulttimezone);
1592          setlocale(LC_TIME, $oldlocale);
1593      }
1594  
1595      /**
1596       * Test get_string and most importantly the implementation of the lang_string
1597       * object.
1598       */
1599      public function test_get_string() {
1600          global $COURSE;
1601  
1602          // Make sure we are using English.
1603          $originallang = $COURSE->lang;
1604          $COURSE->lang = 'en';
1605  
1606          $yes = get_string('yes');
1607          $yesexpected = 'Yes';
1608          $this->assertInternalType('string', $yes);
1609          $this->assertSame($yesexpected, $yes);
1610  
1611          $yes = get_string('yes', 'moodle');
1612          $this->assertInternalType('string', $yes);
1613          $this->assertSame($yesexpected, $yes);
1614  
1615          $yes = get_string('yes', 'core');
1616          $this->assertInternalType('string', $yes);
1617          $this->assertSame($yesexpected, $yes);
1618  
1619          $yes = get_string('yes', '');
1620          $this->assertInternalType('string', $yes);
1621          $this->assertSame($yesexpected, $yes);
1622  
1623          $yes = get_string('yes', null);
1624          $this->assertInternalType('string', $yes);
1625          $this->assertSame($yesexpected, $yes);
1626  
1627          $yes = get_string('yes', null, 1);
1628          $this->assertInternalType('string', $yes);
1629          $this->assertSame($yesexpected, $yes);
1630  
1631          $days = 1;
1632          $numdays = get_string('numdays', 'core', '1');
1633          $numdaysexpected = $days.' days';
1634          $this->assertInternalType('string', $numdays);
1635          $this->assertSame($numdaysexpected, $numdays);
1636  
1637          $yes = get_string('yes', null, null, true);
1638          $this->assertInstanceOf('lang_string', $yes);
1639          $this->assertSame($yesexpected, (string)$yes);
1640  
1641          // Test using a lang_string object as the $a argument for a normal
1642          // get_string call (returning string).
1643          $test = new lang_string('yes', null, null, true);
1644          $testexpected = get_string('numdays', 'core', get_string('yes'));
1645          $testresult = get_string('numdays', null, $test);
1646          $this->assertInternalType('string', $testresult);
1647          $this->assertSame($testexpected, $testresult);
1648  
1649          // Test using a lang_string object as the $a argument for an object
1650          // get_string call (returning lang_string).
1651          $test = new lang_string('yes', null, null, true);
1652          $testexpected = get_string('numdays', 'core', get_string('yes'));
1653          $testresult = get_string('numdays', null, $test, true);
1654          $this->assertInstanceOf('lang_string', $testresult);
1655          $this->assertSame($testexpected, "$testresult");
1656  
1657          // Make sure that object properties that can't be converted don't cause
1658          // errors.
1659          // Level one: This is as deep as current language processing goes.
1660          $test = new stdClass;
1661          $test->one = 'here';
1662          $string = get_string('yes', null, $test, true);
1663          $this->assertEquals($yesexpected, $string);
1664  
1665          // Make sure that object properties that can't be converted don't cause
1666          // errors.
1667          // Level two: Language processing doesn't currently reach this deep.
1668          // only immediate scalar properties are worked with.
1669          $test = new stdClass;
1670          $test->one = new stdClass;
1671          $test->one->two = 'here';
1672          $string = get_string('yes', null, $test, true);
1673          $this->assertEquals($yesexpected, $string);
1674  
1675          // Make sure that object properties that can't be converted don't cause
1676          // errors.
1677          // Level three: It should never ever go this deep, but we're making sure
1678          // it doesn't cause any probs anyway.
1679          $test = new stdClass;
1680          $test->one = new stdClass;
1681          $test->one->two = new stdClass;
1682          $test->one->two->three = 'here';
1683          $string = get_string('yes', null, $test, true);
1684          $this->assertEquals($yesexpected, $string);
1685  
1686          // Make sure that object properties that can't be converted don't cause
1687          // errors and check lang_string properties.
1688          // Level one: This is as deep as current language processing goes.
1689          $test = new stdClass;
1690          $test->one = new lang_string('yes');
1691          $string = get_string('yes', null, $test, true);
1692          $this->assertEquals($yesexpected, $string);
1693  
1694          // Make sure that object properties that can't be converted don't cause
1695          // errors and check lang_string properties.
1696          // Level two: Language processing doesn't currently reach this deep.
1697          // only immediate scalar properties are worked with.
1698          $test = new stdClass;
1699          $test->one = new stdClass;
1700          $test->one->two = new lang_string('yes');
1701          $string = get_string('yes', null, $test, true);
1702          $this->assertEquals($yesexpected, $string);
1703  
1704          // Make sure that object properties that can't be converted don't cause
1705          // errors and check lang_string properties.
1706          // Level three: It should never ever go this deep, but we're making sure
1707          // it doesn't cause any probs anyway.
1708          $test = new stdClass;
1709          $test->one = new stdClass;
1710          $test->one->two = new stdClass;
1711          $test->one->two->three = new lang_string('yes');
1712          $string = get_string('yes', null, $test, true);
1713          $this->assertEquals($yesexpected, $string);
1714  
1715          // Make sure that array properties that can't be converted don't cause
1716          // errors.
1717          $test = array();
1718          $test['one'] = new stdClass;
1719          $test['one']->two = 'here';
1720          $string = get_string('yes', null, $test, true);
1721          $this->assertEquals($yesexpected, $string);
1722  
1723          // Same thing but as above except using an object... this is allowed :P.
1724          $string = get_string('yes', null, null, true);
1725          $object = new stdClass;
1726          $object->$string = 'Yes';
1727          $this->assertEquals($yesexpected, $string);
1728          $this->assertEquals($yesexpected, $object->$string);
1729  
1730          // Reset the language.
1731          $COURSE->lang = $originallang;
1732      }
1733  
1734      /**
1735       * @expectedException PHPUnit_Framework_Error_Warning
1736       */
1737      public function test_get_string_limitation() {
1738          // This is one of the limitations to the lang_string class. It can't be
1739          // used as a key.
1740          $array = array(get_string('yes', null, null, true) => 'yes');
1741      }
1742  
1743      /**
1744       * Test localised float formatting.
1745       */
1746      public function test_format_float() {
1747  
1748          // Special case for null.
1749          $this->assertEquals('', format_float(null));
1750  
1751          // Default 1 decimal place.
1752          $this->assertEquals('5.4', format_float(5.43));
1753          $this->assertEquals('5.0', format_float(5.001));
1754  
1755          // Custom number of decimal places.
1756          $this->assertEquals('5.43000', format_float(5.43, 5));
1757  
1758          // Option to strip ending zeros after rounding.
1759          $this->assertEquals('5.43', format_float(5.43, 5, true, true));
1760          $this->assertEquals('5', format_float(5.0001, 3, true, true));
1761  
1762          // Tests with a localised decimal separator.
1763          $this->define_local_decimal_separator();
1764  
1765          // Localisation on (default).
1766          $this->assertEquals('5X43000', format_float(5.43, 5));
1767          $this->assertEquals('5X43', format_float(5.43, 5, true, true));
1768  
1769          // Localisation off.
1770          $this->assertEquals('5.43000', format_float(5.43, 5, false));
1771          $this->assertEquals('5.43', format_float(5.43, 5, false, true));
1772      }
1773  
1774      /**
1775       * Test localised float unformatting.
1776       */
1777      public function test_unformat_float() {
1778  
1779          // Tests without the localised decimal separator.
1780  
1781          // Special case for null, empty or white spaces only strings.
1782          $this->assertEquals(null, unformat_float(null));
1783          $this->assertEquals(null, unformat_float(''));
1784          $this->assertEquals(null, unformat_float('    '));
1785  
1786          // Regular use.
1787          $this->assertEquals(5.4, unformat_float('5.4'));
1788          $this->assertEquals(5.4, unformat_float('5.4', true));
1789  
1790          // No decimal.
1791          $this->assertEquals(5.0, unformat_float('5'));
1792  
1793          // Custom number of decimal.
1794          $this->assertEquals(5.43267, unformat_float('5.43267'));
1795  
1796          // Empty decimal.
1797          $this->assertEquals(100.0, unformat_float('100.00'));
1798  
1799          // With the thousand separator.
1800          $this->assertEquals(1000.0, unformat_float('1 000'));
1801          $this->assertEquals(1000.32, unformat_float('1 000.32'));
1802  
1803          // Negative number.
1804          $this->assertEquals(-100.0, unformat_float('-100'));
1805  
1806          // Wrong value.
1807          $this->assertEquals(0.0, unformat_float('Wrong value'));
1808          // Wrong value in strict mode.
1809          $this->assertFalse(unformat_float('Wrong value', true));
1810  
1811          // Combining options.
1812          $this->assertEquals(-1023.862567, unformat_float('   -1 023.862567     '));
1813  
1814          // Bad decimal separator (should crop the decimal).
1815          $this->assertEquals(50.0, unformat_float('50,57'));
1816          // Bad decimal separator in strict mode (should return false).
1817          $this->assertFalse(unformat_float('50,57', true));
1818  
1819          // Tests with a localised decimal separator.
1820          $this->define_local_decimal_separator();
1821  
1822          // We repeat the tests above but with the current decimal separator.
1823  
1824          // Regular use without and with the localised separator.
1825          $this->assertEquals (5.4, unformat_float('5.4'));
1826          $this->assertEquals (5.4, unformat_float('5X4'));
1827  
1828          // Custom number of decimal.
1829          $this->assertEquals (5.43267, unformat_float('5X43267'));
1830  
1831          // Empty decimal.
1832          $this->assertEquals (100.0, unformat_float('100X00'));
1833  
1834          // With the thousand separator.
1835          $this->assertEquals (1000.32, unformat_float('1 000X32'));
1836  
1837          // Bad different separator (should crop the decimal).
1838          $this->assertEquals (50.0, unformat_float('50Y57'));
1839          // Bad different separator in strict mode (should return false).
1840          $this->assertFalse (unformat_float('50Y57', true));
1841  
1842          // Combining options.
1843          $this->assertEquals (-1023.862567, unformat_float('   -1 023X862567     '));
1844          // Combining options in strict mode.
1845          $this->assertEquals (-1023.862567, unformat_float('   -1 023X862567     ', true));
1846      }
1847  
1848      /**
1849       * Test deleting of users.
1850       */
1851      public function test_delete_user() {
1852          global $DB, $CFG;
1853  
1854          $this->resetAfterTest();
1855  
1856          $guest = $DB->get_record('user', array('id'=>$CFG->siteguest), '*', MUST_EXIST);
1857          $admin = $DB->get_record('user', array('id'=>$CFG->siteadmins), '*', MUST_EXIST);
1858          $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
1859  
1860          $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
1861          $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
1862  
1863          // Delete user and capture event.
1864          $sink = $this->redirectEvents();
1865          $result = delete_user($user);
1866          $events = $sink->get_events();
1867          $sink->close();
1868          $event = array_pop($events);
1869  
1870          // Test user is deleted in DB.
1871          $this->assertTrue($result);
1872          $deluser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
1873          $this->assertEquals(1, $deluser->deleted);
1874          $this->assertEquals(0, $deluser->picture);
1875          $this->assertSame('', $deluser->idnumber);
1876          $this->assertSame(md5($user->username), $deluser->email);
1877          $this->assertRegExp('/^'.preg_quote($user->email, '/').'\.\d*$/', $deluser->username);
1878  
1879          $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
1880  
1881          // Test Event.
1882          $this->assertInstanceOf('\core\event\user_deleted', $event);
1883          $this->assertSame($user->id, $event->objectid);
1884          $this->assertSame('user_deleted', $event->get_legacy_eventname());
1885          $this->assertEventLegacyData($user, $event);
1886          $expectedlogdata = array(SITEID, 'user', 'delete', "view.php?id=$user->id", $user->firstname.' '.$user->lastname);
1887          $this->assertEventLegacyLogData($expectedlogdata, $event);
1888          $eventdata = $event->get_data();
1889          $this->assertSame($eventdata['other']['username'], $user->username);
1890          $this->assertSame($eventdata['other']['email'], $user->email);
1891          $this->assertSame($eventdata['other']['idnumber'], $user->idnumber);
1892          $this->assertSame($eventdata['other']['picture'], $user->picture);
1893          $this->assertSame($eventdata['other']['mnethostid'], $user->mnethostid);
1894          $this->assertEquals($user, $event->get_record_snapshot('user', $event->objectid));
1895          $this->assertEventContextNotUsed($event);
1896  
1897          // Try invalid params.
1898          $record = new stdClass();
1899          $record->grrr = 1;
1900          try {
1901              delete_user($record);
1902              $this->fail('Expecting exception for invalid delete_user() $user parameter');
1903          } catch (moodle_exception $ex) {
1904              $this->assertInstanceOf('coding_exception', $ex);
1905          }
1906          $record->id = 1;
1907          try {
1908              delete_user($record);
1909              $this->fail('Expecting exception for invalid delete_user() $user parameter');
1910          } catch (moodle_exception $ex) {
1911              $this->assertInstanceOf('coding_exception', $ex);
1912          }
1913  
1914          $record = new stdClass();
1915          $record->id = 666;
1916          $record->username = 'xx';
1917          $this->assertFalse($DB->record_exists('user', array('id'=>666))); // Any non-existent id is ok.
1918          $result = delete_user($record);
1919          $this->assertFalse($result);
1920  
1921          $result = delete_user($guest);
1922          $this->assertFalse($result);
1923  
1924          $result = delete_user($admin);
1925          $this->assertFalse($result);
1926  
1927          $this->resetDebugging();
1928      }
1929  
1930      /**
1931       * Test function convert_to_array()
1932       */
1933      public function test_convert_to_array() {
1934          // Check that normal classes are converted to arrays the same way as (array) would do.
1935          $obj = new stdClass();
1936          $obj->prop1 = 'hello';
1937          $obj->prop2 = array('first', 'second', 13);
1938          $obj->prop3 = 15;
1939          $this->assertEquals(convert_to_array($obj), (array)$obj);
1940  
1941          // Check that context object (with iterator) is converted to array properly.
1942          $obj = context_system::instance();
1943          $ar = array(
1944              'id'           => $obj->id,
1945              'contextlevel' => $obj->contextlevel,
1946              'instanceid'   => $obj->instanceid,
1947              'path'         => $obj->path,
1948              'depth'        => $obj->depth
1949          );
1950          $this->assertEquals(convert_to_array($obj), $ar);
1951      }
1952  
1953      /**
1954       * Test the function date_format_string().
1955       */
1956      public function test_date_format_string() {
1957          global $CFG;
1958  
1959          // Forcing locale and timezone.
1960          $oldlocale = setlocale(LC_TIME, '0');
1961          if ($CFG->ostype == 'WINDOWS') {
1962              setlocale(LC_TIME, 'English_Australia.1252');
1963          } else {
1964              setlocale(LC_TIME, 'en_AU.UTF-8');
1965          }
1966          $systemdefaulttimezone = date_default_timezone_get();
1967          date_default_timezone_set('Australia/Perth');
1968  
1969          $tests = array(
1970              array(
1971                  'tz' => 99,
1972                  'str' => '%A, %d %B %Y, %I:%M %p',
1973                  'expected' => 'Saturday, 01 January 2011, 06:00 PM'
1974              ),
1975              array(
1976                  'tz' => 0,
1977                  'str' => '%A, %d %B %Y, %I:%M %p',
1978                  'expected' => 'Saturday, 01 January 2011, 10:00 AM'
1979              ),
1980              array(
1981                  'tz' => -12,
1982                  'str' => '%A, %d %B %Y, %I:%M %p',
1983                  'expected' => 'Saturday, 01 January 2011, 10:00 AM'
1984              ),
1985              // Following tests pass on Windows only because en lang pack does
1986              // not contain localewincharset, in real life lang pack maintainers
1987              // may use only characters that are present in localewincharset
1988              // in format strings!
1989              array(
1990                  'tz' => 99,
1991                  'str' => 'Žluťoučký koníček %A',
1992                  'expected' => 'Žluťoučký koníček Saturday'
1993              ),
1994              array(
1995                  'tz' => 99,
1996                  'str' => '言語設定言語 %A',
1997                  'expected' => '言語設定言語 Saturday'
1998              ),
1999              array(
2000                  'tz' => 99,
2001                  'str' => '简体中文简体 %A',
2002                  'expected' => '简体中文简体 Saturday'
2003              ),
2004          );
2005  
2006          // Note: date_format_string() uses the timezone only to differenciate
2007          // the server time from the UTC time. It does not modify the timestamp.
2008          // Hence similar results for timezones <= 13.
2009          // On different systems case of AM PM changes so compare case insensitive.
2010          foreach ($tests as $test) {
2011              $str = date_format_string(1293876000, $test['str'], $test['tz']);
2012              $this->assertSame(core_text::strtolower($test['expected']), core_text::strtolower($str));
2013          }
2014  
2015          // Restore system default values.
2016          date_default_timezone_set($systemdefaulttimezone);
2017          setlocale(LC_TIME, $oldlocale);
2018      }
2019  
2020      public function test_get_config() {
2021          global $CFG;
2022  
2023          $this->resetAfterTest();
2024  
2025          // Preparation.
2026          set_config('phpunit_test_get_config_1', 'test 1');
2027          set_config('phpunit_test_get_config_2', 'test 2', 'mod_forum');
2028          if (!is_array($CFG->config_php_settings)) {
2029              $CFG->config_php_settings = array();
2030          }
2031          $CFG->config_php_settings['phpunit_test_get_config_3'] = 'test 3';
2032  
2033          if (!is_array($CFG->forced_plugin_settings)) {
2034              $CFG->forced_plugin_settings = array();
2035          }
2036          if (!array_key_exists('mod_forum', $CFG->forced_plugin_settings)) {
2037              $CFG->forced_plugin_settings['mod_forum'] = array();
2038          }
2039          $CFG->forced_plugin_settings['mod_forum']['phpunit_test_get_config_4'] = 'test 4';
2040          $CFG->phpunit_test_get_config_5 = 'test 5';
2041  
2042          // Testing.
2043          $this->assertSame('test 1', get_config('core', 'phpunit_test_get_config_1'));
2044          $this->assertSame('test 2', get_config('mod_forum', 'phpunit_test_get_config_2'));
2045          $this->assertSame('test 3', get_config('core', 'phpunit_test_get_config_3'));
2046          $this->assertSame('test 4', get_config('mod_forum', 'phpunit_test_get_config_4'));
2047          $this->assertFalse(get_config('core', 'phpunit_test_get_config_5'));
2048          $this->assertFalse(get_config('core', 'phpunit_test_get_config_x'));
2049          $this->assertFalse(get_config('mod_forum', 'phpunit_test_get_config_x'));
2050  
2051          // Test config we know to exist.
2052          $this->assertSame($CFG->dataroot, get_config('core', 'dataroot'));
2053          $this->assertSame($CFG->phpunit_dataroot, get_config('core', 'phpunit_dataroot'));
2054          $this->assertSame($CFG->dataroot, get_config('core', 'phpunit_dataroot'));
2055          $this->assertSame(get_config('core', 'dataroot'), get_config('core', 'phpunit_dataroot'));
2056  
2057          // Test setting a config var that already exists.
2058          set_config('phpunit_test_get_config_1', 'test a');
2059          $this->assertSame('test a', $CFG->phpunit_test_get_config_1);
2060          $this->assertSame('test a', get_config('core', 'phpunit_test_get_config_1'));
2061  
2062          // Test cache invalidation.
2063          $cache = cache::make('core', 'config');
2064          $this->assertInternalType('array', $cache->get('core'));
2065          $this->assertInternalType('array', $cache->get('mod_forum'));
2066          set_config('phpunit_test_get_config_1', 'test b');
2067          $this->assertFalse($cache->get('core'));
2068          set_config('phpunit_test_get_config_4', 'test c', 'mod_forum');
2069          $this->assertFalse($cache->get('mod_forum'));
2070      }
2071  
2072      public function test_get_max_upload_sizes() {
2073          // Test with very low limits so we are not affected by php upload limits.
2074          // Test activity limit smallest.
2075          $sitebytes = 102400;
2076          $coursebytes = 51200;
2077          $modulebytes = 10240;
2078          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
2079  
2080          $this->assertSame('Activity upload limit (10KB)', $result['0']);
2081          $this->assertCount(2, $result);
2082  
2083          // Test course limit smallest.
2084          $sitebytes = 102400;
2085          $coursebytes = 10240;
2086          $modulebytes = 51200;
2087          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
2088  
2089          $this->assertSame('Course upload limit (10KB)', $result['0']);
2090          $this->assertCount(2, $result);
2091  
2092          // Test site limit smallest.
2093          $sitebytes = 10240;
2094          $coursebytes = 102400;
2095          $modulebytes = 51200;
2096          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
2097  
2098          $this->assertSame('Site upload limit (10KB)', $result['0']);
2099          $this->assertCount(2, $result);
2100  
2101          // Test site limit not set.
2102          $sitebytes = 0;
2103          $coursebytes = 102400;
2104          $modulebytes = 51200;
2105          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
2106  
2107          $this->assertSame('Activity upload limit (50KB)', $result['0']);
2108          $this->assertCount(3, $result);
2109  
2110          $sitebytes = 0;
2111          $coursebytes = 51200;
2112          $modulebytes = 102400;
2113          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
2114  
2115          $this->assertSame('Course upload limit (50KB)', $result['0']);
2116          $this->assertCount(3, $result);
2117  
2118          // Test custom bytes in range.
2119          $sitebytes = 102400;
2120          $coursebytes = 51200;
2121          $modulebytes = 51200;
2122          $custombytes = 10240;
2123          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
2124  
2125          $this->assertCount(3, $result);
2126  
2127          // Test custom bytes in range but non-standard.
2128          $sitebytes = 102400;
2129          $coursebytes = 51200;
2130          $modulebytes = 51200;
2131          $custombytes = 25600;
2132          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
2133  
2134          $this->assertCount(4, $result);
2135  
2136          // Test custom bytes out of range.
2137          $sitebytes = 102400;
2138          $coursebytes = 51200;
2139          $modulebytes = 51200;
2140          $custombytes = 102400;
2141          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
2142  
2143          $this->assertCount(3, $result);
2144  
2145          // Test custom bytes out of range and non-standard.
2146          $sitebytes = 102400;
2147          $coursebytes = 51200;
2148          $modulebytes = 51200;
2149          $custombytes = 256000;
2150          $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
2151  
2152          $this->assertCount(3, $result);
2153  
2154          // Test site limit only.
2155          $sitebytes = 51200;
2156          $result = get_max_upload_sizes($sitebytes);
2157  
2158          $this->assertSame('Site upload limit (50KB)', $result['0']);
2159          $this->assertSame('50KB', $result['51200']);
2160          $this->assertSame('10KB', $result['10240']);
2161          $this->assertCount(3, $result);
2162  
2163          // Test no limit.
2164          $result = get_max_upload_sizes();
2165          $this->assertArrayHasKey('0', $result);
2166          $this->assertArrayHasKey(get_max_upload_file_size(), $result);
2167      }
2168  
2169      /**
2170       * Test function password_is_legacy_hash().
2171       */
2172      public function test_password_is_legacy_hash() {
2173          // Well formed md5s should be matched.
2174          foreach (array('some', 'strings', 'to_check!') as $string) {
2175              $md5 = md5($string);
2176              $this->assertTrue(password_is_legacy_hash($md5));
2177          }
2178          // Strings that are not md5s should not be matched.
2179          foreach (array('', AUTH_PASSWORD_NOT_CACHED, 'IPW8WTcsWNgAWcUS1FBVHegzJnw5M2jOmYkmfc8z.xdBOyC4Caeum') as $notmd5) {
2180              $this->assertFalse(password_is_legacy_hash($notmd5));
2181          }
2182      }
2183  
2184      /**
2185       * Test function validate_internal_user_password().
2186       */
2187      public function test_validate_internal_user_password() {
2188          // Test bcrypt hashes.
2189          $validhashes = array(
2190              'pw' => '$2y$10$LOSDi5eaQJhutSRun.OVJ.ZSxQZabCMay7TO1KmzMkDMPvU40zGXK',
2191              'abc' => '$2y$10$VWTOhVdsBbWwtdWNDRHSpewjd3aXBQlBQf5rBY/hVhw8hciarFhXa',
2192              'C0mP1eX_&}<?@*&%` |\"' => '$2y$10$3PJf.q.9ywNJlsInPbqc8.IFeSsvXrGvQLKRFBIhVu1h1I3vpIry6',
2193              'ĩńťėŕňăţĩōŋāĹ' => '$2y$10$3A2Y8WpfRAnP3czJiSv6N.6Xp0T8hW3QZz2hUCYhzyWr1kGP1yUve'
2194          );
2195  
2196          foreach ($validhashes as $password => $hash) {
2197              $user = new stdClass();
2198              $user->auth = 'manual';
2199              $user->password = $hash;
2200              // The correct password should be validated.
2201              $this->assertTrue(validate_internal_user_password($user, $password));
2202              // An incorrect password should not be validated.
2203              $this->assertFalse(validate_internal_user_password($user, 'badpw'));
2204          }
2205      }
2206  
2207      /**
2208       * Test function hash_internal_user_password().
2209       */
2210      public function test_hash_internal_user_password() {
2211          $passwords = array('pw', 'abc123', 'C0mP1eX_&}<?@*&%` |\"', 'ĩńťėŕňăţĩōŋāĹ');
2212  
2213          // Check that some passwords that we convert to hashes can
2214          // be validated.
2215          foreach ($passwords as $password) {
2216              $hash = hash_internal_user_password($password);
2217              $fasthash = hash_internal_user_password($password, true);
2218              $user = new stdClass();
2219              $user->auth = 'manual';
2220              $user->password = $hash;
2221              $this->assertTrue(validate_internal_user_password($user, $password));
2222  
2223              // They should not be in md5 format.
2224              $this->assertFalse(password_is_legacy_hash($hash));
2225  
2226              // Check that cost factor in hash is correctly set.
2227              $this->assertRegExp('/\$10\$/', $hash);
2228              $this->assertRegExp('/\$04\$/', $fasthash);
2229          }
2230      }
2231  
2232      /**
2233       * Test function update_internal_user_password().
2234       */
2235      public function test_update_internal_user_password() {
2236          global $DB;
2237          $this->resetAfterTest();
2238          $passwords = array('password', '1234', 'changeme', '****');
2239          foreach ($passwords as $password) {
2240              $user = $this->getDataGenerator()->create_user(array('auth'=>'manual'));
2241              update_internal_user_password($user, $password);
2242              // The user object should have been updated.
2243              $this->assertTrue(validate_internal_user_password($user, $password));
2244              // The database field for the user should also have been updated to the
2245              // same value.
2246              $this->assertSame($user->password, $DB->get_field('user', 'password', array('id' => $user->id)));
2247          }
2248  
2249          $user = $this->getDataGenerator()->create_user(array('auth'=>'manual'));
2250          // Manually set the user's password to the md5 of the string 'password'.
2251          $DB->set_field('user', 'password', '5f4dcc3b5aa765d61d8327deb882cf99', array('id' => $user->id));
2252  
2253          $sink = $this->redirectEvents();
2254          // Update the password.
2255          update_internal_user_password($user, 'password');
2256          $events = $sink->get_events();
2257          $sink->close();
2258          $event = array_pop($events);
2259  
2260          // Password should have been updated to a bcrypt hash.
2261          $this->assertFalse(password_is_legacy_hash($user->password));
2262  
2263          // Verify event information.
2264          $this->assertInstanceOf('\core\event\user_password_updated', $event);
2265          $this->assertSame($user->id, $event->relateduserid);
2266          $this->assertEquals(context_user::instance($user->id), $event->get_context());
2267          $this->assertEventContextNotUsed($event);
2268  
2269          // Verify recovery of property 'auth'.
2270          unset($user->auth);
2271          update_internal_user_password($user, 'newpassword');
2272          $this->assertDebuggingCalled('User record in update_internal_user_password() must include field auth',
2273                  DEBUG_DEVELOPER);
2274          $this->assertEquals('manual', $user->auth);
2275      }
2276  
2277      /**
2278       * Testing that if the password is not cached, that it does not update
2279       * the user table and fire event.
2280       */
2281      public function test_update_internal_user_password_no_cache() {
2282          $this->resetAfterTest();
2283  
2284          $user = $this->getDataGenerator()->create_user(array('auth' => 'cas'));
2285          $this->assertEquals(AUTH_PASSWORD_NOT_CACHED, $user->password);
2286  
2287          $sink = $this->redirectEvents();
2288          update_internal_user_password($user, 'wonkawonka');
2289          $this->assertEquals(0, $sink->count(), 'User updated event should not fire');
2290      }
2291  
2292      /**
2293       * Test if the user has a password hash, but now their auth method
2294       * says not to cache it.  Then it should update.
2295       */
2296      public function test_update_internal_user_password_update_no_cache() {
2297          $this->resetAfterTest();
2298  
2299          $user = $this->getDataGenerator()->create_user(array('password' => 'test'));
2300          $this->assertNotEquals(AUTH_PASSWORD_NOT_CACHED, $user->password);
2301          $user->auth = 'cas'; // Change to a auth that does not store passwords.
2302  
2303          $sink = $this->redirectEvents();
2304          update_internal_user_password($user, 'wonkawonka');
2305          $this->assertGreaterThanOrEqual(1, $sink->count(), 'User updated event should fire');
2306  
2307          $this->assertEquals(AUTH_PASSWORD_NOT_CACHED, $user->password);
2308      }
2309  
2310      public function test_fullname() {
2311          global $CFG;
2312  
2313          $this->resetAfterTest();
2314  
2315          // Create a user to test the name display on.
2316          $record = array();
2317          $record['firstname'] = 'Scott';
2318          $record['lastname'] = 'Fletcher';
2319          $record['firstnamephonetic'] = 'スコット';
2320          $record['lastnamephonetic'] = 'フレチャー';
2321          $record['alternatename'] = 'No friends';
2322          $user = $this->getDataGenerator()->create_user($record);
2323  
2324          // Back up config settings for restore later.
2325          $originalcfg = new stdClass();
2326          $originalcfg->fullnamedisplay = $CFG->fullnamedisplay;
2327          $originalcfg->alternativefullnameformat = $CFG->alternativefullnameformat;
2328  
2329          // Testing existing fullnamedisplay settings.
2330          $CFG->fullnamedisplay = 'firstname';
2331          $testname = fullname($user);
2332          $this->assertSame($user->firstname, $testname);
2333  
2334          $CFG->fullnamedisplay = 'firstname lastname';
2335          $expectedname = "$user->firstname $user->lastname";
2336          $testname = fullname($user);
2337          $this->assertSame($expectedname, $testname);
2338  
2339          $CFG->fullnamedisplay = 'lastname firstname';
2340          $expectedname = "$user->lastname $user->firstname";
2341          $testname = fullname($user);
2342          $this->assertSame($expectedname, $testname);
2343  
2344          $expectedname = get_string('fullnamedisplay', null, $user);
2345          $CFG->fullnamedisplay = 'language';
2346          $testname = fullname($user);
2347          $this->assertSame($expectedname, $testname);
2348  
2349          // Test override parameter.
2350          $CFG->fullnamedisplay = 'firstname';
2351          $expectedname = "$user->firstname $user->lastname";
2352          $testname = fullname($user, true);
2353          $this->assertSame($expectedname, $testname);
2354  
2355          // Test alternativefullnameformat setting.
2356          // Test alternativefullnameformat that has been set to nothing.
2357          $CFG->alternativefullnameformat = '';
2358          $expectedname = "$user->firstname $user->lastname";
2359          $testname = fullname($user, true);
2360          $this->assertSame($expectedname, $testname);
2361  
2362          // Test alternativefullnameformat that has been set to 'language'.
2363          $CFG->alternativefullnameformat = 'language';
2364          $expectedname = "$user->firstname $user->lastname";
2365          $testname = fullname($user, true);
2366          $this->assertSame($expectedname, $testname);
2367  
2368          // Test customising the alternativefullnameformat setting with all additional name fields.
2369          $CFG->alternativefullnameformat = 'firstname lastname firstnamephonetic lastnamephonetic middlename alternatename';
2370          $expectedname = "$user->firstname $user->lastname $user->firstnamephonetic $user->lastnamephonetic $user->middlename $user->alternatename";
2371          $testname = fullname($user, true);
2372          $this->assertSame($expectedname, $testname);
2373  
2374          // Test additional name fields.
2375          $CFG->fullnamedisplay = 'lastname lastnamephonetic firstname firstnamephonetic';
2376          $expectedname = "$user->lastname $user->lastnamephonetic $user->firstname $user->firstnamephonetic";
2377          $testname = fullname($user);
2378          $this->assertSame($expectedname, $testname);
2379  
2380          // Test for handling missing data.
2381          $user->middlename = null;
2382          // Parenthesis with no data.
2383          $CFG->fullnamedisplay = 'firstname (middlename) lastname';
2384          $expectedname = "$user->firstname $user->lastname";
2385          $testname = fullname($user);
2386          $this->assertSame($expectedname, $testname);
2387  
2388          // Extra spaces due to no data.
2389          $CFG->fullnamedisplay = 'firstname middlename lastname';
2390          $expectedname = "$user->firstname $user->lastname";
2391          $testname = fullname($user);
2392          $this->assertSame($expectedname, $testname);
2393  
2394          // Regular expression testing.
2395          // Remove some data from the user fields.
2396          $user->firstnamephonetic = '';
2397          $user->lastnamephonetic = '';
2398  
2399          // Removing empty brackets and excess whitespace.
2400          // All of these configurations should resolve to just firstname lastname.
2401          $configarray = array();
2402          $configarray[] = 'firstname lastname [firstnamephonetic lastnamephonetic]';
2403          $configarray[] = 'firstname lastname \'middlename\'';
2404          $configarray[] = 'firstname "firstnamephonetic" lastname';
2405          $configarray[] = 'firstname 「firstnamephonetic」 lastname 「lastnamephonetic」';
2406  
2407          foreach ($configarray as $config) {
2408              $CFG->fullnamedisplay = $config;
2409              $expectedname = "$user->firstname $user->lastname";
2410              $testname = fullname($user);
2411              $this->assertSame($expectedname, $testname);
2412          }
2413  
2414          // Check to make sure that other characters are left in place.
2415          $configarray = array();
2416          $configarray['0'] = new stdClass();
2417          $configarray['0']->config = 'lastname firstname, middlename';
2418          $configarray['0']->expectedname = "$user->lastname $user->firstname,";
2419          $configarray['1'] = new stdClass();
2420          $configarray['1']->config = 'lastname firstname + alternatename';
2421          $configarray['1']->expectedname = "$user->lastname $user->firstname + $user->alternatename";
2422          $configarray['2'] = new stdClass();
2423          $configarray['2']->config = 'firstname aka: alternatename';
2424          $configarray['2']->expectedname = "$user->firstname aka: $user->alternatename";
2425          $configarray['3'] = new stdClass();
2426          $configarray['3']->config = 'firstname (alternatename)';
2427          $configarray['3']->expectedname = "$user->firstname ($user->alternatename)";
2428          $configarray['4'] = new stdClass();
2429          $configarray['4']->config = 'firstname [alternatename]';
2430          $configarray['4']->expectedname = "$user->firstname [$user->alternatename]";
2431          $configarray['5'] = new stdClass();
2432          $configarray['5']->config = 'firstname "lastname"';
2433          $configarray['5']->expectedname = "$user->firstname \"$user->lastname\"";
2434  
2435          foreach ($configarray as $config) {
2436              $CFG->fullnamedisplay = $config->config;
2437              $expectedname = $config->expectedname;
2438              $testname = fullname($user);
2439              $this->assertSame($expectedname, $testname);
2440          }
2441  
2442          // Test debugging message displays when
2443          // fullnamedisplay setting is "normal".
2444          $CFG->fullnamedisplay = 'firstname lastname';
2445          unset($user);
2446          $user = new stdClass();
2447          $user->firstname = 'Stan';
2448          $user->lastname = 'Lee';
2449          $namedisplay = fullname($user);
2450          $this->assertDebuggingCalled();
2451  
2452          // Tidy up after we finish testing.
2453          $CFG->fullnamedisplay = $originalcfg->fullnamedisplay;
2454          $CFG->alternativefullnameformat = $originalcfg->alternativefullnameformat;
2455      }
2456  
2457      public function test_get_all_user_name_fields() {
2458          $this->resetAfterTest();
2459  
2460          // Additional names in an array.
2461          $testarray = array('firstnamephonetic' => 'firstnamephonetic',
2462                  'lastnamephonetic' => 'lastnamephonetic',
2463                  'middlename' => 'middlename',
2464                  'alternatename' => 'alternatename',
2465                  'firstname' => 'firstname',
2466                  'lastname' => 'lastname');
2467          $this->assertEquals($testarray, get_all_user_name_fields());
2468  
2469          // Additional names as a string.
2470          $teststring = 'firstnamephonetic,lastnamephonetic,middlename,alternatename,firstname,lastname';
2471          $this->assertEquals($teststring, get_all_user_name_fields(true));
2472  
2473          // Additional names as a string with an alias.
2474          $teststring = 't.firstnamephonetic,t.lastnamephonetic,t.middlename,t.alternatename,t.firstname,t.lastname';
2475          $this->assertEquals($teststring, get_all_user_name_fields(true, 't'));
2476  
2477          // Additional name fields with a prefix - object.
2478          $testarray = array('firstnamephonetic' => 'authorfirstnamephonetic',
2479                  'lastnamephonetic' => 'authorlastnamephonetic',
2480                  'middlename' => 'authormiddlename',
2481                  'alternatename' => 'authoralternatename',
2482                  'firstname' => 'authorfirstname',
2483                  'lastname' => 'authorlastname');
2484          $this->assertEquals($testarray, get_all_user_name_fields(false, null, 'author'));
2485  
2486          // Additional name fields with an alias and a title - string.
2487          $teststring = 'u.firstnamephonetic AS authorfirstnamephonetic,u.lastnamephonetic AS authorlastnamephonetic,u.middlename AS authormiddlename,u.alternatename AS authoralternatename,u.firstname AS authorfirstname,u.lastname AS authorlastname';
2488          $this->assertEquals($teststring, get_all_user_name_fields(true, 'u', null, 'author'));
2489  
2490          // Test the order parameter of the function.
2491          // Returning an array.
2492          $testarray = array('firstname' => 'firstname',
2493                  'lastname' => 'lastname',
2494                  'firstnamephonetic' => 'firstnamephonetic',
2495                  'lastnamephonetic' => 'lastnamephonetic',
2496                  'middlename' => 'middlename',
2497                  'alternatename' => 'alternatename'
2498          );
2499          $this->assertEquals($testarray, get_all_user_name_fields(false, null, null, null, true));
2500  
2501          // Returning a string.
2502          $teststring = 'firstname,lastname,firstnamephonetic,lastnamephonetic,middlename,alternatename';
2503          $this->assertEquals($teststring, get_all_user_name_fields(true, null, null, null, true));
2504      }
2505  
2506      public function test_order_in_string() {
2507          $this->resetAfterTest();
2508  
2509          // Return an array in an order as they are encountered in a string.
2510          $valuearray = array('second', 'firsthalf', 'first');
2511          $formatstring = 'first firsthalf some other text (second)';
2512          $expectedarray = array('0' => 'first', '6' => 'firsthalf', '33' => 'second');
2513          $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring));
2514  
2515          // Try again with a different order for the format.
2516          $valuearray = array('second', 'firsthalf', 'first');
2517          $formatstring = 'firsthalf first second';
2518          $expectedarray = array('0' => 'firsthalf', '10' => 'first', '16' => 'second');
2519          $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring));
2520  
2521          // Try again with yet another different order for the format.
2522          $valuearray = array('second', 'firsthalf', 'first');
2523          $formatstring = 'start seconds away second firstquater first firsthalf';
2524          $expectedarray = array('19' => 'second', '38' => 'first', '44' => 'firsthalf');
2525          $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring));
2526      }
2527  
2528      public function test_complete_user_login() {
2529          global $USER, $DB;
2530  
2531          $this->resetAfterTest();
2532          $user = $this->getDataGenerator()->create_user();
2533          $this->setUser(0);
2534  
2535          $sink = $this->redirectEvents();
2536          $loginuser = clone($user);
2537          $this->setCurrentTimeStart();
2538          @complete_user_login($loginuser); // Hide session header errors.
2539          $this->assertSame($loginuser, $USER);
2540          $this->assertEquals($user->id, $USER->id);
2541          $events = $sink->get_events();
2542          $sink->close();
2543  
2544          $this->assertCount(1, $events);
2545          $event = reset($events);
2546          $this->assertInstanceOf('\core\event\user_loggedin', $event);
2547          $this->assertEquals('user', $event->objecttable);
2548          $this->assertEquals($user->id, $event->objectid);
2549          $this->assertEquals(context_system::instance()->id, $event->contextid);
2550          $this->assertEventContextNotUsed($event);
2551  
2552          $user = $DB->get_record('user', array('id'=>$user->id));
2553  
2554          $this->assertTimeCurrent($user->firstaccess);
2555          $this->assertTimeCurrent($user->lastaccess);
2556  
2557          $this->assertTimeCurrent($USER->firstaccess);
2558          $this->assertTimeCurrent($USER->lastaccess);
2559          $this->assertTimeCurrent($USER->currentlogin);
2560          $this->assertSame(sesskey(), $USER->sesskey);
2561          $this->assertTimeCurrent($USER->preference['_lastloaded']);
2562          $this->assertObjectNotHasAttribute('password', $USER);
2563          $this->assertObjectNotHasAttribute('description', $USER);
2564      }
2565  
2566      /**
2567       * Test require_logout.
2568       */
2569      public function test_require_logout() {
2570          $this->resetAfterTest();
2571          $user = $this->getDataGenerator()->create_user();
2572          $this->setUser($user);
2573  
2574          $this->assertTrue(isloggedin());
2575  
2576          // Logout user and capture event.
2577          $sink = $this->redirectEvents();
2578          require_logout();
2579          $events = $sink->get_events();
2580          $sink->close();
2581          $event = array_pop($events);
2582  
2583          // Check if user is logged out.
2584          $this->assertFalse(isloggedin());
2585  
2586          // Test Event.
2587          $this->assertInstanceOf('\core\event\user_loggedout', $event);
2588          $this->assertSame($user->id, $event->objectid);
2589          $this->assertSame('user_logout', $event->get_legacy_eventname());
2590          $this->assertEventLegacyData($user, $event);
2591          $expectedlogdata = array(SITEID, 'user', 'logout', 'view.php?id='.$event->objectid.'&course='.SITEID, $event->objectid, 0,
2592              $event->objectid);
2593          $this->assertEventLegacyLogData($expectedlogdata, $event);
2594          $this->assertEventContextNotUsed($event);
2595      }
2596  
2597      public function test_email_to_user() {
2598          global $CFG;
2599  
2600          $this->resetAfterTest();
2601  
2602          $user1 = $this->getDataGenerator()->create_user();
2603          $user2 = $this->getDataGenerator()->create_user();
2604  
2605          $subject = 'subject';
2606          $messagetext = 'message text';
2607          $subject2 = 'subject 2';
2608          $messagetext2 = 'message text 2';
2609  
2610          $this->assertNotEmpty($CFG->noemailever);
2611          email_to_user($user1, $user2, $subject, $messagetext);
2612          $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting');
2613  
2614          unset_config('noemailever');
2615  
2616          email_to_user($user1, $user2, $subject, $messagetext);
2617          $this->assertDebuggingCalled('Unit tests must not send real emails! Use $this->redirectEmails()');
2618  
2619          $sink = $this->redirectEmails();
2620          email_to_user($user1, $user2, $subject, $messagetext);
2621          email_to_user($user2, $user1, $subject2, $messagetext2);
2622          $this->assertSame(2, $sink->count());
2623          $result = $sink->get_messages();
2624          $this->assertCount(2, $result);
2625          $sink->close();
2626  
2627          $this->assertSame($subject, $result[0]->subject);
2628          $this->assertSame($messagetext, trim($result[0]->body));
2629          $this->assertSame($user1->email, $result[0]->to);
2630          $this->assertSame($user2->email, $result[0]->from);
2631  
2632          $this->assertSame($subject2, $result[1]->subject);
2633          $this->assertSame($messagetext2, trim($result[1]->body));
2634          $this->assertSame($user2->email, $result[1]->to);
2635          $this->assertSame($user1->email, $result[1]->from);
2636  
2637          email_to_user($user1, $user2, $subject, $messagetext);
2638          $this->assertDebuggingCalled('Unit tests must not send real emails! Use $this->redirectEmails()');
2639  
2640          // Test $CFG->emailonlyfromnoreplyaddress.
2641          set_config('emailonlyfromnoreplyaddress', 1);
2642          $this->assertNotEmpty($CFG->emailonlyfromnoreplyaddress);
2643          $sink = $this->redirectEmails();
2644          email_to_user($user1, $user2, $subject, $messagetext);
2645          unset_config('emailonlyfromnoreplyaddress');
2646          email_to_user($user1, $user2, $subject, $messagetext);
2647          $result = $sink->get_messages();
2648          $this->assertEquals($CFG->noreplyaddress, $result[0]->from);
2649          $this->assertNotEquals($CFG->noreplyaddress, $result[1]->from);
2650          $sink->close();
2651      }
2652  
2653      /**
2654       * Test setnew_password_and_mail.
2655       */
2656      public function test_setnew_password_and_mail() {
2657          global $DB, $CFG;
2658  
2659          $this->resetAfterTest();
2660  
2661          $user = $this->getDataGenerator()->create_user();
2662  
2663          // Set config to allow email_to_user() to be called.
2664          $CFG->noemailever = false;
2665  
2666          // Update user password.
2667          $sink = $this->redirectEvents();
2668          $sink2 = $this->redirectEmails(); // Make sure we are redirecting emails.
2669          setnew_password_and_mail($user);
2670          $events = $sink->get_events();
2671          $sink->close();
2672          $sink2->close();
2673          $event = array_pop($events);
2674  
2675          // Test updated value.
2676          $dbuser = $DB->get_record('user', array('id' => $user->id));
2677          $this->assertSame($user->firstname, $dbuser->firstname);
2678          $this->assertNotEmpty($dbuser->password);
2679  
2680          // Test event.
2681          $this->assertInstanceOf('\core\event\user_password_updated', $event);
2682          $this->assertSame($user->id, $event->relateduserid);
2683          $this->assertEquals(context_user::instance($user->id), $event->get_context());
2684          $this->assertEventContextNotUsed($event);
2685      }
2686  
2687      /**
2688       * Test remove_course_content deletes course contents
2689       * TODO Add asserts to verify other data related to course is deleted as well.
2690       */
2691      public function test_remove_course_contents() {
2692  
2693          $this->resetAfterTest();
2694  
2695          $course = $this->getDataGenerator()->create_course();
2696          $user = $this->getDataGenerator()->create_user();
2697          $gen = $this->getDataGenerator()->get_plugin_generator('core_notes');
2698          $note = $gen->create_instance(array('courseid' => $course->id, 'userid' => $user->id));
2699  
2700          $this->assertNotEquals(false, note_load($note->id));
2701          remove_course_contents($course->id, false);
2702          $this->assertFalse(note_load($note->id));
2703      }
2704  
2705      /**
2706       * Test function username_load_fields_from_object().
2707       */
2708      public function test_username_load_fields_from_object() {
2709          $this->resetAfterTest();
2710  
2711          // This object represents the information returned from an sql query.
2712          $userinfo = new stdClass();
2713          $userinfo->userid = 1;
2714          $userinfo->username = 'loosebruce';
2715          $userinfo->firstname = 'Bruce';
2716          $userinfo->lastname = 'Campbell';
2717          $userinfo->firstnamephonetic = 'ブルース';
2718          $userinfo->lastnamephonetic = 'カンベッル';
2719          $userinfo->middlename = '';
2720          $userinfo->alternatename = '';
2721          $userinfo->email = '';
2722          $userinfo->picture = 23;
2723          $userinfo->imagealt = 'Michael Jordan draining another basket.';
2724          $userinfo->idnumber = 3982;
2725  
2726          // Just user name fields.
2727          $user = new stdClass();
2728          $user = username_load_fields_from_object($user, $userinfo);
2729          $expectedarray = new stdClass();
2730          $expectedarray->firstname = 'Bruce';
2731          $expectedarray->lastname = 'Campbell';
2732          $expectedarray->firstnamephonetic = 'ブルース';
2733          $expectedarray->lastnamephonetic = 'カンベッル';
2734          $expectedarray->middlename = '';
2735          $expectedarray->alternatename = '';
2736          $this->assertEquals($user, $expectedarray);
2737  
2738          // User information for showing a picture.
2739          $user = new stdClass();
2740          $additionalfields = explode(',', user_picture::fields());
2741          $user = username_load_fields_from_object($user, $userinfo, null, $additionalfields);
2742          $user->id = $userinfo->userid;
2743          $expectedarray = new stdClass();
2744          $expectedarray->id = 1;
2745          $expectedarray->firstname = 'Bruce';
2746          $expectedarray->lastname = 'Campbell';
2747          $expectedarray->firstnamephonetic = 'ブルース';
2748          $expectedarray->lastnamephonetic = 'カンベッル';
2749          $expectedarray->middlename = '';
2750          $expectedarray->alternatename = '';
2751          $expectedarray->email = '';
2752          $expectedarray->picture = 23;
2753          $expectedarray->imagealt = 'Michael Jordan draining another basket.';
2754          $this->assertEquals($user, $expectedarray);
2755  
2756          // Alter the userinfo object to have a prefix.
2757          $userinfo->authorfirstname = 'Bruce';
2758          $userinfo->authorlastname = 'Campbell';
2759          $userinfo->authorfirstnamephonetic = 'ブルース';
2760          $userinfo->authorlastnamephonetic = 'カンベッル';
2761          $userinfo->authormiddlename = '';
2762          $userinfo->authorpicture = 23;
2763          $userinfo->authorimagealt = 'Michael Jordan draining another basket.';
2764          $userinfo->authoremail = '[email protected]';
2765  
2766  
2767          // Return an object with user picture information.
2768          $user = new stdClass();
2769          $additionalfields = explode(',', user_picture::fields());
2770          $user = username_load_fields_from_object($user, $userinfo, 'author', $additionalfields);
2771          $user->id = $userinfo->userid;
2772          $expectedarray = new stdClass();
2773          $expectedarray->id = 1;
2774          $expectedarray->firstname = 'Bruce';
2775          $expectedarray->lastname = 'Campbell';
2776          $expectedarray->firstnamephonetic = 'ブルース';
2777          $expectedarray->lastnamephonetic = 'カンベッル';
2778          $expectedarray->middlename = '';
2779          $expectedarray->alternatename = '';
2780          $expectedarray->email = '[email protected]';
2781          $expectedarray->picture = 23;
2782          $expectedarray->imagealt = 'Michael Jordan draining another basket.';
2783          $this->assertEquals($user, $expectedarray);
2784      }
2785  
2786      /**
2787       * Test function count_words().
2788       */
2789      public function test_count_words() {
2790          $count = count_words("one two three'four");
2791          $this->assertEquals(3, $count);
2792  
2793          $count = count_words('one+two three’four');
2794          $this->assertEquals(3, $count);
2795  
2796          $count = count_words('one"two three-four');
2797          $this->assertEquals(3, $count);
2798  
2799          $count = count_words('one@two three_four');
2800          $this->assertEquals(4, $count);
2801  
2802          $count = count_words('one\two three/four');
2803          $this->assertEquals(4, $count);
2804  
2805          $count = count_words(' one ... two &nbsp; three...four ');
2806          $this->assertEquals(4, $count);
2807  
2808          $count = count_words('one.2 3,four');
2809          $this->assertEquals(4, $count);
2810  
2811          $count = count_words('1³ £2 €3.45 $6,789');
2812          $this->assertEquals(4, $count);
2813  
2814          $count = count_words('one—two ブルース カンベッル');
2815          $this->assertEquals(4, $count);
2816  
2817          $count = count_words('one…two ブルース … カンベッル');
2818          $this->assertEquals(4, $count);
2819      }
2820      /**
2821       * Tests the getremoteaddr() function.
2822       */
2823      public function test_getremoteaddr() {
2824          $xforwardedfor = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : null;
2825  
2826          $_SERVER['HTTP_X_FORWARDED_FOR'] = '';
2827          $noip = getremoteaddr('1.1.1.1');
2828          $this->assertEquals('1.1.1.1', $noip);
2829  
2830          $_SERVER['HTTP_X_FORWARDED_FOR'] = '';
2831          $noip = getremoteaddr();
2832          $this->assertEquals('0.0.0.0', $noip);
2833  
2834          $_SERVER['HTTP_X_FORWARDED_FOR'] = '127.0.0.1';
2835          $singleip = getremoteaddr();
2836          $this->assertEquals('127.0.0.1', $singleip);
2837  
2838          $_SERVER['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,127.0.0.2';
2839          $twoip = getremoteaddr();
2840          $this->assertEquals('127.0.0.1', $twoip);
2841  
2842          $_SERVER['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,127.0.0.2, 127.0.0.3';
2843          $threeip = getremoteaddr();
2844          $this->assertEquals('127.0.0.1', $threeip);
2845  
2846          $_SERVER['HTTP_X_FORWARDED_FOR'] = '127.0.0.1:65535,127.0.0.2';
2847          $portip = getremoteaddr();
2848          $this->assertEquals('127.0.0.1', $portip);
2849  
2850          $_SERVER['HTTP_X_FORWARDED_FOR'] = '0:0:0:0:0:0:0:1,127.0.0.2';
2851          $portip = getremoteaddr();
2852          $this->assertEquals('0:0:0:0:0:0:0:1', $portip);
2853  
2854          $_SERVER['HTTP_X_FORWARDED_FOR'] = '0::1,127.0.0.2';
2855          $portip = getremoteaddr();
2856          $this->assertEquals('0:0:0:0:0:0:0:1', $portip);
2857  
2858          $_SERVER['HTTP_X_FORWARDED_FOR'] = '[0:0:0:0:0:0:0:1]:65535,127.0.0.2';
2859          $portip = getremoteaddr();
2860          $this->assertEquals('0:0:0:0:0:0:0:1', $portip);
2861  
2862          $_SERVER['HTTP_X_FORWARDED_FOR'] = $xforwardedfor;
2863  
2864      }
2865  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1