PageRenderTime 63ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/tests/moodlelib_test.php

https://github.com/eduridden/totara
PHP | 2707 lines | 2005 code | 360 blank | 342 comment | 29 complexity | 0437510f5dd95af01ef5852267f167d8 MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0, BSD-3-Clause, LGPL-2.1
  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. * Unit tests for (some of) ../moodlelib.php.
  18. *
  19. * @package core
  20. * @category phpunit
  21. * @copyright &copy; 2006 The Open University
  22. * @author T.J.Hunt@open.ac.uk
  23. * @author nicolas@moodle.com
  24. */
  25. defined('MOODLE_INTERNAL') || die();
  26. global $CFG;
  27. require_once($CFG->libdir . '/moodlelib.php');
  28. class moodlelib_testcase extends advanced_testcase {
  29. public static $includecoverage = array('lib/moodlelib.php');
  30. var $user_agents = array(
  31. 'MSIE' => array(
  32. '5.0' => array('Windows 98' => 'Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)'),
  33. '5.5' => array('Windows 2000' => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)'),
  34. '6.0' => array('Windows XP SP2' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)'),
  35. '7.0' => array('Windows XP SP2' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)'),
  36. '8.0' => array('Windows Vista' => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)'),
  37. '9.0' => array('Windows 7' => 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'),
  38. '9.0i' => array('Windows 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)'),
  39. '10.0' => array('Windows 8' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Touch)'),
  40. '10.0i' => array('Windows 8' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Trident/6.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0)'),
  41. '11.0' => array('Windows 8.1' => 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0)'),
  42. ),
  43. 'Firefox' => array(
  44. '1.0.6' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6'),
  45. '1.5' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8) Gecko/20051107 Firefox/1.5'),
  46. '1.5.0.1' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1'),
  47. '2.0' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1',
  48. 'Ubuntu Linux AMD64' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)'),
  49. '3.0.6' => array('SUSE' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6'),
  50. '3.6' => array('Linux' => 'Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/3.6'),
  51. '11.0' => array('Windows' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko Firefox/11.0'),
  52. '15.0a2' => array('Windows' => 'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2'),
  53. '18.0' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:18.0) Gecko/18.0 Firefox/18.0'),
  54. ),
  55. 'SeaMonkey' => array(
  56. '2.0' => array('Windows' => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0'),
  57. '2.1' => array('Linux' => 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110609 Firefox/4.0.1 SeaMonkey/2.1'),
  58. '2.3' => array('FreeBSD' => 'Mozilla/5.0 (X11; FreeBSD amd64; rv:6.0) Gecko/20110818 Firefox/6.0 SeaMonkey/2.3'),
  59. ),
  60. 'Safari' => array(
  61. '312' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312'),
  62. '412' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412 (KHTML, like Gecko) Safari/412')
  63. ),
  64. 'Safari iOS' => array(
  65. '528' => array('iPhone' => 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; cs-cz) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16'),
  66. '533' => array('iPad' => 'Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5'),
  67. ),
  68. 'WebKit Android' => array(
  69. '525' => array('G1 Phone' => 'Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2 – G1 Phone'),
  70. '530' => array('Nexus' => 'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17 –Nexus'),
  71. ),
  72. 'Chrome' => array(
  73. '8' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10'),
  74. ),
  75. 'Opera' => array(
  76. '8.51' => array('Windows XP' => 'Opera/8.51 (Windows NT 5.1; U; en)'),
  77. '9.0' => array('Windows XP' => 'Opera/9.0 (Windows NT 5.1; U; en)',
  78. 'Debian Linux' => 'Opera/9.01 (X11; Linux i686; U; en)')
  79. )
  80. );
  81. /**
  82. * Define a local decimal separator.
  83. *
  84. * It is not possible to directly change the result of get_string in
  85. * a unit test. Instead, we create a language pack for language 'xx' in
  86. * dataroot and make langconfig.php with the string we need to change.
  87. * The example separator used here is 'X'; on PHP 5.3 and before this
  88. * must be a single byte character due to PHP bug/limitation in
  89. * number_format, so you can't use UTF-8 characters.
  90. *
  91. * @global type $SESSION
  92. * @global type $CFG
  93. */
  94. protected function define_local_decimal_separator() {
  95. global $SESSION, $CFG;
  96. $SESSION->lang = 'xx';
  97. $langconfig = "<?php\n\$string['decsep'] = 'X';";
  98. $langfolder = $CFG->dataroot . '/lang/xx';
  99. check_dir_exists($langfolder);
  100. file_put_contents($langfolder . '/langconfig.php', $langconfig);
  101. }
  102. function test_cleanremoteaddr() {
  103. //IPv4
  104. $this->assertEquals(cleanremoteaddr('1023.121.234.1'), null);
  105. $this->assertEquals(cleanremoteaddr('123.121.234.01 '), '123.121.234.1');
  106. //IPv6
  107. $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:0:0:0'), null);
  108. $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:0:abh'), null);
  109. $this->assertEquals(cleanremoteaddr('0:0:0:::0:0:1'), null);
  110. $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:0:0', true), '::');
  111. $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:1:1', true), '::1:1');
  112. $this->assertEquals(cleanremoteaddr('abcd:00ef:0:0:0:0:0:0', true), 'abcd:ef::');
  113. $this->assertEquals(cleanremoteaddr('1:0:0:0:0:0:0:1', true), '1::1');
  114. $this->assertEquals(cleanremoteaddr('::10:1', false), '0:0:0:0:0:0:10:1');
  115. $this->assertEquals(cleanremoteaddr('01:1::', false), '1:1:0:0:0:0:0:0');
  116. $this->assertEquals(cleanremoteaddr('10::10', false), '10:0:0:0:0:0:0:10');
  117. $this->assertEquals(cleanremoteaddr('::ffff:192.168.1.1', true), '::ffff:c0a8:11');
  118. }
  119. function test_address_in_subnet() {
  120. /// 1: xxx.xxx.xxx.xxx/nn or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/nnn (number of bits in net mask)
  121. $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.1/32'));
  122. $this->assertFalse(address_in_subnet('123.121.23.1', '123.121.23.0/32'));
  123. $this->assertTrue(address_in_subnet('10.10.10.100', '123.121.23.45/0'));
  124. $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/24'));
  125. $this->assertFalse(address_in_subnet('123.121.34.1', '123.121.234.0/24'));
  126. $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/30'));
  127. $this->assertFalse(address_in_subnet('123.121.23.8', '123.121.23.0/30'));
  128. $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128'));
  129. $this->assertFalse(address_in_subnet('bab:baba::baba', 'bab:baba::cece/128'));
  130. $this->assertTrue(address_in_subnet('baba:baba::baba', 'cece:cece::cece/0'));
  131. $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128'));
  132. $this->assertTrue(address_in_subnet('baba:baba::00ba', 'baba:baba::/120'));
  133. $this->assertFalse(address_in_subnet('baba:baba::aba', 'baba:baba::/120'));
  134. $this->assertTrue(address_in_subnet('baba::baba:00ba', 'baba::baba:0/112'));
  135. $this->assertFalse(address_in_subnet('baba::aba:00ba', 'baba::baba:0/112'));
  136. $this->assertFalse(address_in_subnet('aba::baba:0000', 'baba::baba:0/112'));
  137. // fixed input
  138. $this->assertTrue(address_in_subnet('123.121.23.1 ', ' 123.121.23.0 / 24'));
  139. $this->assertTrue(address_in_subnet('::ffff:10.1.1.1', ' 0:0:0:000:0:ffff:a1:10 / 126'));
  140. // incorrect input
  141. $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/-2'));
  142. $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/64'));
  143. $this->assertFalse(address_in_subnet('123.121.234.x', '123.121.234.1/24'));
  144. $this->assertFalse(address_in_subnet('123.121.234.0', '123.121.234.xx/24'));
  145. $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/xx0'));
  146. $this->assertFalse(address_in_subnet('::1', '::aa:0/xx0'));
  147. $this->assertFalse(address_in_subnet('::1', '::aa:0/-5'));
  148. $this->assertFalse(address_in_subnet('::1', '::aa:0/130'));
  149. $this->assertFalse(address_in_subnet('x:1', '::aa:0/130'));
  150. $this->assertFalse(address_in_subnet('::1', '::ax:0/130'));
  151. /// 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)
  152. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12-14'));
  153. $this->assertTrue(address_in_subnet('123.121.234.13', '123.121.234.12-14'));
  154. $this->assertTrue(address_in_subnet('123.121.234.14', '123.121.234.12-14'));
  155. $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.12-14'));
  156. $this->assertFalse(address_in_subnet('123.121.234.20', '123.121.234.12-14'));
  157. $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.234.12-14'));
  158. $this->assertFalse(address_in_subnet('123.12.234.12', '123.121.234.12-14'));
  159. $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba-babe'));
  160. $this->assertTrue(address_in_subnet('baba:baba::babc', 'baba:baba::baba-babe'));
  161. $this->assertTrue(address_in_subnet('baba:baba::babe', 'baba:baba::baba-babe'));
  162. $this->assertFalse(address_in_subnet('bab:baba::bab0', 'bab:baba::baba-babe'));
  163. $this->assertFalse(address_in_subnet('bab:baba::babf', 'bab:baba::baba-babe'));
  164. $this->assertFalse(address_in_subnet('bab:baba::bfbe', 'bab:baba::baba-babe'));
  165. $this->assertFalse(address_in_subnet('bfb:baba::babe', 'bab:baba::baba-babe'));
  166. // fixed input
  167. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12 - 14 '));
  168. $this->assertTrue(address_in_subnet('bab:baba::babe', 'bab:baba::baba - babe '));
  169. // incorrect input
  170. $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-234.14'));
  171. $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-256'));
  172. $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12--256'));
  173. /// 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx. (incomplete address, a bit non-technical ;-)
  174. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12'));
  175. $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.23.13'));
  176. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.'));
  177. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234'));
  178. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121'));
  179. $this->assertTrue(address_in_subnet('123.121.234.12', '123'));
  180. $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234.'));
  181. $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234'));
  182. $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba::bab'));
  183. $this->assertFalse(address_in_subnet('baba:baba::ba', 'baba:baba::bc'));
  184. $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba'));
  185. $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:'));
  186. $this->assertFalse(address_in_subnet('bab:baba::bab', 'baba:'));
  187. /// multiple subnets
  188. $this->assertTrue(address_in_subnet('123.121.234.12', '::1/64, 124., 123.121.234.10-30'));
  189. $this->assertTrue(address_in_subnet('124.121.234.12', '::1/64, 124., 123.121.234.10-30'));
  190. $this->assertTrue(address_in_subnet('::2', '::1/64, 124., 123.121.234.10-30'));
  191. $this->assertFalse(address_in_subnet('12.121.234.12', '::1/64, 124., 123.121.234.10-30'));
  192. /// other incorrect input
  193. $this->assertFalse(address_in_subnet('123.123.123.123', ''));
  194. }
  195. /**
  196. * Modifies $_SERVER['HTTP_USER_AGENT'] manually to check if check_browser_version
  197. * works as expected.
  198. */
  199. function test_check_browser_version()
  200. {
  201. global $CFG;
  202. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['412']['Mac OS X'];
  203. $this->assertTrue(check_browser_version('Safari'));
  204. $this->assertTrue(check_browser_version('WebKit'));
  205. $this->assertTrue(check_browser_version('Safari', '312'));
  206. $this->assertFalse(check_browser_version('Safari', '500'));
  207. $this->assertFalse(check_browser_version('Chrome'));
  208. $this->assertFalse(check_browser_version('Safari iOS'));
  209. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari iOS']['528']['iPhone'];
  210. $this->assertTrue(check_browser_version('Safari iOS'));
  211. $this->assertTrue(check_browser_version('WebKit'));
  212. $this->assertTrue(check_browser_version('Safari iOS', '527'));
  213. $this->assertFalse(check_browser_version('Safari iOS', 590));
  214. $this->assertFalse(check_browser_version('Safari', '312'));
  215. $this->assertFalse(check_browser_version('Safari', '500'));
  216. $this->assertFalse(check_browser_version('Chrome'));
  217. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['WebKit Android']['530']['Nexus'];
  218. $this->assertTrue(check_browser_version('WebKit'));
  219. $this->assertTrue(check_browser_version('WebKit Android', '527'));
  220. $this->assertFalse(check_browser_version('WebKit Android', 590));
  221. $this->assertFalse(check_browser_version('Safari'));
  222. $this->assertFalse(check_browser_version('Chrome'));
  223. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Chrome']['8']['Mac OS X'];
  224. $this->assertTrue(check_browser_version('Chrome'));
  225. $this->assertTrue(check_browser_version('WebKit'));
  226. $this->assertTrue(check_browser_version('Chrome', 8));
  227. $this->assertFalse(check_browser_version('Chrome', 10));
  228. $this->assertFalse(check_browser_version('Safari', '1'));
  229. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
  230. $this->assertTrue(check_browser_version('Opera'));
  231. $this->assertTrue(check_browser_version('Opera', '8.0'));
  232. $this->assertFalse(check_browser_version('Opera', '10.0'));
  233. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['6.0']['Windows XP SP2'];
  234. $this->assertTrue(check_browser_version('MSIE'));
  235. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  236. $this->assertFalse(check_browser_version('MSIE', '7.0'));
  237. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['5.0']['Windows 98'];
  238. $this->assertFalse(check_browser_version('MSIE'));
  239. $this->assertTrue(check_browser_version('MSIE', 0));
  240. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  241. $this->assertFalse(check_browser_version('MSIE', '7.0'));
  242. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0']['Windows 7'];
  243. $this->assertTrue(check_browser_version('MSIE'));
  244. $this->assertTrue(check_browser_version('MSIE', 0));
  245. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  246. $this->assertTrue(check_browser_version('MSIE', '9.0'));
  247. $this->assertFalse(check_browser_version('MSIE', '10'));
  248. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0i']['Windows 7'];
  249. $this->assertTrue(check_browser_version('MSIE'));
  250. $this->assertTrue(check_browser_version('MSIE', 0));
  251. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  252. $this->assertTrue(check_browser_version('MSIE', '9.0'));
  253. $this->assertFalse(check_browser_version('MSIE', '10'));
  254. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0']['Windows 8'];
  255. $this->assertTrue(check_browser_version('MSIE'));
  256. $this->assertTrue(check_browser_version('MSIE', 0));
  257. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  258. $this->assertTrue(check_browser_version('MSIE', '9.0'));
  259. $this->assertTrue(check_browser_version('MSIE', '10'));
  260. $this->assertFalse(check_browser_version('MSIE', '11'));
  261. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0i']['Windows 8'];
  262. $this->assertTrue(check_browser_version('MSIE'));
  263. $this->assertTrue(check_browser_version('MSIE', 0));
  264. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  265. $this->assertTrue(check_browser_version('MSIE', '9.0'));
  266. $this->assertTrue(check_browser_version('MSIE', '10'));
  267. $this->assertFalse(check_browser_version('MSIE', '11'));
  268. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['11.0']['Windows 8.1'];
  269. $this->assertTrue(check_browser_version('MSIE'));
  270. $this->assertTrue(check_browser_version('MSIE', 0));
  271. $this->assertTrue(check_browser_version('MSIE', '5.0'));
  272. $this->assertTrue(check_browser_version('MSIE', '9.0'));
  273. $this->assertTrue(check_browser_version('MSIE', '10'));
  274. $this->assertTrue(check_browser_version('MSIE', '11'));
  275. $this->assertFalse(check_browser_version('MSIE', '12'));
  276. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
  277. $this->assertTrue(check_browser_version('Firefox'));
  278. $this->assertTrue(check_browser_version('Firefox', '1.5'));
  279. $this->assertFalse(check_browser_version('Firefox', '3.0'));
  280. $this->assertTrue(check_browser_version('Gecko', '2'));
  281. $this->assertTrue(check_browser_version('Gecko', 20030516));
  282. $this->assertTrue(check_browser_version('Gecko', 20051106));
  283. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  284. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['1.0.6']['Windows XP'];
  285. $this->assertTrue(check_browser_version('Firefox'));
  286. $this->assertTrue(check_browser_version('Gecko', '1'));
  287. $this->assertFalse(check_browser_version('Gecko', 20030516));
  288. $this->assertFalse(check_browser_version('Gecko', 20051106));
  289. $this->assertFalse(check_browser_version('Gecko', 2006010100));
  290. $this->assertFalse(check_browser_version('Firefox', '1.5'));
  291. $this->assertFalse(check_browser_version('Firefox', '3.0'));
  292. $this->assertFalse(check_browser_version('Gecko', '2'));
  293. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
  294. $this->assertTrue(check_browser_version('Firefox'));
  295. $this->assertTrue(check_browser_version('Firefox', '1.5'));
  296. $this->assertTrue(check_browser_version('Gecko', '1'));
  297. $this->assertTrue(check_browser_version('Gecko', '2'));
  298. $this->assertTrue(check_browser_version('Gecko', 20030516));
  299. $this->assertTrue(check_browser_version('Gecko', 20051106));
  300. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  301. $this->assertFalse(check_browser_version('Firefox', '3.0'));
  302. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
  303. $this->assertTrue(check_browser_version('Firefox'));
  304. $this->assertTrue(check_browser_version('Firefox', '1.5'));
  305. $this->assertTrue(check_browser_version('Firefox', '3.0'));
  306. $this->assertTrue(check_browser_version('Gecko', '2'));
  307. $this->assertTrue(check_browser_version('Gecko', '3.6'));
  308. $this->assertTrue(check_browser_version('Gecko', 20030516));
  309. $this->assertTrue(check_browser_version('Gecko', 20051106));
  310. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  311. $this->assertFalse(check_browser_version('Firefox', '4'));
  312. $this->assertFalse(check_browser_version('Firefox', '10'));
  313. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
  314. $this->assertTrue(check_browser_version('Firefox'));
  315. $this->assertTrue(check_browser_version('Firefox', '1.5'));
  316. $this->assertTrue(check_browser_version('Firefox', '3.0'));
  317. $this->assertTrue(check_browser_version('Gecko', '2'));
  318. $this->assertTrue(check_browser_version('Gecko', '3.6'));
  319. $this->assertTrue(check_browser_version('Gecko', 20030516));
  320. $this->assertTrue(check_browser_version('Gecko', 20051106));
  321. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  322. $this->assertFalse(check_browser_version('Firefox', '4'));
  323. $this->assertFalse(check_browser_version('Firefox', '10'));
  324. $this->assertFalse(check_browser_version('Firefox', '18'));
  325. $this->assertFalse(check_browser_version('Gecko', '4'));
  326. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['15.0a2']['Windows'];
  327. $this->assertTrue(check_browser_version('Firefox'));
  328. $this->assertTrue(check_browser_version('Firefox', '1.5'));
  329. $this->assertTrue(check_browser_version('Firefox', '3.0'));
  330. $this->assertTrue(check_browser_version('Gecko', '2'));
  331. $this->assertTrue(check_browser_version('Gecko', '3.6'));
  332. $this->assertTrue(check_browser_version('Gecko', '15.0'));
  333. $this->assertTrue(check_browser_version('Gecko', 20030516));
  334. $this->assertTrue(check_browser_version('Gecko', 20051106));
  335. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  336. $this->assertTrue(check_browser_version('Firefox', '4'));
  337. $this->assertTrue(check_browser_version('Firefox', '10'));
  338. $this->assertTrue(check_browser_version('Firefox', '15'));
  339. $this->assertFalse(check_browser_version('Firefox', '18'));
  340. $this->assertFalse(check_browser_version('Gecko', '18'));
  341. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['18.0']['Mac OS X'];
  342. $this->assertTrue(check_browser_version('Firefox'));
  343. $this->assertTrue(check_browser_version('Firefox', '1.5'));
  344. $this->assertTrue(check_browser_version('Firefox', '3.0'));
  345. $this->assertTrue(check_browser_version('Gecko', '2'));
  346. $this->assertTrue(check_browser_version('Gecko', '3.6'));
  347. $this->assertTrue(check_browser_version('Gecko', '15.0'));
  348. $this->assertTrue(check_browser_version('Gecko', '18.0'));
  349. $this->assertTrue(check_browser_version('Gecko', 20030516));
  350. $this->assertTrue(check_browser_version('Gecko', 20051106));
  351. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  352. $this->assertTrue(check_browser_version('Firefox', '4'));
  353. $this->assertTrue(check_browser_version('Firefox', '10'));
  354. $this->assertTrue(check_browser_version('Firefox', '15'));
  355. $this->assertTrue(check_browser_version('Firefox', '18'));
  356. $this->assertFalse(check_browser_version('Firefox', '19'));
  357. $this->assertFalse(check_browser_version('Gecko', '19'));
  358. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.0']['Windows'];
  359. $this->assertTrue(check_browser_version('Gecko', '2'));
  360. $this->assertTrue(check_browser_version('Gecko', 20030516));
  361. $this->assertTrue(check_browser_version('Gecko', 20051106));
  362. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  363. $this->assertFalse(check_browser_version('Gecko', '3.6'));
  364. $this->assertFalse(check_browser_version('Gecko', '4.0'));
  365. $this->assertFalse(check_browser_version('Firefox'));
  366. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.1']['Linux'];
  367. $this->assertTrue(check_browser_version('Gecko', '2'));
  368. $this->assertTrue(check_browser_version('Gecko', '3.6'));
  369. $this->assertTrue(check_browser_version('Gecko', '4.0'));
  370. $this->assertTrue(check_browser_version('Gecko', 20030516));
  371. $this->assertTrue(check_browser_version('Gecko', 20051106));
  372. $this->assertTrue(check_browser_version('Gecko', 2006010100));
  373. $this->assertTrue(check_browser_version('Firefox'));
  374. $this->assertTrue(check_browser_version('Firefox', 4.0));
  375. $this->assertFalse(check_browser_version('Firefox', 5));
  376. $this->assertFalse(check_browser_version('Gecko', '18.0'));
  377. }
  378. function test_get_browser_version_classes() {
  379. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['412']['Mac OS X'];
  380. $this->assertEquals(array('safari'), get_browser_version_classes());
  381. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Chrome']['8']['Mac OS X'];
  382. $this->assertEquals(array('safari'), get_browser_version_classes());
  383. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari iOS']['528']['iPhone'];
  384. $this->assertEquals(array('safari', 'ios'), get_browser_version_classes());
  385. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['WebKit Android']['530']['Nexus'];
  386. $this->assertEquals(array('safari', 'android'), get_browser_version_classes());
  387. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Chrome']['8']['Mac OS X'];
  388. $this->assertEquals(array('safari'), get_browser_version_classes());
  389. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
  390. $this->assertEquals(array('opera'), get_browser_version_classes());
  391. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['6.0']['Windows XP SP2'];
  392. $this->assertEquals(array('ie', 'ie6'), get_browser_version_classes());
  393. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['7.0']['Windows XP SP2'];
  394. $this->assertEquals(array('ie', 'ie7'), get_browser_version_classes());
  395. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['8.0']['Windows Vista'];
  396. $this->assertEquals(array('ie', 'ie8'), get_browser_version_classes());
  397. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0']['Windows 7'];
  398. $this->assertEquals(array('ie', 'ie9'), get_browser_version_classes());
  399. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0i']['Windows 7'];
  400. $this->assertEquals(array('ie', 'ie9'), get_browser_version_classes());
  401. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0']['Windows 8'];
  402. $this->assertEquals(array('ie', 'ie10'), get_browser_version_classes());
  403. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0i']['Windows 8'];
  404. $this->assertEquals(array('ie', 'ie10'), get_browser_version_classes());
  405. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
  406. $this->assertEquals(array('gecko', 'gecko18'), get_browser_version_classes());
  407. $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.0.6']['SUSE'];
  408. $this->assertEquals(array('gecko', 'gecko19'), get_browser_version_classes());
  409. }
  410. function test_get_device_type() {
  411. // IE8 (common pattern ~1.5% of IE7/8 users have embedded IE6 agent))
  412. $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; BT Openworld BB; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; Hotbar 10.2.197.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727)';
  413. $this->assertEquals('default', get_device_type());
  414. // Genuine IE6
  415. $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705; Media Center PC 2.8)';
  416. $this->assertEquals('legacy', get_device_type());
  417. }
  418. function test_fix_utf8() {
  419. // make sure valid data including other types is not changed
  420. $this->assertSame(null, fix_utf8(null));
  421. $this->assertSame(1, fix_utf8(1));
  422. $this->assertSame(1.1, fix_utf8(1.1));
  423. $this->assertSame(true, fix_utf8(true));
  424. $this->assertSame('', fix_utf8(''));
  425. $this->assertSame('abc', fix_utf8('abc'));
  426. $array = array('do', 're', 'mi');
  427. $this->assertSame($array, fix_utf8($array));
  428. $object = new stdClass();
  429. $object->a = 'aa';
  430. $object->b = 'bb';
  431. $this->assertEquals($object, fix_utf8($object));
  432. // valid utf8 string
  433. $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"));
  434. // invalid utf8 string
  435. $this->assertSame('aš', fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
  436. }
  437. function test_optional_param() {
  438. global $CFG;
  439. $_POST['username'] = 'post_user';
  440. $_GET['username'] = 'get_user';
  441. $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), $_POST['username']);
  442. unset($_POST['username']);
  443. $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), $_GET['username']);
  444. unset($_GET['username']);
  445. $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), 'default_user');
  446. // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
  447. $_POST['username'] = 'post_user';
  448. try {
  449. optional_param('username', 'default_user', null);
  450. $this->fail('coding_exception expected');
  451. } catch (coding_exception $ex) {
  452. $this->assertTrue(true);
  453. }
  454. try {
  455. @optional_param('username', 'default_user');
  456. $this->fail('coding_exception expected');
  457. } catch (coding_exception $ex) {
  458. $this->assertTrue(true);
  459. }
  460. try {
  461. @optional_param('username');
  462. $this->fail('coding_exception expected');
  463. } catch (coding_exception $ex) {
  464. $this->assertTrue(true);
  465. }
  466. try {
  467. optional_param('', 'default_user', PARAM_RAW);
  468. $this->fail('coding_exception expected');
  469. } catch (coding_exception $ex) {
  470. $this->assertTrue(true);
  471. }
  472. // make sure warning is displayed if array submitted - TODO: throw exception in Moodle 2.3
  473. $_POST['username'] = array('a'=>'a');
  474. $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), $_POST['username']);
  475. $this->assertDebuggingCalled();
  476. }
  477. function test_optional_param_array() {
  478. global $CFG;
  479. $_POST['username'] = array('a'=>'post_user');
  480. $_GET['username'] = array('a'=>'get_user');
  481. $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), $_POST['username']);
  482. unset($_POST['username']);
  483. $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), $_GET['username']);
  484. unset($_GET['username']);
  485. $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), array('a'=>'default_user'));
  486. // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
  487. $_POST['username'] = array('a'=>'post_user');
  488. try {
  489. optional_param_array('username', array('a'=>'default_user'), null);
  490. $this->fail('coding_exception expected');
  491. } catch (coding_exception $ex) {
  492. $this->assertTrue(true);
  493. }
  494. try {
  495. @optional_param_array('username', array('a'=>'default_user'));
  496. $this->fail('coding_exception expected');
  497. } catch (coding_exception $ex) {
  498. $this->assertTrue(true);
  499. }
  500. try {
  501. @optional_param_array('username');
  502. $this->fail('coding_exception expected');
  503. } catch (coding_exception $ex) {
  504. $this->assertTrue(true);
  505. }
  506. try {
  507. optional_param_array('', array('a'=>'default_user'), PARAM_RAW);
  508. $this->fail('coding_exception expected');
  509. } catch (coding_exception $ex) {
  510. $this->assertTrue(true);
  511. }
  512. // do not allow nested arrays
  513. try {
  514. $_POST['username'] = array('a'=>array('b'=>'post_user'));
  515. optional_param_array('username', array('a'=>'default_user'), PARAM_RAW);
  516. $this->fail('coding_exception expected');
  517. } catch (coding_exception $ex) {
  518. $this->assertTrue(true);
  519. }
  520. // do not allow non-arrays
  521. $_POST['username'] = 'post_user';
  522. $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), array('a'=>'default_user'));
  523. $this->assertDebuggingCalled();
  524. // make sure array keys are sanitised
  525. $_POST['username'] = array('abc123_;-/*-+ '=>'arrggh', 'a1_-'=>'post_user');
  526. $this->assertSame(optional_param_array('username', array(), PARAM_RAW), array('a1_-'=>'post_user'));
  527. $this->assertDebuggingCalled();
  528. }
  529. function test_required_param() {
  530. global $CFG;
  531. $_POST['username'] = 'post_user';
  532. $_GET['username'] = 'get_user';
  533. $this->assertSame(required_param('username', PARAM_RAW), 'post_user');
  534. unset($_POST['username']);
  535. $this->assertSame(required_param('username', PARAM_RAW), 'get_user');
  536. unset($_GET['username']);
  537. try {
  538. $this->assertSame(required_param('username', PARAM_RAW), 'default_user');
  539. $this->fail('moodle_exception expected');
  540. } catch (moodle_exception $ex) {
  541. $this->assertTrue(true);
  542. }
  543. // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
  544. $_POST['username'] = 'post_user';
  545. try {
  546. @required_param('username');
  547. $this->fail('coding_exception expected');
  548. } catch (coding_exception $ex) {
  549. $this->assertTrue(true);
  550. }
  551. try {
  552. required_param('username', '');
  553. $this->fail('coding_exception expected');
  554. } catch (coding_exception $ex) {
  555. $this->assertTrue(true);
  556. }
  557. try {
  558. required_param('', PARAM_RAW);
  559. $this->fail('coding_exception expected');
  560. } catch (coding_exception $ex) {
  561. $this->assertTrue(true);
  562. }
  563. // make sure warning is displayed if array submitted - TODO: throw exception in Moodle 2.3
  564. $_POST['username'] = array('a'=>'a');
  565. $this->assertSame(required_param('username', PARAM_RAW), $_POST['username']);
  566. $this->assertDebuggingCalled();
  567. }
  568. function test_required_param_array() {
  569. global $CFG;
  570. $_POST['username'] = array('a'=>'post_user');
  571. $_GET['username'] = array('a'=>'get_user');
  572. $this->assertSame(required_param_array('username', PARAM_RAW), $_POST['username']);
  573. unset($_POST['username']);
  574. $this->assertSame(required_param_array('username', PARAM_RAW), $_GET['username']);
  575. // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
  576. $_POST['username'] = array('a'=>'post_user');
  577. try {
  578. required_param_array('username', null);
  579. $this->fail('coding_exception expected');
  580. } catch (coding_exception $ex) {
  581. $this->assertTrue(true);
  582. }
  583. try {
  584. @required_param_array('username');
  585. $this->fail('coding_exception expected');
  586. } catch (coding_exception $ex) {
  587. $this->assertTrue(true);
  588. }
  589. try {
  590. required_param_array('', PARAM_RAW);
  591. $this->fail('coding_exception expected');
  592. } catch (coding_exception $ex) {
  593. $this->assertTrue(true);
  594. }
  595. // do not allow nested arrays
  596. try {
  597. $_POST['username'] = array('a'=>array('b'=>'post_user'));
  598. required_param_array('username', PARAM_RAW);
  599. $this->fail('coding_exception expected');
  600. } catch (coding_exception $ex) {
  601. $this->assertTrue(true);
  602. }
  603. // do not allow non-arrays
  604. try {
  605. $_POST['username'] = 'post_user';
  606. required_param_array('username', PARAM_RAW);
  607. $this->fail('moodle_exception expected');
  608. } catch (moodle_exception $ex) {
  609. $this->assertTrue(true);
  610. }
  611. // make sure array keys are sanitised
  612. $_POST['username'] = array('abc123_;-/*-+ '=>'arrggh', 'a1_-'=>'post_user');
  613. $this->assertSame(required_param_array('username', PARAM_RAW), array('a1_-'=>'post_user'));
  614. $this->assertDebuggingCalled();
  615. }
  616. function test_clean_param() {
  617. // forbid objects and arrays
  618. try {
  619. clean_param(array('x', 'y'), PARAM_RAW);
  620. $this->fail('coding_exception expected');
  621. } catch (coding_exception $ex) {
  622. $this->assertTrue(true);
  623. }
  624. try {
  625. $param = new stdClass();
  626. $param->id = 1;
  627. clean_param($param, PARAM_RAW);
  628. $this->fail('coding_exception expected');
  629. } catch (coding_exception $ex) {
  630. $this->assertTrue(true);
  631. }
  632. // require correct type
  633. try {
  634. clean_param('x', 'xxxxxx');
  635. $this->fail('moodle_exception expected');
  636. } catch (moodle_exception $ex) {
  637. $this->assertTrue(true);
  638. }
  639. try {
  640. @clean_param('x');
  641. $this->fail('moodle_exception expected');
  642. } catch (moodle_exception $ex) {
  643. $this->assertTrue(true);
  644. }
  645. }
  646. function test_clean_param_array() {
  647. $this->assertSame(clean_param_array(null, PARAM_RAW), array());
  648. $this->assertSame(clean_param_array(array('a', 'b'), PARAM_RAW), array('a', 'b'));
  649. $this->assertSame(clean_param_array(array('a', array('b')), PARAM_RAW, true), array('a', array('b')));
  650. // require correct type
  651. try {
  652. clean_param_array(array('x'), 'xxxxxx');
  653. $this->fail('moodle_exception expected');
  654. } catch (moodle_exception $ex) {
  655. $this->assertTrue(true);
  656. }
  657. try {
  658. @clean_param_array(array('x'));
  659. $this->fail('moodle_exception expected');
  660. } catch (moodle_exception $ex) {
  661. $this->assertTrue(true);
  662. }
  663. try {
  664. clean_param_array(array('x', array('y')), PARAM_RAW);
  665. $this->fail('coding_exception expected');
  666. } catch (coding_exception $ex) {
  667. $this->assertTrue(true);
  668. }
  669. // test recursive
  670. }
  671. function test_clean_param_raw() {
  672. $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_RAW),
  673. '#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)');
  674. }
  675. function test_clean_param_trim() {
  676. $this->assertEquals(clean_param(" Frog toad \r\n ", PARAM_RAW_TRIMMED), 'Frog toad');
  677. }
  678. function test_clean_param_clean() {
  679. // PARAM_CLEAN is an ugly hack, do not use in new code (skodak)
  680. // instead use more specific type, or submit sothing that can be verified properly
  681. $this->assertEquals(clean_param('xx<script>', PARAM_CLEAN), 'xx');
  682. }
  683. function test_clean_param_alpha() {
  684. $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHA),
  685. 'DSFMOSDJ');
  686. }
  687. function test_clean_param_alphanum() {
  688. $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHANUM),
  689. '978942897DSFMOSDJ');
  690. }
  691. function test_clean_param_alphaext() {
  692. $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHAEXT),
  693. 'DSFMOSDJ');
  694. }
  695. function test_clean_param_sequence() {
  696. $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_SEQUENCE),
  697. ',9789,42897');
  698. }
  699. function test_clean_param_component() {
  700. // please note the cleaning of component names is very strict, no guessing here
  701. $this->assertSame(clean_param('mod_forum', PARAM_COMPONENT), 'mod_forum');
  702. $this->assertSame(clean_param('block_online_users', PARAM_COMPONENT), 'block_online_users');
  703. $this->assertSame(clean_param('block_blond_online_users', PARAM_COMPONENT), 'block_blond_online_users');
  704. $this->assertSame(clean_param('mod_something2', PARAM_COMPONENT), 'mod_something2');
  705. $this->assertSame(clean_param('forum', PARAM_COMPONENT), 'forum');
  706. $this->assertSame(clean_param('user', PARAM_COMPONENT), 'user');
  707. $this->assertSame(clean_param('rating', PARAM_COMPONENT), 'rating');
  708. $this->assertSame(clean_param('mod_2something', PARAM_COMPONENT), '');
  709. $this->assertSame(clean_param('2mod_something', PARAM_COMPONENT), '');
  710. $this->assertSame(clean_param('mod_something_xx', PARAM_COMPONENT), '');
  711. $this->assertSame(clean_param('auth_something__xx', PARAM_COMPONENT), '');
  712. $this->assertSame(clean_param('mod_Something', PARAM_COMPONENT), '');
  713. $this->assertSame(clean_param('mod_somethíng', PARAM_COMPONENT), '');
  714. $this->assertSame(clean_param('auth_xx-yy', PARAM_COMPONENT), '');
  715. $this->assertSame(clean_param('_auth_xx', PARAM_COMPONENT), '');
  716. $this->assertSame(clean_param('a2uth_xx', PARAM_COMPONENT), '');
  717. $this->assertSame(clean_param('auth_xx_', PARAM_COMPONENT), '');
  718. $this->assertSame(clean_param('auth_xx.old', PARAM_COMPONENT), '');
  719. $this->assertSame(clean_param('_user', PARAM_COMPONENT), '');
  720. $this->assertSame(clean_param('2rating', PARAM_COMPONENT), '');
  721. $this->assertSame(clean_param('user_', PARAM_COMPONENT), '');
  722. }
  723. function test_is_valid_plugin_name() {
  724. $this->assertTrue(is_valid_plugin_name('forum'));
  725. $this->assertTrue(is_valid_plugin_name('forum2'));
  726. $this->assertTrue(is_valid_plugin_name('online_users'));
  727. $this->assertTrue(is_valid_plugin_name('blond_online_users'));
  728. $this->assertFalse(is_valid_plugin_name('online__users'));
  729. $this->assertFalse(is_valid_plugin_name('forum '));
  730. $this->assertFalse(is_valid_plugin_name('forum.old'));
  731. $this->assertFalse(is_valid_plugin_name('xx-yy'));
  732. $this->assertFalse(is_valid_plugin_name('2xx'));
  733. $this->assertFalse(is_valid_plugin_name('Xx'));
  734. $this->assertFalse(is_valid_plugin_name('_xx'));
  735. $this->assertFalse(is_valid_plugin_name('xx_'));
  736. }
  737. function test_clean_param_plugin() {
  738. // please note the cleaning of plugin names is very strict, no guessing here
  739. $this->assertSame(clean_param('forum', PARAM_PLUGIN), 'forum');
  740. $this->assertSame(clean_param('forum2', PARAM_PLUGIN), 'forum2');
  741. $this->assertSame(clean_param('online_users', PARAM_PLUGIN), 'online_users');
  742. $this->assertSame(clean_param('blond_online_users', PARAM_PLUGIN), 'blond_online_users');
  743. $this->assertSame(clean_param('online__users', PARAM_PLUGIN), '');
  744. $this->assertSame(clean_param('forum ', PARAM_PLUGIN), '');
  745. $this->assertSame(clean_param('forum.old', PARAM_PLUGIN), '');
  746. $this->assertSame(clean_param('xx-yy', PARAM_PLUGIN), '');
  747. $this->assertSame(clean_param('2xx', PARAM_PLUGIN), '');
  748. $this->assertSame(clean_param('Xx', PARAM_PLUGIN), '');
  749. $this->assertSame(clean_param('_xx', PARAM_PLUGIN), '');
  750. $this->assertSame(clean_param('xx_', PARAM_PLUGIN), '');
  751. }
  752. function test_clean_param_area() {
  753. // please note the cleaning of area names is very strict, no guessing here
  754. $this->assertSame(clean_param('something', PARAM_AREA), 'something');
  755. $this->assertSame(clean_param('something2', PARAM_AREA), 'something2');
  756. $this->assertSame(clean_param('some_thing', PARAM_AREA), 'some_thing');
  757. $this->assertSame(clean_param('some_thing_xx', PARAM_AREA), 'some_thing_xx');
  758. $this->assertSame(clean_param('_something', PARAM_AREA), '');
  759. $this->assertSame(clean_param('something_', PARAM_AREA), '');
  760. $this->assertSame(clean_param('2something', PARAM_AREA), '');
  761. $this->assertSame(clean_param('Something', PARAM_AREA), '');
  762. $this->assertSame(clean_param('some-thing', PARAM_AREA), '');
  763. $this->assertSame(clean_param('somethííng', PARAM_AREA), '');
  764. $this->assertSame(clean_param('something.x', PARAM_AREA), '');
  765. }
  766. function test_clean_param_text() {
  767. $this->assertEquals(PARAM_TEXT, PARAM_MULTILANG);
  768. //standard
  769. $this->assertEquals(clean_param('xx<lang lang="en">aa</lang><lang lang="yy">pp</lang>', PARAM_TEXT), 'xx<lang lang="en">aa</lang><lang lang="yy">pp</lang>');
  770. $this->assertEquals(clean_param('<span lang="en" class="multilang">aa</span><span lang="xy" class="multilang">bb</span>', PARAM_TEXT), '<span lang="en" class="multilang">aa</span><span lang="xy" class="multilang">bb</span>');
  771. $this->assertEquals(clean_param('xx<lang lang="en">aa'."\n".'</lang><lang lang="yy">pp</lang>', PARAM_TEXT), 'xx<lang lang="en">aa'."\n".'</lang><lang lang="yy">pp</lang>');
  772. //malformed
  773. $this->assertEquals(clean_param('<span lang="en" class="multilang">aa</span>', PARAM_TEXT), '<span lang="en" class="multilang">aa</span>');
  774. $this->assertEquals(clean_param('<span lang="en" class="nothing" class="multilang">aa</span>', PARAM_TEXT), 'aa');
  775. $this->assertEquals(clean_param('<lang lang="en" class="multilang">aa</lang>', PARAM_TEXT), 'aa');
  776. $this->assertEquals(clean_param('<lang lang="en!!">aa</lang>', PARAM_TEXT), 'aa');
  777. $this->assertEquals(clean_param('<span lang="en==" class="multilang">aa</span>', PARAM_TEXT), 'aa');
  778. $this->assertEquals(clean_param('a<em>b</em>c', PARAM_TEXT), 'abc');
  779. $this->assertEquals(clean_param('a><xx >c>', PARAM_TEXT), 'a>c>'); // standard strip_tags() behaviour
  780. $this->assertEquals(clean_param('a<b', PARAM_TEXT), 'a');
  781. $this->assertEquals(clean_param('a>b', PARAM_TEXT), 'a>b');
  782. $this->assertEquals(clean_param('<lang lang="en">a>a</lang>', PARAM_TEXT), '<lang lang="en">a>a</lang>'); // standard strip_tags() behaviour
  783. $this->assertEquals(clean_param('<lang lang="en">a<a</lang>', PARAM_TEXT), 'a');
  784. $this->assertEquals(clean_param('<lang lang="en">a<br>a</lang>', PARAM_TEXT), '<lang lang="en">aa</lang>');
  785. }
  786. function test_clean_param_url() {
  787. // Test PARAM_URL and PARAM_LOCALURL a bit
  788. $this->assertEquals(clean_param('http://google.com/', PARAM_URL), 'http://google.com/');
  789. $this->assertEquals(clean_param('http://some.very.long.and.silly.domain/with/a/path/', PARAM_URL), 'http://some.very.long.and.silly.domain/with/a/path/');
  790. $this->assertEquals(clean_param('http://localhost/', PARAM_URL), 'http://localhost/');
  791. $this->assertEquals(clean_param('http://0.255.1.1/numericip.php', PARAM_URL), 'http://0.255.1.1/numericip.php');
  792. $this->assertEquals(clean_param('/just/a/path', PARAM_URL), '/just/a/path');
  793. $this->assertEquals(clean_param('funny:thing', PARAM_URL), '');
  794. }
  795. function test_clean_param_localurl() {
  796. global $CFG;
  797. $this->assertEquals(clean_param('http://google.com/', PARAM_LOCALURL), '');
  798. $this->assertEquals(clean_param('http://some.very.long.and.silly.domain/with/a/path/', PARAM_LOCALURL), '');
  799. $this->assertEquals(clean_param($CFG->wwwroot, PARAM_LOCALURL), $CFG->wwwroot);
  800. $this->assertEquals(clean_param('/just/a/path', PARAM_LOCALURL), '/just/a/path');
  801. $this->assertEquals(clean_param('funny:thing', PARAM_LOCALURL), '');
  802. $this->assertEquals(clean_param('course/view.php?id=3', PARAM_LOCALURL), 'course/view.php?id=3');
  803. }
  804. function test_clean_param_file() {
  805. $this->assertEquals(clean_param('correctfile.txt', PARAM_FILE), 'correctfile.txt');
  806. $this->assertEquals(clean_param('b\'a<d`\\/fi:l>e.t"x|t', PARAM_FILE), 'badfile.txt');
  807. $this->assertEquals(clean_param('../parentdirfile.txt', PARAM_FILE), '..parentdirfile.txt');
  808. $this->assertEquals(clean_param('../../grandparentdirfile.txt', PARAM_FILE), '....grandparentdirfile.txt');
  809. $this->assertEquals(clean_param('..\winparentdirfile.txt', PARAM_FILE), '..winparentdirfile.txt');
  810. $this->assertEquals(clean_param('..\..\wingrandparentdir.txt', PARAM_FILE), '....wingrandparentdir.txt');
  811. $this->assertEquals(clean_param('myfile.a.b.txt', PARAM_FILE), 'myfile.a.b.txt');
  812. $this->assertEquals(clean_param('myfile..a..b.txt', PARAM_FILE), 'myfile..a..b.txt');
  813. $this->assertEquals(clean_param('myfile.a..b...txt', PARAM_FILE), 'myfile.a..b...txt');
  814. $this->assertEquals(clean_param('myfile.a.txt', PARAM_FILE), 'myfile.a.txt');
  815. $this->assertEquals(clean_param('myfile...txt', PARAM_FILE), 'myfile...txt');
  816. $this->assertEquals(clean_param('...jpg', PARAM_FILE), '...jpg');
  817. $this->assertEquals(clean_param('.a.b.', PARAM_FILE), '.a.b.');
  818. $this->assertEquals(clean_param('.', PARAM_FILE), '');
  819. $this->assertEquals(clean_param('..', PARAM_FILE), '');
  820. $this->assertEquals(clean_param('...', PARAM_FILE), '...');
  821. $this->assertEquals(clean_param('. . . .', PARAM_FILE), '. . . .');
  822. $this->assertEquals(clean_param('dontrtrim.me. .. .. . ', PARAM_FILE), 'dontrtrim.me. .. .. . ');
  823. $this->assertEquals(clean_param(' . .dontltrim.me', PARAM_FILE), ' . .dontltrim.me');
  824. $this->assertEquals(clean_param("here is a tab\t.txt", PARAM_FILE), 'here is a tab.txt');
  825. $this->assertEquals(clean_param("here is a line\r\nbreak.txt", PARAM_FILE), 'here is a linebreak.txt');
  826. //The following behaviours have been maintained although they seem a little odd
  827. $this->assertEquals(clean_param('funny:thing', PARAM_FILE), 'funnything');
  828. $this->assertEquals(clean_param('./currentdirfile.txt', PARAM_FILE), '.currentdirfile.txt');
  829. $this->assertEquals(clean_param('c:\temp\windowsfile.txt', PARAM_FILE), 'ctempwindowsfile.txt');
  830. $this->assertEquals(clean_param('/home/user/linuxfile.txt', PARAM_FILE), 'homeuserlinuxfile.txt');
  831. $this->assertEquals(clean_param('~/myfile.txt', PARAM_FILE), '~myfile.txt');
  832. }
  833. function test_clean_param_path() {
  834. $this->assertEquals(clean_param('correctfile.txt', PARAM_PATH), 'correctfile.txt');
  835. $this->assertEquals(clean_param('b\'a<d`\\/fi:l>e.t"x|t', PARAM_PATH), 'bad/file.txt');
  836. $this->assertEquals(clean_param('../parentdirfile.txt', PARAM_PATH), '/parentdirfile.txt');
  837. $this->assertEquals(clean_param('../../grandparentdirfile.txt', PARAM_PATH), '/grandparentdirfile.txt');
  838. $this->assertEquals(clean_param('..\winparentdirfile.txt', PARAM_PATH), '/winparentdirfile.txt');
  839. $this->assertEquals(clean_param('..\..\wingrandparentdir.txt', PARAM_PATH), '/wingrandparentdir.txt');
  840. $this->assertEquals(clean_param('funny:thing', PARAM_PATH), 'funnything');
  841. $this->assertEquals(clean_param('./././here', PARAM_PATH), './here');
  842. $this->assertEquals(clean_param('./currentdirfile.txt', PARAM_PATH), './currentdirfile.txt');
  843. $this->assertEquals(clean_param('c:\temp\windowsfile.txt', PARAM_PATH), 'c/temp/windowsfile.txt');
  844. $this->assertEquals(clean_param('/home/user/linuxfile.txt', PARAM_PATH), '/home/user/linuxfile.txt');
  845. $this->assertEquals(clean_param('/home../user ./.linuxfile.txt', PARAM_PATH), '/home../user ./.linuxfile.txt');
  846. $this->assertEquals(clean_param('~/myfile.txt', PARAM_PATH), '~/myfile.txt');
  847. $this->assertEquals(clean_param('~/../myfile.txt', PARAM_PATH), '~/myfile.txt');
  848. $this->assertEquals(clean_param('/..b../.../myfile.txt', PARAM_PATH), '/..b../.../myfile.txt');
  849. $this->assertEquals(clean_param('..b../.../myfile.txt', PARAM_PATH), '..b../.../myfile.txt');
  850. $this->assertEquals(clean_param('/super//slashes///', PARAM_PATH), '/super/slashes/');
  851. }
  852. function test_clean_param_username() {
  853. global $CFG;
  854. $currentstatus = $CFG->extendedusernamechars;
  855. // Run tests with extended character == FALSE;
  856. $CFG->extendedusernamechars = FALSE;
  857. $this->assertEquals(clean_param('johndoe123', PARAM_USERNAME), 'johndoe123' );
  858. $this->assertEquals(clean_param('john.doe', PARAM_USERNAME), 'john.doe');
  859. $this->assertEquals(clean_param('john-doe', PARAM_USERNAME), 'john-doe');
  860. $this->assertEquals(clean_param('john- doe', PARAM_USERNAME), 'john-doe');
  861. $this->assertEquals(clean_param('john_doe', PARAM_USERNAME), 'john_doe');
  862. $this->assertEquals(clean_param('john@doe', PARAM_USERNAME), 'john@doe');
  863. $this->assertEquals(clean_param('john~doe', PARAM_USERNAME), 'johndoe');
  864. $this->assertEquals(clean_param('john´doe', PARAM_USERNAME), 'johndoe');
  865. $this->assertEquals(clean_param('john#$%&() ', PARAM_USERNAME), 'john');
  866. $this->assertEquals(clean_param('JOHNdóé ', PARAM_USERNAME), 'johnd');
  867. $this->assertEquals(clean_param('john.,:;-_/|\ñÑ[]A_X-,D {} ~!@#$%^&*()_+ ?><[] ščřžžý ?ýáž?žý??šdoe ', PARAM_USERNAME), 'john.-_a_x-d@_doe');
  868. // Test success condition, if extendedusernamechars == ENABLE;
  869. $CFG->extendedusernamechars = TRUE;
  870. $this->assertEquals(clean_param('john_doe', PARAM_USERNAME), 'john_doe');
  871. $this->assertEquals(clean_param('john@doe', PARAM_USERNAME), 'john@doe');
  872. $this->assertEquals(clean_param('john# $%&()+_^', PARAM_USERNAME), 'john#$%&()+_^');
  873. $this->assertEquals(clean_param('john~doe', PARAM_USERNAME), 'john~doe');
  874. $this->assertEquals(clean_param('joHN´doe', PARAM_USERNAME), 'john´doe');
  875. $this->assertEquals(clean_param('johnDOE', PARAM_USERNAME), 'johndoe');
  876. $this->assertEquals(clean_param('johndóé ', PARAM_USERNAME), 'johndóé');
  877. $CFG->extendedusernamechars = $currentstatus;
  878. }
  879. function test_clean_param_stringid() {
  880. // Test string identifiers validation
  881. // valid strings:
  882. $this->assertEquals(clean_param('validstring', PARAM_STRINGID), 'validstring');
  883. $this->assertEquals(clean_param('mod/foobar:valid_capability', PARAM_STRINGID), 'mod/foobar:valid_capability');
  884. $this->assertEquals(clean_param('CZ', PARAM_STRINGID), 'CZ');
  885. $this->assertEquals(clean_param('application/vnd.ms-powerpoint', PARAM_STRINGID), 'application/vnd.ms-powerpoint');
  886. $this->assertEquals(clean_param('grade2', PARAM_STRINGID), 'grade2');
  887. // invalid strings:
  888. $this->assertEquals(clean_param('trailing ', PARAM_STRINGID), '');
  889. $this->assertEquals(clean_param('space bar', PARAM_STRINGID), '');
  890. $this->assertEquals(clean_param('0numeric', PARAM_STRINGID), '');
  891. $this->assertEquals(clean_param('*', PARAM_STRINGID), '');
  892. $this->assertEquals(clean_param(' ', PARAM_STRINGID), '');
  893. }
  894. function test_clean_param_timezone() {
  895. // Test timezone validation
  896. $testvalues = array (
  897. 'America/Jamaica' => 'America/Jamaica',
  898. 'America/Argentina/Cordoba' => 'America/Argentina/Cordoba',
  899. 'America/Port-au-Prince' => 'America/Port-au-Prince',
  900. 'America/Argentina/Buenos_Aires' => 'America/Argentina/Buenos_Aires',
  901. 'PST8PDT' => 'PST8PDT',
  902. 'Wrong.Value' => '',
  903. 'Wrong/.Value' => '',
  904. 'Wrong(Value)' => '',
  905. '0' => '0',
  906. '0.0' => '0.0',
  907. '0.5' => '0.5',
  908. '9.0' => '9.0',
  909. '-9.0' => '-9.0',
  910. '+9.0' => '+9.0',
  911. '9.5' => '9.5',
  912. '-9.5' => '-9.5',
  913. '+9.5' => '+9.5',
  914. '12.0' => '12.0',
  915. '-12.0' => '-12.0',
  916. '+12.0' => '+12.0',
  917. '12.5' => '12.5',
  918. '-12.5' => '-12.5',
  919. '+12.5' => '+12.5',
  920. '13.0' => '13.0',
  921. '-13.0' => '-13.0',
  922. '+13.0' => '+13.0',
  923. '13.5' => '',
  924. '+13.5' => '',
  925. '-13.5' => '',
  926. '0.2' => '');
  927. foreach ($testvalues as $testvalue => $expectedvalue) {
  928. $actualvalue = clean_param($testvalue, PARAM_TIMEZONE);
  929. $this->assertEquals($actualvalue, $expectedvalue);
  930. }
  931. }
  932. function test_validate_param() {
  933. try {
  934. $param = validate_param('11a', PARAM_INT);
  935. $this->fail('invalid_parameter_exception expected');
  936. } catch (invalid_parameter_exception $ex) {
  937. $this->assertTrue(true);
  938. }
  939. try {
  940. $param = validate_param('11', PARAM_INT);
  941. $this->assertEquals($param, 11);
  942. } catch (invalid_parameter_exception $ex) {
  943. $this->fail('invalid_parameter_exception not expected');
  944. }
  945. try {
  946. $param = validate_param(null, PARAM_INT, false);
  947. $this->fail('invalid_parameter_exception expected');
  948. } catch (invalid_parameter_exception $ex) {
  949. $this->assertTrue(true);
  950. }
  951. try {
  952. $param = validate_param(null, PARAM_INT, true);
  953. $this->assertTrue($param===null);
  954. } catch (invalid_parameter_exception $ex) {
  955. $this->fail('invalid_parameter_exception expected');
  956. }
  957. try {
  958. $param = validate_param(array(), PARAM_INT);
  959. $this->fail('invalid_parameter_exception expected');
  960. } catch (invalid_parameter_exception $ex) {
  961. $this->assertTrue(true);
  962. }
  963. try {
  964. $param = validate_param(new stdClass, PARAM_INT);
  965. $this->fail('invalid_parameter_exception expected');
  966. } catch (invalid_parameter_exception $ex) {
  967. $this->assertTrue(true);
  968. }
  969. try {
  970. $param = validate_param('1.0', PARAM_FLOAT);
  971. $this->assertSame(1.0, $param);
  972. // Make sure valid floats do not cause exception.
  973. validate_param(1.0, PARAM_FLOAT);
  974. validate_param(10, PARAM_FLOAT);
  975. validate_param('0', PARAM_FLOAT);
  976. validate_param('119813454.545464564564546564545646556564465465456465465465645645465645645645', PARAM_FLOAT);
  977. validate_param('011.1', PARAM_FLOAT);
  978. validate_param('11', PARAM_FLOAT);
  979. validate_param('+.1', PARAM_FLOAT);
  980. validate_param('-.1', PARAM_FLOAT);
  981. validate_param('1e10', PARAM_FLOAT);
  982. validate_param('.1e+10', PARAM_FLOAT);
  983. validate_param('1E-1', PARAM_FLOAT);
  984. $this->assertTrue(true);
  985. } catch (invalid_parameter_exception $ex) {
  986. $this->fail('Valid float notation not accepted');
  987. }
  988. try {
  989. $param = validate_param('1,2', PARAM_FLOAT);
  990. $this->fail('invalid_parameter_exception expected');
  991. } catch (invalid_parameter_exception $ex) {
  992. $this->assertTrue(true);
  993. }
  994. try {
  995. $param = validate_param('', PARAM_FLOAT);
  996. $this->fail('invalid_parameter_exception expected');
  997. } catch (invalid_parameter_exception $ex) {
  998. $this->assertTrue(true);
  999. }
  1000. try {
  1001. $param = validate_param('.', PARAM_FLOAT);
  1002. $this->fail('invalid_parameter_exception expected');
  1003. } catch (invalid_parameter_exception $ex) {
  1004. $this->assertTrue(true);
  1005. }
  1006. try {
  1007. $param = validate_param('e10', PARAM_FLOAT);
  1008. $this->fail('invalid_parameter_exception expected');
  1009. } catch (invalid_parameter_exception $ex) {
  1010. $this->assertTrue(true);
  1011. }
  1012. try {
  1013. $param = validate_param('abc', PARAM_FLOAT);
  1014. $this->fail('invalid_parameter_exception expected');
  1015. } catch (invalid_parameter_exception $ex) {
  1016. $this->assertTrue(true);
  1017. }
  1018. }
  1019. function test_shorten_text_no_tags_already_short_enough() {
  1020. // ......12345678901234567890123456.
  1021. $text = "short text already no tags";
  1022. $this->assertEquals($text, shorten_text($text));
  1023. }
  1024. function test_shorten_text_with_tags_already_short_enough() {
  1025. // .........123456...7890....12345678.......901234567.
  1026. $text = "<p>short <b>text</b> already</p><p>with tags</p>";
  1027. $this->assertEquals($text, shorten_text($text));
  1028. }
  1029. function test_shorten_text_no_tags_needs_shortening() {
  1030. // Default truncation is after 30 chars, but allowing 3 for the final '...'.
  1031. // ......12345678901234567890123456789023456789012345678901234.
  1032. $text = "long text without any tags blah de blah blah blah what";
  1033. $this->assertEquals('long text without any tags ...', shorten_text($text));
  1034. }
  1035. function test_shorten_text_with_tags_needs_shortening() {
  1036. // .......................................123456789012345678901234567890...
  1037. $text = "<div class='frog'><p><blockquote>Long text with tags that will ".
  1038. "be chopped off but <b>should be added back again</b></blockquote></p></div>";
  1039. $this->assertEquals("<div class='frog'><p><blockquote>Long text with " .
  1040. "tags that ...</blockquote></p></div>", shorten_text($text));
  1041. }
  1042. function test_shorten_text_with_entities() {
  1043. // Remember to allow 3 chars for the final '...'.
  1044. // ......123456789012345678901234567_____890...
  1045. $text = "some text which shouldn't &nbsp; break there";
  1046. $this->assertEquals("some text which shouldn't &nbsp; ...",
  1047. shorten_text($text, 31));
  1048. $this->assertEquals("some text which shouldn't &nbsp;...",
  1049. shorten_text($text, 30));
  1050. $this->assertEquals("some text which shouldn't ...",
  1051. shorten_text($text, 29));
  1052. }
  1053. function test_shorten_text_known_tricky_case() {
  1054. // This case caused a bug up to 1.9.5
  1055. // ..........123456789012345678901234567890123456789.....0_____1___2___...
  1056. $text = "<h3>standard 'break-out' sub groups in TGs?</h3>&nbsp;&lt;&lt;There are several";
  1057. $this->assertEquals("<h3>standard 'break-out' sub groups in ...</h3>",
  1058. shorten_text($text, 41));
  1059. $this->assertEquals("<h3>standard 'break-out' sub groups in TGs?...</h3>",
  1060. shorten_text($text, 42));
  1061. $this->assertEquals("<h3>standard 'break-out' sub groups in TGs?</h3>&nbsp;...",
  1062. shorten_text($text, 43));
  1063. }
  1064. function test_shorten_text_no_spaces() {
  1065. // ..........123456789.
  1066. $text = "<h1>123456789</h1>"; // A string with no convenient breaks.
  1067. $this->assertEquals("<h1>12345...</h1>",
  1068. shorten_text($text, 8));
  1069. }
  1070. function test_shorten_text_utf8_european() {
  1071. // Text without tags.
  1072. // ......123456789012345678901234567.
  1073. $text = "Žluťoučký koníček přeskočil";
  1074. $this->assertEquals($text, shorten_text($text)); // 30 chars by default.
  1075. $this->assertEquals("Žluťoučký koníče...", shorten_text($text, 19, true));
  1076. $this->assertEquals("Žluťoučký ...", shorten_text($text, 19, false));
  1077. // And try it with 2-less (that are, in bytes, the middle of a sequence).
  1078. $this->assertEquals("Žluťoučký koní...", shorten_text($text, 17, true));
  1079. $this->assertEquals("Žluťoučký ...", shorten_text($text, 17, false));
  1080. // .........123456789012345678...901234567....89012345.
  1081. $text = "<p>Žluťoučký koníček <b>přeskočil</b> potůček</p>";
  1082. $this->assertEquals($text, shorten_text($text, 60));
  1083. $this->assertEquals("<p>Žluťoučký koníček ...</p>", shorten_text($text, 21));
  1084. $this->assertEquals("<p>Žluťoučký koníče...</p>", shorten_text($text, 19, true));
  1085. $this->assertEquals("<p>Žluťoučký ...</p>", shorten_text($text, 19, false));
  1086. // And try it with 2 fewer (that are, in bytes, the middle of a sequence).
  1087. $this->assertEquals("<p>Žluťoučký koní...</p>", shorten_text($text, 17, true));
  1088. $this->assertEquals("<p>Žluťoučký ...</p>", shorten_text($text, 17, false));
  1089. // And try over one tag (start/end), it does proper text len.
  1090. $this->assertEquals("<p>Žluťoučký koníček <b>př...</b></p>", shorten_text($text, 23, true));
  1091. $this->assertEquals("<p>Žluťoučký koníček <b>přeskočil</b> pot...</p>", shorten_text($text, 34, true));
  1092. // And in the middle of one tag.
  1093. $this->assertEquals("<p>Žluťoučký koníček <b>přeskočil...</b></p>", shorten_text($text, 30, true));
  1094. }
  1095. function test_shorten_text_utf8_oriental() {
  1096. // Japanese
  1097. // text without tags
  1098. // ......123456789012345678901234.
  1099. $text = '言語設定言語設定abcdefghijkl';
  1100. $this->assertEquals($text, shorten_text($text)); // 30 chars by default
  1101. $this->assertEquals("言語設定言語...", shorten_text($text, 9, true));
  1102. $this->assertEquals("言語設定言語...", shorten_text($text, 9, false));
  1103. $this->assertEquals("言語設定言語設定ab...", shorten_text($text, 13, true));
  1104. $this->assertEquals("言語設定言語設定...", shorten_text($text, 13, false));
  1105. // Chinese
  1106. // text without tags
  1107. // ......123456789012345678901234.
  1108. $text = '简体中文简体中文abcdefghijkl';
  1109. $this->assertEquals($text, shorten_text($text)); // 30 chars by default
  1110. $this->assertEquals("简体中文简体...", shorten_text($text, 9, true));
  1111. $this->assertEquals("简体中文简体...", shorten_text($text, 9, false));
  1112. $this->assertEquals("简体中文简体中文ab...", shorten_text($text, 13, true));
  1113. $this->assertEquals("简体中文简体中文...", shorten_text($text, 13, false));
  1114. }
  1115. function test_shorten_text_multilang() {
  1116. // This is not necessaryily specific to multilang. The issue is really
  1117. // tags with attributes, where before we were generating invalid HTML
  1118. // output like shorten_text('<span id="x" class="y">A</span> B', 1);
  1119. // returning '<span id="x" ...</span>'. It is just that multilang
  1120. // requires the sort of HTML that is quite likely to trigger this.
  1121. // ........................................1...
  1122. $text = '<span lang="en" class="multilang">A</span>' .
  1123. '<span lang="fr" class="multilang">B</span>';
  1124. $this->assertEquals('<span lang="en" class="multilang">...</span>',
  1125. shorten_text($text, 1));
  1126. }
  1127. function test_usergetdate() {
  1128. global $USER, $CFG, $DB;
  1129. //Check if forcetimezone is set then save it and set it to use user timezone
  1130. $cfgforcetimezone = null;
  1131. if (isset($CFG->forcetimezone)) {
  1132. $cfgforcetimezone = $CFG->forcetimezone;
  1133. $CFG->forcetimezone = 99; //get user default timezone.
  1134. }
  1135. $olduser = $USER;
  1136. $USER = $DB->get_record('user', array('id'=>2)); //admin
  1137. $userstimezone = $USER->timezone;
  1138. $USER->timezone = 2;//set the timezone to a known state
  1139. // The string version of date comes from server locale setting and does
  1140. // not respect user language, so it is necessary to reset that.
  1141. $oldlocale = setlocale(LC_TIME, '0');
  1142. setlocale(LC_TIME, 'en_AU.UTF-8');
  1143. $ts = 1261540267; //the time this function was created
  1144. $arr = usergetdate($ts,1);//specify the timezone as an argument
  1145. $arr = array_values($arr);
  1146. list($seconds,$minutes,$hours,$mday,$wday,$mon,$year,$yday,$weekday,$month) = $arr;
  1147. $this->assertSame($seconds, 7);
  1148. $this->assertSame($minutes, 51);
  1149. $this->assertSame($hours, 4);
  1150. $this->assertSame($mday, 23);
  1151. $this->assertSame($wday, 3);
  1152. $this->assertSame($mon, 12);
  1153. $this->assertSame($year, 2009);
  1154. $this->assertSame($yday, 356);
  1155. $this->assertSame($weekday, 'Wednesday');
  1156. $this->assertSame($month, 'December');
  1157. $arr = usergetdate($ts);//gets the timezone from the $USER object
  1158. $arr = array_values($arr);
  1159. list($seconds,$minutes,$hours,$mday,$wday,$mon,$year,$yday,$weekday,$month) = $arr;
  1160. $this->assertSame($seconds, 7);
  1161. $this->assertSame($minutes, 51);
  1162. $this->assertSame($hours, 5);
  1163. $this->assertSame($mday, 23);
  1164. $this->assertSame($wday, 3);
  1165. $this->assertSame($mon, 12);
  1166. $this->assertSame($year, 2009);
  1167. $this->assertSame($yday, 356);
  1168. $this->assertSame($weekday, 'Wednesday');
  1169. $this->assertSame($month, 'December');
  1170. //set the timezone back to what it was
  1171. $USER->timezone = $userstimezone;
  1172. //restore forcetimezone if changed.
  1173. if (!is_null($cfgforcetimezone)) {
  1174. $CFG->forcetimezone = $cfgforcetimezone;
  1175. }
  1176. setlocale(LC_TIME, $oldlocale);
  1177. $USER = $olduser;
  1178. }
  1179. public function test_normalize_component() {
  1180. // moodle core
  1181. $this->assertEquals(normalize_component('moodle'), array('core', null));
  1182. $this->assertEquals(normalize_component('core'), array('core', null));
  1183. // moodle core subsystems
  1184. $this->assertEquals(normalize_component('admin'), array('core', 'admin'));
  1185. $this->assertEquals(normalize_component('core_admin'), array('core', 'admin'));
  1186. // activity modules and their subplugins
  1187. $this->assertEquals(normalize_component('workshop'), array('mod', 'workshop'));
  1188. $this->assertEquals(normalize_component('mod_workshop'), array('mod', 'workshop'));
  1189. $this->assertEquals(normalize_component('workshopform_accumulative'), array('workshopform', 'accumulative'));
  1190. $this->assertEquals(normalize_component('quiz'), array('mod', 'quiz'));
  1191. $this->assertEquals(normalize_component('quiz_grading'), array('quiz', 'grading'));
  1192. $this->assertEquals(normalize_component('data'), array('mod', 'data'));
  1193. $this->assertEquals(normalize_component('datafield_checkbox'), array('datafield', 'checkbox'));
  1194. // other plugin types
  1195. $this->assertEquals(normalize_component('auth_mnet'), array('auth', 'mnet'));
  1196. $this->assertEquals(normalize_component('enrol_self'), array('enrol', 'self'));
  1197. $this->assertEquals(normalize_component('block_html'), array('block', 'html'));
  1198. $this->assertEquals(normalize_component('block_mnet_hosts'), array('block', 'mnet_hosts'));
  1199. $this->assertEquals(normalize_component('local_amos'), array('local', 'amos'));
  1200. // unknown components are supposed to be activity modules
  1201. $this->assertEquals(normalize_component('whothefuckwouldcomewithsuchastupidnameofcomponent'),
  1202. array('mod', 'whothefuckwouldcomewithsuchastupidnameofcomponent'));
  1203. $this->assertEquals(normalize_component('whothefuck_wouldcomewithsuchastupidnameofcomponent'),
  1204. array('mod', 'whothefuck_wouldcomewithsuchastupidnameofcomponent'));
  1205. $this->assertEquals(normalize_component('whothefuck_would_come_withsuchastupidnameofcomponent'),
  1206. array('mod', 'whothefuck_would_come_withsuchastupidnameofcomponent'));
  1207. }
  1208. protected function get_fake_preference_test_userid() {
  1209. global $DB;
  1210. // we need some nonexistent user id
  1211. $id = 2147483647 - 666;
  1212. if ($DB->get_records('user', array('id'=>$id))) {
  1213. //weird!
  1214. return false;
  1215. }
  1216. return $id;
  1217. }
  1218. public function test_mark_user_preferences_changed() {
  1219. $this->resetAfterTest(true);
  1220. if (!$otheruserid = $this->get_fake_preference_test_userid()) {
  1221. $this->fail('Can not find unused user id for the preferences test');
  1222. return;
  1223. }
  1224. set_cache_flag('userpreferenceschanged', $otheruserid, NULL);
  1225. mark_user_preferences_changed($otheruserid);
  1226. $this->assertEquals(get_cache_flag('userpreferenceschanged', $otheruserid, time()-10), 1);
  1227. set_cache_flag('userpreferenceschanged', $otheruserid, NULL);
  1228. }
  1229. public function test_check_user_preferences_loaded() {
  1230. global $DB;
  1231. $this->resetAfterTest(true);
  1232. if (!$otheruserid = $this->get_fake_preference_test_userid()) {
  1233. $this->fail('Can not find unused user id for the preferences test');
  1234. return;
  1235. }
  1236. $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
  1237. set_cache_flag('userpreferenceschanged', $otheruserid, NULL);
  1238. $user = new stdClass();
  1239. $user->id = $otheruserid;
  1240. // load
  1241. check_user_preferences_loaded($user);
  1242. $this->assertTrue(isset($user->preference));
  1243. $this->assertTrue(is_array($user->preference));
  1244. $this->assertTrue(isset($user->preference['_lastloaded']));
  1245. $this->assertEquals(count($user->preference), 1);
  1246. // add preference via direct call
  1247. $DB->insert_record('user_preferences', array('name'=>'xxx', 'value'=>'yyy', 'userid'=>$user->id));
  1248. // no cache reload yet
  1249. check_user_preferences_loaded($user);
  1250. $this->assertEquals(count($user->preference), 1);
  1251. // forced reloading of cache
  1252. unset($user->preference);
  1253. check_user_preferences_loaded($user);
  1254. $this->assertEquals(count($user->preference), 2);
  1255. $this->assertEquals($user->preference['xxx'], 'yyy');
  1256. // add preference via direct call
  1257. $DB->insert_record('user_preferences', array('name'=>'aaa', 'value'=>'bbb', 'userid'=>$user->id));
  1258. // test timeouts and modifications from different session
  1259. set_cache_flag('userpreferenceschanged', $user->id, 1, time() + 1000);
  1260. $user->preference['_lastloaded'] = $user->preference['_lastloaded'] - 20;
  1261. check_user_preferences_loaded($user);
  1262. $this->assertEquals(count($user->preference), 2);
  1263. check_user_preferences_loaded($user, 10);
  1264. $this->assertEquals(count($user->preference), 3);
  1265. $this->assertEquals($user->preference['aaa'], 'bbb');
  1266. set_cache_flag('userpreferenceschanged', $user->id, null);
  1267. }
  1268. public function test_set_user_preference() {
  1269. global $DB, $USER;
  1270. $this->resetAfterTest(true);
  1271. $olduser = $USER;
  1272. $USER = $DB->get_record('user', array('id'=>2)); //admin
  1273. if (!$otheruserid = $this->get_fake_preference_test_userid()) {
  1274. $this->fail('Can not find unused user id for the preferences test');
  1275. return;
  1276. }
  1277. $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
  1278. set_cache_flag('userpreferenceschanged', $otheruserid, null);
  1279. $user = new stdClass();
  1280. $user->id = $otheruserid;
  1281. set_user_preference('aaa', 'bbb', $otheruserid);
  1282. $this->assertEquals('bbb', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'aaa')));
  1283. $this->assertEquals('bbb', get_user_preferences('aaa', null, $otheruserid));
  1284. set_user_preference('xxx', 'yyy', $user);
  1285. $this->assertEquals('yyy', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx')));
  1286. $this->assertEquals('yyy', get_user_preferences('xxx', null, $otheruserid));
  1287. $this->assertTrue(is_array($user->preference));
  1288. $this->assertEquals($user->preference['aaa'], 'bbb');
  1289. $this->assertEquals($user->preference['xxx'], 'yyy');
  1290. set_user_preference('xxx', NULL, $user);
  1291. $this->assertSame(false, $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx')));
  1292. $this->assertSame(null, get_user_preferences('xxx', null, $otheruserid));
  1293. set_user_preference('ooo', true, $user);
  1294. $prefs = get_user_preferences(null, null, $otheruserid);
  1295. $this->assertSame($prefs['aaa'], $user->preference['aaa']);
  1296. $this->assertSame($prefs['ooo'], $user->preference['ooo']);
  1297. $this->assertSame($prefs['ooo'], '1');
  1298. set_user_preference('null', 0, $user);
  1299. $this->assertSame('0', get_user_preferences('null', null, $otheruserid));
  1300. $this->assertSame('lala', get_user_preferences('undefined', 'lala', $otheruserid));
  1301. $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
  1302. set_cache_flag('userpreferenceschanged', $otheruserid, null);
  1303. // test $USER default
  1304. set_user_preference('_test_user_preferences_pref', 'ok');
  1305. $this->assertSame('ok', $USER->preference['_test_user_preferences_pref']);
  1306. unset_user_preference('_test_user_preferences_pref');
  1307. $this->assertTrue(!isset($USER->preference['_test_user_preferences_pref']));
  1308. // Test 1333 char values (no need for unicode, there are already tests for that in DB tests)
  1309. $longvalue = str_repeat('a', 1333);
  1310. set_user_preference('_test_long_user_preference', $longvalue);
  1311. $this->assertEquals($longvalue, get_user_preferences('_test_long_user_preference'));
  1312. $this->assertEquals($longvalue,
  1313. $DB->get_field('user_preferences', 'value', array('userid' => $USER->id, 'name' => '_test_long_user_preference')));
  1314. // Test > 1333 char values, coding_exception expected
  1315. $longvalue = str_repeat('a', 1334);
  1316. try {
  1317. set_user_preference('_test_long_user_preference', $longvalue);
  1318. $this->fail('Exception expected - longer than 1333 chars not allowed as preference value');
  1319. } catch (coding_exception $ex) {
  1320. $this->assertTrue(true);
  1321. }
  1322. //test invalid params
  1323. try {
  1324. set_user_preference('_test_user_preferences_pref', array());
  1325. $this->fail('Exception expected - array not valid preference value');
  1326. } catch (coding_exception $ex) {
  1327. $this->assertTrue(true);
  1328. }
  1329. try {
  1330. set_user_preference('_test_user_preferences_pref', new stdClass);
  1331. $this->fail('Exception expected - class not valid preference value');
  1332. } catch (coding_exception $ex) {
  1333. $this->assertTrue(true);
  1334. }
  1335. try {
  1336. set_user_preference('_test_user_preferences_pref', 1, array('xx' => 1));
  1337. $this->fail('Exception expected - user instance expected');
  1338. } catch (coding_exception $ex) {
  1339. $this->assertTrue(true);
  1340. }
  1341. try {
  1342. set_user_preference('_test_user_preferences_pref', 1, 'abc');
  1343. $this->fail('Exception expected - user instance expected');
  1344. } catch (coding_exception $ex) {
  1345. $this->assertTrue(true);
  1346. }
  1347. try {
  1348. set_user_preference('', 1);
  1349. $this->fail('Exception expected - invalid name accepted');
  1350. } catch (coding_exception $ex) {
  1351. $this->assertTrue(true);
  1352. }
  1353. try {
  1354. set_user_preference('1', 1);
  1355. $this->fail('Exception expected - invalid name accepted');
  1356. } catch (coding_exception $ex) {
  1357. $this->assertTrue(true);
  1358. }
  1359. $USER = $olduser;
  1360. }
  1361. public function test_get_extra_user_fields() {
  1362. global $CFG, $USER, $DB;
  1363. $oldshowuseridentity = $CFG->showuseridentity;
  1364. $olduser = $USER;
  1365. $USER = $DB->get_record('user', array('id'=>2)); //admin
  1366. // It would be really nice if there were a way to 'mock' has_capability
  1367. // checks (either to return true or false) but as there is not, this
  1368. // test doesn't test the capability check. Presumably, anyone running
  1369. // unit tests will have the capability.
  1370. $context = context_system::instance();
  1371. // No fields
  1372. $CFG->showuseridentity = '';
  1373. $this->assertEquals(array(), get_extra_user_fields($context));
  1374. // One field
  1375. $CFG->showuseridentity = 'frog';
  1376. $this->assertEquals(array('frog'), get_extra_user_fields($context));
  1377. // Two fields
  1378. $CFG->showuseridentity = 'frog,zombie';
  1379. $this->assertEquals(array('frog', 'zombie'), get_extra_user_fields($context));
  1380. // No fields, except
  1381. $CFG->showuseridentity = '';
  1382. $this->assertEquals(array(), get_extra_user_fields($context, array('frog')));
  1383. // One field
  1384. $CFG->showuseridentity = 'frog';
  1385. $this->assertEquals(array(), get_extra_user_fields($context, array('frog')));
  1386. // Two fields
  1387. $CFG->showuseridentity = 'frog,zombie';
  1388. $this->assertEquals(array('zombie'), get_extra_user_fields($context, array('frog')));
  1389. // As long as this test passes, the value will be set back. This is only
  1390. // in-memory anyhow
  1391. $CFG->showuseridentity = $oldshowuseridentity;
  1392. $USER = $olduser;
  1393. }
  1394. public function test_get_extra_user_fields_sql() {
  1395. global $CFG, $USER, $DB;
  1396. $olduser = $USER;
  1397. $USER = $DB->get_record('user', array('id'=>2)); //admin
  1398. $oldshowuseridentity = $CFG->showuseridentity;
  1399. $context = context_system::instance();
  1400. // No fields
  1401. $CFG->showuseridentity = '';
  1402. $this->assertEquals('', get_extra_user_fields_sql($context));
  1403. // One field
  1404. $CFG->showuseridentity = 'frog';
  1405. $this->assertEquals(', frog', get_extra_user_fields_sql($context));
  1406. // Two fields with table prefix
  1407. $CFG->showuseridentity = 'frog,zombie';
  1408. $this->assertEquals(', u1.frog, u1.zombie', get_extra_user_fields_sql($context, 'u1'));
  1409. // Two fields with field prefix
  1410. $CFG->showuseridentity = 'frog,zombie';
  1411. $this->assertEquals(', frog AS u_frog, zombie AS u_zombie',
  1412. get_extra_user_fields_sql($context, '', 'u_'));
  1413. // One field excluded
  1414. $CFG->showuseridentity = 'frog';
  1415. $this->assertEquals('', get_extra_user_fields_sql($context, '', '', array('frog')));
  1416. // Two fields, one excluded, table+field prefix
  1417. $CFG->showuseridentity = 'frog,zombie';
  1418. $this->assertEquals(', u1.zombie AS u_zombie',
  1419. get_extra_user_fields_sql($context, 'u1', 'u_', array('frog')));
  1420. // As long as this test passes, the value will be set back. This is only
  1421. // in-memory anyhow
  1422. $CFG->showuseridentity = $oldshowuseridentity;
  1423. $USER = $olduser;
  1424. }
  1425. /**
  1426. * Test some critical TZ/DST.
  1427. *
  1428. * This method tests some special TZ/DST combinations that were fixed
  1429. * by MDL-38999. The tests are done by comparing the results of the
  1430. * output using Moodle TZ/DST support and PHP native one.
  1431. *
  1432. * Note: If you don't trust PHP TZ/DST support, can verify the
  1433. * harcoded expectations below with:
  1434. * http://www.tools4noobs.com/online_tools/unix_timestamp_to_datetime/
  1435. */
  1436. public function test_some_moodle_special_dst() {
  1437. $stamp = 1365386400; // 2013/04/08 02:00:00 GMT/UTC.
  1438. // In Europe/Tallinn it was 2013/04/08 05:00:00.
  1439. $expectation = '2013/04/08 05:00:00';
  1440. $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
  1441. $phpdt->setTimezone(new DateTimeZone('Europe/Tallinn'));
  1442. $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
  1443. $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'Europe/Tallinn', false); // Moodle result.
  1444. $this->assertSame($expectation, $phpres);
  1445. $this->assertSame($expectation, $moodleres);
  1446. // In St. Johns it was 2013/04/07 23:30:00.
  1447. $expectation = '2013/04/07 23:30:00';
  1448. $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
  1449. $phpdt->setTimezone(new DateTimeZone('America/St_Johns'));
  1450. $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
  1451. $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'America/St_Johns', false); // Moodle result.
  1452. $this->assertSame($expectation, $phpres);
  1453. $this->assertSame($expectation, $moodleres);
  1454. $stamp = 1383876000; // 2013/11/08 02:00:00 GMT/UTC.
  1455. // In Europe/Tallinn it was 2013/11/08 04:00:00.
  1456. $expectation = '2013/11/08 04:00:00';
  1457. $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
  1458. $phpdt->setTimezone(new DateTimeZone('Europe/Tallinn'));
  1459. $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
  1460. $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'Europe/Tallinn', false); // Moodle result.
  1461. $this->assertSame($expectation, $phpres);
  1462. $this->assertSame($expectation, $moodleres);
  1463. // In St. Johns it was 2013/11/07 22:30:00.
  1464. $expectation = '2013/11/07 22:30:00';
  1465. $phpdt = DateTime::createFromFormat('U', $stamp, new DateTimeZone('UTC'));
  1466. $phpdt->setTimezone(new DateTimeZone('America/St_Johns'));
  1467. $phpres = $phpdt->format('Y/m/d H:i:s'); // PHP result.
  1468. $moodleres = userdate($stamp, '%Y/%m/%d %H:%M:%S', 'America/St_Johns', false); // Moodle result.
  1469. $this->assertSame($expectation, $phpres);
  1470. $this->assertSame($expectation, $moodleres);
  1471. }
  1472. public function test_userdate() {
  1473. global $USER, $CFG, $DB;
  1474. $olduser = $USER;
  1475. $USER = $DB->get_record('user', array('id'=>2)); //admin
  1476. $testvalues = array(
  1477. array(
  1478. 'time' => '1309514400',
  1479. 'usertimezone' => 'America/Moncton',
  1480. 'timezone' => '0.0', //no dst offset
  1481. 'expectedoutput' => 'Friday, 1 July 2011, 10:00 AM'
  1482. ),
  1483. array(
  1484. 'time' => '1309514400',
  1485. 'usertimezone' => 'America/Moncton',
  1486. 'timezone' => '99', //dst offset and timezone offset.
  1487. 'expectedoutput' => 'Friday, 1 July 2011, 7:00 AM'
  1488. ),
  1489. array(
  1490. 'time' => '1309514400',
  1491. 'usertimezone' => 'America/Moncton',
  1492. 'timezone' => 'America/Moncton', //dst offset and timezone offset.
  1493. 'expectedoutput' => 'Friday, 1 July 2011, 7:00 AM'
  1494. ),
  1495. array(
  1496. 'time' => '1293876000 ',
  1497. 'usertimezone' => 'America/Moncton',
  1498. 'timezone' => '0.0', //no dst offset
  1499. 'expectedoutput' => 'Saturday, 1 January 2011, 10:00 AM'
  1500. ),
  1501. array(
  1502. 'time' => '1293876000 ',
  1503. 'usertimezone' => 'America/Moncton',
  1504. 'timezone' => '99', //no dst offset in jan, so just timezone offset.
  1505. 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 AM'
  1506. ),
  1507. array(
  1508. 'time' => '1293876000 ',
  1509. 'usertimezone' => 'America/Moncton',
  1510. 'timezone' => 'America/Moncton', //no dst offset in jan
  1511. 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 AM'
  1512. ),
  1513. array(
  1514. 'time' => '1293876000 ',
  1515. 'usertimezone' => '2',
  1516. 'timezone' => '99', //take user timezone
  1517. 'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
  1518. ),
  1519. array(
  1520. 'time' => '1293876000 ',
  1521. 'usertimezone' => '-2',
  1522. 'timezone' => '99', //take user timezone
  1523. 'expectedoutput' => 'Saturday, 1 January 2011, 8:00 AM'
  1524. ),
  1525. array(
  1526. 'time' => '1293876000 ',
  1527. 'usertimezone' => '-10',
  1528. 'timezone' => '2', //take this timezone
  1529. 'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
  1530. ),
  1531. array(
  1532. 'time' => '1293876000 ',
  1533. 'usertimezone' => '-10',
  1534. 'timezone' => '-2', //take this timezone
  1535. 'expectedoutput' => 'Saturday, 1 January 2011, 8:00 AM'
  1536. ),
  1537. array(
  1538. 'time' => '1293876000 ',
  1539. 'usertimezone' => '-10',
  1540. 'timezone' => 'random/time', //this should show server time
  1541. 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 PM'
  1542. ),
  1543. array(
  1544. 'time' => '1293876000 ',
  1545. 'usertimezone' => '14', //server time zone
  1546. 'timezone' => '99', //this should show user time
  1547. 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 PM'
  1548. ),
  1549. );
  1550. //Check if forcetimezone is set then save it and set it to use user timezone
  1551. $cfgforcetimezone = null;
  1552. if (isset($CFG->forcetimezone)) {
  1553. $cfgforcetimezone = $CFG->forcetimezone;
  1554. $CFG->forcetimezone = 99; //get user default timezone.
  1555. }
  1556. //store user default timezone to restore later
  1557. $userstimezone = $USER->timezone;
  1558. // The string version of date comes from server locale setting and does
  1559. // not respect user language, so it is necessary to reset that.
  1560. $oldlocale = setlocale(LC_TIME, '0');
  1561. setlocale(LC_TIME, 'en_AU.UTF-8');
  1562. //set default timezone to Australia/Perth, else time calculated
  1563. //will not match expected values. Before that save system defaults.
  1564. $systemdefaulttimezone = date_default_timezone_get();
  1565. date_default_timezone_set('Australia/Perth');
  1566. foreach ($testvalues as $vals) {
  1567. $USER->timezone = $vals['usertimezone'];
  1568. $actualoutput = userdate($vals['time'], '%A, %d %B %Y, %I:%M %p', $vals['timezone']);
  1569. //On different systems case of AM PM changes so compare case insensitive
  1570. $vals['expectedoutput'] = textlib::strtolower($vals['expectedoutput']);
  1571. $actualoutput = textlib::strtolower($actualoutput);
  1572. $this->assertEquals($vals['expectedoutput'], $actualoutput,
  1573. "Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
  1574. Please check if timezones are updated (Site adminstration -> location -> update timezone)");
  1575. }
  1576. //restore user timezone back to what it was
  1577. $USER->timezone = $userstimezone;
  1578. //restore forcetimezone
  1579. if (!is_null($cfgforcetimezone)) {
  1580. $CFG->forcetimezone = $cfgforcetimezone;
  1581. }
  1582. //restore system default values.
  1583. date_default_timezone_set($systemdefaulttimezone);
  1584. setlocale(LC_TIME, $oldlocale);
  1585. $USER = $olduser;
  1586. }
  1587. public function test_make_timestamp() {
  1588. global $USER, $CFG, $DB;
  1589. $olduser = $USER;
  1590. $USER = $DB->get_record('user', array('id'=>2)); //admin
  1591. $testvalues = array(
  1592. array(
  1593. 'usertimezone' => 'America/Moncton',
  1594. 'year' => '2011',
  1595. 'month' => '7',
  1596. 'day' => '1',
  1597. 'hour' => '10',
  1598. 'minutes' => '00',
  1599. 'seconds' => '00',
  1600. 'timezone' => '0.0',
  1601. 'applydst' => false, //no dst offset
  1602. 'expectedoutput' => '1309514400' // 6pm at UTC+0
  1603. ),
  1604. array(
  1605. 'usertimezone' => 'America/Moncton',
  1606. 'year' => '2011',
  1607. 'month' => '7',
  1608. 'day' => '1',
  1609. 'hour' => '10',
  1610. 'minutes' => '00',
  1611. 'seconds' => '00',
  1612. 'timezone' => '99', //user default timezone
  1613. 'applydst' => false, //don't apply dst
  1614. 'expectedoutput' => '1309528800'
  1615. ),
  1616. array(
  1617. 'usertimezone' => 'America/Moncton',
  1618. 'year' => '2011',
  1619. 'month' => '7',
  1620. 'day' => '1',
  1621. 'hour' => '10',
  1622. 'minutes' => '00',
  1623. 'seconds' => '00',
  1624. 'timezone' => '99', //user default timezone
  1625. 'applydst' => true, //apply dst
  1626. 'expectedoutput' => '1309525200'
  1627. ),
  1628. array(
  1629. 'usertimezone' => 'America/Moncton',
  1630. 'year' => '2011',
  1631. 'month' => '7',
  1632. 'day' => '1',
  1633. 'hour' => '10',
  1634. 'minutes' => '00',
  1635. 'seconds' => '00',
  1636. 'timezone' => 'America/Moncton', //string timezone
  1637. 'applydst' => true, //apply dst
  1638. 'expectedoutput' => '1309525200'
  1639. ),
  1640. array(
  1641. 'usertimezone' => '2',//no dst applyed
  1642. 'year' => '2011',
  1643. 'month' => '7',
  1644. 'day' => '1',
  1645. 'hour' => '10',
  1646. 'minutes' => '00',
  1647. 'seconds' => '00',
  1648. 'timezone' => '99', //take user timezone
  1649. 'applydst' => true, //apply dst
  1650. 'expectedoutput' => '1309507200'
  1651. ),
  1652. array(
  1653. 'usertimezone' => '-2',//no dst applyed
  1654. 'year' => '2011',
  1655. 'month' => '7',
  1656. 'day' => '1',
  1657. 'hour' => '10',
  1658. 'minutes' => '00',
  1659. 'seconds' => '00',
  1660. 'timezone' => '99', //take usertimezone
  1661. 'applydst' => true, //apply dst
  1662. 'expectedoutput' => '1309521600'
  1663. ),
  1664. array(
  1665. 'usertimezone' => '-10',//no dst applyed
  1666. 'year' => '2011',
  1667. 'month' => '7',
  1668. 'day' => '1',
  1669. 'hour' => '10',
  1670. 'minutes' => '00',
  1671. 'seconds' => '00',
  1672. 'timezone' => '2', //take this timezone
  1673. 'applydst' => true, //apply dst
  1674. 'expectedoutput' => '1309507200'
  1675. ),
  1676. array(
  1677. 'usertimezone' => '-10',//no dst applyed
  1678. 'year' => '2011',
  1679. 'month' => '7',
  1680. 'day' => '1',
  1681. 'hour' => '10',
  1682. 'minutes' => '00',
  1683. 'seconds' => '00',
  1684. 'timezone' => '-2', //take this timezone
  1685. 'applydst' => true, //apply dst,
  1686. 'expectedoutput' => '1309521600'
  1687. ),
  1688. array(
  1689. 'usertimezone' => '-10',//no dst applyed
  1690. 'year' => '2011',
  1691. 'month' => '7',
  1692. 'day' => '1',
  1693. 'hour' => '10',
  1694. 'minutes' => '00',
  1695. 'seconds' => '00',
  1696. 'timezone' => 'random/time', //This should show server time
  1697. 'applydst' => true, //apply dst,
  1698. 'expectedoutput' => '1309485600'
  1699. ),
  1700. array(
  1701. 'usertimezone' => '14',//server time
  1702. 'year' => '2011',
  1703. 'month' => '7',
  1704. 'day' => '1',
  1705. 'hour' => '10',
  1706. 'minutes' => '00',
  1707. 'seconds' => '00',
  1708. 'timezone' => '99', //get user time
  1709. 'applydst' => true, //apply dst,
  1710. 'expectedoutput' => '1309485600'
  1711. )
  1712. );
  1713. //Check if forcetimezone is set then save it and set it to use user timezone
  1714. $cfgforcetimezone = null;
  1715. if (isset($CFG->forcetimezone)) {
  1716. $cfgforcetimezone = $CFG->forcetimezone;
  1717. $CFG->forcetimezone = 99; //get user default timezone.
  1718. }
  1719. //store user default timezone to restore later
  1720. $userstimezone = $USER->timezone;
  1721. // The string version of date comes from server locale setting and does
  1722. // not respect user language, so it is necessary to reset that.
  1723. $oldlocale = setlocale(LC_TIME, '0');
  1724. setlocale(LC_TIME, 'en_AU.UTF-8');
  1725. //set default timezone to Australia/Perth, else time calulated
  1726. //will not match expected values. Before that save system defaults.
  1727. $systemdefaulttimezone = date_default_timezone_get();
  1728. date_default_timezone_set('Australia/Perth');
  1729. //Test make_timestamp with all testvals and assert if anything wrong.
  1730. foreach ($testvalues as $vals) {
  1731. $USER->timezone = $vals['usertimezone'];
  1732. $actualoutput = make_timestamp(
  1733. $vals['year'],
  1734. $vals['month'],
  1735. $vals['day'],
  1736. $vals['hour'],
  1737. $vals['minutes'],
  1738. $vals['seconds'],
  1739. $vals['timezone'],
  1740. $vals['applydst']
  1741. );
  1742. //On different systems case of AM PM changes so compare case insenitive
  1743. $vals['expectedoutput'] = textlib::strtolower($vals['expectedoutput']);
  1744. $actualoutput = textlib::strtolower($actualoutput);
  1745. $this->assertEquals($vals['expectedoutput'], $actualoutput,
  1746. "Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
  1747. Please check if timezones are updated (Site adminstration -> location -> update timezone)");
  1748. }
  1749. //restore user timezone back to what it was
  1750. $USER->timezone = $userstimezone;
  1751. //restore forcetimezone
  1752. if (!is_null($cfgforcetimezone)) {
  1753. $CFG->forcetimezone = $cfgforcetimezone;
  1754. }
  1755. //restore system default values.
  1756. date_default_timezone_set($systemdefaulttimezone);
  1757. setlocale(LC_TIME, $oldlocale);
  1758. $USER = $olduser;
  1759. }
  1760. /**
  1761. * Test get_string and most importantly the implementation of the lang_string
  1762. * object.
  1763. */
  1764. public function test_get_string() {
  1765. global $COURSE;
  1766. // Make sure we are using English
  1767. $originallang = $COURSE->lang;
  1768. $COURSE->lang = 'en';
  1769. $yes = get_string('yes');
  1770. $yesexpected = 'Yes';
  1771. $this->assertEquals(getType($yes), 'string');
  1772. $this->assertEquals($yes, $yesexpected);
  1773. $yes = get_string('yes', 'moodle');
  1774. $this->assertEquals(getType($yes), 'string');
  1775. $this->assertEquals($yes, $yesexpected);
  1776. $yes = get_string('yes', 'core');
  1777. $this->assertEquals(getType($yes), 'string');
  1778. $this->assertEquals($yes, $yesexpected);
  1779. $yes = get_string('yes', '');
  1780. $this->assertEquals(getType($yes), 'string');
  1781. $this->assertEquals($yes, $yesexpected);
  1782. $yes = get_string('yes', null);
  1783. $this->assertEquals(getType($yes), 'string');
  1784. $this->assertEquals($yes, $yesexpected);
  1785. $yes = get_string('yes', null, 1);
  1786. $this->assertEquals(getType($yes), 'string');
  1787. $this->assertEquals($yes, $yesexpected);
  1788. $days = 1;
  1789. $numdays = get_string('numdays', 'core', '1');
  1790. $numdaysexpected = $days.' days';
  1791. $this->assertEquals(getType($numdays), 'string');
  1792. $this->assertEquals($numdays, $numdaysexpected);
  1793. $yes = get_string('yes', null, null, true);
  1794. $this->assertEquals(get_class($yes), 'lang_string');
  1795. $this->assertEquals((string)$yes, $yesexpected);
  1796. // Test using a lang_string object as the $a argument for a normal
  1797. // get_string call (returning string)
  1798. $test = new lang_string('yes', null, null, true);
  1799. $testexpected = get_string('numdays', 'core', get_string('yes'));
  1800. $testresult = get_string('numdays', null, $test);
  1801. $this->assertEquals(getType($testresult), 'string');
  1802. $this->assertEquals($testresult, $testexpected);
  1803. // Test using a lang_string object as the $a argument for an object
  1804. // get_string call (returning lang_string)
  1805. $test = new lang_string('yes', null, null, true);
  1806. $testexpected = get_string('numdays', 'core', get_string('yes'));
  1807. $testresult = get_string('numdays', null, $test, true);
  1808. $this->assertEquals(get_class($testresult), 'lang_string');
  1809. $this->assertEquals("$testresult", $testexpected);
  1810. // Make sure that object properties that can't be converted don't cause
  1811. // errors
  1812. // Level one: This is as deep as current language processing goes
  1813. $test = new stdClass;
  1814. $test->one = 'here';
  1815. $string = get_string('yes', null, $test, true);
  1816. $this->assertEquals($string, $yesexpected);
  1817. // Make sure that object properties that can't be converted don't cause
  1818. // errors.
  1819. // Level two: Language processing doesn't currently reach this deep.
  1820. // only immediate scalar properties are worked with.
  1821. $test = new stdClass;
  1822. $test->one = new stdClass;
  1823. $test->one->two = 'here';
  1824. $string = get_string('yes', null, $test, true);
  1825. $this->assertEquals($string, $yesexpected);
  1826. // Make sure that object properties that can't be converted don't cause
  1827. // errors.
  1828. // Level three: It should never ever go this deep, but we're making sure
  1829. // it doesn't cause any probs anyway.
  1830. $test = new stdClass;
  1831. $test->one = new stdClass;
  1832. $test->one->two = new stdClass;
  1833. $test->one->two->three = 'here';
  1834. $string = get_string('yes', null, $test, true);
  1835. $this->assertEquals($string, $yesexpected);
  1836. // Make sure that object properties that can't be converted don't cause
  1837. // errors and check lang_string properties.
  1838. // Level one: This is as deep as current language processing goes
  1839. $test = new stdClass;
  1840. $test->one = new lang_string('yes');
  1841. $string = get_string('yes', null, $test, true);
  1842. $this->assertEquals($string, $yesexpected);
  1843. // Make sure that object properties that can't be converted don't cause
  1844. // errors and check lang_string properties.
  1845. // Level two: Language processing doesn't currently reach this deep.
  1846. // only immediate scalar properties are worked with.
  1847. $test = new stdClass;
  1848. $test->one = new stdClass;
  1849. $test->one->two = new lang_string('yes');
  1850. $string = get_string('yes', null, $test, true);
  1851. $this->assertEquals($string, $yesexpected);
  1852. // Make sure that object properties that can't be converted don't cause
  1853. // errors and check lang_string properties.
  1854. // Level three: It should never ever go this deep, but we're making sure
  1855. // it doesn't cause any probs anyway.
  1856. $test = new stdClass;
  1857. $test->one = new stdClass;
  1858. $test->one->two = new stdClass;
  1859. $test->one->two->three = new lang_string('yes');
  1860. $string = get_string('yes', null, $test, true);
  1861. $this->assertEquals($string, $yesexpected);
  1862. // Make sure that array properties that can't be converted don't cause
  1863. // errors
  1864. $test = array();
  1865. $test['one'] = new stdClass;
  1866. $test['one']->two = 'here';
  1867. $string = get_string('yes', null, $test, true);
  1868. $this->assertEquals($string, $yesexpected);
  1869. // Same thing but as above except using an object... this is allowed :P
  1870. $string = get_string('yes', null, null, true);
  1871. $object = new stdClass;
  1872. $object->$string = 'Yes';
  1873. $this->assertEquals($string, $yesexpected);
  1874. $this->assertEquals($object->$string, $yesexpected);
  1875. // Reset the language
  1876. $COURSE->lang = $originallang;
  1877. }
  1878. /**
  1879. * @expectedException PHPUnit_Framework_Error_Warning
  1880. * @return void
  1881. */
  1882. public function test_get_string_limitation() {
  1883. // This is one of the limitations to the lang_string class. It can't be
  1884. // used as a key
  1885. $array = array(get_string('yes', null, null, true) => 'yes');
  1886. }
  1887. /**
  1888. * Test localised float formatting.
  1889. */
  1890. public function test_format_float() {
  1891. // Special case for null
  1892. $this->assertEquals('', format_float(null));
  1893. // Default 1 decimal place
  1894. $this->assertEquals('5.4', format_float(5.43));
  1895. $this->assertEquals('5.0', format_float(5.001));
  1896. // Custom number of decimal places
  1897. $this->assertEquals('5.43000', format_float(5.43, 5));
  1898. // Option to strip ending zeros after rounding
  1899. $this->assertEquals('5.43', format_float(5.43, 5, true, true));
  1900. $this->assertEquals('5', format_float(5.0001, 3, true, true));
  1901. // Tests with a localised decimal separator.
  1902. $this->define_local_decimal_separator();
  1903. // Localisation on (default)
  1904. $this->assertEquals('5X43000', format_float(5.43, 5));
  1905. $this->assertEquals('5X43', format_float(5.43, 5, true, true));
  1906. // Localisation off
  1907. $this->assertEquals('5.43000', format_float(5.43, 5, false));
  1908. $this->assertEquals('5.43', format_float(5.43, 5, false, true));
  1909. }
  1910. /**
  1911. * Test localised float unformatting.
  1912. */
  1913. public function test_unformat_float() {
  1914. // Tests without the localised decimal separator.
  1915. // Special case for null, empty or white spaces only strings.
  1916. $this->assertEquals(null, unformat_float(null));
  1917. $this->assertEquals(null, unformat_float(''));
  1918. $this->assertEquals(null, unformat_float(' '));
  1919. // Regular use.
  1920. $this->assertEquals(5.4, unformat_float('5.4'));
  1921. $this->assertEquals(5.4, unformat_float('5.4', true));
  1922. // No decimal.
  1923. $this->assertEquals(5.0, unformat_float('5'));
  1924. // Custom number of decimal.
  1925. $this->assertEquals(5.43267, unformat_float('5.43267'));
  1926. // Empty decimal.
  1927. $this->assertEquals(100.0, unformat_float('100.00'));
  1928. // With the thousand separator.
  1929. $this->assertEquals(1000.0, unformat_float('1 000'));
  1930. $this->assertEquals(1000.32, unformat_float('1 000.32'));
  1931. // Negative number.
  1932. $this->assertEquals(-100.0, unformat_float('-100'));
  1933. // Wrong value.
  1934. $this->assertEquals(0.0, unformat_float('Wrong value'));
  1935. // Wrong value in strict mode.
  1936. $this->assertFalse(unformat_float('Wrong value', true));
  1937. // Combining options.
  1938. $this->assertEquals(-1023.862567, unformat_float(' -1 023.862567 '));
  1939. // Bad decimal separator (should crop the decimal).
  1940. $this->assertEquals(50.0, unformat_float('50,57'));
  1941. // Bad decimal separator in strict mode (should return false).
  1942. $this->assertFalse(unformat_float('50,57', true));
  1943. // Tests with a localised decimal separator.
  1944. $this->define_local_decimal_separator();
  1945. // We repeat the tests above but with the current decimal separator.
  1946. // Regular use without and with the localised separator.
  1947. $this->assertEquals (5.4, unformat_float('5.4'));
  1948. $this->assertEquals (5.4, unformat_float('5X4'));
  1949. // Custom number of decimal.
  1950. $this->assertEquals (5.43267, unformat_float('5X43267'));
  1951. // Empty decimal.
  1952. $this->assertEquals (100.0, unformat_float('100X00'));
  1953. // With the thousand separator.
  1954. $this->assertEquals (1000.32, unformat_float('1 000X32'));
  1955. // Bad different separator (should crop the decimal).
  1956. $this->assertEquals (50.0, unformat_float('50Y57'));
  1957. // Bad different separator in strict mode (should return false).
  1958. $this->assertFalse (unformat_float('50Y57', true));
  1959. // Combining options.
  1960. $this->assertEquals (-1023.862567, unformat_float(' -1 023X862567 '));
  1961. // Combining options in strict mode.
  1962. $this->assertEquals (-1023.862567, unformat_float(' -1 023X862567 ', true));
  1963. }
  1964. /**
  1965. * Test deleting of users.
  1966. */
  1967. public function test_delete_user() {
  1968. global $DB, $CFG;
  1969. $this->resetAfterTest();
  1970. $guest = $DB->get_record('user', array('id'=>$CFG->siteguest), '*', MUST_EXIST);
  1971. $admin = $DB->get_record('user', array('id'=>$CFG->siteadmins), '*', MUST_EXIST);
  1972. $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
  1973. $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
  1974. $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
  1975. $result = delete_user($user);
  1976. $this->assertTrue($result);
  1977. $deluser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
  1978. $this->assertEquals(1, $deluser->deleted);
  1979. // in totara we just mark them as deleted
  1980. $this->assertEquals($user->picture, $deluser->picture);
  1981. $this->assertSame($user->idnumber, $deluser->idnumber);
  1982. $this->assertSame($user->username, $deluser->username);
  1983. $this->assertSame($user->email, $deluser->email);
  1984. $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
  1985. // Try invalid params.
  1986. $record = new stdClass();
  1987. $record->grrr = 1;
  1988. try {
  1989. delete_user($record);
  1990. $this->fail('Expecting exception for invalid delete_user() $user parameter');
  1991. } catch (coding_exception $e) {
  1992. $this->assertTrue(true);
  1993. }
  1994. $record->id = 1;
  1995. try {
  1996. delete_user($record);
  1997. $this->fail('Expecting exception for invalid delete_user() $user parameter');
  1998. } catch (coding_exception $e) {
  1999. $this->assertTrue(true);
  2000. }
  2001. $record = new stdClass();
  2002. $record->id = 666;
  2003. $record->username = 'xx';
  2004. $this->assertFalse($DB->record_exists('user', array('id'=>666))); // Any non-existent id is ok.
  2005. $result = delete_user($record);
  2006. $this->assertFalse($result);
  2007. $result = delete_user($guest);
  2008. $this->assertFalse($result);
  2009. $result = delete_user($admin);
  2010. $this->assertFalse($result);
  2011. $this->resetDebugging();
  2012. }
  2013. /**
  2014. * Test function convert_to_array()
  2015. */
  2016. public function test_convert_to_array() {
  2017. // check that normal classes are converted to arrays the same way as (array) would do
  2018. $obj = new stdClass();
  2019. $obj->prop1 = 'hello';
  2020. $obj->prop2 = array('first', 'second', 13);
  2021. $obj->prop3 = 15;
  2022. $this->assertEquals(convert_to_array($obj), (array)$obj);
  2023. // check that context object (with iterator) is converted to array properly
  2024. $obj = get_system_context();
  2025. $ar = array(
  2026. 'id' => $obj->id,
  2027. 'contextlevel' => $obj->contextlevel,
  2028. 'instanceid' => $obj->instanceid,
  2029. 'path' => $obj->path,
  2030. 'depth' => $obj->depth
  2031. );
  2032. $this->assertEquals(convert_to_array($obj), $ar);
  2033. }
  2034. /**
  2035. * Test the function date_format_string().
  2036. */
  2037. function test_date_format_string() {
  2038. global $CFG;
  2039. if ($CFG->ostype == 'WINDOWS' && get_string('localewincharset', 'langconfig') == '') {
  2040. $this->markTestSkipped('This test requires \'localewincharset\' to be configured in \'langconfig\' file on Windows environment');
  2041. }
  2042. // Forcing locale and timezone.
  2043. $oldlocale = setlocale(LC_TIME, '0');
  2044. if ($CFG->ostype == 'WINDOWS') {
  2045. setlocale(LC_TIME, 'English_Australia.1252');
  2046. } else {
  2047. setlocale(LC_TIME, 'en_AU.UTF-8');
  2048. }
  2049. $systemdefaulttimezone = date_default_timezone_get();
  2050. date_default_timezone_set('Australia/Perth');
  2051. $tests = array(
  2052. array(
  2053. 'tz' => 99,
  2054. 'str' => '%A, %d %B %Y, %I:%M %p',
  2055. 'expected' => 'Saturday, 01 January 2011, 06:00 PM'
  2056. ),
  2057. array(
  2058. 'tz' => 0,
  2059. 'str' => '%A, %d %B %Y, %I:%M %p',
  2060. 'expected' => 'Saturday, 01 January 2011, 10:00 AM'
  2061. ),
  2062. array(
  2063. 'tz' => -12,
  2064. 'str' => '%A, %d %B %Y, %I:%M %p',
  2065. 'expected' => 'Saturday, 01 January 2011, 10:00 AM'
  2066. ),
  2067. // Following tests pass on Windows only because en lang pack does
  2068. // not contain localewincharset, in real life lang pack maintainers
  2069. // may use only characters that are present in localewincharset
  2070. // in format strings!
  2071. array(
  2072. 'tz' => 99,
  2073. 'str' => 'Žluťoučký koníček %A',
  2074. 'expected' => 'Žluťoučký koníček Saturday'
  2075. ),
  2076. array(
  2077. 'tz' => 99,
  2078. 'str' => '言語設定言語 %A',
  2079. 'expected' => '言語設定言語 Saturday'
  2080. ),
  2081. array(
  2082. 'tz' => 99,
  2083. 'str' => '简体中文简体 %A',
  2084. 'expected' => '简体中文简体 Saturday'
  2085. ),
  2086. );
  2087. // Note: date_format_string() uses the timezone only to differenciate
  2088. // the server time from the UTC time. It does not modify the timestamp.
  2089. // Hence similar results for timezones <= 13.
  2090. // On different systems case of AM PM changes so compare case insensitive.
  2091. foreach ($tests as $test) {
  2092. $str = date_format_string(1293876000, $test['str'], $test['tz']);
  2093. $this->assertEquals(textlib::strtolower($test['expected']), textlib::strtolower($str));
  2094. }
  2095. // Restore system default values.
  2096. date_default_timezone_set($systemdefaulttimezone);
  2097. setlocale(LC_TIME, $oldlocale);
  2098. }
  2099. public function test_get_config() {
  2100. global $CFG;
  2101. $this->resetAfterTest();
  2102. // Preparation.
  2103. set_config('phpunit_test_get_config_1', 'test 1');
  2104. set_config('phpunit_test_get_config_2', 'test 2', 'mod_forum');
  2105. if (!is_array($CFG->config_php_settings)) {
  2106. $CFG->config_php_settings = array();
  2107. }
  2108. $CFG->config_php_settings['phpunit_test_get_config_3'] = 'test 3';
  2109. if (!is_array($CFG->forced_plugin_settings)) {
  2110. $CFG->forced_plugin_settings = array();
  2111. }
  2112. if (!array_key_exists('mod_forum', $CFG->forced_plugin_settings)) {
  2113. $CFG->forced_plugin_settings['mod_forum'] = array();
  2114. }
  2115. $CFG->forced_plugin_settings['mod_forum']['phpunit_test_get_config_4'] = 'test 4';
  2116. $CFG->phpunit_test_get_config_5 = 'test 5';
  2117. // Testing.
  2118. $this->assertEquals('test 1', get_config('core', 'phpunit_test_get_config_1'));
  2119. $this->assertEquals('test 2', get_config('mod_forum', 'phpunit_test_get_config_2'));
  2120. $this->assertEquals('test 3', get_config('core', 'phpunit_test_get_config_3'));
  2121. $this->assertEquals('test 4', get_config('mod_forum', 'phpunit_test_get_config_4'));
  2122. $this->assertFalse(get_config('core', 'phpunit_test_get_config_5'));
  2123. $this->assertFalse(get_config('core', 'phpunit_test_get_config_x'));
  2124. $this->assertFalse(get_config('mod_forum', 'phpunit_test_get_config_x'));
  2125. // Test config we know to exist.
  2126. $this->assertEquals($CFG->dataroot, get_config('core', 'dataroot'));
  2127. $this->assertEquals($CFG->phpunit_dataroot, get_config('core', 'phpunit_dataroot'));
  2128. $this->assertEquals($CFG->dataroot, get_config('core', 'phpunit_dataroot'));
  2129. $this->assertEquals(get_config('core', 'dataroot'), get_config('core', 'phpunit_dataroot'));
  2130. // Test setting a config var that already exists.
  2131. set_config('phpunit_test_get_config_1', 'test a');
  2132. $this->assertEquals('test a', $CFG->phpunit_test_get_config_1);
  2133. $this->assertEquals('test a', get_config('core', 'phpunit_test_get_config_1'));
  2134. // Test cache invalidation.
  2135. $cache = cache::make('core', 'config');
  2136. $this->assertInternalType('array', $cache->get('core'));
  2137. $this->assertInternalType('array', $cache->get('mod_forum'));
  2138. set_config('phpunit_test_get_config_1', 'test b');
  2139. $this->assertFalse($cache->get('core'));
  2140. set_config('phpunit_test_get_config_4', 'test c', 'mod_forum');
  2141. $this->assertFalse($cache->get('mod_forum'));
  2142. }
  2143. function test_get_max_upload_sizes() {
  2144. // Test with very low limits so we are not affected by php upload limits.
  2145. // Test activity limit smallest.
  2146. $sitebytes = 102400;
  2147. $coursebytes = 51200;
  2148. $modulebytes = 10240;
  2149. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
  2150. $this->assertEquals('Activity upload limit (10KB)', $result['0']);
  2151. $this->assertEquals(2, count($result));
  2152. // Test course limit smallest.
  2153. $sitebytes = 102400;
  2154. $coursebytes = 10240;
  2155. $modulebytes = 51200;
  2156. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
  2157. $this->assertEquals('Course upload limit (10KB)', $result['0']);
  2158. $this->assertEquals(2, count($result));
  2159. // Test site limit smallest.
  2160. $sitebytes = 10240;
  2161. $coursebytes = 102400;
  2162. $modulebytes = 51200;
  2163. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
  2164. $this->assertEquals('Site upload limit (10KB)', $result['0']);
  2165. $this->assertEquals(2, count($result));
  2166. // Test site limit not set.
  2167. $sitebytes = 0;
  2168. $coursebytes = 102400;
  2169. $modulebytes = 51200;
  2170. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
  2171. $this->assertEquals('Activity upload limit (50KB)', $result['0']);
  2172. $this->assertEquals(3, count($result));
  2173. $sitebytes = 0;
  2174. $coursebytes = 51200;
  2175. $modulebytes = 102400;
  2176. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes);
  2177. $this->assertEquals('Course upload limit (50KB)', $result['0']);
  2178. $this->assertEquals(3, count($result));
  2179. // Test custom bytes in range.
  2180. $sitebytes = 102400;
  2181. $coursebytes = 51200;
  2182. $modulebytes = 51200;
  2183. $custombytes = 10240;
  2184. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
  2185. $this->assertEquals(3, count($result));
  2186. // Test custom bytes in range but non-standard.
  2187. $sitebytes = 102400;
  2188. $coursebytes = 51200;
  2189. $modulebytes = 51200;
  2190. $custombytes = 25600;
  2191. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
  2192. $this->assertEquals(4, count($result));
  2193. // Test custom bytes out of range.
  2194. $sitebytes = 102400;
  2195. $coursebytes = 51200;
  2196. $modulebytes = 51200;
  2197. $custombytes = 102400;
  2198. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
  2199. $this->assertEquals(3, count($result));
  2200. // Test custom bytes out of range and non-standard.
  2201. $sitebytes = 102400;
  2202. $coursebytes = 51200;
  2203. $modulebytes = 51200;
  2204. $custombytes = 256000;
  2205. $result = get_max_upload_sizes($sitebytes, $coursebytes, $modulebytes, $custombytes);
  2206. $this->assertEquals(3, count($result));
  2207. // Test site limit only.
  2208. $sitebytes = 51200;
  2209. $result = get_max_upload_sizes($sitebytes);
  2210. $this->assertEquals('Site upload limit (50KB)', $result['0']);
  2211. $this->assertEquals('50KB', $result['51200']);
  2212. $this->assertEquals('10KB', $result['10240']);
  2213. $this->assertCount(3, $result);
  2214. // Test no limit.
  2215. $result = get_max_upload_sizes();
  2216. $this->assertArrayHasKey('0', $result);
  2217. $this->assertArrayHasKey(get_max_upload_file_size(), $result);
  2218. }
  2219. /**
  2220. * Test function password_is_legacy_hash().
  2221. */
  2222. public function test_password_is_legacy_hash() {
  2223. // Well formed md5s should be matched.
  2224. foreach (array('some', 'strings', 'to_check!') as $string) {
  2225. $md5 = md5($string);
  2226. $this->assertTrue(password_is_legacy_hash($md5));
  2227. }
  2228. // Strings that are not md5s should not be matched.
  2229. foreach (array('', AUTH_PASSWORD_NOT_CACHED, 'IPW8WTcsWNgAWcUS1FBVHegzJnw5M2jOmYkmfc8z.xdBOyC4Caeum') as $notmd5) {
  2230. $this->assertFalse(password_is_legacy_hash($notmd5));
  2231. }
  2232. }
  2233. /**
  2234. * Test function validate_internal_user_password().
  2235. */
  2236. public function test_validate_internal_user_password() {
  2237. if (password_compat_not_supported()) {
  2238. // If bcrypt is not properly supported test legacy md5 hashes instead.
  2239. // Can't hardcode these as we don't know the site's password salt.
  2240. $validhashes = array(
  2241. 'pw' => hash_internal_user_password('pw'),
  2242. 'abc' => hash_internal_user_password('abc'),
  2243. 'C0mP1eX_&}<?@*&%` |\"' => hash_internal_user_password('C0mP1eX_&}<?@*&%` |\"'),
  2244. 'ĩńťėŕňăţĩōŋāĹ' => hash_internal_user_password('ĩńťėŕňăţĩōŋāĹ')
  2245. );
  2246. } else {
  2247. // Otherwise test bcrypt hashes.
  2248. $validhashes = array(
  2249. 'pw' => '$2y$10$LOSDi5eaQJhutSRun.OVJ.ZSxQZabCMay7TO1KmzMkDMPvU40zGXK',
  2250. 'abc' => '$2y$10$VWTOhVdsBbWwtdWNDRHSpewjd3aXBQlBQf5rBY/hVhw8hciarFhXa',
  2251. 'C0mP1eX_&}<?@*&%` |\"' => '$2y$10$3PJf.q.9ywNJlsInPbqc8.IFeSsvXrGvQLKRFBIhVu1h1I3vpIry6',
  2252. 'ĩńťėŕňăţĩōŋāĹ' => '$2y$10$3A2Y8WpfRAnP3czJiSv6N.6Xp0T8hW3QZz2hUCYhzyWr1kGP1yUve'
  2253. );
  2254. }
  2255. foreach ($validhashes as $password => $hash) {
  2256. $user = new stdClass();
  2257. $user->auth = 'manual';
  2258. $user->password = $hash;
  2259. // The correct password should be validated.
  2260. $this->assertTrue(validate_internal_user_password($user, $password));
  2261. // An incorrect password should not be validated.
  2262. $this->assertFalse(validate_internal_user_password($user, 'badpw'));
  2263. }
  2264. }
  2265. /**
  2266. * Test function hash_internal_user_password().
  2267. */
  2268. public function test_hash_internal_user_password() {
  2269. $passwords = array('pw', 'abc123', 'C0mP1eX_&}<?@*&%` |\"', 'ĩńťėŕňăţĩōŋāĹ');
  2270. // Check that some passwords that we convert to hashes can
  2271. // be validated.
  2272. foreach ($passwords as $password) {
  2273. $hash = hash_internal_user_password($password);
  2274. $fasthash = hash_internal_user_password($password, true);
  2275. $user = new stdClass();
  2276. $user->auth = 'manual';
  2277. $user->password = $hash;
  2278. $this->assertTrue(validate_internal_user_password($user, $password));
  2279. if (password_compat_not_supported()) {
  2280. // If bcrypt is not properly supported make sure the passwords are in md5 format.
  2281. $this->assertTrue(password_is_legacy_hash($hash));
  2282. } else {
  2283. // Otherwise they should not be in md5 format.
  2284. $this->assertFalse(password_is_legacy_hash($hash));
  2285. // Check that cost factor in hash is correctly set.
  2286. $this->assertRegExp('/\$10\$/', $hash);
  2287. $this->assertRegExp('/\$04\$/', $fasthash);
  2288. }
  2289. }
  2290. }
  2291. /**
  2292. * Test function update_internal_user_password().
  2293. */
  2294. public function test_update_internal_user_password() {
  2295. global $DB;
  2296. $this->resetAfterTest();
  2297. $passwords = array('password', '1234', 'changeme', '****');
  2298. foreach ($passwords as $password) {
  2299. $user = $this->getDataGenerator()->create_user(array('auth'=>'manual'));
  2300. update_internal_user_password($user, $password);
  2301. // The user object should have been updated.
  2302. $this->assertTrue(validate_internal_user_password($user, $password));
  2303. // The database field for the user should also have been updated to the
  2304. // same value.
  2305. $this->assertEquals($user->password, $DB->get_field('user', 'password', array('id' => $user->id)));
  2306. }
  2307. $user = $this->getDataGenerator()->create_user(array('auth'=>'manual'));
  2308. // Manually set the user's password to the md5 of the string 'password'.
  2309. $DB->set_field('user', 'password', '5f4dcc3b5aa765d61d8327deb882cf99', array('id' => $user->id));
  2310. // Update the password.
  2311. update_internal_user_password($user, 'password');
  2312. if (password_compat_not_supported()) {
  2313. // If bcrypt not properly supported the password should remain as an md5 hash.
  2314. $expected_hash = hash_internal_user_password('password', true);
  2315. $this->assertEquals($user->password, $expected_hash);
  2316. $this->assertTrue(password_is_legacy_hash($user->password));
  2317. } else {
  2318. // Otherwise password should have been updated to a bcrypt hash.
  2319. $this->assertFalse(password_is_legacy_hash($user->password));
  2320. }
  2321. }
  2322. public function test_email_to_user() {
  2323. $this->resetAfterTest();
  2324. $user1 = $this->getDataGenerator()->create_user();
  2325. $user2 = $this->getDataGenerator()->create_user();
  2326. $subject = 'subject';
  2327. $messagetext = 'message text';
  2328. $subject2 = 'subject 2';
  2329. $messagetext2 = 'message text 2';
  2330. unset_config('noemailever');
  2331. $sink = $this->redirectEmails();
  2332. email_to_user($user1, $user2, $subject, $messagetext);
  2333. email_to_user($user2, $user1, $subject2, $messagetext2);
  2334. $this->assertSame(2, $sink->count());
  2335. $result = $sink->get_messages();
  2336. $this->assertCount(2, $result);
  2337. $sink->close();
  2338. $this->assertSame($subject, $result[0]->subject);
  2339. $this->assertSame($messagetext, trim($result[0]->body));
  2340. $this->assertSame($user1->email, $result[0]->to);
  2341. $this->assertSame($user2->email, $result[0]->from);
  2342. $this->assertSame($subject2, $result[1]->subject);
  2343. $this->assertSame($messagetext2, trim($result[1]->body));
  2344. $this->assertSame($user2->email, $result[1]->to);
  2345. $this->assertSame($user1->email, $result[1]->from);
  2346. }
  2347. }