Merge branch 'MDL-37854_master' of https://github.com/markn86/moodle
[moodle.git] / lib / tests / moodlelib_test.php
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/>.
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  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
30 require_once($CFG->libdir . '/moodlelib.php');
33 class moodlelib_testcase extends advanced_testcase {
35     public static $includecoverage = array('lib/moodlelib.php');
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)'),
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)'),
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',
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'),
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     );
88     function test_cleanremoteaddr() {
89         //IPv4
90         $this->assertEquals(cleanremoteaddr('1023.121.234.1'), null);
91         $this->assertEquals(cleanremoteaddr('123.121.234.01 '), '123.121.234.1');
93         //IPv6
94         $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:0:0:0'), null);
95         $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:0:abh'), null);
96         $this->assertEquals(cleanremoteaddr('0:0:0:::0:0:1'), null);
97         $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:0:0', true), '::');
98         $this->assertEquals(cleanremoteaddr('0:0:0:0:0:0:1:1', true), '::1:1');
99         $this->assertEquals(cleanremoteaddr('abcd:00ef:0:0:0:0:0:0', true), 'abcd:ef::');
100         $this->assertEquals(cleanremoteaddr('1:0:0:0:0:0:0:1', true), '1::1');
101         $this->assertEquals(cleanremoteaddr('::10:1', false), '0:0:0:0:0:0:10:1');
102         $this->assertEquals(cleanremoteaddr('01:1::', false), '1:1:0:0:0:0:0:0');
103         $this->assertEquals(cleanremoteaddr('10::10', false), '10:0:0:0:0:0:0:10');
104         $this->assertEquals(cleanremoteaddr('::ffff:192.168.1.1', true), '::ffff:c0a8:11');
105     }
107     function test_address_in_subnet() {
108         /// 1: xxx.xxx.xxx.xxx/nn or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/nnn          (number of bits in net mask)
109         $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.1/32'));
110         $this->assertFalse(address_in_subnet('123.121.23.1', '123.121.23.0/32'));
111         $this->assertTrue(address_in_subnet('10.10.10.100',  '123.121.23.45/0'));
112         $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/24'));
113         $this->assertFalse(address_in_subnet('123.121.34.1', '123.121.234.0/24'));
114         $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/30'));
115         $this->assertFalse(address_in_subnet('123.121.23.8', '123.121.23.0/30'));
116         $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128'));
117         $this->assertFalse(address_in_subnet('bab:baba::baba', 'bab:baba::cece/128'));
118         $this->assertTrue(address_in_subnet('baba:baba::baba', 'cece:cece::cece/0'));
119         $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128'));
120         $this->assertTrue(address_in_subnet('baba:baba::00ba', 'baba:baba::/120'));
121         $this->assertFalse(address_in_subnet('baba:baba::aba', 'baba:baba::/120'));
122         $this->assertTrue(address_in_subnet('baba::baba:00ba', 'baba::baba:0/112'));
123         $this->assertFalse(address_in_subnet('baba::aba:00ba', 'baba::baba:0/112'));
124         $this->assertFalse(address_in_subnet('aba::baba:0000', 'baba::baba:0/112'));
126         // fixed input
127         $this->assertTrue(address_in_subnet('123.121.23.1   ', ' 123.121.23.0 / 24'));
128         $this->assertTrue(address_in_subnet('::ffff:10.1.1.1', ' 0:0:0:000:0:ffff:a1:10 / 126'));
130         // incorrect input
131         $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/-2'));
132         $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/64'));
133         $this->assertFalse(address_in_subnet('123.121.234.x', '123.121.234.1/24'));
134         $this->assertFalse(address_in_subnet('123.121.234.0', '123.121.234.xx/24'));
135         $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/xx0'));
136         $this->assertFalse(address_in_subnet('::1', '::aa:0/xx0'));
137         $this->assertFalse(address_in_subnet('::1', '::aa:0/-5'));
138         $this->assertFalse(address_in_subnet('::1', '::aa:0/130'));
139         $this->assertFalse(address_in_subnet('x:1', '::aa:0/130'));
140         $this->assertFalse(address_in_subnet('::1', '::ax:0/130'));
143         /// 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)
144         $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12-14'));
145         $this->assertTrue(address_in_subnet('123.121.234.13', '123.121.234.12-14'));
146         $this->assertTrue(address_in_subnet('123.121.234.14', '123.121.234.12-14'));
147         $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.12-14'));
148         $this->assertFalse(address_in_subnet('123.121.234.20', '123.121.234.12-14'));
149         $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.234.12-14'));
150         $this->assertFalse(address_in_subnet('123.12.234.12', '123.121.234.12-14'));
151         $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba-babe'));
152         $this->assertTrue(address_in_subnet('baba:baba::babc', 'baba:baba::baba-babe'));
153         $this->assertTrue(address_in_subnet('baba:baba::babe', 'baba:baba::baba-babe'));
154         $this->assertFalse(address_in_subnet('bab:baba::bab0', 'bab:baba::baba-babe'));
155         $this->assertFalse(address_in_subnet('bab:baba::babf', 'bab:baba::baba-babe'));
156         $this->assertFalse(address_in_subnet('bab:baba::bfbe', 'bab:baba::baba-babe'));
157         $this->assertFalse(address_in_subnet('bfb:baba::babe', 'bab:baba::baba-babe'));
159         // fixed input
160         $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12 - 14 '));
161         $this->assertTrue(address_in_subnet('bab:baba::babe', 'bab:baba::baba - babe  '));
163         // incorrect input
164         $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-234.14'));
165         $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-256'));
166         $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12--256'));
169         /// 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx.                  (incomplete address, a bit non-technical ;-)
170         $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12'));
171         $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.23.13'));
172         $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.'));
173         $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234'));
174         $this->assertTrue(address_in_subnet('123.121.234.12', '123.121'));
175         $this->assertTrue(address_in_subnet('123.121.234.12', '123'));
176         $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234.'));
177         $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234'));
178         $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba::bab'));
179         $this->assertFalse(address_in_subnet('baba:baba::ba', 'baba:baba::bc'));
180         $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba'));
181         $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:'));
182         $this->assertFalse(address_in_subnet('bab:baba::bab', 'baba:'));
185         /// multiple subnets
186         $this->assertTrue(address_in_subnet('123.121.234.12', '::1/64, 124., 123.121.234.10-30'));
187         $this->assertTrue(address_in_subnet('124.121.234.12', '::1/64, 124., 123.121.234.10-30'));
188         $this->assertTrue(address_in_subnet('::2',            '::1/64, 124., 123.121.234.10-30'));
189         $this->assertFalse(address_in_subnet('12.121.234.12', '::1/64, 124., 123.121.234.10-30'));
192         /// other incorrect input
193         $this->assertFalse(address_in_subnet('123.123.123.123', ''));
194     }
196     /**
197      * Modifies $_SERVER['HTTP_USER_AGENT'] manually to check if check_browser_version
198      * works as expected.
199      */
200     function test_check_browser_version()
201     {
202         global $CFG;
204         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['412']['Mac OS X'];
205         $this->assertTrue(check_browser_version('Safari'));
206         $this->assertTrue(check_browser_version('WebKit'));
207         $this->assertTrue(check_browser_version('Safari', '312'));
208         $this->assertFalse(check_browser_version('Safari', '500'));
209         $this->assertFalse(check_browser_version('Chrome'));
210         $this->assertFalse(check_browser_version('Safari iOS'));
212         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari iOS']['528']['iPhone'];
213         $this->assertTrue(check_browser_version('Safari iOS'));
214         $this->assertTrue(check_browser_version('WebKit'));
215         $this->assertTrue(check_browser_version('Safari iOS', '527'));
216         $this->assertFalse(check_browser_version('Safari iOS', 590));
217         $this->assertFalse(check_browser_version('Safari', '312'));
218         $this->assertFalse(check_browser_version('Safari', '500'));
219         $this->assertFalse(check_browser_version('Chrome'));
221         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['WebKit Android']['530']['Nexus'];
222         $this->assertTrue(check_browser_version('WebKit'));
223         $this->assertTrue(check_browser_version('WebKit Android', '527'));
224         $this->assertFalse(check_browser_version('WebKit Android', 590));
225         $this->assertFalse(check_browser_version('Safari'));
226         $this->assertFalse(check_browser_version('Chrome'));
228         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Chrome']['8']['Mac OS X'];
229         $this->assertTrue(check_browser_version('Chrome'));
230         $this->assertTrue(check_browser_version('WebKit'));
231         $this->assertTrue(check_browser_version('Chrome', 8));
232         $this->assertFalse(check_browser_version('Chrome', 10));
233         $this->assertFalse(check_browser_version('Safari', '1'));
235         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
236         $this->assertTrue(check_browser_version('Opera'));
237         $this->assertTrue(check_browser_version('Opera', '8.0'));
238         $this->assertFalse(check_browser_version('Opera', '10.0'));
240         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['6.0']['Windows XP SP2'];
241         $this->assertTrue(check_browser_version('MSIE'));
242         $this->assertTrue(check_browser_version('MSIE', '5.0'));
243         $this->assertFalse(check_browser_version('MSIE', '7.0'));
245         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['5.0']['Windows 98'];
246         $this->assertFalse(check_browser_version('MSIE'));
247         $this->assertTrue(check_browser_version('MSIE', 0));
248         $this->assertTrue(check_browser_version('MSIE', '5.0'));
249         $this->assertFalse(check_browser_version('MSIE', '7.0'));
251         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0']['Windows 7'];
252         $this->assertTrue(check_browser_version('MSIE'));
253         $this->assertTrue(check_browser_version('MSIE', 0));
254         $this->assertTrue(check_browser_version('MSIE', '5.0'));
255         $this->assertTrue(check_browser_version('MSIE', '9.0'));
256         $this->assertFalse(check_browser_version('MSIE', '10'));
258         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0i']['Windows 7'];
259         $this->assertTrue(check_browser_version('MSIE'));
260         $this->assertTrue(check_browser_version('MSIE', 0));
261         $this->assertTrue(check_browser_version('MSIE', '5.0'));
262         $this->assertTrue(check_browser_version('MSIE', '9.0'));
263         $this->assertFalse(check_browser_version('MSIE', '10'));
265         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0']['Windows 8'];
266         $this->assertTrue(check_browser_version('MSIE'));
267         $this->assertTrue(check_browser_version('MSIE', 0));
268         $this->assertTrue(check_browser_version('MSIE', '5.0'));
269         $this->assertTrue(check_browser_version('MSIE', '9.0'));
270         $this->assertTrue(check_browser_version('MSIE', '10'));
271         $this->assertFalse(check_browser_version('MSIE', '11'));
273         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0i']['Windows 8'];
274         $this->assertTrue(check_browser_version('MSIE'));
275         $this->assertTrue(check_browser_version('MSIE', 0));
276         $this->assertTrue(check_browser_version('MSIE', '5.0'));
277         $this->assertTrue(check_browser_version('MSIE', '9.0'));
278         $this->assertTrue(check_browser_version('MSIE', '10'));
279         $this->assertFalse(check_browser_version('MSIE', '11'));
281         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
282         $this->assertTrue(check_browser_version('Firefox'));
283         $this->assertTrue(check_browser_version('Firefox', '1.5'));
284         $this->assertFalse(check_browser_version('Firefox', '3.0'));
285         $this->assertTrue(check_browser_version('Gecko', '2'));
286         $this->assertTrue(check_browser_version('Gecko', 20030516));
287         $this->assertTrue(check_browser_version('Gecko', 20051106));
288         $this->assertTrue(check_browser_version('Gecko', 2006010100));
290         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['1.0.6']['Windows XP'];
291         $this->assertTrue(check_browser_version('Firefox'));
292         $this->assertTrue(check_browser_version('Gecko', '1'));
293         $this->assertFalse(check_browser_version('Gecko', 20030516));
294         $this->assertFalse(check_browser_version('Gecko', 20051106));
295         $this->assertFalse(check_browser_version('Gecko', 2006010100));
296         $this->assertFalse(check_browser_version('Firefox', '1.5'));
297         $this->assertFalse(check_browser_version('Firefox', '3.0'));
298         $this->assertFalse(check_browser_version('Gecko', '2'));
300         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
301         $this->assertTrue(check_browser_version('Firefox'));
302         $this->assertTrue(check_browser_version('Firefox', '1.5'));
303         $this->assertTrue(check_browser_version('Gecko', '1'));
304         $this->assertTrue(check_browser_version('Gecko', '2'));
305         $this->assertTrue(check_browser_version('Gecko', 20030516));
306         $this->assertTrue(check_browser_version('Gecko', 20051106));
307         $this->assertTrue(check_browser_version('Gecko', 2006010100));
308         $this->assertFalse(check_browser_version('Firefox', '3.0'));
310         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
311         $this->assertTrue(check_browser_version('Firefox'));
312         $this->assertTrue(check_browser_version('Firefox', '1.5'));
313         $this->assertTrue(check_browser_version('Firefox', '3.0'));
314         $this->assertTrue(check_browser_version('Gecko', '2'));
315         $this->assertTrue(check_browser_version('Gecko', '3.6'));
316         $this->assertTrue(check_browser_version('Gecko', 20030516));
317         $this->assertTrue(check_browser_version('Gecko', 20051106));
318         $this->assertTrue(check_browser_version('Gecko', 2006010100));
319         $this->assertFalse(check_browser_version('Firefox', '4'));
320         $this->assertFalse(check_browser_version('Firefox', '10'));
322         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
323         $this->assertTrue(check_browser_version('Firefox'));
324         $this->assertTrue(check_browser_version('Firefox', '1.5'));
325         $this->assertTrue(check_browser_version('Firefox', '3.0'));
326         $this->assertTrue(check_browser_version('Gecko', '2'));
327         $this->assertTrue(check_browser_version('Gecko', '3.6'));
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', '4'));
332         $this->assertFalse(check_browser_version('Firefox', '10'));
333         $this->assertFalse(check_browser_version('Firefox', '18'));
334         $this->assertFalse(check_browser_version('Gecko', '4'));
336         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['15.0a2']['Windows'];
337         $this->assertTrue(check_browser_version('Firefox'));
338         $this->assertTrue(check_browser_version('Firefox', '1.5'));
339         $this->assertTrue(check_browser_version('Firefox', '3.0'));
340         $this->assertTrue(check_browser_version('Gecko', '2'));
341         $this->assertTrue(check_browser_version('Gecko', '3.6'));
342         $this->assertTrue(check_browser_version('Gecko', '15.0'));
343         $this->assertTrue(check_browser_version('Gecko', 20030516));
344         $this->assertTrue(check_browser_version('Gecko', 20051106));
345         $this->assertTrue(check_browser_version('Gecko', 2006010100));
346         $this->assertTrue(check_browser_version('Firefox', '4'));
347         $this->assertTrue(check_browser_version('Firefox', '10'));
348         $this->assertTrue(check_browser_version('Firefox', '15'));
349         $this->assertFalse(check_browser_version('Firefox', '18'));
350         $this->assertFalse(check_browser_version('Gecko', '18'));
352         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['18.0']['Mac OS X'];
353         $this->assertTrue(check_browser_version('Firefox'));
354         $this->assertTrue(check_browser_version('Firefox', '1.5'));
355         $this->assertTrue(check_browser_version('Firefox', '3.0'));
356         $this->assertTrue(check_browser_version('Gecko', '2'));
357         $this->assertTrue(check_browser_version('Gecko', '3.6'));
358         $this->assertTrue(check_browser_version('Gecko', '15.0'));
359         $this->assertTrue(check_browser_version('Gecko', '18.0'));
360         $this->assertTrue(check_browser_version('Gecko', 20030516));
361         $this->assertTrue(check_browser_version('Gecko', 20051106));
362         $this->assertTrue(check_browser_version('Gecko', 2006010100));
363         $this->assertTrue(check_browser_version('Firefox', '4'));
364         $this->assertTrue(check_browser_version('Firefox', '10'));
365         $this->assertTrue(check_browser_version('Firefox', '15'));
366         $this->assertTrue(check_browser_version('Firefox', '18'));
367         $this->assertFalse(check_browser_version('Firefox', '19'));
368         $this->assertFalse(check_browser_version('Gecko', '19'));
370         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.0']['Windows'];
372         $this->assertTrue(check_browser_version('Gecko', '2'));
373         $this->assertTrue(check_browser_version('Gecko', 20030516));
374         $this->assertTrue(check_browser_version('Gecko', 20051106));
375         $this->assertTrue(check_browser_version('Gecko', 2006010100));
376         $this->assertFalse(check_browser_version('Gecko', '3.6'));
377         $this->assertFalse(check_browser_version('Gecko', '4.0'));
378         $this->assertFalse(check_browser_version('Firefox'));
380         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.1']['Linux'];
381         $this->assertTrue(check_browser_version('Gecko', '2'));
382         $this->assertTrue(check_browser_version('Gecko', '3.6'));
383         $this->assertTrue(check_browser_version('Gecko', '4.0'));
384         $this->assertTrue(check_browser_version('Gecko', 20030516));
385         $this->assertTrue(check_browser_version('Gecko', 20051106));
386         $this->assertTrue(check_browser_version('Gecko', 2006010100));
387         $this->assertTrue(check_browser_version('Firefox'));
388         $this->assertTrue(check_browser_version('Firefox', 4.0));
389         $this->assertFalse(check_browser_version('Firefox', 5));
390         $this->assertFalse(check_browser_version('Gecko', '18.0'));
392     }
394     function test_get_browser_version_classes() {
395         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari']['412']['Mac OS X'];
396         $this->assertEquals(array('safari'), get_browser_version_classes());
398         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Chrome']['8']['Mac OS X'];
399         $this->assertEquals(array('safari'), get_browser_version_classes());
401         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Safari iOS']['528']['iPhone'];
402         $this->assertEquals(array('safari', 'ios'), get_browser_version_classes());
404         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['WebKit Android']['530']['Nexus'];
405         $this->assertEquals(array('safari', 'android'), get_browser_version_classes());
407         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Chrome']['8']['Mac OS X'];
408         $this->assertEquals(array('safari'), get_browser_version_classes());
410         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Opera']['9.0']['Windows XP'];
411         $this->assertEquals(array('opera'), get_browser_version_classes());
413         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['6.0']['Windows XP SP2'];
414         $this->assertEquals(array('ie', 'ie6'), get_browser_version_classes());
416         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['7.0']['Windows XP SP2'];
417         $this->assertEquals(array('ie', 'ie7'), get_browser_version_classes());
419         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['8.0']['Windows Vista'];
420         $this->assertEquals(array('ie', 'ie8'), get_browser_version_classes());
422         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0']['Windows 7'];
423         $this->assertEquals(array('ie', 'ie9'), get_browser_version_classes());
425         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['9.0i']['Windows 7'];
426         $this->assertEquals(array('ie', 'ie9'), get_browser_version_classes());
428         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0']['Windows 8'];
429         $this->assertEquals(array('ie', 'ie10'), get_browser_version_classes());
431         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['MSIE']['10.0i']['Windows 8'];
432         $this->assertEquals(array('ie', 'ie10'), get_browser_version_classes());
434         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
435         $this->assertEquals(array('gecko', 'gecko18'), get_browser_version_classes());
437         $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.0.6']['SUSE'];
438         $this->assertEquals(array('gecko', 'gecko19'), get_browser_version_classes());
439     }
441     function test_get_device_type() {
442         // IE8 (common pattern ~1.5% of IE7/8 users have embedded IE6 agent))
443         $_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)';
444         $this->assertEquals('default', get_device_type());
445         // Genuine IE6
446         $_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)';
447         $this->assertEquals('legacy', get_device_type());
448     }
450     function test_fix_utf8() {
451         // make sure valid data including other types is not changed
452         $this->assertSame(null, fix_utf8(null));
453         $this->assertSame(1, fix_utf8(1));
454         $this->assertSame(1.1, fix_utf8(1.1));
455         $this->assertSame(true, fix_utf8(true));
456         $this->assertSame('', fix_utf8(''));
457         $this->assertSame('abc', fix_utf8('abc'));
458         $array = array('do', 're', 'mi');
459         $this->assertSame($array, fix_utf8($array));
460         $object = new stdClass();
461         $object->a = 'aa';
462         $object->b = 'bb';
463         $this->assertEquals($object, fix_utf8($object));
465         // valid utf8 string
466         $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"));
468         // invalid utf8 string
469         $this->assertSame('aš', fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
470     }
472     function test_optional_param() {
473         global $CFG;
475         $_POST['username'] = 'post_user';
476         $_GET['username'] = 'get_user';
477         $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), $_POST['username']);
479         unset($_POST['username']);
480         $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), $_GET['username']);
482         unset($_GET['username']);
483         $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), 'default_user');
485         // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
486         $_POST['username'] = 'post_user';
487         try {
488             optional_param('username', 'default_user', null);
489             $this->fail('coding_exception expected');
490         } catch (coding_exception $ex) {
491             $this->assertTrue(true);
492         }
493         try {
494             @optional_param('username', 'default_user');
495             $this->fail('coding_exception expected');
496         } catch (coding_exception $ex) {
497             $this->assertTrue(true);
498         }
499         try {
500             @optional_param('username');
501             $this->fail('coding_exception expected');
502         } catch (coding_exception $ex) {
503             $this->assertTrue(true);
504         }
505         try {
506             optional_param('', 'default_user', PARAM_RAW);
507             $this->fail('coding_exception expected');
508         } catch (coding_exception $ex) {
509             $this->assertTrue(true);
510         }
512         // make sure warning is displayed if array submitted - TODO: throw exception in Moodle 2.3
513         $_POST['username'] = array('a'=>'a');
514         $this->assertSame(optional_param('username', 'default_user', PARAM_RAW), $_POST['username']);
515         $this->assertDebuggingCalled();
516     }
518     function test_optional_param_array() {
519         global $CFG;
521         $_POST['username'] = array('a'=>'post_user');
522         $_GET['username'] = array('a'=>'get_user');
523         $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), $_POST['username']);
525         unset($_POST['username']);
526         $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), $_GET['username']);
528         unset($_GET['username']);
529         $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), array('a'=>'default_user'));
531         // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
532         $_POST['username'] = array('a'=>'post_user');
533         try {
534             optional_param_array('username', array('a'=>'default_user'), null);
535             $this->fail('coding_exception expected');
536         } catch (coding_exception $ex) {
537             $this->assertTrue(true);
538         }
539         try {
540             @optional_param_array('username', array('a'=>'default_user'));
541             $this->fail('coding_exception expected');
542         } catch (coding_exception $ex) {
543             $this->assertTrue(true);
544         }
545         try {
546             @optional_param_array('username');
547             $this->fail('coding_exception expected');
548         } catch (coding_exception $ex) {
549             $this->assertTrue(true);
550         }
551         try {
552             optional_param_array('', array('a'=>'default_user'), PARAM_RAW);
553             $this->fail('coding_exception expected');
554         } catch (coding_exception $ex) {
555             $this->assertTrue(true);
556         }
558         // do not allow nested arrays
559         try {
560             $_POST['username'] = array('a'=>array('b'=>'post_user'));
561             optional_param_array('username', array('a'=>'default_user'), PARAM_RAW);
562             $this->fail('coding_exception expected');
563         } catch (coding_exception $ex) {
564             $this->assertTrue(true);
565         }
567         // do not allow non-arrays
568         $_POST['username'] = 'post_user';
569         $this->assertSame(optional_param_array('username', array('a'=>'default_user'), PARAM_RAW), array('a'=>'default_user'));
570         $this->assertDebuggingCalled();
572         // make sure array keys are sanitised
573         $_POST['username'] = array('abc123_;-/*-+ '=>'arrggh', 'a1_-'=>'post_user');
574         $this->assertSame(optional_param_array('username', array(), PARAM_RAW), array('a1_-'=>'post_user'));
575         $this->assertDebuggingCalled();
576     }
578     function test_required_param() {
579         global $CFG;
581         $_POST['username'] = 'post_user';
582         $_GET['username'] = 'get_user';
583         $this->assertSame(required_param('username', PARAM_RAW), 'post_user');
585         unset($_POST['username']);
586         $this->assertSame(required_param('username', PARAM_RAW), 'get_user');
588         unset($_GET['username']);
589         try {
590             $this->assertSame(required_param('username', PARAM_RAW), 'default_user');
591             $this->fail('moodle_exception expected');
592         } catch (moodle_exception $ex) {
593             $this->assertTrue(true);
594         }
596         // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
597         $_POST['username'] = 'post_user';
598         try {
599             @required_param('username');
600             $this->fail('coding_exception expected');
601         } catch (coding_exception $ex) {
602             $this->assertTrue(true);
603         }
604         try {
605             required_param('username', '');
606             $this->fail('coding_exception expected');
607         } catch (coding_exception $ex) {
608             $this->assertTrue(true);
609         }
610         try {
611             required_param('', PARAM_RAW);
612             $this->fail('coding_exception expected');
613         } catch (coding_exception $ex) {
614             $this->assertTrue(true);
615         }
617         // make sure warning is displayed if array submitted - TODO: throw exception in Moodle 2.3
618         $_POST['username'] = array('a'=>'a');
619         $this->assertSame(required_param('username', PARAM_RAW), $_POST['username']);
620         $this->assertDebuggingCalled();
621     }
623     function test_required_param_array() {
624         global $CFG;
626         $_POST['username'] = array('a'=>'post_user');
627         $_GET['username'] = array('a'=>'get_user');
628         $this->assertSame(required_param_array('username', PARAM_RAW), $_POST['username']);
630         unset($_POST['username']);
631         $this->assertSame(required_param_array('username', PARAM_RAW), $_GET['username']);
633         // make sure exception is triggered when some params are missing, hide error notices here - new in 2.2
634         $_POST['username'] = array('a'=>'post_user');
635         try {
636             required_param_array('username', null);
637             $this->fail('coding_exception expected');
638         } catch (coding_exception $ex) {
639             $this->assertTrue(true);
640         }
641         try {
642             @required_param_array('username');
643             $this->fail('coding_exception expected');
644         } catch (coding_exception $ex) {
645             $this->assertTrue(true);
646         }
647         try {
648             required_param_array('', PARAM_RAW);
649             $this->fail('coding_exception expected');
650         } catch (coding_exception $ex) {
651             $this->assertTrue(true);
652         }
654         // do not allow nested arrays
655         try {
656             $_POST['username'] = array('a'=>array('b'=>'post_user'));
657             required_param_array('username', PARAM_RAW);
658             $this->fail('coding_exception expected');
659         } catch (coding_exception $ex) {
660             $this->assertTrue(true);
661         }
663         // do not allow non-arrays
664         try {
665             $_POST['username'] = 'post_user';
666             required_param_array('username', PARAM_RAW);
667             $this->fail('moodle_exception expected');
668         } catch (moodle_exception $ex) {
669             $this->assertTrue(true);
670         }
672         // make sure array keys are sanitised
673         $_POST['username'] = array('abc123_;-/*-+ '=>'arrggh', 'a1_-'=>'post_user');
674         $this->assertSame(required_param_array('username', PARAM_RAW), array('a1_-'=>'post_user'));
675         $this->assertDebuggingCalled();
676     }
678     function test_clean_param() {
679         // forbid objects and arrays
680         try {
681             clean_param(array('x', 'y'), PARAM_RAW);
682             $this->fail('coding_exception expected');
683         } catch (coding_exception $ex) {
684             $this->assertTrue(true);
685         }
686         try {
687             $param = new stdClass();
688             $param->id = 1;
689             clean_param($param, PARAM_RAW);
690             $this->fail('coding_exception expected');
691         } catch (coding_exception $ex) {
692             $this->assertTrue(true);
693         }
695         // require correct type
696         try {
697             clean_param('x', 'xxxxxx');
698             $this->fail('moodle_exception expected');
699         } catch (moodle_exception $ex) {
700             $this->assertTrue(true);
701         }
702         try {
703             @clean_param('x');
704             $this->fail('moodle_exception expected');
705         } catch (moodle_exception $ex) {
706             $this->assertTrue(true);
707         }
709     }
711     function test_clean_param_array() {
712         $this->assertSame(clean_param_array(null, PARAM_RAW), array());
713         $this->assertSame(clean_param_array(array('a', 'b'), PARAM_RAW), array('a', 'b'));
714         $this->assertSame(clean_param_array(array('a', array('b')), PARAM_RAW, true), array('a', array('b')));
716         // require correct type
717         try {
718             clean_param_array(array('x'), 'xxxxxx');
719             $this->fail('moodle_exception expected');
720         } catch (moodle_exception $ex) {
721             $this->assertTrue(true);
722         }
723         try {
724             @clean_param_array(array('x'));
725             $this->fail('moodle_exception expected');
726         } catch (moodle_exception $ex) {
727             $this->assertTrue(true);
728         }
730         try {
731             clean_param_array(array('x', array('y')), PARAM_RAW);
732             $this->fail('coding_exception expected');
733         } catch (coding_exception $ex) {
734             $this->assertTrue(true);
735         }
737         // test recursive
738     }
740     function test_clean_param_raw() {
741         $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_RAW),
742             '#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)');
743     }
745     function test_clean_param_trim() {
746         $this->assertEquals(clean_param("   Frog toad   \r\n  ", PARAM_RAW_TRIMMED), 'Frog toad');
747     }
749     function test_clean_param_clean() {
750         // PARAM_CLEAN is an ugly hack, do not use in new code (skodak)
751         // instead use more specific type, or submit sothing that can be verified properly
752         $this->assertEquals(clean_param('xx<script>', PARAM_CLEAN), 'xx');
753     }
755     function test_clean_param_alpha() {
756         $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHA),
757             'DSFMOSDJ');
758     }
760     function test_clean_param_alphanum() {
761         $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHANUM),
762             '978942897DSFMOSDJ');
763     }
765     function test_clean_param_alphaext() {
766         $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_ALPHAEXT),
767             'DSFMOSDJ');
768     }
770     function test_clean_param_sequence() {
771         $this->assertEquals(clean_param('#()*#,9789\'".,<42897></?$(*DSFMO#$*)(SDJ)($*)', PARAM_SEQUENCE),
772             ',9789,42897');
773     }
775     function test_clean_param_component() {
776         // please note the cleaning of component names is very strict, no guessing here
777         $this->assertSame(clean_param('mod_forum', PARAM_COMPONENT), 'mod_forum');
778         $this->assertSame(clean_param('block_online_users', PARAM_COMPONENT), 'block_online_users');
779         $this->assertSame(clean_param('block_blond_online_users', PARAM_COMPONENT), 'block_blond_online_users');
780         $this->assertSame(clean_param('mod_something2', PARAM_COMPONENT), 'mod_something2');
781         $this->assertSame(clean_param('forum', PARAM_COMPONENT), 'forum');
782         $this->assertSame(clean_param('user', PARAM_COMPONENT), 'user');
783         $this->assertSame(clean_param('rating', PARAM_COMPONENT), 'rating');
784         $this->assertSame(clean_param('mod_2something', PARAM_COMPONENT), '');
785         $this->assertSame(clean_param('2mod_something', PARAM_COMPONENT), '');
786         $this->assertSame(clean_param('mod_something_xx', PARAM_COMPONENT), '');
787         $this->assertSame(clean_param('auth_something__xx', PARAM_COMPONENT), '');
788         $this->assertSame(clean_param('mod_Something', PARAM_COMPONENT), '');
789         $this->assertSame(clean_param('mod_somethíng', PARAM_COMPONENT), '');
790         $this->assertSame(clean_param('auth_xx-yy', PARAM_COMPONENT), '');
791         $this->assertSame(clean_param('_auth_xx', PARAM_COMPONENT), '');
792         $this->assertSame(clean_param('a2uth_xx', PARAM_COMPONENT), '');
793         $this->assertSame(clean_param('auth_xx_', PARAM_COMPONENT), '');
794         $this->assertSame(clean_param('auth_xx.old', PARAM_COMPONENT), '');
795         $this->assertSame(clean_param('_user', PARAM_COMPONENT), '');
796         $this->assertSame(clean_param('2rating', PARAM_COMPONENT), '');
797         $this->assertSame(clean_param('user_', PARAM_COMPONENT), '');
798     }
800     function test_clean_param_plugin() {
801         // please note the cleaning of plugin names is very strict, no guessing here
802         $this->assertSame(clean_param('forum', PARAM_PLUGIN), 'forum');
803         $this->assertSame(clean_param('forum2', PARAM_PLUGIN), 'forum2');
804         $this->assertSame(clean_param('online_users', PARAM_PLUGIN), 'online_users');
805         $this->assertSame(clean_param('blond_online_users', PARAM_PLUGIN), 'blond_online_users');
806         $this->assertSame(clean_param('online__users', PARAM_PLUGIN), '');
807         $this->assertSame(clean_param('forum ', PARAM_PLUGIN), '');
808         $this->assertSame(clean_param('forum.old', PARAM_PLUGIN), '');
809         $this->assertSame(clean_param('xx-yy', PARAM_PLUGIN), '');
810         $this->assertSame(clean_param('2xx', PARAM_PLUGIN), '');
811         $this->assertSame(clean_param('Xx', PARAM_PLUGIN), '');
812         $this->assertSame(clean_param('_xx', PARAM_PLUGIN), '');
813         $this->assertSame(clean_param('xx_', PARAM_PLUGIN), '');
814     }
816     function test_clean_param_area() {
817         // please note the cleaning of area names is very strict, no guessing here
818         $this->assertSame(clean_param('something', PARAM_AREA), 'something');
819         $this->assertSame(clean_param('something2', PARAM_AREA), 'something2');
820         $this->assertSame(clean_param('some_thing', PARAM_AREA), 'some_thing');
821         $this->assertSame(clean_param('some_thing_xx', PARAM_AREA), 'some_thing_xx');
822         $this->assertSame(clean_param('_something', PARAM_AREA), '');
823         $this->assertSame(clean_param('something_', PARAM_AREA), '');
824         $this->assertSame(clean_param('2something', PARAM_AREA), '');
825         $this->assertSame(clean_param('Something', PARAM_AREA), '');
826         $this->assertSame(clean_param('some-thing', PARAM_AREA), '');
827         $this->assertSame(clean_param('somethííng', PARAM_AREA), '');
828         $this->assertSame(clean_param('something.x', PARAM_AREA), '');
829     }
831     function test_clean_param_text() {
832         $this->assertEquals(PARAM_TEXT, PARAM_MULTILANG);
833         //standard
834         $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>');
835         $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>');
836         $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>');
837         //malformed
838         $this->assertEquals(clean_param('<span lang="en" class="multilang">aa</span>', PARAM_TEXT), '<span lang="en" class="multilang">aa</span>');
839         $this->assertEquals(clean_param('<span lang="en" class="nothing" class="multilang">aa</span>', PARAM_TEXT), 'aa');
840         $this->assertEquals(clean_param('<lang lang="en" class="multilang">aa</lang>', PARAM_TEXT), 'aa');
841         $this->assertEquals(clean_param('<lang lang="en!!">aa</lang>', PARAM_TEXT), 'aa');
842         $this->assertEquals(clean_param('<span lang="en==" class="multilang">aa</span>', PARAM_TEXT), 'aa');
843         $this->assertEquals(clean_param('a<em>b</em>c', PARAM_TEXT), 'abc');
844         $this->assertEquals(clean_param('a><xx >c>', PARAM_TEXT), 'a>c>'); // standard strip_tags() behaviour
845         $this->assertEquals(clean_param('a<b', PARAM_TEXT), 'a');
846         $this->assertEquals(clean_param('a>b', PARAM_TEXT), 'a>b');
847         $this->assertEquals(clean_param('<lang lang="en">a>a</lang>', PARAM_TEXT), '<lang lang="en">a>a</lang>'); // standard strip_tags() behaviour
848         $this->assertEquals(clean_param('<lang lang="en">a<a</lang>', PARAM_TEXT), 'a');
849         $this->assertEquals(clean_param('<lang lang="en">a<br>a</lang>', PARAM_TEXT), '<lang lang="en">aa</lang>');
850     }
852     function test_clean_param_url() {
853         // Test PARAM_URL and PARAM_LOCALURL a bit
854         $this->assertEquals(clean_param('http://google.com/', PARAM_URL), 'http://google.com/');
855         $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/');
856         $this->assertEquals(clean_param('http://localhost/', PARAM_URL), 'http://localhost/');
857         $this->assertEquals(clean_param('http://0.255.1.1/numericip.php', PARAM_URL), 'http://0.255.1.1/numericip.php');
858         $this->assertEquals(clean_param('/just/a/path', PARAM_URL), '/just/a/path');
859         $this->assertEquals(clean_param('funny:thing', PARAM_URL), '');
860     }
862     function test_clean_param_localurl() {
863         global $CFG;
864         $this->assertEquals(clean_param('http://google.com/', PARAM_LOCALURL), '');
865         $this->assertEquals(clean_param('http://some.very.long.and.silly.domain/with/a/path/', PARAM_LOCALURL), '');
866         $this->assertEquals(clean_param($CFG->wwwroot, PARAM_LOCALURL), $CFG->wwwroot);
867         $this->assertEquals(clean_param('/just/a/path', PARAM_LOCALURL), '/just/a/path');
868         $this->assertEquals(clean_param('funny:thing', PARAM_LOCALURL), '');
869         $this->assertEquals(clean_param('course/view.php?id=3', PARAM_LOCALURL), 'course/view.php?id=3');
870     }
872     function test_clean_param_file() {
873         $this->assertEquals(clean_param('correctfile.txt', PARAM_FILE), 'correctfile.txt');
874         $this->assertEquals(clean_param('b\'a<d`\\/fi:l>e.t"x|t', PARAM_FILE), 'badfile.txt');
875         $this->assertEquals(clean_param('../parentdirfile.txt', PARAM_FILE), '..parentdirfile.txt');
876         $this->assertEquals(clean_param('../../grandparentdirfile.txt', PARAM_FILE), '....grandparentdirfile.txt');
877         $this->assertEquals(clean_param('..\winparentdirfile.txt', PARAM_FILE), '..winparentdirfile.txt');
878         $this->assertEquals(clean_param('..\..\wingrandparentdir.txt', PARAM_FILE), '....wingrandparentdir.txt');
879         $this->assertEquals(clean_param('myfile.a.b.txt', PARAM_FILE), 'myfile.a.b.txt');
880         $this->assertEquals(clean_param('myfile..a..b.txt', PARAM_FILE), 'myfile..a..b.txt');
881         $this->assertEquals(clean_param('myfile.a..b...txt', PARAM_FILE), 'myfile.a..b...txt');
882         $this->assertEquals(clean_param('myfile.a.txt', PARAM_FILE), 'myfile.a.txt');
883         $this->assertEquals(clean_param('myfile...txt', PARAM_FILE), 'myfile...txt');
884         $this->assertEquals(clean_param('...jpg', PARAM_FILE), '...jpg');
885         $this->assertEquals(clean_param('.a.b.', PARAM_FILE), '.a.b.');
886         $this->assertEquals(clean_param('.', PARAM_FILE), '');
887         $this->assertEquals(clean_param('..', PARAM_FILE), '');
888         $this->assertEquals(clean_param('...', PARAM_FILE), '...');
889         $this->assertEquals(clean_param('. . . .', PARAM_FILE), '. . . .');
890         $this->assertEquals(clean_param('dontrtrim.me. .. .. . ', PARAM_FILE), 'dontrtrim.me. .. .. . ');
891         $this->assertEquals(clean_param(' . .dontltrim.me', PARAM_FILE), ' . .dontltrim.me');
892         $this->assertEquals(clean_param("here is a tab\t.txt", PARAM_FILE), 'here is a tab.txt');
893         $this->assertEquals(clean_param("here is a line\r\nbreak.txt", PARAM_FILE), 'here is a linebreak.txt');
895         //The following behaviours have been maintained although they seem a little odd
896         $this->assertEquals(clean_param('funny:thing', PARAM_FILE), 'funnything');
897         $this->assertEquals(clean_param('./currentdirfile.txt', PARAM_FILE), '.currentdirfile.txt');
898         $this->assertEquals(clean_param('c:\temp\windowsfile.txt', PARAM_FILE), 'ctempwindowsfile.txt');
899         $this->assertEquals(clean_param('/home/user/linuxfile.txt', PARAM_FILE), 'homeuserlinuxfile.txt');
900         $this->assertEquals(clean_param('~/myfile.txt', PARAM_FILE), '~myfile.txt');
901     }
903     function test_clean_param_path() {
904         $this->assertEquals(clean_param('correctfile.txt', PARAM_PATH), 'correctfile.txt');
905         $this->assertEquals(clean_param('b\'a<d`\\/fi:l>e.t"x|t', PARAM_PATH), 'bad/file.txt');
906         $this->assertEquals(clean_param('../parentdirfile.txt', PARAM_PATH), '/parentdirfile.txt');
907         $this->assertEquals(clean_param('../../grandparentdirfile.txt', PARAM_PATH), '/grandparentdirfile.txt');
908         $this->assertEquals(clean_param('..\winparentdirfile.txt', PARAM_PATH), '/winparentdirfile.txt');
909         $this->assertEquals(clean_param('..\..\wingrandparentdir.txt', PARAM_PATH), '/wingrandparentdir.txt');
910         $this->assertEquals(clean_param('funny:thing', PARAM_PATH), 'funnything');
911         $this->assertEquals(clean_param('./././here', PARAM_PATH), './here');
912         $this->assertEquals(clean_param('./currentdirfile.txt', PARAM_PATH), './currentdirfile.txt');
913         $this->assertEquals(clean_param('c:\temp\windowsfile.txt', PARAM_PATH), 'c/temp/windowsfile.txt');
914         $this->assertEquals(clean_param('/home/user/linuxfile.txt', PARAM_PATH), '/home/user/linuxfile.txt');
915         $this->assertEquals(clean_param('/home../user ./.linuxfile.txt', PARAM_PATH), '/home../user ./.linuxfile.txt');
916         $this->assertEquals(clean_param('~/myfile.txt', PARAM_PATH), '~/myfile.txt');
917         $this->assertEquals(clean_param('~/../myfile.txt', PARAM_PATH), '~/myfile.txt');
918         $this->assertEquals(clean_param('/..b../.../myfile.txt', PARAM_PATH), '/..b../.../myfile.txt');
919         $this->assertEquals(clean_param('..b../.../myfile.txt', PARAM_PATH), '..b../.../myfile.txt');
920         $this->assertEquals(clean_param('/super//slashes///', PARAM_PATH), '/super/slashes/');
921     }
923     function test_clean_param_username() {
924         global $CFG;
925         $currentstatus =  $CFG->extendedusernamechars;
927         // Run tests with extended character == FALSE;
928         $CFG->extendedusernamechars = FALSE;
929         $this->assertEquals(clean_param('johndoe123', PARAM_USERNAME), 'johndoe123' );
930         $this->assertEquals(clean_param('john.doe', PARAM_USERNAME), 'john.doe');
931         $this->assertEquals(clean_param('john-doe', PARAM_USERNAME), 'john-doe');
932         $this->assertEquals(clean_param('john- doe', PARAM_USERNAME), 'john-doe');
933         $this->assertEquals(clean_param('john_doe', PARAM_USERNAME), 'john_doe');
934         $this->assertEquals(clean_param('john@doe', PARAM_USERNAME), 'john@doe');
935         $this->assertEquals(clean_param('john~doe', PARAM_USERNAME), 'johndoe');
936         $this->assertEquals(clean_param('john´doe', PARAM_USERNAME), 'johndoe');
937         $this->assertEquals(clean_param('john#$%&() ', PARAM_USERNAME), 'john');
938         $this->assertEquals(clean_param('JOHNdóé ', PARAM_USERNAME), 'johnd');
939         $this->assertEquals(clean_param('john.,:;-_/|\ñÑ[]A_X-,D {} ~!@#$%^&*()_+ ?><[] ščřžžý ?ýá\9e?\9eý??\9adoe ', PARAM_USERNAME), 'john.-_a_x-d@_doe');
942         // Test success condition, if extendedusernamechars == ENABLE;
943         $CFG->extendedusernamechars = TRUE;
944         $this->assertEquals(clean_param('john_doe', PARAM_USERNAME), 'john_doe');
945         $this->assertEquals(clean_param('john@doe', PARAM_USERNAME), 'john@doe');
946         $this->assertEquals(clean_param('john# $%&()+_^', PARAM_USERNAME), 'john#$%&()+_^');
947         $this->assertEquals(clean_param('john~doe', PARAM_USERNAME), 'john~doe');
948         $this->assertEquals(clean_param('joHN´doe', PARAM_USERNAME), 'john´doe');
949         $this->assertEquals(clean_param('johnDOE', PARAM_USERNAME), 'johndoe');
950         $this->assertEquals(clean_param('johndóé ', PARAM_USERNAME), 'johndóé');
952         $CFG->extendedusernamechars = $currentstatus;
953     }
955     function test_clean_param_stringid() {
956         // Test string identifiers validation
957         // valid strings:
958         $this->assertEquals(clean_param('validstring', PARAM_STRINGID), 'validstring');
959         $this->assertEquals(clean_param('mod/foobar:valid_capability', PARAM_STRINGID), 'mod/foobar:valid_capability');
960         $this->assertEquals(clean_param('CZ', PARAM_STRINGID), 'CZ');
961         $this->assertEquals(clean_param('application/vnd.ms-powerpoint', PARAM_STRINGID), 'application/vnd.ms-powerpoint');
962         $this->assertEquals(clean_param('grade2', PARAM_STRINGID), 'grade2');
963         // invalid strings:
964         $this->assertEquals(clean_param('trailing ', PARAM_STRINGID), '');
965         $this->assertEquals(clean_param('space bar', PARAM_STRINGID), '');
966         $this->assertEquals(clean_param('0numeric', PARAM_STRINGID), '');
967         $this->assertEquals(clean_param('*', PARAM_STRINGID), '');
968         $this->assertEquals(clean_param(' ', PARAM_STRINGID), '');
969     }
971     function test_clean_param_timezone() {
972         // Test timezone validation
973         $testvalues = array (
974             'America/Jamaica'                => 'America/Jamaica',
975             'America/Argentina/Cordoba'      => 'America/Argentina/Cordoba',
976             'America/Port-au-Prince'         => 'America/Port-au-Prince',
977             'America/Argentina/Buenos_Aires' => 'America/Argentina/Buenos_Aires',
978             'PST8PDT'                        => 'PST8PDT',
979             'Wrong.Value'                    => '',
980             'Wrong/.Value'                   => '',
981             'Wrong(Value)'                   => '',
982             '0'                              => '0',
983             '0.0'                            => '0.0',
984             '0.5'                            => '0.5',
985             '9.0'                            => '9.0',
986             '-9.0'                           => '-9.0',
987             '+9.0'                           => '+9.0',
988             '9.5'                            => '9.5',
989             '-9.5'                           => '-9.5',
990             '+9.5'                           => '+9.5',
991             '12.0'                           => '12.0',
992             '-12.0'                          => '-12.0',
993             '+12.0'                          => '+12.0',
994             '12.5'                           => '12.5',
995             '-12.5'                          => '-12.5',
996             '+12.5'                          => '+12.5',
997             '13.0'                           => '13.0',
998             '-13.0'                          => '-13.0',
999             '+13.0'                          => '+13.0',
1000             '13.5'                           => '',
1001             '+13.5'                          => '',
1002             '-13.5'                          => '',
1003             '0.2'                            => '');
1005         foreach ($testvalues as $testvalue => $expectedvalue) {
1006             $actualvalue = clean_param($testvalue, PARAM_TIMEZONE);
1007             $this->assertEquals($actualvalue, $expectedvalue);
1008         }
1009     }
1011     function test_validate_param() {
1012         try {
1013             $param = validate_param('11a', PARAM_INT);
1014             $this->fail('invalid_parameter_exception expected');
1015         } catch (invalid_parameter_exception $ex) {
1016             $this->assertTrue(true);
1017         }
1018         try {
1019             $param = validate_param('11', PARAM_INT);
1020             $this->assertEquals($param, 11);
1021         } catch (invalid_parameter_exception $ex) {
1022             $this->fail('invalid_parameter_exception not expected');
1023         }
1024         try {
1025             $param = validate_param(null, PARAM_INT, false);
1026             $this->fail('invalid_parameter_exception expected');
1027         } catch (invalid_parameter_exception $ex) {
1028             $this->assertTrue(true);
1029         }
1030         try {
1031             $param = validate_param(null, PARAM_INT, true);
1032             $this->assertTrue($param===null);
1033         } catch (invalid_parameter_exception $ex) {
1034             $this->fail('invalid_parameter_exception expected');
1035         }
1036         try {
1037             $param = validate_param(array(), PARAM_INT);
1038             $this->fail('invalid_parameter_exception expected');
1039         } catch (invalid_parameter_exception $ex) {
1040             $this->assertTrue(true);
1041         }
1042         try {
1043             $param = validate_param(new stdClass, PARAM_INT);
1044             $this->fail('invalid_parameter_exception expected');
1045         } catch (invalid_parameter_exception $ex) {
1046             $this->assertTrue(true);
1047         }
1048         try {
1049             $param = validate_param('1.0', PARAM_FLOAT);
1050             $this->assertSame(1.0, $param);
1052             // Make sure valid floats do not cause exception.
1053             validate_param(1.0, PARAM_FLOAT);
1054             validate_param(10, PARAM_FLOAT);
1055             validate_param('0', PARAM_FLOAT);
1056             validate_param('119813454.545464564564546564545646556564465465456465465465645645465645645645', PARAM_FLOAT);
1057             validate_param('011.1', PARAM_FLOAT);
1058             validate_param('11', PARAM_FLOAT);
1059             validate_param('+.1', PARAM_FLOAT);
1060             validate_param('-.1', PARAM_FLOAT);
1061             validate_param('1e10', PARAM_FLOAT);
1062             validate_param('.1e+10', PARAM_FLOAT);
1063             validate_param('1E-1', PARAM_FLOAT);
1064             $this->assertTrue(true);
1065         } catch (invalid_parameter_exception $ex) {
1066             $this->fail('Valid float notation not accepted');
1067         }
1068         try {
1069             $param = validate_param('1,2', PARAM_FLOAT);
1070             $this->fail('invalid_parameter_exception expected');
1071         } catch (invalid_parameter_exception $ex) {
1072             $this->assertTrue(true);
1073         }
1074         try {
1075             $param = validate_param('', PARAM_FLOAT);
1076             $this->fail('invalid_parameter_exception expected');
1077         } catch (invalid_parameter_exception $ex) {
1078             $this->assertTrue(true);
1079         }
1080         try {
1081             $param = validate_param('.', PARAM_FLOAT);
1082             $this->fail('invalid_parameter_exception expected');
1083         } catch (invalid_parameter_exception $ex) {
1084             $this->assertTrue(true);
1085         }
1086         try {
1087             $param = validate_param('e10', PARAM_FLOAT);
1088             $this->fail('invalid_parameter_exception expected');
1089         } catch (invalid_parameter_exception $ex) {
1090             $this->assertTrue(true);
1091         }
1092         try {
1093             $param = validate_param('abc', PARAM_FLOAT);
1094             $this->fail('invalid_parameter_exception expected');
1095         } catch (invalid_parameter_exception $ex) {
1096             $this->assertTrue(true);
1097         }
1098     }
1100     function test_shorten_text() {
1101         $text = "short text already no tags";
1102         $this->assertEquals($text, shorten_text($text));
1104         $text = "<p>short <b>text</b> already</p><p>with tags</p>";
1105         $this->assertEquals($text, shorten_text($text));
1107         $text = "long text without any tags blah de blah blah blah what";
1108         $this->assertEquals('long text without any tags ...', shorten_text($text));
1110         $text = "<div class='frog'><p><blockquote>Long text with tags that will ".
1111             "be chopped off but <b>should be added back again</b></blockquote></p></div>";
1112         $this->assertEquals("<div class='frog'><p><blockquote>Long text with " .
1113             "tags that ...</blockquote></p></div>", shorten_text($text));
1115         $text = "some text which shouldn't &nbsp; break there";
1116         $this->assertEquals("some text which shouldn't &nbsp; ...",
1117             shorten_text($text, 31));
1118         $this->assertEquals("some text which shouldn't ...",
1119             shorten_text($text, 30));
1121         // This case caused a bug up to 1.9.5
1122         $text = "<h3>standard 'break-out' sub groups in TGs?</h3>&nbsp;&lt;&lt;There are several";
1123         $this->assertEquals("<h3>standard 'break-out' sub groups in ...</h3>",
1124             shorten_text($text, 43));
1126         $text = "<h1>123456789</h1>";//a string with no convenient breaks
1127         $this->assertEquals("<h1>12345...</h1>",
1128             shorten_text($text, 8));
1130         // ==== this must work with UTF-8 too! ======
1132         // text without tags
1133         $text = "Žluťoučký koníček přeskočil";
1134         $this->assertEquals($text, shorten_text($text)); // 30 chars by default
1135         $this->assertEquals("Žluťoučký koníče...", shorten_text($text, 19, true));
1136         $this->assertEquals("Žluťoučký ...", shorten_text($text, 19, false));
1137         // And try it with 2-less (that are, in bytes, the middle of a sequence)
1138         $this->assertEquals("Žluťoučký koní...", shorten_text($text, 17, true));
1139         $this->assertEquals("Žluťoučký ...", shorten_text($text, 17, false));
1141         $text = "<p>Žluťoučký koníček <b>přeskočil</b> potůček</p>";
1142         $this->assertEquals($text, shorten_text($text, 60));
1143         $this->assertEquals("<p>Žluťoučký koníček ...</p>", shorten_text($text, 21));
1144         $this->assertEquals("<p>Žluťoučký koníče...</p>", shorten_text($text, 19, true));
1145         $this->assertEquals("<p>Žluťoučký ...</p>", shorten_text($text, 19, false));
1146         // And try it with 2-less (that are, in bytes, the middle of a sequence)
1147         $this->assertEquals("<p>Žluťoučký koní...</p>", shorten_text($text, 17, true));
1148         $this->assertEquals("<p>Žluťoučký ...</p>", shorten_text($text, 17, false));
1149         // And try over one tag (start/end), it does proper text len
1150         $this->assertEquals("<p>Žluťoučký koníček <b>př...</b></p>", shorten_text($text, 23, true));
1151         $this->assertEquals("<p>Žluťoučký koníček <b>přeskočil</b> pot...</p>", shorten_text($text, 34, true));
1152         // And in the middle of one tag
1153         $this->assertEquals("<p>Žluťoučký koníček <b>přeskočil...</b></p>", shorten_text($text, 30, true));
1155         // Japanese
1156         $text = '言語設定言語設定abcdefghijkl';
1157         $this->assertEquals($text, shorten_text($text)); // 30 chars by default
1158         $this->assertEquals("言語設定言語...", shorten_text($text, 9, true));
1159         $this->assertEquals("言語設定言語...", shorten_text($text, 9, false));
1160         $this->assertEquals("言語設定言語設定ab...", shorten_text($text, 13, true));
1161         $this->assertEquals("言語設定言語設定...", shorten_text($text, 13, false));
1163         // Chinese
1164         $text = '简体中文简体中文abcdefghijkl';
1165         $this->assertEquals($text, shorten_text($text)); // 30 chars by default
1166         $this->assertEquals("简体中文简体...", shorten_text($text, 9, true));
1167         $this->assertEquals("简体中文简体...", shorten_text($text, 9, false));
1168         $this->assertEquals("简体中文简体中文ab...", shorten_text($text, 13, true));
1169         $this->assertEquals("简体中文简体中文...", shorten_text($text, 13, false));
1171     }
1173     function test_usergetdate() {
1174         global $USER, $CFG, $DB;
1176         //Check if forcetimezone is set then save it and set it to use user timezone
1177         $cfgforcetimezone = null;
1178         if (isset($CFG->forcetimezone)) {
1179             $cfgforcetimezone = $CFG->forcetimezone;
1180             $CFG->forcetimezone = 99; //get user default timezone.
1181         }
1183         $olduser = $USER;
1184         $USER = $DB->get_record('user', array('id'=>2)); //admin
1186         $userstimezone = $USER->timezone;
1187         $USER->timezone = 2;//set the timezone to a known state
1189         // The string version of date comes from server locale setting and does
1190         // not respect user language, so it is necessary to reset that.
1191         $oldlocale = setlocale(LC_TIME, '0');
1192         setlocale(LC_TIME, 'en_AU.UTF-8');
1194         $ts = 1261540267; //the time this function was created
1196         $arr = usergetdate($ts,1);//specify the timezone as an argument
1197         $arr = array_values($arr);
1199         list($seconds,$minutes,$hours,$mday,$wday,$mon,$year,$yday,$weekday,$month) = $arr;
1200         $this->assertSame($seconds, 7);
1201         $this->assertSame($minutes, 51);
1202         $this->assertSame($hours, 4);
1203         $this->assertSame($mday, 23);
1204         $this->assertSame($wday, 3);
1205         $this->assertSame($mon, 12);
1206         $this->assertSame($year, 2009);
1207         $this->assertSame($yday, 356);
1208         $this->assertSame($weekday, 'Wednesday');
1209         $this->assertSame($month, 'December');
1210         $arr = usergetdate($ts);//gets the timezone from the $USER object
1211         $arr = array_values($arr);
1213         list($seconds,$minutes,$hours,$mday,$wday,$mon,$year,$yday,$weekday,$month) = $arr;
1214         $this->assertSame($seconds, 7);
1215         $this->assertSame($minutes, 51);
1216         $this->assertSame($hours, 5);
1217         $this->assertSame($mday, 23);
1218         $this->assertSame($wday, 3);
1219         $this->assertSame($mon, 12);
1220         $this->assertSame($year, 2009);
1221         $this->assertSame($yday, 356);
1222         $this->assertSame($weekday, 'Wednesday');
1223         $this->assertSame($month, 'December');
1224         //set the timezone back to what it was
1225         $USER->timezone = $userstimezone;
1227         //restore forcetimezone if changed.
1228         if (!is_null($cfgforcetimezone)) {
1229             $CFG->forcetimezone = $cfgforcetimezone;
1230         }
1232         setlocale(LC_TIME, $oldlocale);
1234         $USER = $olduser;
1235     }
1237     public function test_normalize_component() {
1239         // moodle core
1240         $this->assertEquals(normalize_component('moodle'), array('core', null));
1241         $this->assertEquals(normalize_component('core'), array('core', null));
1243         // moodle core subsystems
1244         $this->assertEquals(normalize_component('admin'), array('core', 'admin'));
1245         $this->assertEquals(normalize_component('core_admin'), array('core', 'admin'));
1247         // activity modules and their subplugins
1248         $this->assertEquals(normalize_component('workshop'), array('mod', 'workshop'));
1249         $this->assertEquals(normalize_component('mod_workshop'), array('mod', 'workshop'));
1250         $this->assertEquals(normalize_component('workshopform_accumulative'), array('workshopform', 'accumulative'));
1251         $this->assertEquals(normalize_component('quiz'), array('mod', 'quiz'));
1252         $this->assertEquals(normalize_component('quiz_grading'), array('quiz', 'grading'));
1253         $this->assertEquals(normalize_component('data'), array('mod', 'data'));
1254         $this->assertEquals(normalize_component('datafield_checkbox'), array('datafield', 'checkbox'));
1256         // other plugin types
1257         $this->assertEquals(normalize_component('auth_mnet'), array('auth', 'mnet'));
1258         $this->assertEquals(normalize_component('enrol_self'), array('enrol', 'self'));
1259         $this->assertEquals(normalize_component('block_html'), array('block', 'html'));
1260         $this->assertEquals(normalize_component('block_mnet_hosts'), array('block', 'mnet_hosts'));
1261         $this->assertEquals(normalize_component('local_amos'), array('local', 'amos'));
1263         // unknown components are supposed to be activity modules
1264         $this->assertEquals(normalize_component('whothefuckwouldcomewithsuchastupidnameofcomponent'),
1265             array('mod', 'whothefuckwouldcomewithsuchastupidnameofcomponent'));
1266         $this->assertEquals(normalize_component('whothefuck_wouldcomewithsuchastupidnameofcomponent'),
1267             array('mod', 'whothefuck_wouldcomewithsuchastupidnameofcomponent'));
1268         $this->assertEquals(normalize_component('whothefuck_would_come_withsuchastupidnameofcomponent'),
1269             array('mod', 'whothefuck_would_come_withsuchastupidnameofcomponent'));
1270     }
1272     protected function get_fake_preference_test_userid() {
1273         global $DB;
1275         // we need some nonexistent user id
1276         $id = 2147483647 - 666;
1277         if ($DB->get_records('user', array('id'=>$id))) {
1278             //weird!
1279             return false;
1280         }
1281         return $id;
1282     }
1284     public function test_mark_user_preferences_changed() {
1285         $this->resetAfterTest(true);
1286         if (!$otheruserid = $this->get_fake_preference_test_userid()) {
1287             $this->fail('Can not find unused user id for the preferences test');
1288             return;
1289         }
1291         set_cache_flag('userpreferenceschanged', $otheruserid, NULL);
1292         mark_user_preferences_changed($otheruserid);
1294         $this->assertEquals(get_cache_flag('userpreferenceschanged', $otheruserid, time()-10), 1);
1295         set_cache_flag('userpreferenceschanged', $otheruserid, NULL);
1296     }
1298     public function test_check_user_preferences_loaded() {
1299         global $DB;
1300         $this->resetAfterTest(true);
1302         if (!$otheruserid = $this->get_fake_preference_test_userid()) {
1303             $this->fail('Can not find unused user id for the preferences test');
1304             return;
1305         }
1307         $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
1308         set_cache_flag('userpreferenceschanged', $otheruserid, NULL);
1310         $user = new stdClass();
1311         $user->id = $otheruserid;
1313         // load
1314         check_user_preferences_loaded($user);
1315         $this->assertTrue(isset($user->preference));
1316         $this->assertTrue(is_array($user->preference));
1317         $this->assertTrue(isset($user->preference['_lastloaded']));
1318         $this->assertEquals(count($user->preference), 1);
1320         // add preference via direct call
1321         $DB->insert_record('user_preferences', array('name'=>'xxx', 'value'=>'yyy', 'userid'=>$user->id));
1323         // no cache reload yet
1324         check_user_preferences_loaded($user);
1325         $this->assertEquals(count($user->preference), 1);
1327         // forced reloading of cache
1328         unset($user->preference);
1329         check_user_preferences_loaded($user);
1330         $this->assertEquals(count($user->preference), 2);
1331         $this->assertEquals($user->preference['xxx'], 'yyy');
1333         // add preference via direct call
1334         $DB->insert_record('user_preferences', array('name'=>'aaa', 'value'=>'bbb', 'userid'=>$user->id));
1336         // test timeouts and modifications from different session
1337         set_cache_flag('userpreferenceschanged', $user->id, 1, time() + 1000);
1338         $user->preference['_lastloaded'] = $user->preference['_lastloaded'] - 20;
1339         check_user_preferences_loaded($user);
1340         $this->assertEquals(count($user->preference), 2);
1341         check_user_preferences_loaded($user, 10);
1342         $this->assertEquals(count($user->preference), 3);
1343         $this->assertEquals($user->preference['aaa'], 'bbb');
1344         set_cache_flag('userpreferenceschanged', $user->id, null);
1345     }
1347     public function test_set_user_preference() {
1348         global $DB, $USER;
1349         $this->resetAfterTest(true);
1351         $olduser = $USER;
1352         $USER = $DB->get_record('user', array('id'=>2)); //admin
1354         if (!$otheruserid = $this->get_fake_preference_test_userid()) {
1355             $this->fail('Can not find unused user id for the preferences test');
1356             return;
1357         }
1359         $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
1360         set_cache_flag('userpreferenceschanged', $otheruserid, null);
1362         $user = new stdClass();
1363         $user->id = $otheruserid;
1365         set_user_preference('aaa', 'bbb', $otheruserid);
1366         $this->assertEquals('bbb', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'aaa')));
1367         $this->assertEquals('bbb', get_user_preferences('aaa', null, $otheruserid));
1369         set_user_preference('xxx', 'yyy', $user);
1370         $this->assertEquals('yyy', $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx')));
1371         $this->assertEquals('yyy', get_user_preferences('xxx', null, $otheruserid));
1372         $this->assertTrue(is_array($user->preference));
1373         $this->assertEquals($user->preference['aaa'], 'bbb');
1374         $this->assertEquals($user->preference['xxx'], 'yyy');
1376         set_user_preference('xxx', NULL, $user);
1377         $this->assertSame(false, $DB->get_field('user_preferences', 'value', array('userid'=>$otheruserid, 'name'=>'xxx')));
1378         $this->assertSame(null, get_user_preferences('xxx', null, $otheruserid));
1380         set_user_preference('ooo', true, $user);
1381         $prefs = get_user_preferences(null, null, $otheruserid);
1382         $this->assertSame($prefs['aaa'], $user->preference['aaa']);
1383         $this->assertSame($prefs['ooo'], $user->preference['ooo']);
1384         $this->assertSame($prefs['ooo'], '1');
1386         set_user_preference('null', 0, $user);
1387         $this->assertSame('0', get_user_preferences('null', null, $otheruserid));
1389         $this->assertSame('lala', get_user_preferences('undefined', 'lala', $otheruserid));
1391         $DB->delete_records('user_preferences', array('userid'=>$otheruserid));
1392         set_cache_flag('userpreferenceschanged', $otheruserid, null);
1394         // test $USER default
1395         set_user_preference('_test_user_preferences_pref', 'ok');
1396         $this->assertSame('ok', $USER->preference['_test_user_preferences_pref']);
1397         unset_user_preference('_test_user_preferences_pref');
1398         $this->assertTrue(!isset($USER->preference['_test_user_preferences_pref']));
1400         // Test 1333 char values (no need for unicode, there are already tests for that in DB tests)
1401         $longvalue = str_repeat('a', 1333);
1402         set_user_preference('_test_long_user_preference', $longvalue);
1403         $this->assertEquals($longvalue, get_user_preferences('_test_long_user_preference'));
1404         $this->assertEquals($longvalue,
1405             $DB->get_field('user_preferences', 'value', array('userid' => $USER->id, 'name' => '_test_long_user_preference')));
1407         // Test > 1333 char values, coding_exception expected
1408         $longvalue = str_repeat('a', 1334);
1409         try {
1410             set_user_preference('_test_long_user_preference', $longvalue);
1411             $this->fail('Exception expected - longer than 1333 chars not allowed as preference value');
1412         } catch (coding_exception $ex) {
1413             $this->assertTrue(true);
1414         }
1416         //test invalid params
1417         try {
1418             set_user_preference('_test_user_preferences_pref', array());
1419             $this->fail('Exception expected - array not valid preference value');
1420         } catch (coding_exception $ex) {
1421             $this->assertTrue(true);
1422         }
1423         try {
1424             set_user_preference('_test_user_preferences_pref', new stdClass);
1425             $this->fail('Exception expected - class not valid preference value');
1426         } catch (coding_exception $ex) {
1427             $this->assertTrue(true);
1428         }
1429         try {
1430             set_user_preference('_test_user_preferences_pref', 1, array('xx' => 1));
1431             $this->fail('Exception expected - user instance expected');
1432         } catch (coding_exception $ex) {
1433             $this->assertTrue(true);
1434         }
1435         try {
1436             set_user_preference('_test_user_preferences_pref', 1, 'abc');
1437             $this->fail('Exception expected - user instance expected');
1438         } catch (coding_exception $ex) {
1439             $this->assertTrue(true);
1440         }
1441         try {
1442             set_user_preference('', 1);
1443             $this->fail('Exception expected - invalid name accepted');
1444         } catch (coding_exception $ex) {
1445             $this->assertTrue(true);
1446         }
1447         try {
1448             set_user_preference('1', 1);
1449             $this->fail('Exception expected - invalid name accepted');
1450         } catch (coding_exception $ex) {
1451             $this->assertTrue(true);
1452         }
1454         $USER = $olduser;
1455     }
1457     public function test_get_extra_user_fields() {
1458         global $CFG, $USER, $DB;
1459         $oldshowuseridentity = $CFG->showuseridentity;
1461         $olduser = $USER;
1462         $USER = $DB->get_record('user', array('id'=>2)); //admin
1464         // It would be really nice if there were a way to 'mock' has_capability
1465         // checks (either to return true or false) but as there is not, this
1466         // test doesn't test the capability check. Presumably, anyone running
1467         // unit tests will have the capability.
1468         $context = context_system::instance();
1470         // No fields
1471         $CFG->showuseridentity = '';
1472         $this->assertEquals(array(), get_extra_user_fields($context));
1474         // One field
1475         $CFG->showuseridentity = 'frog';
1476         $this->assertEquals(array('frog'), get_extra_user_fields($context));
1478         // Two fields
1479         $CFG->showuseridentity = 'frog,zombie';
1480         $this->assertEquals(array('frog', 'zombie'), get_extra_user_fields($context));
1482         // No fields, except
1483         $CFG->showuseridentity = '';
1484         $this->assertEquals(array(), get_extra_user_fields($context, array('frog')));
1486         // One field
1487         $CFG->showuseridentity = 'frog';
1488         $this->assertEquals(array(), get_extra_user_fields($context, array('frog')));
1490         // Two fields
1491         $CFG->showuseridentity = 'frog,zombie';
1492         $this->assertEquals(array('zombie'), get_extra_user_fields($context, array('frog')));
1494         // As long as this test passes, the value will be set back. This is only
1495         // in-memory anyhow
1496         $CFG->showuseridentity = $oldshowuseridentity;
1498         $USER = $olduser;
1499     }
1501     public function test_get_extra_user_fields_sql() {
1502         global $CFG, $USER, $DB;
1504         $olduser = $USER;
1505         $USER = $DB->get_record('user', array('id'=>2)); //admin
1507         $oldshowuseridentity = $CFG->showuseridentity;
1508         $context = context_system::instance();
1510         // No fields
1511         $CFG->showuseridentity = '';
1512         $this->assertEquals('', get_extra_user_fields_sql($context));
1514         // One field
1515         $CFG->showuseridentity = 'frog';
1516         $this->assertEquals(', frog', get_extra_user_fields_sql($context));
1518         // Two fields with table prefix
1519         $CFG->showuseridentity = 'frog,zombie';
1520         $this->assertEquals(', u1.frog, u1.zombie', get_extra_user_fields_sql($context, 'u1'));
1522         // Two fields with field prefix
1523         $CFG->showuseridentity = 'frog,zombie';
1524         $this->assertEquals(', frog AS u_frog, zombie AS u_zombie',
1525             get_extra_user_fields_sql($context, '', 'u_'));
1527         // One field excluded
1528         $CFG->showuseridentity = 'frog';
1529         $this->assertEquals('', get_extra_user_fields_sql($context, '', '', array('frog')));
1531         // Two fields, one excluded, table+field prefix
1532         $CFG->showuseridentity = 'frog,zombie';
1533         $this->assertEquals(', u1.zombie AS u_zombie',
1534             get_extra_user_fields_sql($context, 'u1', 'u_', array('frog')));
1536         // As long as this test passes, the value will be set back. This is only
1537         // in-memory anyhow
1538         $CFG->showuseridentity = $oldshowuseridentity;
1539         $USER = $olduser;
1540     }
1542     public function test_userdate() {
1543         global $USER, $CFG, $DB;
1545         $olduser = $USER;
1546         $USER = $DB->get_record('user', array('id'=>2)); //admin
1548         $testvalues = array(
1549             array(
1550                 'time' => '1309514400',
1551                 'usertimezone' => 'America/Moncton',
1552                 'timezone' => '0.0', //no dst offset
1553                 'expectedoutput' => 'Friday, 1 July 2011, 10:00 AM'
1554             ),
1555             array(
1556                 'time' => '1309514400',
1557                 'usertimezone' => 'America/Moncton',
1558                 'timezone' => '99', //dst offset and timezone offset.
1559                 'expectedoutput' => 'Friday, 1 July 2011, 7:00 AM'
1560             ),
1561             array(
1562                 'time' => '1309514400',
1563                 'usertimezone' => 'America/Moncton',
1564                 'timezone' => 'America/Moncton', //dst offset and timezone offset.
1565                 'expectedoutput' => 'Friday, 1 July 2011, 7:00 AM'
1566             ),
1567             array(
1568                 'time' => '1293876000 ',
1569                 'usertimezone' => 'America/Moncton',
1570                 'timezone' => '0.0', //no dst offset
1571                 'expectedoutput' => 'Saturday, 1 January 2011, 10:00 AM'
1572             ),
1573             array(
1574                 'time' => '1293876000 ',
1575                 'usertimezone' => 'America/Moncton',
1576                 'timezone' => '99', //no dst offset in jan, so just timezone offset.
1577                 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 AM'
1578             ),
1579             array(
1580                 'time' => '1293876000 ',
1581                 'usertimezone' => 'America/Moncton',
1582                 'timezone' => 'America/Moncton', //no dst offset in jan
1583                 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 AM'
1584             ),
1585             array(
1586                 'time' => '1293876000 ',
1587                 'usertimezone' => '2',
1588                 'timezone' => '99', //take user timezone
1589                 'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
1590             ),
1591             array(
1592                 'time' => '1293876000 ',
1593                 'usertimezone' => '-2',
1594                 'timezone' => '99', //take user timezone
1595                 'expectedoutput' => 'Saturday, 1 January 2011, 8:00 AM'
1596             ),
1597             array(
1598                 'time' => '1293876000 ',
1599                 'usertimezone' => '-10',
1600                 'timezone' => '2', //take this timezone
1601                 'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
1602             ),
1603             array(
1604                 'time' => '1293876000 ',
1605                 'usertimezone' => '-10',
1606                 'timezone' => '-2', //take this timezone
1607                 'expectedoutput' => 'Saturday, 1 January 2011, 8:00 AM'
1608             ),
1609             array(
1610                 'time' => '1293876000 ',
1611                 'usertimezone' => '-10',
1612                 'timezone' => 'random/time', //this should show server time
1613                 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 PM'
1614             ),
1615             array(
1616                 'time' => '1293876000 ',
1617                 'usertimezone' => '14', //server time zone
1618                 'timezone' => '99', //this should show user time
1619                 'expectedoutput' => 'Saturday, 1 January 2011, 6:00 PM'
1620             ),
1621         );
1623         //Check if forcetimezone is set then save it and set it to use user timezone
1624         $cfgforcetimezone = null;
1625         if (isset($CFG->forcetimezone)) {
1626             $cfgforcetimezone = $CFG->forcetimezone;
1627             $CFG->forcetimezone = 99; //get user default timezone.
1628         }
1629         //store user default timezone to restore later
1630         $userstimezone = $USER->timezone;
1632         // The string version of date comes from server locale setting and does
1633         // not respect user language, so it is necessary to reset that.
1634         $oldlocale = setlocale(LC_TIME, '0');
1635         setlocale(LC_TIME, 'en_AU.UTF-8');
1637         //set default timezone to Australia/Perth, else time calculated
1638         //will not match expected values. Before that save system defaults.
1639         $systemdefaulttimezone = date_default_timezone_get();
1640         date_default_timezone_set('Australia/Perth');
1642         foreach ($testvalues as $vals) {
1643             $USER->timezone = $vals['usertimezone'];
1644             $actualoutput = userdate($vals['time'], '%A, %d %B %Y, %I:%M %p', $vals['timezone']);
1646             //On different systems case of AM PM changes so compare case insensitive
1647             $vals['expectedoutput'] = textlib::strtolower($vals['expectedoutput']);
1648             $actualoutput = textlib::strtolower($actualoutput);
1650             $this->assertEquals($vals['expectedoutput'], $actualoutput,
1651                 "Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
1652                 Please check if timezones are updated (Site adminstration -> location -> update timezone)");
1653         }
1655         //restore user timezone back to what it was
1656         $USER->timezone = $userstimezone;
1658         //restore forcetimezone
1659         if (!is_null($cfgforcetimezone)) {
1660             $CFG->forcetimezone = $cfgforcetimezone;
1661         }
1663         //restore system default values.
1664         date_default_timezone_set($systemdefaulttimezone);
1665         setlocale(LC_TIME, $oldlocale);
1667         $USER = $olduser;
1668     }
1670     public function test_make_timestamp() {
1671         global $USER, $CFG, $DB;
1673         $olduser = $USER;
1674         $USER = $DB->get_record('user', array('id'=>2)); //admin
1676         $testvalues = array(
1677             array(
1678                 'usertimezone' => 'America/Moncton',
1679                 'year' => '2011',
1680                 'month' => '7',
1681                 'day' => '1',
1682                 'hour' => '10',
1683                 'minutes' => '00',
1684                 'seconds' => '00',
1685                 'timezone' => '0.0',
1686                 'applydst' => false, //no dst offset
1687                 'expectedoutput' => '1309514400' // 6pm at UTC+0
1688             ),
1689             array(
1690                 'usertimezone' => 'America/Moncton',
1691                 'year' => '2011',
1692                 'month' => '7',
1693                 'day' => '1',
1694                 'hour' => '10',
1695                 'minutes' => '00',
1696                 'seconds' => '00',
1697                 'timezone' => '99', //user default timezone
1698                 'applydst' => false, //don't apply dst
1699                 'expectedoutput' => '1309528800'
1700             ),
1701             array(
1702                 'usertimezone' => 'America/Moncton',
1703                 'year' => '2011',
1704                 'month' => '7',
1705                 'day' => '1',
1706                 'hour' => '10',
1707                 'minutes' => '00',
1708                 'seconds' => '00',
1709                 'timezone' => '99', //user default timezone
1710                 'applydst' => true, //apply dst
1711                 'expectedoutput' => '1309525200'
1712             ),
1713             array(
1714                 'usertimezone' => 'America/Moncton',
1715                 'year' => '2011',
1716                 'month' => '7',
1717                 'day' => '1',
1718                 'hour' => '10',
1719                 'minutes' => '00',
1720                 'seconds' => '00',
1721                 'timezone' => 'America/Moncton', //string timezone
1722                 'applydst' => true, //apply dst
1723                 'expectedoutput' => '1309525200'
1724             ),
1725             array(
1726                 'usertimezone' => '2',//no dst applyed
1727                 'year' => '2011',
1728                 'month' => '7',
1729                 'day' => '1',
1730                 'hour' => '10',
1731                 'minutes' => '00',
1732                 'seconds' => '00',
1733                 'timezone' => '99', //take user timezone
1734                 'applydst' => true, //apply dst
1735                 'expectedoutput' => '1309507200'
1736             ),
1737             array(
1738                 'usertimezone' => '-2',//no dst applyed
1739                 'year' => '2011',
1740                 'month' => '7',
1741                 'day' => '1',
1742                 'hour' => '10',
1743                 'minutes' => '00',
1744                 'seconds' => '00',
1745                 'timezone' => '99', //take usertimezone
1746                 'applydst' => true, //apply dst
1747                 'expectedoutput' => '1309521600'
1748             ),
1749             array(
1750                 'usertimezone' => '-10',//no dst applyed
1751                 'year' => '2011',
1752                 'month' => '7',
1753                 'day' => '1',
1754                 'hour' => '10',
1755                 'minutes' => '00',
1756                 'seconds' => '00',
1757                 'timezone' => '2', //take this timezone
1758                 'applydst' => true, //apply dst
1759                 'expectedoutput' => '1309507200'
1760             ),
1761             array(
1762                 'usertimezone' => '-10',//no dst applyed
1763                 'year' => '2011',
1764                 'month' => '7',
1765                 'day' => '1',
1766                 'hour' => '10',
1767                 'minutes' => '00',
1768                 'seconds' => '00',
1769                 'timezone' => '-2', //take this timezone
1770                 'applydst' => true, //apply dst,
1771                 'expectedoutput' => '1309521600'
1772             ),
1773             array(
1774                 'usertimezone' => '-10',//no dst applyed
1775                 'year' => '2011',
1776                 'month' => '7',
1777                 'day' => '1',
1778                 'hour' => '10',
1779                 'minutes' => '00',
1780                 'seconds' => '00',
1781                 'timezone' => 'random/time', //This should show server time
1782                 'applydst' => true, //apply dst,
1783                 'expectedoutput' => '1309485600'
1784             ),
1785             array(
1786                 'usertimezone' => '14',//server time
1787                 'year' => '2011',
1788                 'month' => '7',
1789                 'day' => '1',
1790                 'hour' => '10',
1791                 'minutes' => '00',
1792                 'seconds' => '00',
1793                 'timezone' => '99', //get user time
1794                 'applydst' => true, //apply dst,
1795                 'expectedoutput' => '1309485600'
1796             )
1797         );
1799         //Check if forcetimezone is set then save it and set it to use user timezone
1800         $cfgforcetimezone = null;
1801         if (isset($CFG->forcetimezone)) {
1802             $cfgforcetimezone = $CFG->forcetimezone;
1803             $CFG->forcetimezone = 99; //get user default timezone.
1804         }
1806         //store user default timezone to restore later
1807         $userstimezone = $USER->timezone;
1809         // The string version of date comes from server locale setting and does
1810         // not respect user language, so it is necessary to reset that.
1811         $oldlocale = setlocale(LC_TIME, '0');
1812         setlocale(LC_TIME, 'en_AU.UTF-8');
1814         //set default timezone to Australia/Perth, else time calulated
1815         //will not match expected values. Before that save system defaults.
1816         $systemdefaulttimezone = date_default_timezone_get();
1817         date_default_timezone_set('Australia/Perth');
1819         //Test make_timestamp with all testvals and assert if anything wrong.
1820         foreach ($testvalues as $vals) {
1821             $USER->timezone = $vals['usertimezone'];
1822             $actualoutput = make_timestamp(
1823                 $vals['year'],
1824                 $vals['month'],
1825                 $vals['day'],
1826                 $vals['hour'],
1827                 $vals['minutes'],
1828                 $vals['seconds'],
1829                 $vals['timezone'],
1830                 $vals['applydst']
1831             );
1833             //On different systems case of AM PM changes so compare case insenitive
1834             $vals['expectedoutput'] = textlib::strtolower($vals['expectedoutput']);
1835             $actualoutput = textlib::strtolower($actualoutput);
1837             $this->assertEquals($vals['expectedoutput'], $actualoutput,
1838                 "Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
1839                 Please check if timezones are updated (Site adminstration -> location -> update timezone)");
1840         }
1842         //restore user timezone back to what it was
1843         $USER->timezone = $userstimezone;
1845         //restore forcetimezone
1846         if (!is_null($cfgforcetimezone)) {
1847             $CFG->forcetimezone = $cfgforcetimezone;
1848         }
1850         //restore system default values.
1851         date_default_timezone_set($systemdefaulttimezone);
1852         setlocale(LC_TIME, $oldlocale);
1854         $USER = $olduser;
1855     }
1857     /**
1858      * Test get_string and most importantly the implementation of the lang_string
1859      * object.
1860      */
1861     public function test_get_string() {
1862         global $COURSE;
1864         // Make sure we are using English
1865         $originallang = $COURSE->lang;
1866         $COURSE->lang = 'en';
1868         $yes = get_string('yes');
1869         $yesexpected = 'Yes';
1870         $this->assertEquals(getType($yes), 'string');
1871         $this->assertEquals($yes, $yesexpected);
1873         $yes = get_string('yes', 'moodle');
1874         $this->assertEquals(getType($yes), 'string');
1875         $this->assertEquals($yes, $yesexpected);
1877         $yes = get_string('yes', 'core');
1878         $this->assertEquals(getType($yes), 'string');
1879         $this->assertEquals($yes, $yesexpected);
1881         $yes = get_string('yes', '');
1882         $this->assertEquals(getType($yes), 'string');
1883         $this->assertEquals($yes, $yesexpected);
1885         $yes = get_string('yes', null);
1886         $this->assertEquals(getType($yes), 'string');
1887         $this->assertEquals($yes, $yesexpected);
1889         $yes = get_string('yes', null, 1);
1890         $this->assertEquals(getType($yes), 'string');
1891         $this->assertEquals($yes, $yesexpected);
1893         $days = 1;
1894         $numdays = get_string('numdays', 'core', '1');
1895         $numdaysexpected = $days.' days';
1896         $this->assertEquals(getType($numdays), 'string');
1897         $this->assertEquals($numdays, $numdaysexpected);
1899         $yes = get_string('yes', null, null, true);
1900         $this->assertEquals(get_class($yes), 'lang_string');
1901         $this->assertEquals((string)$yes, $yesexpected);
1903         // Test using a lang_string object as the $a argument for a normal
1904         // get_string call (returning string)
1905         $test = new lang_string('yes', null, null, true);
1906         $testexpected = get_string('numdays', 'core', get_string('yes'));
1907         $testresult = get_string('numdays', null, $test);
1908         $this->assertEquals(getType($testresult), 'string');
1909         $this->assertEquals($testresult, $testexpected);
1911         // Test using a lang_string object as the $a argument for an object
1912         // get_string call (returning lang_string)
1913         $test = new lang_string('yes', null, null, true);
1914         $testexpected = get_string('numdays', 'core', get_string('yes'));
1915         $testresult = get_string('numdays', null, $test, true);
1916         $this->assertEquals(get_class($testresult), 'lang_string');
1917         $this->assertEquals("$testresult", $testexpected);
1919         // Make sure that object properties that can't be converted don't cause
1920         // errors
1921         // Level one: This is as deep as current language processing goes
1922         $test = new stdClass;
1923         $test->one = 'here';
1924         $string = get_string('yes', null, $test, true);
1925         $this->assertEquals($string, $yesexpected);
1927         // Make sure that object properties that can't be converted don't cause
1928         // errors.
1929         // Level two: Language processing doesn't currently reach this deep.
1930         // only immediate scalar properties are worked with.
1931         $test = new stdClass;
1932         $test->one = new stdClass;
1933         $test->one->two = 'here';
1934         $string = get_string('yes', null, $test, true);
1935         $this->assertEquals($string, $yesexpected);
1937         // Make sure that object properties that can't be converted don't cause
1938         // errors.
1939         // Level three: It should never ever go this deep, but we're making sure
1940         // it doesn't cause any probs anyway.
1941         $test = new stdClass;
1942         $test->one = new stdClass;
1943         $test->one->two = new stdClass;
1944         $test->one->two->three = 'here';
1945         $string = get_string('yes', null, $test, true);
1946         $this->assertEquals($string, $yesexpected);
1948         // Make sure that object properties that can't be converted don't cause
1949         // errors and check lang_string properties.
1950         // Level one: This is as deep as current language processing goes
1951         $test = new stdClass;
1952         $test->one = new lang_string('yes');
1953         $string = get_string('yes', null, $test, true);
1954         $this->assertEquals($string, $yesexpected);
1956         // Make sure that object properties that can't be converted don't cause
1957         // errors and check lang_string properties.
1958         // Level two: Language processing doesn't currently reach this deep.
1959         // only immediate scalar properties are worked with.
1960         $test = new stdClass;
1961         $test->one = new stdClass;
1962         $test->one->two = new lang_string('yes');
1963         $string = get_string('yes', null, $test, true);
1964         $this->assertEquals($string, $yesexpected);
1966         // Make sure that object properties that can't be converted don't cause
1967         // errors and check lang_string properties.
1968         // Level three: It should never ever go this deep, but we're making sure
1969         // it doesn't cause any probs anyway.
1970         $test = new stdClass;
1971         $test->one = new stdClass;
1972         $test->one->two = new stdClass;
1973         $test->one->two->three = new lang_string('yes');
1974         $string = get_string('yes', null, $test, true);
1975         $this->assertEquals($string, $yesexpected);
1977         // Make sure that array properties that can't be converted don't cause
1978         // errors
1979         $test = array();
1980         $test['one'] = new stdClass;
1981         $test['one']->two = 'here';
1982         $string = get_string('yes', null, $test, true);
1983         $this->assertEquals($string, $yesexpected);
1985         // Same thing but as above except using an object... this is allowed :P
1986         $string = get_string('yes', null, null, true);
1987         $object = new stdClass;
1988         $object->$string = 'Yes';
1989         $this->assertEquals($string, $yesexpected);
1990         $this->assertEquals($object->$string, $yesexpected);
1992         // Reset the language
1993         $COURSE->lang = $originallang;
1994     }
1996     /**
1997      * @expectedException PHPUnit_Framework_Error_Warning
1998      * @return void
1999      */
2000     public function test_get_string_limitation() {
2001         // This is one of the limitations to the lang_string class. It can't be
2002         // used as a key
2003         $array = array(get_string('yes', null, null, true) => 'yes');
2004     }
2006     /**
2007      * Test localised float formatting.
2008      */
2009     public function test_format_float() {
2010         global $SESSION, $CFG;
2012         // Special case for null
2013         $this->assertEquals('', format_float(null));
2015         // Default 1 decimal place
2016         $this->assertEquals('5.4', format_float(5.43));
2017         $this->assertEquals('5.0', format_float(5.001));
2019         // Custom number of decimal places
2020         $this->assertEquals('5.43000', format_float(5.43, 5));
2022         // Option to strip ending zeros after rounding
2023         $this->assertEquals('5.43', format_float(5.43, 5, true, true));
2024         $this->assertEquals('5', format_float(5.0001, 3, true, true));
2026         // It is not possible to directly change the result of get_string in
2027         // a unit test. Instead, we create a language pack for language 'xx' in
2028         // dataroot and make langconfig.php with the string we need to change.
2029         // The example separator used here is 'X'; on PHP 5.3 and before this
2030         // must be a single byte character due to PHP bug/limitation in
2031         // number_format, so you can't use UTF-8 characters.
2032         $SESSION->lang = 'xx';
2033         $langconfig = "<?php\n\$string['decsep'] = 'X';";
2034         $langfolder = $CFG->dataroot . '/lang/xx';
2035         check_dir_exists($langfolder);
2036         file_put_contents($langfolder . '/langconfig.php', $langconfig);
2038         // Localisation on (default)
2039         $this->assertEquals('5X43000', format_float(5.43, 5));
2040         $this->assertEquals('5X43', format_float(5.43, 5, true, true));
2042         // Localisation off
2043         $this->assertEquals('5.43000', format_float(5.43, 5, false));
2044         $this->assertEquals('5.43', format_float(5.43, 5, false, true));
2045     }
2047     /**
2048      * Test deleting of users.
2049      */
2050     public function test_delete_user() {
2051         global $DB, $CFG;
2053         $this->resetAfterTest();
2055         $guest = $DB->get_record('user', array('id'=>$CFG->siteguest), '*', MUST_EXIST);
2056         $admin = $DB->get_record('user', array('id'=>$CFG->siteadmins), '*', MUST_EXIST);
2057         $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
2059         $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
2060         $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
2062         $result = delete_user($user);
2063         $this->assertTrue($result);
2064         $deluser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
2065         $this->assertEquals(1, $deluser->deleted);
2066         $this->assertEquals(0, $deluser->picture);
2067         $this->assertSame('', $deluser->idnumber);
2068         $this->assertSame(md5($user->username), $deluser->email);
2069         $this->assertRegExp('/^'.preg_quote($user->email, '/').'\.\d*$/', $deluser->username);
2071         $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
2073         // Try invalid params.
2075         $record = new stdClass();
2076         $record->grrr = 1;
2077         try {
2078             delete_user($record);
2079             $this->fail('Expecting exception for invalid delete_user() $user parameter');
2080         } catch (coding_exception $e) {
2081             $this->assertTrue(true);
2082         }
2083         $record->id = 1;
2084         try {
2085             delete_user($record);
2086             $this->fail('Expecting exception for invalid delete_user() $user parameter');
2087         } catch (coding_exception $e) {
2088             $this->assertTrue(true);
2089         }
2091         $record = new stdClass();
2092         $record->id = 666;
2093         $record->username = 'xx';
2094         $this->assertFalse($DB->record_exists('user', array('id'=>666))); // Any non-existent id is ok.
2095         $result = delete_user($record);
2096         $this->assertFalse($result);
2098         $result = delete_user($guest);
2099         $this->assertFalse($result);
2101         $result = delete_user($admin);
2102         $this->assertFalse($result);
2104         $this->resetDebugging();
2105     }
2107     /**
2108      * Test function convert_to_array()
2109      */
2110     public function test_convert_to_array() {
2111         // check that normal classes are converted to arrays the same way as (array) would do
2112         $obj = new stdClass();
2113         $obj->prop1 = 'hello';
2114         $obj->prop2 = array('first', 'second', 13);
2115         $obj->prop3 = 15;
2116         $this->assertEquals(convert_to_array($obj), (array)$obj);
2118         // check that context object (with iterator) is converted to array properly
2119         $obj = get_system_context();
2120         $ar = array(
2121             'id'           => $obj->id,
2122             'contextlevel' => $obj->contextlevel,
2123             'instanceid'   => $obj->instanceid,
2124             'path'         => $obj->path,
2125             'depth'        => $obj->depth
2126         );
2127         $this->assertEquals(convert_to_array($obj), $ar);
2128     }
2130     /**
2131      * Test the function date_format_string().
2132      */
2133     function test_date_format_string() {
2134         global $CFG;
2136         // Forcing locale and timezone.
2137         $oldlocale = setlocale(LC_TIME, '0');
2138         if ($CFG->ostype == 'WINDOWS') {
2139             setlocale(LC_TIME, 'English_Australia.1252');
2140         } else {
2141             setlocale(LC_TIME, 'en_AU.UTF-8');
2142         }
2143         $systemdefaulttimezone = date_default_timezone_get();
2144         date_default_timezone_set('Australia/Perth');
2146         $tests = array(
2147             array(
2148                 'tz' => 99,
2149                 'str' => '%A, %d %B %Y, %I:%M %p',
2150                 'expected' => 'Saturday, 01 January 2011, 06:00 PM'
2151             ),
2152             array(
2153                 'tz' => 0,
2154                 'str' => '%A, %d %B %Y, %I:%M %p',
2155                 'expected' => 'Saturday, 01 January 2011, 10:00 AM'
2156             ),
2157             array(
2158                 'tz' => -12,
2159                 'str' => '%A, %d %B %Y, %I:%M %p',
2160                 'expected' => 'Saturday, 01 January 2011, 10:00 AM'
2161             ),
2162             // Following tests pass on Windows only because en lang pack does
2163             // not contain localewincharset, in real life lang pack maintainers
2164             // may use only characters that are present in localewincharset
2165             // in format strings!
2166             array(
2167                 'tz' => 99,
2168                 'str' => 'Žluťoučký koníček %A',
2169                 'expected' => 'Žluťoučký koníček Saturday'
2170             ),
2171             array(
2172                 'tz' => 99,
2173                 'str' => '言語設定言語 %A',
2174                 'expected' => '言語設定言語 Saturday'
2175             ),
2176             array(
2177                 'tz' => 99,
2178                 'str' => '简体中文简体 %A',
2179                 'expected' => '简体中文简体 Saturday'
2180             ),
2181         );
2183         // Note: date_format_string() uses the timezone only to differenciate
2184         // the server time from the UTC time. It does not modify the timestamp.
2185         // Hence similar results for timezones <= 13.
2186         // On different systems case of AM PM changes so compare case insensitive.
2187         foreach ($tests as $test) {
2188             $str = date_format_string(1293876000, $test['str'], $test['tz']);
2189             $this->assertEquals(textlib::strtolower($test['expected']), textlib::strtolower($str));
2190         }
2192         // Restore system default values.
2193         date_default_timezone_set($systemdefaulttimezone);
2194         setlocale(LC_TIME, $oldlocale);
2195     }
2197     public function test_get_config() {
2198         global $CFG;
2200         $this->resetAfterTest();
2202         // Preparation.
2203         set_config('phpunit_test_get_config_1', 'test 1');
2204         set_config('phpunit_test_get_config_2', 'test 2', 'mod_forum');
2205         if (!is_array($CFG->config_php_settings)) {
2206             $CFG->config_php_settings = array();
2207         }
2208         $CFG->config_php_settings['phpunit_test_get_config_3'] = 'test 3';
2210         if (!is_array($CFG->forced_plugin_settings)) {
2211             $CFG->forced_plugin_settings = array();
2212         }
2213         if (!array_key_exists('mod_forum', $CFG->forced_plugin_settings)) {
2214             $CFG->forced_plugin_settings['mod_forum'] = array();
2215         }
2216         $CFG->forced_plugin_settings['mod_forum']['phpunit_test_get_config_4'] = 'test 4';
2217         $CFG->phpunit_test_get_config_5 = 'test 5';
2219         // Testing.
2220         $this->assertEquals('test 1', get_config('core', 'phpunit_test_get_config_1'));
2221         $this->assertEquals('test 2', get_config('mod_forum', 'phpunit_test_get_config_2'));
2222         $this->assertEquals('test 3', get_config('core', 'phpunit_test_get_config_3'));
2223         $this->assertEquals('test 4', get_config('mod_forum', 'phpunit_test_get_config_4'));
2224         $this->assertFalse(get_config('core', 'phpunit_test_get_config_5'));
2225         $this->assertFalse(get_config('core', 'phpunit_test_get_config_x'));
2226         $this->assertFalse(get_config('mod_forum', 'phpunit_test_get_config_x'));
2228         // Test config we know to exist.
2229         $this->assertEquals($CFG->dataroot, get_config('core', 'dataroot'));
2230         $this->assertEquals($CFG->phpunit_dataroot, get_config('core', 'phpunit_dataroot'));
2231         $this->assertEquals($CFG->dataroot, get_config('core', 'phpunit_dataroot'));
2232         $this->assertEquals(get_config('core', 'dataroot'), get_config('core', 'phpunit_dataroot'));
2234         // Test setting a config var that already exists.
2235         set_config('phpunit_test_get_config_1', 'test a');
2236         $this->assertEquals('test a', $CFG->phpunit_test_get_config_1);
2237         $this->assertEquals('test a', get_config('core', 'phpunit_test_get_config_1'));
2239         // Test cache invalidation.
2240         $cache = cache::make('core', 'config');
2241         $this->assertInternalType('array', $cache->get('core'));
2242         $this->assertInternalType('array', $cache->get('mod_forum'));
2243         set_config('phpunit_test_get_config_1', 'test b');
2244         $this->assertFalse($cache->get('core'));
2245         set_config('phpunit_test_get_config_4', 'test c', 'mod_forum');
2246         $this->assertFalse($cache->get('mod_forum'));
2247     }