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