commit | author | age
|
c83b83
|
1 |
<?php |
AM |
2 |
|
|
3 |
/** |
|
4 |
* Test class to test rcube_utils class |
|
5 |
* |
|
6 |
* @package Tests |
|
7 |
*/ |
9b05f1
|
8 |
class Framework_Utils extends PHPUnit_Framework_TestCase |
c83b83
|
9 |
{ |
AM |
10 |
|
|
11 |
/** |
|
12 |
* Valid email addresses for test_valid_email() |
|
13 |
*/ |
|
14 |
function data_valid_email() |
|
15 |
{ |
|
16 |
return array( |
|
17 |
array('email@domain.com', 'Valid email'), |
|
18 |
array('firstname.lastname@domain.com', 'Email contains dot in the address field'), |
|
19 |
array('email@subdomain.domain.com', 'Email contains dot with subdomain'), |
|
20 |
array('firstname+lastname@domain.com', 'Plus sign is considered valid character'), |
da2812
|
21 |
array('email@[123.123.123.123]', 'Square bracket around IP address'), |
AM |
22 |
array('email@[IPv6:::1]', 'Square bracket around IPv6 address (1)'), |
|
23 |
array('email@[IPv6:::1.2.3.4]', 'Square bracket around IPv6 address (2)'), |
|
24 |
array('email@[IPv6:2001:2d12:c4fe:5afe::1]', 'Square bracket around IPv6 address (3)'), |
c83b83
|
25 |
array('"email"@domain.com', 'Quotes around email is considered valid'), |
AM |
26 |
array('1234567890@domain.com', 'Digits in address are valid'), |
|
27 |
array('email@domain-one.com', 'Dash in domain name is valid'), |
|
28 |
array('_______@domain.com', 'Underscore in the address field is valid'), |
|
29 |
array('email@domain.name', '.name is valid Top Level Domain name'), |
|
30 |
array('email@domain.co.jp', 'Dot in Top Level Domain name also considered valid (use co.jp as example here)'), |
|
31 |
array('firstname-lastname@domain.com', 'Dash in address field is valid'), |
848e20
|
32 |
array('test@xn--e1aaa0cbbbcacac.xn--p1ai', 'IDNA domain'), |
c83b83
|
33 |
); |
AM |
34 |
} |
|
35 |
|
|
36 |
/** |
|
37 |
* Invalid email addresses for test_invalid_email() |
|
38 |
*/ |
|
39 |
function data_invalid_email() |
|
40 |
{ |
|
41 |
return array( |
|
42 |
array('plainaddress', 'Missing @ sign and domain'), |
|
43 |
array('#@%^%#$@#$@#.com', 'Garbage'), |
|
44 |
array('@domain.com', 'Missing username'), |
|
45 |
array('Joe Smith <email@domain.com>', 'Encoded html within email is invalid'), |
|
46 |
array('email.domain.com', 'Missing @'), |
|
47 |
array('email@domain@domain.com', 'Two @ sign'), |
|
48 |
array('.email@domain.com', 'Leading dot in address is not allowed'), |
|
49 |
array('email.@domain.com', 'Trailing dot in address is not allowed'), |
|
50 |
array('email..email@domain.com', 'Multiple dots'), |
|
51 |
array('あいうえお@domain.com', 'Unicode char as address'), |
|
52 |
array('email@domain.com (Joe Smith)', 'Text followed email is not allowed'), |
|
53 |
array('email@domain', 'Missing top level domain (.com/.net/.org/etc)'), |
|
54 |
array('email@-domain.com', 'Leading dash in front of domain is invalid'), |
|
55 |
// array('email@domain.web', '.web is not a valid top level domain'), |
da2812
|
56 |
array('email@123.123.123.123', 'IP address without brackets'), |
AM |
57 |
array('email@2001:2d12:c4fe:5afe::1', 'IPv6 address without brackets'), |
|
58 |
array('email@IPv6:2001:2d12:c4fe:5afe::1', 'IPv6 address without brackets (2)'), |
|
59 |
array('email@[111.222.333.44444]', 'Invalid IP format'), |
|
60 |
array('email@[111.222.255.257]', 'Invalid IP format (2)'), |
|
61 |
array('email@[.222.255.257]', 'Invalid IP format (3)'), |
|
62 |
array('email@[::1]', 'Invalid IPv6 format (1)'), |
|
63 |
array('email@[IPv6:2001:23x2:1]', 'Invalid IPv6 format (2)'), |
|
64 |
array('email@[IPv6:1111:2222:33333::4444:5555]', 'Invalid IPv6 format (3)'), |
|
65 |
array('email@[IPv6:1111::3333::4444:5555]', 'Invalid IPv6 format (4)'), |
c83b83
|
66 |
array('email@domain..com', 'Multiple dot in the domain portion is invalid'), |
AM |
67 |
); |
|
68 |
} |
|
69 |
|
|
70 |
/** |
|
71 |
* @dataProvider data_valid_email |
|
72 |
*/ |
|
73 |
function test_valid_email($email, $title) |
|
74 |
{ |
|
75 |
$this->assertTrue(rcube_utils::check_email($email, false), $title); |
|
76 |
} |
|
77 |
|
|
78 |
/** |
|
79 |
* @dataProvider data_invalid_email |
|
80 |
*/ |
|
81 |
function test_invalid_email($email, $title) |
|
82 |
{ |
|
83 |
$this->assertFalse(rcube_utils::check_email($email, false), $title); |
|
84 |
} |
|
85 |
|
9b05f1
|
86 |
/** |
a65ce5
|
87 |
* Valid IP addresses for test_valid_ip() |
AM |
88 |
*/ |
|
89 |
function data_valid_ip() |
|
90 |
{ |
|
91 |
return array( |
|
92 |
array('0.0.0.0'), |
|
93 |
array('123.123.123.123'), |
|
94 |
array('::'), |
|
95 |
array('::1'), |
|
96 |
array('::1.2.3.4'), |
|
97 |
array('2001:2d12:c4fe:5afe::1'), |
|
98 |
); |
|
99 |
} |
|
100 |
|
|
101 |
/** |
|
102 |
* Valid IP addresses for test_invalid_ip() |
|
103 |
*/ |
|
104 |
function data_invalid_ip() |
|
105 |
{ |
|
106 |
return array( |
|
107 |
array(''), |
|
108 |
array(0), |
|
109 |
array('123.123.123.1234'), |
|
110 |
array('1.1.1.1.1'), |
|
111 |
array('::1.2.3.260'), |
|
112 |
array('::1.0'), |
|
113 |
array('2001::c4fe:5afe::1'), |
|
114 |
); |
|
115 |
} |
|
116 |
|
|
117 |
/** |
|
118 |
* @dataProvider data_valid_ip |
|
119 |
*/ |
|
120 |
function test_valid_ip($ip) |
|
121 |
{ |
|
122 |
$this->assertTrue(rcube_utils::check_ip($ip)); |
|
123 |
} |
|
124 |
|
|
125 |
/** |
|
126 |
* @dataProvider data_invalid_ip |
|
127 |
*/ |
|
128 |
function test_invalid_ip($ip) |
|
129 |
{ |
|
130 |
$this->assertFalse(rcube_utils::check_ip($ip)); |
|
131 |
} |
|
132 |
|
|
133 |
/** |
5f8097
|
134 |
* Data for test_rep_specialchars_output() |
AM |
135 |
*/ |
|
136 |
function data_rep_specialchars_output() |
|
137 |
{ |
|
138 |
return array( |
|
139 |
array('', '', 'abc', 'abc'), |
|
140 |
array('', '', '?', '?'), |
|
141 |
array('', '', '"', '"'), |
|
142 |
array('', '', '<', '<'), |
|
143 |
array('', '', '>', '>'), |
|
144 |
array('', '', '&', '&'), |
|
145 |
array('', '', '&', '&amp;'), |
|
146 |
array('', '', '<a>', '<a>'), |
|
147 |
array('', 'remove', '<a>', ''), |
|
148 |
); |
|
149 |
} |
|
150 |
|
|
151 |
/** |
|
152 |
* Test for rep_specialchars_output |
|
153 |
* @dataProvider data_rep_specialchars_output |
|
154 |
*/ |
|
155 |
function test_rep_specialchars_output($type, $mode, $str, $res) |
|
156 |
{ |
|
157 |
$result = rcube_utils::rep_specialchars_output( |
|
158 |
$str, $type ? $type : 'html', $mode ? $mode : 'strict'); |
|
159 |
|
|
160 |
$this->assertEquals($result, $res); |
|
161 |
} |
|
162 |
|
|
163 |
/** |
9b05f1
|
164 |
* rcube_utils::mod_css_styles() |
AM |
165 |
*/ |
|
166 |
function test_mod_css_styles() |
|
167 |
{ |
|
168 |
$css = file_get_contents(TESTS_DIR . 'src/valid.css'); |
|
169 |
$mod = rcube_utils::mod_css_styles($css, 'rcmbody'); |
|
170 |
|
|
171 |
$this->assertRegExp('/#rcmbody\s+\{/', $mod, "Replace body style definition"); |
|
172 |
$this->assertRegExp('/#rcmbody h1\s\{/', $mod, "Prefix tag styles (single)"); |
|
173 |
$this->assertRegExp('/#rcmbody h1, #rcmbody h2, #rcmbody h3, #rcmbody textarea\s+\{/', $mod, "Prefix tag styles (multiple)"); |
|
174 |
$this->assertRegExp('/#rcmbody \.noscript\s+\{/', $mod, "Prefix class styles"); |
fdb30f
|
175 |
|
TB |
176 |
$css = file_get_contents(TESTS_DIR . 'src/media.css'); |
|
177 |
$mod = rcube_utils::mod_css_styles($css, 'rcmbody'); |
|
178 |
|
|
179 |
$this->assertContains('#rcmbody table[class=w600]', $mod, 'Replace styles nested in @media block'); |
|
180 |
$this->assertContains('#rcmbody {width:600px', $mod, 'Replace body selector nested in @media block'); |
9b05f1
|
181 |
} |
AM |
182 |
|
|
183 |
/** |
|
184 |
* rcube_utils::mod_css_styles() |
|
185 |
*/ |
|
186 |
function test_mod_css_styles_xss() |
|
187 |
{ |
|
188 |
$mod = rcube_utils::mod_css_styles("body.main2cols { background-image: url('../images/leftcol.png'); }", 'rcmbody'); |
|
189 |
$this->assertEquals("/* evil! */", $mod, "No url() values allowed"); |
|
190 |
|
|
191 |
$mod = rcube_utils::mod_css_styles("@import url('http://localhost/somestuff/css/master.css');", 'rcmbody'); |
|
192 |
$this->assertEquals("/* evil! */", $mod, "No import statements"); |
|
193 |
|
|
194 |
$mod = rcube_utils::mod_css_styles("left:expression(document.body.offsetWidth-20)", 'rcmbody'); |
|
195 |
$this->assertEquals("/* evil! */", $mod, "No expression properties"); |
|
196 |
|
|
197 |
$mod = rcube_utils::mod_css_styles("left:exp/* */ression( alert('xss3') )", 'rcmbody'); |
|
198 |
$this->assertEquals("/* evil! */", $mod, "Don't allow encoding quirks"); |
|
199 |
|
|
200 |
$mod = rcube_utils::mod_css_styles("background:\\0075\\0072\\006c( javascript:alert('xss') )", 'rcmbody'); |
|
201 |
$this->assertEquals("/* evil! */", $mod, "Don't allow encoding quirks (2)"); |
|
202 |
} |
3a54cc
|
203 |
|
AM |
204 |
/** |
5383ad
|
205 |
* Check rcube_utils::explode_quoted_string() |
AM |
206 |
*/ |
|
207 |
function test_explode_quoted_string() |
|
208 |
{ |
|
209 |
$data = array( |
|
210 |
'"a,b"' => array('"a,b"'), |
|
211 |
'"a,b","c,d"' => array('"a,b"','"c,d"'), |
|
212 |
'"a,\\"b",d' => array('"a,\\"b"', 'd'), |
|
213 |
); |
|
214 |
|
|
215 |
foreach ($data as $text => $res) { |
|
216 |
$result = rcube_utils::explode_quoted_string(',', $text); |
|
217 |
$this->assertSame($res, $result); |
|
218 |
} |
|
219 |
} |
|
220 |
|
|
221 |
/** |
3a54cc
|
222 |
* Check rcube_utils::explode_quoted_string() compat. with explode() |
AM |
223 |
*/ |
|
224 |
function test_explode_quoted_string_compat() |
|
225 |
{ |
|
226 |
$data = array('', 'a,b,c', 'a', ',', ',a'); |
|
227 |
|
|
228 |
foreach ($data as $text) { |
|
229 |
$result = rcube_utils::explode_quoted_string(',', $text); |
|
230 |
$this->assertSame(explode(',', $text), $result); |
|
231 |
} |
|
232 |
} |
0c82e9
|
233 |
|
AM |
234 |
/** |
|
235 |
* rcube_utils::get_boolean() |
|
236 |
*/ |
|
237 |
function test_get_boolean() |
|
238 |
{ |
|
239 |
$input = array( |
|
240 |
false, 'false', '0', 'no', 'off', 'nein', 'FALSE', '', null, |
|
241 |
); |
|
242 |
|
|
243 |
foreach ($input as $idx => $value) { |
11eb07
|
244 |
$this->assertFalse(rcube_utils::get_boolean($value), "Invalid result for $idx test item"); |
0c82e9
|
245 |
} |
AM |
246 |
|
|
247 |
$input = array( |
|
248 |
true, 'true', '1', 1, 'yes', 'anything', 1000, |
|
249 |
); |
|
250 |
|
|
251 |
foreach ($input as $idx => $value) { |
11eb07
|
252 |
$this->assertTrue(rcube_utils::get_boolean($value), "Invalid result for $idx test item"); |
0c82e9
|
253 |
} |
AM |
254 |
} |
|
255 |
|
fe0f1d
|
256 |
/** |
AM |
257 |
* rcube:utils::file2class() |
|
258 |
*/ |
|
259 |
function test_file2class() |
|
260 |
{ |
|
261 |
$test = array( |
|
262 |
array('', '', 'unknown'), |
|
263 |
array('text', 'text', 'text'), |
|
264 |
array('image/png', 'image.png', 'image png'), |
|
265 |
); |
|
266 |
|
|
267 |
foreach ($test as $v) { |
|
268 |
$result = rcube_utils::file2class($v[0], $v[1]); |
|
269 |
$this->assertSame($v[2], $result); |
|
270 |
} |
|
271 |
} |
896e2b
|
272 |
|
AM |
273 |
/** |
|
274 |
* rcube:utils::strtotime() |
|
275 |
*/ |
|
276 |
function test_strtotime() |
|
277 |
{ |
04e767
|
278 |
// this test depends on system timezone if not set |
AM |
279 |
date_default_timezone_set('UTC'); |
|
280 |
|
896e2b
|
281 |
$test = array( |
AM |
282 |
'1' => 1, |
|
283 |
'' => 0, |
09c58d
|
284 |
'abc-555' => 0, |
04e767
|
285 |
'2013-04-22' => 1366588800, |
AM |
286 |
'2013/04/22' => 1366588800, |
|
287 |
'2013.04.22' => 1366588800, |
|
288 |
'22-04-2013' => 1366588800, |
|
289 |
'22/04/2013' => 1366588800, |
|
290 |
'22.04.2013' => 1366588800, |
|
291 |
'22.4.2013' => 1366588800, |
|
292 |
'20130422' => 1366588800, |
09c58d
|
293 |
'2013/06/21 12:00:00 UTC' => 1371816000, |
TB |
294 |
'2013/06/21 12:00:00 Europe/Berlin' => 1371808800, |
896e2b
|
295 |
); |
AM |
296 |
|
|
297 |
foreach ($test as $datetime => $ts) { |
|
298 |
$result = rcube_utils::strtotime($datetime); |
b32fab
|
299 |
$this->assertSame($ts, $result, "Error parsing date: $datetime"); |
896e2b
|
300 |
} |
AM |
301 |
} |
|
302 |
|
|
303 |
/** |
b1f3c3
|
304 |
* rcube:utils::anytodatetime() |
AM |
305 |
*/ |
|
306 |
function test_anytodatetime() |
|
307 |
{ |
|
308 |
$test = array( |
|
309 |
'2013-04-22' => '2013-04-22', |
|
310 |
'2013/04/22' => '2013-04-22', |
|
311 |
'2013.04.22' => '2013-04-22', |
|
312 |
'22-04-2013' => '2013-04-22', |
|
313 |
'22/04/2013' => '2013-04-22', |
|
314 |
'22.04.2013' => '2013-04-22', |
|
315 |
'04/22/2013' => '2013-04-22', |
|
316 |
'22.4.2013' => '2013-04-22', |
|
317 |
'20130422' => '2013-04-22', |
|
318 |
'1900-10-10' => '1900-10-10', |
|
319 |
'01-01-1900' => '1900-01-01', |
|
320 |
'01/30/1960' => '1960-01-30' |
|
321 |
); |
|
322 |
|
|
323 |
foreach ($test as $datetime => $ts) { |
|
324 |
$result = rcube_utils::anytodatetime($datetime); |
09c58d
|
325 |
$this->assertSame($ts, $result ? $result->format('Y-m-d') : false, "Error parsing date: $datetime"); |
TB |
326 |
} |
|
327 |
} |
|
328 |
|
|
329 |
/** |
|
330 |
* rcube:utils::anytodatetime() |
|
331 |
*/ |
|
332 |
function test_anytodatetime_timezone() |
|
333 |
{ |
|
334 |
$tz = new DateTimeZone('Europe/Helsinki'); |
|
335 |
$test = array( |
|
336 |
'Jan 1st 2014 +0800' => '2013-12-31 18:00', // result in target timezone |
|
337 |
'Jan 1st 14 45:42' => '2014-01-01 00:00', // force fallback to rcube_utils::strtotime() |
|
338 |
'Jan 1st 2014 UK' => '2014-01-01 00:00', |
|
339 |
'Invalid date' => false, |
|
340 |
); |
|
341 |
|
|
342 |
foreach ($test as $datetime => $ts) { |
|
343 |
$result = rcube_utils::anytodatetime($datetime, $tz); |
|
344 |
if ($result) $result->setTimezone($tz); // move to target timezone for comparison |
|
345 |
$this->assertSame($ts, $result ? $result->format('Y-m-d H:i') : false, "Error parsing date: $datetime"); |
b1f3c3
|
346 |
} |
AM |
347 |
} |
|
348 |
|
|
349 |
/** |
e8b82c
|
350 |
* rcube:utils::tokenize_string() |
TB |
351 |
*/ |
|
352 |
function test_tokenize_string() |
|
353 |
{ |
|
354 |
$test = array( |
|
355 |
'' => array(), |
|
356 |
'abc d' => array('abc'), |
|
357 |
'abc de' => array('abc','de'), |
|
358 |
'äàé;êöü-xyz' => array('äàé','êöü','xyz'), |
|
359 |
'日期格式' => array('日期格式'), |
|
360 |
); |
|
361 |
|
|
362 |
foreach ($test as $input => $output) { |
|
363 |
$result = rcube_utils::tokenize_string($input); |
|
364 |
$this->assertSame($output, $result); |
|
365 |
} |
|
366 |
} |
|
367 |
|
|
368 |
/** |
517c9f
|
369 |
* rcube:utils::normalize_string() |
896e2b
|
370 |
*/ |
AM |
371 |
function test_normalize_string() |
|
372 |
{ |
|
373 |
$test = array( |
d92158
|
374 |
'' => '', |
896e2b
|
375 |
'abc def' => 'abc def', |
49dad5
|
376 |
'ÇçäâàåæéêëèïîìÅÉöôòüûùÿøØáíóúñÑÁÂÀãÃÊËÈÍÎÏÓÔõÕÚÛÙýÝ' => 'ccaaaaaeeeeiiiaeooouuuyooaiounnaaaaaeeeiiioooouuuyy', |
AM |
377 |
'ąáâäćçčéęëěíîłľĺńňóôöŕřśšşťţůúűüźžżýĄŚŻŹĆ' => 'aaaaccceeeeiilllnnooorrsssttuuuuzzzyaszzc', |
e8b82c
|
378 |
'ßs' => 'sss', |
TB |
379 |
'Xae' => 'xa', |
|
380 |
'Xoe' => 'xo', |
|
381 |
'Xue' => 'xu', |
|
382 |
'项目' => '项目', |
896e2b
|
383 |
); |
AM |
384 |
|
884070
|
385 |
// this test fails on PHP 5.3.3 |
AM |
386 |
if (PHP_VERSION_ID > 50303) { |
|
387 |
$test['ß'] = ''; |
|
388 |
$test['日'] = ''; |
|
389 |
} |
|
390 |
|
896e2b
|
391 |
foreach ($test as $input => $output) { |
AM |
392 |
$result = rcube_utils::normalize_string($input); |
e8b82c
|
393 |
$this->assertSame($output, $result, "Error normalizing '$input'"); |
896e2b
|
394 |
} |
AM |
395 |
} |
517c9f
|
396 |
|
AM |
397 |
/** |
5143c4
|
398 |
* rcube:utils::words_match() |
AM |
399 |
*/ |
|
400 |
function test_words_match() |
|
401 |
{ |
|
402 |
$test = array( |
|
403 |
array('', 'test', false), |
|
404 |
array('test', 'test', true), |
|
405 |
array('test', 'none', false), |
|
406 |
array('test', 'test xyz', false), |
|
407 |
array('test xyz', 'test xyz', true), |
|
408 |
array('this is test', 'test', true), |
|
409 |
// try some binary content |
|
410 |
array('this is test ' . base64_decode('R0lGODlhDwAPAIAAAMDAwAAAACH5BAEAAAAALAAAAAAPAA8AQAINhI+py+0Po5y02otnAQA7'), 'test', true), |
|
411 |
array('this is test ' . base64_decode('R0lGODlhDwAPAIAAAMDAwAAAACH5BAEAAAAALAAAAAAPAA8AQAINhI+py+0Po5y02otnAQA7'), 'none', false), |
|
412 |
); |
|
413 |
|
|
414 |
foreach ($test as $idx => $params) { |
|
415 |
$result = rcube_utils::words_match($params[0], $params[1]); |
|
416 |
$this->assertSame($params[2], $result, "words_match() at index $idx"); |
|
417 |
} |
|
418 |
} |
|
419 |
|
|
420 |
/** |
517c9f
|
421 |
* rcube:utils::is_absolute_path() |
AM |
422 |
*/ |
|
423 |
function test_is_absolute_path() |
|
424 |
{ |
|
425 |
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { |
|
426 |
$test = array( |
|
427 |
'' => false, |
|
428 |
"C:\\" => true, |
|
429 |
'some/path' => false, |
|
430 |
); |
|
431 |
} |
|
432 |
else { |
|
433 |
$test = array( |
|
434 |
'' => false, |
|
435 |
'/path' => true, |
|
436 |
'some/path' => false, |
|
437 |
); |
|
438 |
} |
|
439 |
|
|
440 |
foreach ($test as $input => $output) { |
|
441 |
$result = rcube_utils::is_absolute_path($input); |
|
442 |
$this->assertSame($output, $result); |
|
443 |
} |
|
444 |
} |
5529d9
|
445 |
|
AM |
446 |
/** |
|
447 |
* rcube:utils::random_bytes() |
|
448 |
*/ |
|
449 |
function test_random_bytes() |
|
450 |
{ |
|
451 |
$this->assertSame(15, strlen(rcube_utils::random_bytes(15))); |
|
452 |
$this->assertSame(1, strlen(rcube_utils::random_bytes(1))); |
|
453 |
$this->assertSame(0, strlen(rcube_utils::random_bytes(0))); |
|
454 |
$this->assertSame(0, strlen(rcube_utils::random_bytes(-1))); |
|
455 |
} |
c83b83
|
456 |
} |