[SECURITY] t3lib_div::quoteJSvalue allows XSS
[Packages/TYPO3.CMS.git] / tests / Unit / t3lib / class.t3lib_divTest.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009-2011 Ingo Renner <ingo@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * Testcase for class t3lib_div
27 *
28 * @author Ingo Renner <ingo@typo3.org>
29 * @author Oliver Klee <typo3-coding@oliverklee.de>
30 *
31 * @package TYPO3
32 * @subpackage t3lib
33 */
34 class t3lib_divTest extends tx_phpunit_testcase {
35
36 /**
37 * Enable backup of global and system variables
38 *
39 * @var boolean
40 */
41 protected $backupGlobals = TRUE;
42
43 /**
44 * Exclude TYPO3_DB from backup/ restore of $GLOBALS
45 * because resource types cannot be handled during serializing
46 *
47 * @var array
48 */
49 protected $backupGlobalsBlacklist = array('TYPO3_DB');
50
51 public function tearDown() {
52 t3lib_div::purgeInstances();
53 }
54
55 ///////////////////////////
56 // Tests concerning _GP
57 ///////////////////////////
58
59 /**
60 * @test
61 * @dataProvider gpDataProvider
62 */
63 public function canRetrieveValueWithGP($key, $get, $post, $expected) {
64 $_GET = $get;
65 $_POST = $post;
66 $this->assertSame($expected, t3lib_div::_GP($key));
67 }
68
69 /**
70 * Data provider for canRetrieveValueWithGP.
71 * All test values also check whether slashes are stripped properly.
72 *
73 * @return array
74 */
75 public function gpDataProvider() {
76 return array(
77 'No key parameter'
78 => array(NULL, array(), array(), NULL),
79 'Key not found'
80 => array('cake', array(), array(), NULL),
81 'Value only in GET'
82 => array('cake', array('cake' => 'li\\e'), array(), 'lie'),
83 'Value only in POST'
84 => array('cake', array(), array('cake' => 'l\\ie'), 'lie'),
85 'Value from POST preferred over GET'
86 => array('cake', array('cake' => 'is a'), array('cake' => '\\lie'), 'lie'),
87 'Value can be an array'
88 => array(
89 'cake',
90 array('cake' => array('is a' => 'l\\ie')),
91 array(),
92 array('is a' => 'lie')
93 ),
94 );
95 }
96
97 ///////////////////////////
98 // Tests concerning _GPmerged
99 ///////////////////////////
100
101 /**
102 * @test
103 * @dataProvider gpMergedDataProvider
104 */
105 public function gpMergedWillMergeArraysFromGetAndPost($get, $post, $expected) {
106 $_POST = $post;
107 $_GET = $get;
108 $this->assertEquals($expected, t3lib_div::_GPmerged('cake'));
109 }
110
111 /**
112 * Data provider for gpMergedWillMergeArraysFromGetAndPost
113 *
114 * @return array
115 */
116 public function gpMergedDataProvider() {
117 $fullDataArray = array('cake' => array('a' => 'is a','b' => 'lie'));
118 $postPartData = array('cake' => array('b' => 'lie'));
119 $getPartData = array('cake' => array('a' => 'is a'));
120 $getPartDataModified = array('cake' => array('a' => 'is not a'));
121 return array(
122 'Key doesn\' exist'
123 => array(array('foo'), array('bar'), array()),
124 'No POST data'
125 => array($fullDataArray, array(), $fullDataArray['cake']),
126 'No GET data'
127 => array(array(), $fullDataArray, $fullDataArray['cake']),
128 'POST and GET are merged'
129 => array($getPartData, $postPartData, $fullDataArray['cake']),
130 'POST is preferred over GET'
131 => array($getPartDataModified, $fullDataArray, $fullDataArray['cake'])
132 );
133 }
134
135 ///////////////////////////////
136 // Tests concerning _GET / _POST
137 ///////////////////////////////
138
139 /**
140 * Data provider for canRetrieveGlobalInputsThroughGet
141 * and canRetrieveGlobalInputsThroughPost
142 *
143 * @return array
144 */
145 public function getAndPostDataProvider() {
146 return array(
147 'Requested input data doesn\'t exist'
148 => array('cake', array(), NULL),
149 'No key will return entire input data'
150 => array(NULL, array('cake' => 'l\\ie'), array('cake' => 'lie')),
151 'Can retrieve specific input'
152 => array('cake', array('cake' => 'li\\e', 'foo'), 'lie'),
153 'Can retrieve nested input data'
154 => array('cake', array('cake' => array('is a' => 'l\\ie')), array('is a' => 'lie'))
155 );
156 }
157
158 /**
159 * @test
160 * @dataProvider getAndPostDataProvider
161 */
162 public function canRetrieveGlobalInputsThroughGet($key, $get, $expected) {
163 $_GET = $get;
164 $this->assertSame($expected, t3lib_div::_GET($key));
165 }
166
167 /**
168 * @test
169 * @dataProvider getAndPostDataProvider
170 */
171 public function canRetrieveGlobalInputsThroughPost($key, $post, $expected) {
172 $_POST = $post;
173 $this->assertSame($expected, t3lib_div::_POST($key));
174 }
175
176 ///////////////////////////////
177 // Tests concerning _GETset
178 ///////////////////////////////
179
180 /**
181 * @test
182 * @dataProvider getSetDataProvider
183 */
184 public function canSetNewGetInputValues($input, $key, $expected, $getPreset=array()) {
185 $_GET = $getPreset;
186 t3lib_div::_GETset($input, $key);
187 $this->assertSame($expected, $_GET);
188 }
189
190 /**
191 * Data provider for canSetNewGetInputValues
192 *
193 * @return array
194 */
195 public function getSetDataProvider() {
196 return array(
197 'No input data used without target key'
198 => array(NULL, NULL, array()),
199 'No input data used with target key'
200 => array(NULL, 'cake', array('cake' => '')),
201 'No target key used with string input data'
202 => array('data', NULL, array()),
203 'No target key used with array input data'
204 => array(array('cake' => 'lie'), NULL, array('cake' => 'lie')),
205 'Target key and string input data'
206 => array('lie', 'cake', array('cake' => 'lie')),
207 'Replace existing GET data'
208 => array('lie', 'cake', array('cake' => 'lie'), array('cake' => 'is a lie')),
209 'Target key pointing to sublevels and string input data'
210 => array('lie', 'cake|is', array('cake' => array('is' => 'lie'))),
211 'Target key pointing to sublevels and array input data'
212 => array(array('a' => 'lie'), 'cake|is', array('cake' => array('is' => array('a' => 'lie'))))
213 );
214 }
215
216 ///////////////////////////////
217 // Tests concerning gif_compress
218 ///////////////////////////////
219
220 /**
221 * @test
222 */
223 public function gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() {
224 if (TYPO3_OS == 'WIN') {
225 $this->markTestSkipped('gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() test not available on Windows.');
226 }
227
228 if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] || !$GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']) {
229 $this->markTestSkipped('gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() test not available without imagemagick setup.');
230 }
231
232 $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
233 $fixtureGifFile = $testFinder->getAbsoluteCoreTestsPath() . 'Unit/t3lib/fixtures/clear.gif';
234
235 $GLOBALS['TYPO3_CONF_VARS']['GFX']['gif_compress'] = TRUE;
236
237 // Copy file to unique filename in typo3temp, set target permissions and run method
238 $testFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.gif';
239 @copy($fixtureGifFile, $testFilename);
240 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
241 t3lib_div::gif_compress($testFilename, 'IM');
242
243 // Get actual permissions and clean up
244 clearstatcache();
245 $resultFilePermissions = substr(decoct(fileperms($testFilename)), 2);
246 t3lib_div::unlink_tempfile($testFilename);
247
248 $this->assertEquals($resultFilePermissions, '0777');
249 }
250
251 /**
252 * @test
253 */
254 public function gifCompressFixesPermissionOfConvertedFileIfUsingGd() {
255 if (TYPO3_OS == 'WIN') {
256 $this->markTestSkipped('gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() test not available on Windows.');
257 }
258
259 $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
260 $fixtureGifFile = $testFinder->getAbsoluteCoreTestsPath() . 'Unit/t3lib/fixtures/clear.gif';
261
262 $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'] = TRUE;
263 $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] = FALSE;
264
265 $GLOBALS['TYPO3_CONF_VARS']['GFX']['gif_compress'] = TRUE;
266
267 // Copy file to unique filename in typo3temp, set target permissions and run method
268 $testFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.gif';
269 @copy($fixtureGifFile, $testFilename);
270 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
271 t3lib_div::gif_compress($testFilename, 'GD');
272
273 // Get actual permissions and clean up
274 clearstatcache();
275 $resultFilePermissions = substr(decoct(fileperms($testFilename)), 2);
276 t3lib_div::unlink_tempfile($testFilename);
277
278 $this->assertEquals($resultFilePermissions, '0777');
279 }
280
281 ///////////////////////////////
282 // Tests concerning png_to_gif_by_imagemagick
283 ///////////////////////////////
284
285 /**
286 * @test
287 */
288 public function pngToGifByImagemagickFixesPermissionsOfConvertedFile() {
289 if (TYPO3_OS == 'WIN') {
290 $this->markTestSkipped('pngToGifByImagemagickFixesPermissionsOfConvertedFile() test not available on Windows.');
291 }
292
293 if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] || !$GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']) {
294 $this->markTestSkipped('pngToGifByImagemagickFixesPermissionsOfConvertedFile() test not available without imagemagick setup.');
295 }
296
297 $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
298 $fixturePngFile = $testFinder->getAbsoluteCoreTestsPath() . 'Unit/t3lib/fixtures/clear.png';
299
300 $GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif'] = TRUE;
301
302 // Copy file to unique filename in typo3temp, set target permissions and run method
303 $testFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.png';
304 @copy($fixturePngFile, $testFilename);
305 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
306 $newGifFile = t3lib_div::png_to_gif_by_imagemagick($testFilename);
307
308 // Get actual permissions and clean up
309 clearstatcache();
310 $resultFilePermissions = substr(decoct(fileperms($newGifFile)), 2);
311 t3lib_div::unlink_tempfile($newGifFile);
312
313 $this->assertEquals($resultFilePermissions, '0777');
314 }
315
316 ///////////////////////////////
317 // Tests concerning read_png_gif
318 ///////////////////////////////
319
320 /**
321 * @test
322 */
323 public function readPngGifFixesPermissionsOfConvertedFile() {
324 if (TYPO3_OS == 'WIN') {
325 $this->markTestSkipped('readPngGifFixesPermissionsOfConvertedFile() test not available on Windows.');
326 }
327
328 if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
329 $this->markTestSkipped('readPngGifFixesPermissionsOfConvertedFile() test not available without imagemagick setup.');
330 }
331
332 $testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
333 $testGifFile = $testFinder->getAbsoluteCoreTestsPath() . 'Unit/t3lib/fixtures/clear.gif';
334
335 // Set target permissions and run method
336 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
337 $newPngFile = t3lib_div::read_png_gif($testGifFile, TRUE);
338
339 // Get actual permissions and clean up
340 clearstatcache();
341 $resultFilePermissions = substr(decoct(fileperms($newPngFile)), 2);
342 t3lib_div::unlink_tempfile($newPngFile);
343
344 $this->assertEquals($resultFilePermissions, '0777');
345 }
346
347 ///////////////////////////
348 // Tests concerning cmpIPv4
349 ///////////////////////////
350
351 /**
352 * Data provider for cmpIPv4ReturnsTrueForMatchingAddress
353 *
354 * @return array Data sets
355 */
356 public static function cmpIPv4DataProviderMatching() {
357 return array(
358 'host with full IP address' => array('127.0.0.1', '127.0.0.1'),
359 'host with two wildcards at the end' => array('127.0.0.1', '127.0.*.*'),
360 'host with wildcard at third octet' => array('127.0.0.1', '127.0.*.1'),
361 'host with wildcard at second octet' => array('127.0.0.1', '127.*.0.1'),
362 '/8 subnet' => array('127.0.0.1', '127.1.1.1/8'),
363 '/32 subnet (match only name)' => array('127.0.0.1', '127.0.0.1/32'),
364 '/30 subnet' => array('10.10.3.1', '10.10.3.3/30'),
365 'host with wildcard in list with IPv4/IPv6 addresses' => array('192.168.1.1', '127.0.0.1, 1234:5678::/126, 192.168.*'),
366 'host in list with IPv4/IPv6 addresses' => array('192.168.1.1', '::1, 1234:5678::/126, 192.168.1.1'),
367 );
368 }
369
370 /**
371 * @test
372 * @dataProvider cmpIPv4DataProviderMatching
373 */
374 public function cmpIPv4ReturnsTrueForMatchingAddress($ip, $list) {
375 $this->assertTrue(t3lib_div::cmpIPv4($ip, $list));
376 }
377
378 /**
379 * Data provider for cmpIPv4ReturnsFalseForNotMatchingAddress
380 *
381 * @return array Data sets
382 */
383 public static function cmpIPv4DataProviderNotMatching() {
384 return array(
385 'single host' => array('127.0.0.1', '127.0.0.2'),
386 'single host with wildcard' => array('127.0.0.1', '127.*.1.1'),
387 'single host with /32 subnet mask' => array('127.0.0.1', '127.0.0.2/32'),
388 '/31 subnet' => array('127.0.0.1', '127.0.0.2/31'),
389 'list with IPv4/IPv6 addresses' => array('127.0.0.1', '10.0.2.3, 192.168.1.1, ::1'),
390 'list with only IPv6 addresses' => array('10.20.30.40', '::1, 1234:5678::/127'),
391 );
392 }
393
394 /**
395 * @test
396 * @dataProvider cmpIPv4DataProviderNotMatching
397 */
398 public function cmpIPv4ReturnsFalseForNotMatchingAddress($ip, $list) {
399 $this->assertFalse(t3lib_div::cmpIPv4($ip, $list));
400 }
401 ///////////////////////////
402 // Tests concerning cmpIPv6
403 ///////////////////////////
404
405 /**
406 * Data provider for cmpIPv6ReturnsTrueForMatchingAddress
407 *
408 * @return array Data sets
409 */
410 public static function cmpIPv6DataProviderMatching() {
411 return array(
412 'empty address' => array('::', '::'),
413 'empty with netmask in list' => array('::', '::/0'),
414 'empty with netmask 0 and host-bits set in list' => array('::', '::123/0'),
415 'localhost' => array('::1', '::1'),
416 'localhost with leading zero blocks' => array('::1', '0:0::1'),
417 'host with submask /128' => array('::1', '0:0::1/128'),
418 '/16 subnet' => array('1234::1', '1234:5678::/16'),
419 '/126 subnet' => array('1234:5678::3', '1234:5678::/126'),
420 '/126 subnet with host-bits in list set' => array('1234:5678::3', '1234:5678::2/126'),
421 'list with IPv4/IPv6 addresses' => array('1234:5678::3', '::1, 127.0.0.1, 1234:5678::/126, 192.168.1.1'),
422 );
423 }
424
425 /**
426 * @test
427 * @dataProvider cmpIPv6DataProviderMatching
428 */
429 public function cmpIPv6ReturnsTrueForMatchingAddress($ip, $list) {
430 $this->assertTrue(t3lib_div::cmpIPv6($ip, $list));
431 }
432
433 /**
434 * Data provider for cmpIPv6ReturnsFalseForNotMatchingAddress
435 *
436 * @return array Data sets
437 */
438 public static function cmpIPv6DataProviderNotMatching() {
439 return array(
440 'empty against localhost' => array('::', '::1'),
441 'empty against localhost with /128 netmask' => array('::', '::1/128'),
442 'localhost against different host' => array('::1', '::2'),
443 'localhost against host with prior bits set' => array('::1', '::1:1'),
444 'host against different /17 subnet' => array('1234::1', '1234:f678::/17'),
445 'host against different /127 subnet' => array('1234:5678::3', '1234:5678::/127'),
446 'host against IPv4 address list' => array('1234:5678::3', '127.0.0.1, 192.168.1.1'),
447 'host against mixed list with IPv6 host in different subnet' => array('1234:5678::3', '::1, 1234:5678::/127'),
448 );
449 }
450
451 /**
452 * @test
453 * @dataProvider cmpIPv6DataProviderNotMatching
454 */
455 public function cmpIPv6ReturnsFalseForNotMatchingAddress($ip, $list) {
456 $this->assertFalse(t3lib_div::cmpIPv6($ip, $list));
457 }
458
459 ///////////////////////////////
460 // Tests concerning IPv6Hex2Bin
461 ///////////////////////////////
462
463 /**
464 * Data provider for IPv6Hex2BinCorrect
465 *
466 * @return array Data sets
467 */
468 public static function IPv6Hex2BinDataProviderCorrect() {
469 return array(
470 'empty 1' => array('::', str_pad('', 16, "\x00")),
471 'empty 2, already normalized' => array('0000:0000:0000:0000:0000:0000:0000:0000', str_pad('', 16, "\x00")),
472 'already normalized' => array('0102:0304:0000:0000:0000:0000:0506:0078', "\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78"),
473 'expansion in middle 1' => array('1::2', "\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02"),
474 'expansion in middle 2' => array('beef::fefa', "\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa"),
475 );
476 }
477
478 /**
479 * @test
480 * @dataProvider IPv6Hex2BinDataProviderCorrect
481 */
482 public function IPv6Hex2BinCorrectlyConvertsAddresses($hex, $binary) {
483 $this->assertTrue(t3lib_div::IPv6Hex2Bin($hex) === $binary);
484 }
485
486 ///////////////////////////////
487 // Tests concerning IPv6Bin2Hex
488 ///////////////////////////////
489
490 /**
491 * Data provider for IPv6Bin2HexCorrect
492 *
493 * @return array Data sets
494 */
495 public static function IPv6Bin2HexDataProviderCorrect() {
496 return array(
497 'empty' => array(str_pad('', 16, "\x00"), '::'),
498 'non-empty front' => array("\x01" . str_pad('', 15, "\x00"), '100::'),
499 'non-empty back' => array(str_pad('', 15, "\x00") . "\x01", '::1'),
500 'normalized' => array("\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78", '102:304::506:78'),
501 'expansion in middle 1' => array("\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02", '1::2'),
502 'expansion in middle 2' => array("\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa", 'beef::fefa'),
503 );
504 }
505
506 /**
507 * @test
508 * @dataProvider IPv6Bin2HexDataProviderCorrect
509 */
510 public function IPv6Bin2HexCorrectlyConvertsAddresses($binary, $hex) {
511 $this->assertEquals(t3lib_div::IPv6Bin2Hex($binary), $hex);
512 }
513
514 ////////////////////////////////////////////////
515 // Tests concerning normalizeIPv6 / compressIPv6
516 ////////////////////////////////////////////////
517
518 /**
519 * Data provider for normalizeIPv6ReturnsCorrectlyNormalizedFormat
520 *
521 * @return array Data sets
522 */
523 public static function normalizeCompressIPv6DataProviderCorrect() {
524 return array(
525 'empty' => array('::', '0000:0000:0000:0000:0000:0000:0000:0000'),
526 'localhost' => array('::1', '0000:0000:0000:0000:0000:0000:0000:0001'),
527 'some address on right side' => array('::f0f', '0000:0000:0000:0000:0000:0000:0000:0f0f'),
528 'expansion in middle 1' => array('1::2', '0001:0000:0000:0000:0000:0000:0000:0002'),
529 'expansion in middle 2' => array('1:2::3', '0001:0002:0000:0000:0000:0000:0000:0003'),
530 'expansion in middle 3' => array('1::2:3', '0001:0000:0000:0000:0000:0000:0002:0003'),
531 'expansion in middle 4' => array('1:2::3:4:5', '0001:0002:0000:0000:0000:0003:0004:0005'),
532 );
533 }
534
535 /**
536 * @test
537 * @dataProvider normalizeCompressIPv6DataProviderCorrect
538 */
539 public function normalizeIPv6CorrectlyNormalizesAddresses($compressed, $normalized) {
540 $this->assertEquals(t3lib_div::normalizeIPv6($compressed), $normalized);
541 }
542
543 /**
544 * @test
545 * @dataProvider normalizeCompressIPv6DataProviderCorrect
546 */
547 public function compressIPv6CorrectlyCompressesAdresses($compressed, $normalized) {
548 $this->assertEquals(t3lib_div::compressIPv6($normalized), $compressed);
549 }
550
551 ///////////////////////////////
552 // Tests concerning validIP
553 ///////////////////////////////
554
555 /**
556 * Data provider for checkValidIpReturnsTrueForValidIp
557 *
558 * @return array Data sets
559 */
560 public static function validIpDataProvider() {
561 return array(
562 '0.0.0.0' => array('0.0.0.0'),
563 'private IPv4 class C' => array('192.168.0.1'),
564 'private IPv4 class A' => array('10.0.13.1'),
565 'private IPv6' => array('fe80::daa2:5eff:fe8b:7dfb'),
566 );
567 }
568
569 /**
570 * @test
571 * @dataProvider validIpDataProvider
572 */
573 public function validIpReturnsTrueForValidIp($ip) {
574 $this->assertTrue(t3lib_div::validIP($ip));
575 }
576
577 /**
578 * Data provider for checkValidIpReturnsFalseForInvalidIp
579 *
580 * @return array Data sets
581 */
582 public static function invalidIpDataProvider() {
583 return array(
584 'null' => array(NULL),
585 'zero' => array(0),
586 'string' => array('test'),
587 'string empty' => array(''),
588 'string NULL' => array('NULL'),
589 'out of bounds IPv4' => array('300.300.300.300'),
590 'dotted decimal notation with only two dots' => array('127.0.1'),
591 );
592 }
593
594 /**
595 * @test
596 * @dataProvider invalidIpDataProvider
597 */
598 public function validIpReturnsFalseForInvalidIp($ip) {
599 $this->assertFalse(t3lib_div::validIP($ip));
600 }
601
602 ///////////////////////////////
603 // Tests concerning cmpFQDN
604 ///////////////////////////////
605
606 /**
607 * Data provider for cmpFqdnReturnsTrue
608 *
609 * @return array Data sets
610 */
611 public static function cmpFqdnValidDataProvider() {
612 return array(
613 'localhost should usually resolve, IPv4' => array('127.0.0.1', '*'),
614 'localhost should usually resolve, IPv6' => array('::1', '*'),
615 // other testcases with resolving not possible since it would
616 // require a working IPv4/IPv6-connectivity
617 'aaa.bbb.ccc.ddd.eee, full' => array('aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.ddd.eee'),
618 'aaa.bbb.ccc.ddd.eee, wildcard first' => array('aaa.bbb.ccc.ddd.eee', '*.ccc.ddd.eee'),
619 'aaa.bbb.ccc.ddd.eee, wildcard last' => array('aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.*'),
620 'aaa.bbb.ccc.ddd.eee, wildcard middle' => array('aaa.bbb.ccc.ddd.eee', 'aaa.*.eee'),
621 'list-matches, 1' => array('aaa.bbb.ccc.ddd.eee', 'xxx, yyy, zzz, aaa.*.eee'),
622 'list-matches, 2' => array('aaa.bbb.ccc.ddd.eee', '127:0:0:1,,aaa.*.eee,::1'),
623 );
624 }
625
626 /**
627 * @test
628 * @dataProvider cmpFqdnValidDataProvider
629 */
630 public function cmpFqdnReturnsTrue($baseHost, $list) {
631 $this->assertTrue(t3lib_div::cmpFQDN($baseHost, $list));
632 }
633
634 /**
635 * Data provider for cmpFqdnReturnsFalse
636 *
637 * @return array Data sets
638 */
639 public static function cmpFqdnInvalidDataProvider() {
640 return array(
641 'num-parts of hostname to check can only be less or equal than hostname, 1' => array('aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.ddd.eee.fff'),
642 'num-parts of hostname to check can only be less or equal than hostname, 2' => array('aaa.bbb.ccc.ddd.eee', 'aaa.*.bbb.ccc.ddd.eee'),
643 );
644 }
645
646 /**
647 * @test
648 * @dataProvider cmpFqdnInvalidDataProvider
649 */
650 public function cmpFqdnReturnsFalse($baseHost, $list) {
651 $this->assertFalse(t3lib_div::cmpFQDN($baseHost, $list));
652 }
653
654 ///////////////////////////////
655 // Tests concerning inList
656 ///////////////////////////////
657
658 /**
659 * @test
660 *
661 * @param string $haystack
662 *
663 * @dataProvider inListForItemContainedReturnsTrueDataProvider
664 */
665 public function inListForItemContainedReturnsTrue($haystack) {
666 $this->assertTrue(
667 t3lib_div::inList($haystack, 'findme')
668 );
669 }
670
671 /**
672 * Data provider for inListForItemContainedReturnsTrue.
673 *
674 * @return array
675 */
676 public function inListForItemContainedReturnsTrueDataProvider() {
677 return array(
678 'Element as second element of four items' => array('one,findme,three,four'),
679 'Element at beginning of list' => array('findme,one,two'),
680 'Element at end of list' => array('one,two,findme'),
681 'One item list' => array('findme'),
682 );
683 }
684
685 /**
686 * @test
687 *
688 * @param string $haystack
689 *
690 * @dataProvider inListForItemNotContainedReturnsFalseDataProvider
691 */
692 public function inListForItemNotContainedReturnsFalse($haystack) {
693 $this->assertFalse(
694 t3lib_div::inList($haystack, 'findme')
695 );
696 }
697
698 /**
699 * Data provider for inListForItemNotContainedReturnsFalse.
700 *
701 * @return array
702 */
703 public function inListForItemNotContainedReturnsFalseDataProvider() {
704 return array(
705 'Four item list' => array('one,two,three,four'),
706 'One item list' => array('one'),
707 'Empty list' => array(''),
708 );
709 }
710
711 ///////////////////////////////
712 // Tests concerning rmFromList
713 ///////////////////////////////
714
715 /**
716 * @test
717 *
718 * @param string $initialList
719 * @param string $listWithElementRemoved
720 *
721 * @dataProvider rmFromListRemovesElementsFromCommaSeparatedListDataProvider
722 */
723 public function rmFromListRemovesElementsFromCommaSeparatedList($initialList, $listWithElementRemoved) {
724 $this->assertSame(
725 $listWithElementRemoved,
726 t3lib_div::rmFromList('removeme', $initialList)
727 );
728 }
729
730 /**
731 * Data provider for rmFromListRemovesElementsFromCommaSeparatedList
732 *
733 * @return array
734 */
735 public function rmFromListRemovesElementsFromCommaSeparatedListDataProvider() {
736 return array(
737 'Element as second element of three' => array('one,removeme,two', 'one,two'),
738 'Element at beginning of list' => array('removeme,one,two', 'one,two'),
739 'Element at end of list' => array('one,two,removeme', 'one,two'),
740 'One item list' => array('removeme', ''),
741 'Element not contained in list' => array('one,two,three', 'one,two,three'),
742 'Empty list' => array('', ''),
743 );
744 }
745
746 ///////////////////////////////
747 // Tests concerning expandList
748 ///////////////////////////////
749
750 /**
751 * @test
752 *
753 * @param string $list
754 * @param string $expectation
755 *
756 * @dataProvider expandListExpandsIntegerRangesDataProvider
757 */
758 public function expandListExpandsIntegerRanges($list, $expectation) {
759 $this->assertSame(
760 $expectation,
761 t3lib_div::expandList($list)
762 );
763 }
764
765 /**
766 * Data provider for expandListExpandsIntegerRangesDataProvider
767 *
768 * @return array
769 */
770 public function expandListExpandsIntegerRangesDataProvider() {
771 return array(
772 'Expand for the same number' => array('1,2-2,7', '1,2,7'),
773 'Small range expand with parameters reversed ignores reversed items' => array('1,5-3,7', '1,7'),
774 'Small range expand' => array('1,3-5,7', '1,3,4,5,7'),
775 'Expand at beginning' => array('3-5,1,7', '3,4,5,1,7'),
776 'Expand at end' => array('1,7,3-5', '1,7,3,4,5'),
777 'Multiple small range expands' => array('1,3-5,7-10,12', '1,3,4,5,7,8,9,10,12'),
778 'One item list' => array('1-5', '1,2,3,4,5'),
779 'Nothing to expand' => array('1,2,3,4', '1,2,3,4'),
780 'Empty list' => array('', ''),
781 );
782 }
783
784 /**
785 * @test
786 */
787 public function expandListExpandsForTwoThousandElementsExpandsOnlyToThousandElementsMaximum() {
788 $list = t3lib_div::expandList('1-2000');
789
790 $this->assertSame(
791 1000,
792 count(explode(',', $list))
793 );
794 }
795
796 ///////////////////////////////
797 // Tests concerning uniqueList
798 ///////////////////////////////
799
800 /**
801 * @test
802 *
803 * @param string $initialList
804 * @param string $unifiedList
805 *
806 * @dataProvider uniqueListUnifiesCommaSeparatedListDataProvider
807 */
808 public function uniqueListUnifiesCommaSeparatedList($initialList, $unifiedList) {
809 $this->assertSame(
810 $unifiedList,
811 t3lib_div::uniqueList($initialList)
812 );
813 }
814
815 /**
816 * Data provider for uniqueListUnifiesCommaSeparatedList
817 *
818 * @return array
819 */
820 public function uniqueListUnifiesCommaSeparatedListDataProvider() {
821 return array(
822 'List without duplicates' => array('one,two,three', 'one,two,three'),
823 'List with two consecutive duplicates' => array('one,two,two,three,three', 'one,two,three'),
824 'List with non-consecutive duplicates' => array('one,two,three,two,three', 'one,two,three'),
825 'One item list' => array('one', 'one'),
826 'Empty list' => array('', ''),
827 );
828 }
829
830
831 ///////////////////////////////
832 // Tests concerning isFirstPartOfStr
833 ///////////////////////////////
834
835 /**
836 * Data provider for isFirstPartOfStrReturnsTrueForMatchingFirstParts
837 *
838 * @return array
839 */
840 public function isFirstPartOfStrReturnsTrueForMatchingFirstPartDataProvider() {
841 return array(
842 'match first part of string' => array('hello world', 'hello'),
843 'match whole string' => array('hello', 'hello'),
844 'integer is part of string with same number' => array('24', 24),
845 'string is part of integer with same number' => array(24, '24'),
846 'integer is part of string starting with same number' => array('24 beer please', 24),
847 );
848 }
849
850 /**
851 * @test
852 * @dataProvider isFirstPartOfStrReturnsTrueForMatchingFirstPartDataProvider
853 */
854 public function isFirstPartOfStrReturnsTrueForMatchingFirstPart($string, $part) {
855 $this->assertTrue(t3lib_div::isFirstPartOfStr($string, $part));
856 }
857
858 /**
859 * Data provider for checkIsFirstPartOfStrReturnsFalseForNotMatchingFirstParts
860 *
861 * @return array
862 */
863 public function isFirstPartOfStrReturnsFalseForNotMatchingFirstPartDataProvider() {
864 return array(
865 'no string match' => array('hello', 'bye'),
866 'no case sensitive string match' => array('hello world', 'Hello'),
867 'array is not part of string' => array('string', array()),
868 'string is not part of array' => array(array(), 'string'),
869 'NULL is not part of string' => array('string', NULL),
870 'string is not part of array' => array(NULL, 'string'),
871 'NULL is not part of array' => array(array(), NULL),
872 'array is not part of string' => array(NULL, array()),
873 'empty string is not part of empty string' => array('', ''),
874 'NULL is not part of empty string' => array('', NULL),
875 'false is not part of empty string' => array('', FALSE),
876 'empty string is not part of NULL' => array(NULL, ''),
877 'empty string is not part of false' => array(FALSE, ''),
878 'empty string is not part of zero integer' => array(0, ''),
879 'zero integer is not part of NULL' => array(NULL, 0),
880 'zero integer is not part of empty string' => array('', 0),
881 );
882 }
883
884 /**
885 * @test
886 * @dataProvider isFirstPartOfStrReturnsFalseForNotMatchingFirstPartDataProvider
887 */
888 public function isFirstPartOfStrReturnsFalseForNotMatchingFirstPart($string, $part) {
889 $this->assertFalse(t3lib_div::isFirstPartOfStr($string, $part));
890 }
891
892 ///////////////////////////////
893 // Tests concerning formatSize
894 ///////////////////////////////
895
896 /**
897 * @test
898 * @dataProvider formatSizeDataProvider
899 */
900 public function formatSizeTranslatesBytesToHigherOrderRepresentation($size, $label, $expected) {
901 $this->assertEquals($expected, t3lib_div::formatSize($size, $label));
902 }
903
904 /**
905 * Data provider for formatSizeTranslatesBytesToHigherOrderRepresentation
906 *
907 * @return array
908 */
909 public function formatSizeDataProvider() {
910 return array(
911 'Bytes keep beeing bytes (min)' => array(1, '', '1 '),
912 'Bytes keep beeing bytes (max)' => array(899, '', '899 '),
913 'Kilobytes are detected' => array(1024, '', '1.0 K'),
914 'Megabytes are detected' => array(1048576, '', '1.0 M'),
915 'Gigabytes are detected' => array(1073741824, '', '1.0 G'),
916 'Decimal is omitted for large kilobytes' => array(31080, '', '30 K'),
917 'Decimal is omitted for large megabytes' => array(31458000, '', '30 M'),
918 'Decimal is omitted for large gigabytes' => array(32212254720, '', '30 G'),
919 'Label for bytes can be exchanged' => array(1, ' Foo|||', '1 Foo'),
920 'Label for kilobytes can be exchanged' => array(1024, '| Foo||', '1.0 Foo'),
921 'Label for megabyes can be exchanged' => array(1048576, '|| Foo|', '1.0 Foo'),
922 'Label for gigabytes can be exchanged' => array(1073741824, '||| Foo', '1.0 Foo')
923 );
924 }
925
926 ///////////////////////////////
927 // Tests concerning splitCalc
928 ///////////////////////////////
929
930 /**
931 * Data provider for splitCalc
932 *
933 * @return array expected values, arithmetic expression
934 */
935 public function splitCalcDataProvider() {
936 return array(
937 'empty string returns empty array' => array(
938 array(),
939 '',
940 ),
941 'number without operator returns array with plus and number' => array(
942 array(array('+', 42)),
943 '42',
944 ),
945 'two numbers with asterisk return first number with plus and second number with asterisk' => array(
946 array(array('+', 42), array('*', 31)),
947 '42 * 31',
948 ),
949 );
950 }
951
952 /**
953 * @test
954 * @dataProvider splitCalcDataProvider
955 */
956 public function splitCalcCorrectlySplitsExpression($expected, $expression) {
957 $this->assertEquals($expected, t3lib_div::splitCalc($expression, '+-*/'));
958 }
959
960 ///////////////////////////////
961 // Tests concerning htmlspecialchars_decode
962 ///////////////////////////////
963
964 /**
965 * @test
966 */
967 public function htmlspecialcharsDecodeReturnsDecodedString() {
968 $string ='<typo3 version="6.0">&nbsp;</typo3>';
969 $encoded = htmlspecialchars($string);
970 $decoded = t3lib_div::htmlspecialchars_decode($encoded);
971 $this->assertEquals($string, $decoded);
972 }
973
974 ///////////////////////////////
975 // Tests concerning deHSCentities
976 ///////////////////////////////
977
978 /**
979 * @test
980 * @dataProvider deHSCentitiesReturnsDecodedStringDataProvider
981 */
982 public function deHSCentitiesReturnsDecodedString($input, $expected) {
983 $this->assertEquals($expected, t3lib_div::deHSCentities($input));
984 }
985
986 /**
987 * Data provider for deHSCentitiesReturnsDecodedString
988 *
989 * @return array
990 */
991 public function deHSCentitiesReturnsDecodedStringDataProvider() {
992 return array(
993 'Empty string' => array('', ''),
994 'Double encoded &' => array('&amp;amp;', '&amp;'),
995 'Double encoded numeric entity' => array('&amp;#1234;', '&#1234;'),
996 'Double encoded hexadecimal entity' => array('&amp;#x1b;', '&#x1b;'),
997 'Single encoded entities are not touched' => array('&amp; &#1234; &#x1b;', '&amp; &#1234; &#x1b;')
998 );
999 }
1000
1001 //////////////////////////////////
1002 // Tests concerning slashJS
1003 //////////////////////////////////
1004
1005 /**
1006 * @test
1007 * @dataProvider slashJsDataProvider
1008 */
1009 public function slashJsEscapesSingleQuotesAndSlashes($input, $extended, $expected) {
1010 $this->assertEquals($expected, t3lib_div::slashJS($input, $extended));
1011 }
1012
1013 /**
1014 * Data provider for slashJsEscapesSingleQuotesAndSlashes
1015 *
1016 * @return array
1017 */
1018 public function slashJsDataProvider() {
1019 return array(
1020 'Empty string is not changed' => array('', FALSE, ''),
1021 'Normal string is not changed' => array('The cake is a lie √', FALSE, 'The cake is a lie √'),
1022 'String with single quotes' => array("The 'cake' is a lie", FALSE, "The \\'cake\\' is a lie"),
1023 'String with single quotes and backslashes - just escape single quotes'
1024 => array("The \\'cake\\' is a lie", FALSE, "The \\\\'cake\\\\' is a lie"),
1025 'String with single quotes and backslashes - escape both'
1026 => array("The \\'cake\\' is a lie", TRUE, "The \\\\\\'cake\\\\\\' is a lie")
1027 );
1028 }
1029
1030 //////////////////////////////////
1031 // Tests concerning rawUrlEncodeJS
1032 //////////////////////////////////
1033
1034 /**
1035 * @test
1036 */
1037 public function rawUrlEncodeJsPreservesWhitespaces() {
1038 $input = "Encode 'me', but leave my spaces √";
1039 $expected = "Encode %27me%27%2C but leave my spaces %E2%88%9A";
1040 $this->assertEquals($expected, t3lib_div::rawUrlEncodeJS($input));
1041 }
1042
1043 //////////////////////////////////
1044 // Tests concerning rawUrlEncodeJS
1045 //////////////////////////////////
1046
1047 /**
1048 * @test
1049 */
1050 public function rawUrlEncodeFpPreservesSlashes() {
1051 $input = "Encode 'me', but leave my / √";
1052 $expected = "Encode%20%27me%27%2C%20but%20leave%20my%20/%20%E2%88%9A";
1053 $this->assertEquals($expected, t3lib_div::rawUrlEncodeFP($input));
1054 }
1055
1056 //////////////////////////////////
1057 // Tests concerning strtoupper / strtolower
1058 //////////////////////////////////
1059
1060 /**
1061 * Data provider for strtoupper and strtolower
1062 *
1063 * @return array
1064 */
1065 public function strtouppperDataProvider() {
1066 return array(
1067 'Empty string' => array('', ''),
1068 'String containing only latin characters' => array('the cake is a lie.', 'THE CAKE IS A LIE.'),
1069 'String with umlauts and accent characters' => array('the càkê is ä lie.', 'THE CàKê IS ä LIE.')
1070 );
1071 }
1072
1073 /**
1074 * @test
1075 * @dataProvider strtouppperDataProvider
1076 */
1077 public function strtoupperConvertsOnlyLatinCharacters($input, $expected) {
1078 $this->assertEquals($expected, t3lib_div::strtoupper($input));
1079 }
1080
1081 /**
1082 * @test
1083 * @dataProvider strtouppperDataProvider
1084 */
1085 public function strtolowerConvertsOnlyLatinCharacters($expected, $input) {
1086 $this->assertEquals($expected, t3lib_div::strtolower($input));
1087 }
1088
1089
1090 //////////////////////////////////
1091 // Tests concerning validEmail
1092 //////////////////////////////////
1093
1094 /**
1095 * Data provider for valid validEmail's
1096 *
1097 * @return array Valid email addresses
1098 */
1099 public function validEmailValidDataProvider() {
1100 return array(
1101 'short mail address' => array('a@b.c'),
1102 'simple mail address' => array('test@example.com'),
1103 'uppercase characters' => array('QWERTYUIOPASDFGHJKLZXCVBNM@QWERTYUIOPASDFGHJKLZXCVBNM.NET'),
1104 // Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6 and 5.3.2 but fails with 5.3.0 on windows
1105 // 'equal sign in local part' => array('test=mail@example.com'),
1106 'dash in local part' => array('test-mail@example.com'),
1107 'plus in local part' => array('test+mail@example.com'),
1108 // Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6 and 5.3.2 but fails with 5.3.0 on windows
1109 // 'question mark in local part' => array('test?mail@example.com'),
1110 'slash in local part' => array('foo/bar@example.com'),
1111 'hash in local part' => array('foo#bar@example.com'),
1112 // Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6 and 5.3.2 but fails with 5.3.0 on windows
1113 // 'dot in local part' => array('firstname.lastname@employee.2something.com'),
1114 // Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6, but not ok with 5.3.2
1115 // 'dash as local part' => array('-@foo.com'),
1116 'umlauts in local part' => array('äöüfoo@bar.com'),
1117 'umlauts in domain part' => array('foo@äöüfoo.com'),
1118 );
1119 }
1120
1121 /**
1122 * @test
1123 * @dataProvider validEmailValidDataProvider
1124 */
1125 public function validEmailReturnsTrueForValidMailAddress($address) {
1126 $this->assertTrue(t3lib_div::validEmail($address));
1127 }
1128
1129 /**
1130 * Data provider for invalid validEmail's
1131 *
1132 * @return array Invalid email addresses
1133 */
1134 public function validEmailInvalidDataProvider() {
1135 return array(
1136 '@ sign only' => array('@'),
1137 'duplicate @' => array('test@@example.com'),
1138 'duplicate @ combined with further special characters in local part' => array('test!.!@#$%^&*@example.com'),
1139 'opening parenthesis in local part' => array('foo(bar@example.com'),
1140 'closing parenthesis in local part' => array('foo)bar@example.com'),
1141 'opening square bracket in local part' => array('foo[bar@example.com'),
1142 'closing square bracket as local part' => array(']@example.com'),
1143 // Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6, but not ok with 5.3.2
1144 // 'top level domain only' => array('test@com'),
1145 'dash as second level domain' => array('foo@-.com'),
1146 'domain part starting with dash' => array('foo@-foo.com'),
1147 'domain part ending with dash' => array('foo@foo-.com'),
1148 'number as top level domain' => array('foo@bar.123'),
1149 // Fix / change if TYPO3 php requirement changed: Address not ok with 5.2.6, but ok with 5.3.2 (?)
1150 // 'dash as top level domain' => array('foo@bar.-'),
1151 'dot at beginning of domain part' => array('test@.com'),
1152 // Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6, but not ok with 5.3.2
1153 // 'local part ends with dot' => array('e.x.a.m.p.l.e.@example.com'),
1154 'trailing whitespace' => array('test@example.com '),
1155 'trailing carriage return' => array('test@example.com' . CR),
1156 'trailing linefeed' => array('test@example.com' . LF),
1157 'trailing carriage return linefeed' => array('test@example.com' . CRLF),
1158 'trailing tab' => array('test@example.com' . TAB),
1159 );
1160 }
1161
1162 /**
1163 * @test
1164 * @dataProvider validEmailInvalidDataProvider
1165 */
1166 public function validEmailReturnsFalseForInvalidMailAddress($address) {
1167 $this->assertFalse(t3lib_div::validEmail($address));
1168 }
1169
1170 //////////////////////////////////
1171 // Tests concerning inArray
1172 //////////////////////////////////
1173
1174 /**
1175 * @test
1176 * @dataProvider inArrayDataProvider
1177 */
1178 public function inArrayChecksStringExistenceWithinArray($array, $item, $expected) {
1179 $this->assertEquals($expected, t3lib_div::inArray($array, $item));
1180 }
1181
1182 /**
1183 * Data provider for inArrayChecksStringExistenceWithinArray
1184 *
1185 * @return array
1186 */
1187 public function inArrayDataProvider() {
1188 return array(
1189 'Empty array' => array(array(), 'search', FALSE),
1190 'One item array no match' => array(array('one'), 'two', FALSE),
1191 'One item array match' => array(array('one'), 'one', TRUE),
1192 'Multiple items array no match' => array(array('one', 2, 'three', 4), 'four', FALSE),
1193 'Multiple items array match' => array(array('one', 2, 'three', 4), 'three', TRUE),
1194 'Integer search items can match string values' => array(array('0', '1', '2'), 1, TRUE),
1195 'Search item is not casted to integer for a match' => array(array(4), '4a', FALSE),
1196 'Empty item won\'t match - in contrast to the php-builtin ' => array(array(0, 1, 2), '', FALSE),
1197 );
1198 }
1199
1200 //////////////////////////////////
1201 // Tests concerning intExplode
1202 //////////////////////////////////
1203
1204 /**
1205 * @test
1206 */
1207 public function intExplodeConvertsStringsToInteger() {
1208 $testString = '1,foo,2';
1209 $expectedArray = array(1, 0, 2);
1210 $actualArray = t3lib_div::intExplode(',', $testString);
1211
1212 $this->assertEquals($expectedArray, $actualArray);
1213 }
1214
1215 //////////////////////////////////
1216 // Tests concerning keepItemsInArray
1217 //////////////////////////////////
1218
1219 /**
1220 * @test
1221 * @dataProvider keepItemsInArrayWorksWithOneArgumentDataProvider
1222 */
1223 public function keepItemsInArrayWorksWithOneArgument($search, $array, $expected) {
1224 $this->assertEquals($expected, t3lib_div::keepItemsInArray($array, $search));
1225 }
1226
1227 /**
1228 * Data provider for keepItemsInArrayWorksWithOneArgument
1229 *
1230 * @return array
1231 */
1232 public function keepItemsInArrayWorksWithOneArgumentDataProvider() {
1233 $array = array(
1234 'one' => 'one',
1235 'two' => 'two',
1236 'three' => 'three'
1237 );
1238 return array(
1239 'Empty argument will match "all" elements' => array(NULL, $array, $array),
1240 'No match' => array('four', $array, array()),
1241 'One match' => array('two', $array, array('two' => 'two')),
1242 'Multiple matches' => array('two,one', $array, array('one' => 'one', 'two' => 'two')),
1243 'Argument can be an array' => array(array('three'), $array, array('three' => 'three'))
1244 );
1245 }
1246
1247 /**
1248 * Shows the exmaple from the doc comment where
1249 * a function is used to reduce the sub arrays to one item which
1250 * is then used for the matching.
1251 *
1252 * @test
1253 */
1254 public function keepItemsInArrayCanUseCallbackOnSearchArray() {
1255 $array = array(
1256 'aa' => array('first', 'second'),
1257 'bb' => array('third', 'fourth'),
1258 'cc' => array('fifth', 'sixth')
1259 );
1260 $expected = array('bb' => array('third', 'fourth'));
1261 $keepItems = 'third';
1262 $getValueFunc = create_function('$value', 'return $value[0];');
1263
1264 $match = t3lib_div::keepItemsInArray($array, $keepItems, $getValueFunc);
1265 $this->assertEquals($expected, $match);
1266 }
1267
1268 //////////////////////////////////
1269 // Tests concerning implodeArrayForUrl / explodeUrl2Array
1270 //////////////////////////////////
1271
1272 /**
1273 * Data provider for implodeArrayForUrlBuildsValidParameterString and
1274 * explodeUrl2ArrayTransformsParameterStringToArray
1275 *
1276 * @return array
1277 */
1278 public function implodeArrayForUrlDataProvider() {
1279 $valueArray = array('one' => '√', 'two' => 2);
1280 return array(
1281 'Empty input'
1282 => array('foo', array(), ''),
1283 'String parameters'
1284 => array('foo', $valueArray, '&foo[one]=%E2%88%9A&foo[two]=2'),
1285 'Nested array parameters'
1286 => array('foo', array($valueArray), '&foo[0][one]=%E2%88%9A&foo[0][two]=2'),
1287 'Keep blank parameters'
1288 => array('foo', array('one'=> '√', ''), '&foo[one]=%E2%88%9A&foo[0]=')
1289 );
1290 }
1291
1292 /**
1293 * @test
1294 * @dataProvider implodeArrayForUrlDataProvider
1295 */
1296 public function implodeArrayForUrlBuildsValidParameterString($name, $input, $expected) {
1297 $this->assertSame($expected, t3lib_div::implodeArrayForUrl($name, $input));
1298 }
1299
1300 /**
1301 * @test
1302 */
1303 public function implodeArrayForUrlCanSkipEmptyParameters() {
1304 $input = array('one'=> '√', '');
1305 $expected = '&foo[one]=%E2%88%9A';
1306 $this->assertSame($expected, t3lib_div::implodeArrayForUrl('foo', $input, '', TRUE));
1307 }
1308
1309 /**
1310 * @test
1311 */
1312 public function implodeArrayForUrlCanUrlEncodeKeyNames() {
1313 $input = array('one'=> '√', '');
1314 $expected = '&foo%5Bone%5D=%E2%88%9A&foo%5B0%5D=';
1315 $this->assertSame($expected, t3lib_div::implodeArrayForUrl('foo', $input, '', FALSE, TRUE));
1316 }
1317
1318 /**
1319 * @test
1320 * @dataProvider implodeArrayForUrlDataProvider
1321 */
1322 public function explodeUrl2ArrayTransformsParameterStringToNestedArray($name, $array, $input) {
1323 $expected = $array ? array($name => $array) : array();
1324 $this->assertEquals($expected, t3lib_div::explodeUrl2Array($input, TRUE));
1325 }
1326
1327 /**
1328 * @test
1329 * @dataProvider explodeUrl2ArrayDataProvider
1330 */
1331 public function explodeUrl2ArrayTransformsParameterStringToFlatArray($input, $expected) {
1332 $this->assertEquals($expected, t3lib_div::explodeUrl2Array($input, FALSE));
1333 }
1334
1335 /**
1336 * Data provider for explodeUrl2ArrayTransformsParameterStringToFlatArray
1337 *
1338 * @return array
1339 */
1340 public function explodeUrl2ArrayDataProvider() {
1341 return array(
1342 'Empty string'
1343 => array('', array()),
1344 'Simple parameter string'
1345 => array('&one=%E2%88%9A&two=2', array('one' => '√', 'two' => 2)),
1346 'Nested parameter string'
1347 => array('&foo[one]=%E2%88%9A&two=2', array('foo[one]' => '√', 'two' => 2))
1348 );
1349 }
1350
1351 //////////////////////////////////
1352 // Tests concerning compileSelectedGetVarsFromArray
1353 //////////////////////////////////
1354
1355 /**
1356 * @test
1357 */
1358 public function compileSelectedGetVarsFromArrayFiltersIncomingData() {
1359 $filter = 'foo,bar';
1360 $getArray = array('foo' => 1, 'cake' => 'lie');
1361 $expected = array('foo' => 1);
1362 $result = t3lib_div::compileSelectedGetVarsFromArray($filter, $getArray, FALSE);
1363 $this->assertSame($expected, $result);
1364 }
1365
1366 /**
1367 * @test
1368 */
1369 public function compileSelectedGetVarsFromArrayUsesGetPostDataFallback() {
1370 $_GET['bar'] = '2';
1371 $filter = 'foo,bar';
1372 $getArray = array('foo' => 1, 'cake' => 'lie');
1373 $expected = array('foo' => 1, 'bar' => '2');
1374 $result = t3lib_div::compileSelectedGetVarsFromArray($filter, $getArray, TRUE);
1375 $this->assertSame($expected, $result);
1376 }
1377
1378 //////////////////////////////////
1379 // Tests concerning remapArrayKeys
1380 //////////////////////////////////
1381
1382 /**
1383 * @test
1384 */
1385 public function remapArrayKeysExchangesKeysWithGivenMapping() {
1386 $array = array(
1387 'one' => 'one',
1388 'two' => 'two',
1389 'three' => 'three'
1390 );
1391 $keyMapping = array(
1392 'one' => '1',
1393 'two' => '2'
1394 );
1395 $expected = array(
1396 '1' => 'one',
1397 '2' => 'two',
1398 'three' => 'three'
1399 );
1400
1401 t3lib_div::remapArrayKeys($array, $keyMapping);
1402 $this->assertEquals($expected, $array);
1403 }
1404
1405 //////////////////////////////////
1406 // Tests concerning array_merge
1407 //////////////////////////////////
1408
1409 /**
1410 * Test demonstrating array_merge. This is actually
1411 * a native PHP operator, therefore this test is mainly used to
1412 * show how this function can be used.
1413 *
1414 * @test
1415 */
1416 public function arrayMergeKeepsIndexesAfterMerge() {
1417 $array1 = array(10 => 'FOO', '20' => 'BAR');
1418 $array2 = array('5' => 'PLONK');
1419 $expected = array('5' => 'PLONK', 10 => 'FOO', '20' => 'BAR');
1420 $this->assertEquals($expected, t3lib_div::array_merge($array1, $array2));
1421 }
1422
1423
1424 //////////////////////////////////
1425 // Tests concerning int_from_ver
1426 //////////////////////////////////
1427 /**
1428 * Data Provider for intFromVerConvertsVersionNumbersToIntegersDataProvider
1429 *
1430 * return array
1431 */
1432 public function intFromVerConvertsVersionNumbersToIntegersDataProvider() {
1433 return array(
1434 array('4003003', '4.3.3'),
1435 array('4012003', '4.12.3'),
1436 array('5000000', '5.0.0'),
1437 array('3008001', '3.8.1'),
1438 array('1012', '0.1.12')
1439 );
1440 }
1441
1442 /**
1443 * @test
1444 * @dataProvider intFromVerConvertsVersionNumbersToIntegersDataProvider
1445 */
1446 public function intFromVerConvertsVersionNumbersToIntegers($expected, $version) {
1447 $this->assertEquals($expected, t3lib_div::int_from_ver($version));
1448 }
1449
1450 //////////////////////////////////
1451 // Tests concerning revExplode
1452 //////////////////////////////////
1453
1454 /**
1455 * @test
1456 */
1457 public function revExplodeExplodesString() {
1458 $testString = 'my:words:here';
1459 $expectedArray = array('my:words', 'here');
1460 $actualArray = t3lib_div::revExplode(':', $testString, 2);
1461
1462 $this->assertEquals($expectedArray, $actualArray);
1463 }
1464
1465
1466 //////////////////////////////////
1467 // Tests concerning trimExplode
1468 //////////////////////////////////
1469
1470 /**
1471 * @test
1472 */
1473 public function checkTrimExplodeTrimsSpacesAtElementStartAndEnd() {
1474 $testString = ' a , b , c ,d ,, e,f,';
1475 $expectedArray = array('a', 'b', 'c', 'd', '', 'e', 'f', '');
1476 $actualArray = t3lib_div::trimExplode(',', $testString);
1477
1478 $this->assertEquals($expectedArray, $actualArray);
1479 }
1480
1481 /**
1482 * @test
1483 */
1484 public function checkTrimExplodeRemovesNewLines() {
1485 $testString = ' a , b , ' . LF . ' ,d ,, e,f,';
1486 $expectedArray = array('a', 'b', 'd', 'e', 'f');
1487 $actualArray = t3lib_div::trimExplode(',', $testString, TRUE);
1488
1489 $this->assertEquals($expectedArray, $actualArray);
1490 }
1491
1492 /**
1493 * @test
1494 */
1495 public function checkTrimExplodeRemovesEmptyElements() {
1496 $testString = 'a , b , c , ,d ,, ,e,f,';
1497 $expectedArray = array('a', 'b', 'c', 'd', 'e', 'f');
1498 $actualArray = t3lib_div::trimExplode(',', $testString, TRUE);
1499
1500 $this->assertEquals($expectedArray, $actualArray);
1501 }
1502
1503 /**
1504 * @test
1505 */
1506 public function checkTrimExplodeKeepsRemainingResultsWithEmptyItemsAfterReachingLimitWithPositiveParameter() {
1507 $testString = ' a , b , c , , d,, ,e ';
1508 $expectedArray = array('a', 'b', 'c,,d,,,e');
1509 // Limiting returns the rest of the string as the last element
1510 $actualArray = t3lib_div::trimExplode(',', $testString, FALSE, 3);
1511
1512 $this->assertEquals($expectedArray, $actualArray);
1513 }
1514
1515 /**
1516 * @test
1517 */
1518 public function checkTrimExplodeKeepsRemainingResultsWithoutEmptyItemsAfterReachingLimitWithPositiveParameter() {
1519 $testString = ' a , b , c , , d,, ,e ';
1520 $expectedArray = array('a', 'b', 'c,d,e');
1521 // Limiting returns the rest of the string as the last element
1522 $actualArray = t3lib_div::trimExplode(',', $testString, TRUE, 3);
1523
1524 $this->assertEquals($expectedArray, $actualArray);
1525 }
1526
1527 /**
1528 * @test
1529 */
1530 public function checkTrimExplodeKeepsRamainingResultsWithEmptyItemsAfterReachingLimitWithNegativeParameter() {
1531 $testString = ' a , b , c , d, ,e, f , , ';
1532 $expectedArray = array('a', 'b', 'c', 'd', '', 'e');
1533 // limiting returns the rest of the string as the last element
1534 $actualArray = t3lib_div::trimExplode(',', $testString, FALSE, -3);
1535
1536 $this->assertEquals($expectedArray, $actualArray);
1537 }
1538
1539 /**
1540 * @test
1541 */
1542 public function checkTrimExplodeKeepsRamainingResultsWithoutEmptyItemsAfterReachingLimitWithNegativeParameter() {
1543 $testString = ' a , b , c , d, ,e, f , , ';
1544 $expectedArray = array('a', 'b', 'c');
1545 // Limiting returns the rest of the string as the last element
1546 $actualArray = t3lib_div::trimExplode(',', $testString, TRUE, -3);
1547
1548 $this->assertEquals($expectedArray, $actualArray);
1549 }
1550
1551 /**
1552 * @test
1553 */
1554 public function checkTrimExplodeReturnsExactResultsWithoutReachingLimitWithPositiveParameter() {
1555 $testString = ' a , b , , c , , , ';
1556 $expectedArray = array('a', 'b', 'c');
1557 // Limiting returns the rest of the string as the last element
1558 $actualArray = t3lib_div::trimExplode(',', $testString, TRUE, 4);
1559
1560 $this->assertEquals($expectedArray, $actualArray);
1561 }
1562
1563 /**
1564 * @test
1565 */
1566 public function checkTrimExplodeKeepsZeroAsString() {
1567 $testString = 'a , b , c , ,d ,, ,e,f, 0 ,';
1568 $expectedArray = array('a', 'b', 'c', 'd', 'e', 'f', '0');
1569 $actualArray = t3lib_div::trimExplode(',', $testString, TRUE);
1570
1571 $this->assertEquals($expectedArray, $actualArray);
1572 }
1573
1574
1575 //////////////////////////////////
1576 // Tests concerning removeArrayEntryByValue
1577 //////////////////////////////////
1578
1579 /**
1580 * @test
1581 */
1582 public function checkRemoveArrayEntryByValueRemovesEntriesFromOneDimensionalArray() {
1583 $inputArray = array(
1584 '0' => 'test1',
1585 '1' => 'test2',
1586 '2' => 'test3',
1587 '3' => 'test2',
1588 );
1589 $compareValue = 'test2';
1590 $expectedResult = array(
1591 '0' => 'test1',
1592 '2' => 'test3',
1593 );
1594 $actualResult = t3lib_div::removeArrayEntryByValue($inputArray, $compareValue);
1595 $this->assertEquals($expectedResult, $actualResult);
1596 }
1597
1598 /**
1599 * @test
1600 */
1601 public function checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray() {
1602 $inputArray = array(
1603 '0' => 'foo',
1604 '1' => array(
1605 '10' => 'bar',
1606 ),
1607 '2' => 'bar',
1608 );
1609 $compareValue = 'bar';
1610 $expectedResult = array(
1611 '0' => 'foo',
1612 '1' => array(),
1613 );
1614 $actualResult = t3lib_div::removeArrayEntryByValue($inputArray, $compareValue);
1615 $this->assertEquals($expectedResult, $actualResult);
1616 }
1617
1618 /**
1619 * @test
1620 */
1621 public function checkRemoveArrayEntryByValueRemovesEntryWithEmptyString() {
1622 $inputArray = array(
1623 '0' => 'foo',
1624 '1' => '',
1625 '2' => 'bar',
1626 );
1627 $compareValue = '';
1628 $expectedResult = array(
1629 '0' => 'foo',
1630 '2' => 'bar',
1631 );
1632 $actualResult = t3lib_div::removeArrayEntryByValue($inputArray, $compareValue);
1633 $this->assertEquals($expectedResult, $actualResult);
1634 }
1635
1636 //////////////////////////////////
1637 // Tests concerning getBytesFromSizeMeasurement
1638 //////////////////////////////////
1639
1640 /**
1641 * Data provider for getBytesFromSizeMeasurement
1642 *
1643 * @return array expected value, input string
1644 */
1645 public function getBytesFromSizeMeasurementDataProvider() {
1646 return array(
1647 '100 kilo Bytes' => array('102400', '100k'),
1648 '100 mega Bytes' => array('104857600', '100m'),
1649 '100 giga Bytes' => array('107374182400', '100g'),
1650 );
1651 }
1652
1653 /**
1654 * @test
1655 * @dataProvider getBytesFromSizeMeasurementDataProvider
1656 */
1657 public function getBytesFromSizeMeasurementCalculatesCorrectByteValue($expected, $byteString) {
1658 $this->assertEquals($expected, t3lib_div::getBytesFromSizeMeasurement($byteString));
1659 }
1660
1661
1662 //////////////////////////////////
1663 // Tests concerning getIndpEnv
1664 //////////////////////////////////
1665
1666 /**
1667 * @test
1668 */
1669 public function getIndpEnvTypo3SitePathReturnNonEmptyString() {
1670 $this->assertTrue(strlen(t3lib_div::getIndpEnv('TYPO3_SITE_PATH')) >= 1);
1671 }
1672
1673 /**
1674 * @test
1675 */
1676 public function getIndpEnvTypo3SitePathReturnsStringStartingWithSlash() {
1677 $result = t3lib_div::getIndpEnv('TYPO3_SITE_PATH');
1678 $this->assertEquals('/', $result[0]);
1679 }
1680
1681 /**
1682 * @test
1683 */
1684 public function getIndpEnvTypo3SitePathReturnsStringEndingWithSlash() {
1685 $result = t3lib_div::getIndpEnv('TYPO3_SITE_PATH');
1686 $this->assertEquals('/', $result[strlen($result) - 1]);
1687 }
1688
1689 /**
1690 * @return array
1691 */
1692 public static function hostnameAndPortDataProvider() {
1693 return array(
1694 'localhost ipv4 without port' => array('127.0.0.1', '127.0.0.1', ''),
1695 'localhost ipv4 with port' => array('127.0.0.1:81', '127.0.0.1', '81'),
1696 'localhost ipv6 without port' => array('[::1]', '[::1]', ''),
1697 'localhost ipv6 with port' => array('[::1]:81', '[::1]', '81'),
1698 'ipv6 without port' => array('[2001:DB8::1]', '[2001:DB8::1]', ''),
1699 'ipv6 with port' => array('[2001:DB8::1]:81', '[2001:DB8::1]', '81'),
1700 'hostname without port' => array('lolli.did.this', 'lolli.did.this', ''),
1701 'hostname with port' => array('lolli.did.this:42', 'lolli.did.this', '42'),
1702 );
1703 }
1704
1705 /**
1706 * @test
1707 * @dataProvider hostnameAndPortDataProvider
1708 */
1709 public function getIndpEnvTypo3HostOnlyParsesHostnamesAndIpAdresses($httpHost, $expectedIp) {
1710 $_SERVER['HTTP_HOST'] = $httpHost;
1711 $this->assertEquals($expectedIp, t3lib_div::getIndpEnv('TYPO3_HOST_ONLY'));
1712 }
1713
1714 /**
1715 * @test
1716 * @dataProvider hostnameAndPortDataProvider
1717 */
1718 public function getIndpEnvTypo3PortParsesHostnamesAndIpAdresses($httpHost, $dummy, $expectedPort) {
1719 $_SERVER['HTTP_HOST'] = $httpHost;
1720 $this->assertEquals($expectedPort, t3lib_div::getIndpEnv('TYPO3_PORT'));
1721 }
1722
1723
1724 //////////////////////////////////
1725 // Tests concerning underscoredToUpperCamelCase
1726 //////////////////////////////////
1727
1728 /**
1729 * Data provider for underscoredToUpperCamelCase
1730 *
1731 * @return array expected, input string
1732 */
1733 public function underscoredToUpperCamelCaseDataProvider() {
1734 return array(
1735 'single word' => array('Blogexample', 'blogexample'),
1736 'multiple words' => array('BlogExample', 'blog_example'),
1737 );
1738 }
1739
1740 /**
1741 * @test
1742 * @dataProvider underscoredToUpperCamelCaseDataProvider
1743 */
1744 public function underscoredToUpperCamelCase($expected, $inputString) {
1745 $this->assertEquals($expected, t3lib_div::underscoredToUpperCamelCase($inputString));
1746 }
1747
1748
1749 //////////////////////////////////
1750 // Tests concerning underscoredToLowerCamelCase
1751 //////////////////////////////////
1752
1753 /**
1754 * Data provider for underscoredToLowerCamelCase
1755 *
1756 * @return array expected, input string
1757 */
1758 public function underscoredToLowerCamelCaseDataProvider() {
1759 return array(
1760 'single word' => array('minimalvalue', 'minimalvalue'),
1761 'multiple words' => array('minimalValue', 'minimal_value'),
1762 );
1763 }
1764
1765 /**
1766 * @test
1767 * @dataProvider underscoredToLowerCamelCaseDataProvider
1768 */
1769 public function underscoredToLowerCamelCase($expected, $inputString) {
1770 $this->assertEquals($expected, t3lib_div::underscoredToLowerCamelCase($inputString));
1771 }
1772
1773 //////////////////////////////////
1774 // Tests concerning camelCaseToLowerCaseUnderscored
1775 //////////////////////////////////
1776
1777 /**
1778 * Data provider for camelCaseToLowerCaseUnderscored
1779 *
1780 * @return array expected, input string
1781 */
1782 public function camelCaseToLowerCaseUnderscoredDataProvider() {
1783 return array(
1784 'single word' => array('blogexample', 'blogexample'),
1785 'single word starting upper case' => array('blogexample', 'Blogexample'),
1786 'two words starting lower case' => array('minimal_value', 'minimalValue'),
1787 'two words starting upper case' => array('blog_example', 'BlogExample'),
1788 );
1789 }
1790
1791 /**
1792 * @test
1793 * @dataProvider camelCaseToLowerCaseUnderscoredDataProvider
1794 */
1795 public function camelCaseToLowerCaseUnderscored($expected, $inputString) {
1796 $this->assertEquals($expected, t3lib_div::camelCaseToLowerCaseUnderscored($inputString));
1797 }
1798
1799
1800 //////////////////////////////////
1801 // Tests concerning lcFirst
1802 //////////////////////////////////
1803
1804 /**
1805 * Data provider for lcFirst
1806 *
1807 * @return array expected, input string
1808 */
1809 public function lcfirstDataProvider() {
1810 return array(
1811 'single word' => array('blogexample', 'blogexample'),
1812 'single Word starting upper case' => array('blogexample', 'Blogexample'),
1813 'two words' => array('blogExample', 'BlogExample'),
1814 );
1815 }
1816
1817 /**
1818 * @test
1819 * @dataProvider lcfirstDataProvider
1820 */
1821 public function lcFirst($expected, $inputString) {
1822 $this->assertEquals($expected, t3lib_div::lcfirst($inputString));
1823 }
1824
1825
1826 //////////////////////////////////
1827 // Tests concerning encodeHeader
1828 //////////////////////////////////
1829
1830 /**
1831 * @test
1832 */
1833 public function encodeHeaderEncodesWhitespacesInQuotedPrintableMailHeader() {
1834 $this->assertEquals(
1835 '=?utf-8?Q?We_test_whether_the_copyright_character_=C2=A9_is_encoded_correctly?=',
1836 t3lib_div::encodeHeader(
1837 "We test whether the copyright character \xc2\xa9 is encoded correctly",
1838 'quoted-printable',
1839 'utf-8'
1840 )
1841 );
1842 }
1843
1844 /**
1845 * @test
1846 */
1847 public function encodeHeaderEncodesQuestionmarksInQuotedPrintableMailHeader() {
1848 $this->assertEquals(
1849 '=?utf-8?Q?Is_the_copyright_character_=C2=A9_really_encoded_correctly=3F_Really=3F?=',
1850 t3lib_div::encodeHeader(
1851 "Is the copyright character \xc2\xa9 really encoded correctly? Really?",
1852 'quoted-printable',
1853 'utf-8'
1854 )
1855 );
1856 }
1857
1858
1859 //////////////////////////////////
1860 // Tests concerning isValidUrl
1861 //////////////////////////////////
1862
1863 /**
1864 * Data provider for valid isValidUrl's
1865 *
1866 * @return array Valid ressource
1867 */
1868 public function validUrlValidRessourceDataProvider() {
1869 return array(
1870 'http' => array('http://www.example.org/'),
1871 'http without trailing slash' => array('http://qwe'),
1872 'http directory with trailing slash' => array('http://www.example/img/dir/'),
1873 'http directory without trailing slash' => array('http://www.example/img/dir'),
1874 'http index.html' => array('http://example.com/index.html'),
1875 'http index.php' => array('http://www.example.com/index.php'),
1876 'http test.png' => array('http://www.example/img/test.png'),
1877 'http username password querystring and ancher' => array('https://user:pw@www.example.org:80/path?arg=value#fragment'),
1878 'file' => array('file:///tmp/test.c'),
1879 'file directory' => array('file://foo/bar'),
1880 'ftp directory' => array('ftp://ftp.example.com/tmp/'),
1881 'mailto' => array('mailto:foo@bar.com'),
1882 'news' => array('news:news.php.net'),
1883 'telnet'=> array('telnet://192.0.2.16:80/'),
1884 'ldap' => array('ldap://[2001:db8::7]/c=GB?objectClass?one'),
1885 'http punycode domain name' => array('http://www.xn--bb-eka.at'),
1886 'http punicode subdomain' => array('http://xn--h-zfa.oebb.at'),
1887 'http domain-name umlauts' => array('http://www.öbb.at'),
1888 'http subdomain umlauts' => array('http://äh.oebb.at'),
1889 'http directory umlauts' => array('http://www.oebb.at/äöü/'),
1890 );
1891 }
1892
1893 /**
1894 * @test
1895 * @dataProvider validUrlValidRessourceDataProvider
1896 */
1897 public function validURLReturnsTrueForValidRessource($url) {
1898 $this->assertTrue(t3lib_div::isValidUrl($url));
1899 }
1900
1901 /**
1902 * Data provider for invalid isValidUrl's
1903 *
1904 * @return array Invalid ressource
1905 */
1906 public function isValidUrlInvalidRessourceDataProvider() {
1907 return array(
1908 'http missing colon' => array('http//www.example/wrong/url/'),
1909 'http missing slash' => array('http:/www.example'),
1910 'hostname only' => array('www.example.org/'),
1911 'file missing protocol specification' => array('/tmp/test.c'),
1912 'slash only' => array('/'),
1913 'string http://' => array('http://'),
1914 'string http:/' => array('http:/'),
1915 'string http:' => array('http:'),
1916 'string http' => array('http'),
1917 'empty string' => array(''),
1918 'string -1' => array('-1'),
1919 'string array()' => array('array()'),
1920 'random string' => array('qwe'),
1921 );
1922 }
1923
1924 /**
1925 * @test
1926 * @dataProvider isValidUrlInvalidRessourceDataProvider
1927 */
1928 public function validURLReturnsFalseForInvalidRessoure($url) {
1929 $this->assertFalse(t3lib_div::isValidUrl($url));
1930 }
1931
1932
1933 //////////////////////////////////
1934 // Tests concerning isOnCurrentHost
1935 //////////////////////////////////
1936
1937 /**
1938 * @test
1939 */
1940 public function isOnCurrentHostReturnsTrueWithCurrentHost() {
1941 $testUrl = t3lib_div::getIndpEnv('TYPO3_REQUEST_URL');
1942 $this->assertTrue(t3lib_div::isOnCurrentHost($testUrl));
1943 }
1944
1945 /**
1946 * Data provider for invalid isOnCurrentHost's
1947 *
1948 * @return array Invalid Hosts
1949 */
1950 public function checkisOnCurrentHostInvalidHosts() {
1951 return array(
1952 'empty string' => array(''),
1953 'arbitrary string' => array('arbitrary string'),
1954 'localhost IP' => array('127.0.0.1'),
1955 'relative path' => array('./relpath/file.txt'),
1956 'absolute path' => array('/abspath/file.txt?arg=value'),
1957 'differnt host' => array(t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST') . '.example.org'),
1958 );
1959 }
1960
1961
1962 ////////////////////////////////////////
1963 // Tests concerning sanitizeLocalUrl
1964 ////////////////////////////////////////
1965
1966 /**
1967 * Data provider for valid sanitizeLocalUrl's
1968 *
1969 * @return array Valid url
1970 */
1971 public function sanitizeLocalUrlValidUrlDataProvider() {
1972 $subDirectory = t3lib_div::getIndpEnv('TYPO3_SITE_PATH');
1973 $typo3SiteUrl = t3lib_div::getIndpEnv('TYPO3_SITE_URL');
1974 $typo3RequestHost = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST');
1975
1976 return array(
1977 'alt_intro.php' => array('alt_intro.php'),
1978 'alt_intro.php?foo=1&bar=2' => array('alt_intro.php?foo=1&bar=2'),
1979 $subDirectory . 'typo3/alt_intro.php' => array($subDirectory . 'typo3/alt_intro.php'),
1980 $subDirectory . 'index.php' => array($subDirectory . 'index.php'),
1981 '../index.php' => array('../index.php'),
1982 '../typo3/alt_intro.php' => array('../typo3/alt_intro.php'),
1983 '../~userDirectory/index.php' => array('../~userDirectory/index.php'),
1984 '../typo3/mod.php?var1=test-case&var2=~user' => array('../typo3/mod.php?var1=test-case&var2=~user'),
1985 PATH_site . 'typo3/alt_intro.php' => array(PATH_site . 'typo3/alt_intro.php'),
1986 $typo3SiteUrl . 'typo3/alt_intro.php' => array($typo3SiteUrl . 'typo3/alt_intro.php'),
1987 $typo3RequestHost . $subDirectory . '/index.php' => array($typo3RequestHost . $subDirectory . '/index.php'),
1988 );
1989 }
1990
1991 /**
1992 * @test
1993 * @dataProvider sanitizeLocalUrlValidUrlDataProvider
1994 */
1995 public function sanitizeLocalUrlAcceptsNotEncodedValidUrls($url) {
1996 $this->assertEquals($url, t3lib_div::sanitizeLocalUrl($url));
1997 }
1998
1999 /**
2000 * @test
2001 * @dataProvider sanitizeLocalUrlValidUrlDataProvider
2002 */
2003 public function sanitizeLocalUrlAcceptsEncodedValidUrls($url) {
2004 $this->assertEquals(rawurlencode($url), t3lib_div::sanitizeLocalUrl(rawurlencode($url)));
2005 }
2006
2007 /**
2008 * Data provider for invalid sanitizeLocalUrl's
2009 *
2010 * @return array Valid url
2011 */
2012 public function sanitizeLocalUrlInvalidDataProvider() {
2013 return array(
2014 'empty string' => array(''),
2015 'http domain' => array('http://www.google.de/'),
2016 'https domain' => array('https://www.google.de/'),
2017 'relative path with XSS' => array('../typo3/whatever.php?argument=javascript:alert(0)'),
2018 );
2019 }
2020
2021 /**
2022 * @test
2023 * @dataProvider sanitizeLocalUrlInvalidDataProvider
2024 */
2025 public function sanitizeLocalUrlDeniesPlainInvalidUrls($url) {
2026 $this->assertEquals('', t3lib_div::sanitizeLocalUrl($url));
2027 }
2028
2029 /**
2030 * @test
2031 * @dataProvider sanitizeLocalUrlInvalidDataProvider
2032 */
2033 public function sanitizeLocalUrlDeniesEncodedInvalidUrls($url) {
2034 $this->assertEquals('', t3lib_div::sanitizeLocalUrl(rawurlencode($url)));
2035 }
2036
2037
2038 //////////////////////////////////////
2039 // Tests concerning addSlashesOnArray
2040 //////////////////////////////////////
2041
2042 /**
2043 * @test
2044 */
2045 public function addSlashesOnArrayAddsSlashesRecursive() {
2046 $inputArray = array(
2047 'key1' => array(
2048 'key11' => "val'ue1",
2049 'key12' => 'val"ue2',
2050 ),
2051 'key2' => 'val\ue3',
2052 );
2053 $expectedResult = array(
2054 'key1' => array(
2055 'key11' => "val\'ue1",
2056 'key12' => 'val\"ue2',
2057 ),
2058 'key2' => 'val\\\\ue3',
2059 );
2060 t3lib_div::addSlashesOnArray($inputArray);
2061 $this->assertEquals(
2062 $expectedResult,
2063 $inputArray
2064 );
2065 }
2066
2067
2068 //////////////////////////////////////
2069 // Tests concerning addSlashesOnArray
2070 //////////////////////////////////////
2071
2072 /**
2073 * @test
2074 */
2075 public function stripSlashesOnArrayStripsSlashesRecursive() {
2076 $inputArray = array(
2077 'key1' => array(
2078 'key11' => "val\'ue1",
2079 'key12' => 'val\"ue2',
2080 ),
2081 'key2' => 'val\\\\ue3',
2082 );
2083 $expectedResult = array(
2084 'key1' => array(
2085 'key11' => "val'ue1",
2086 'key12' => 'val"ue2',
2087 ),
2088 'key2' => 'val\ue3',
2089 );
2090 t3lib_div::stripSlashesOnArray($inputArray);
2091 $this->assertEquals(
2092 $expectedResult,
2093 $inputArray
2094 );
2095 }
2096
2097
2098 //////////////////////////////////////
2099 // Tests concerning arrayDiffAssocRecursive
2100 //////////////////////////////////////
2101
2102 /**
2103 * @test
2104 */
2105 public function arrayDiffAssocRecursiveHandlesOneDimensionalArrays() {
2106 $array1 = array(
2107 'key1' => 'value1',
2108 'key2' => 'value2',
2109 'key3' => 'value3',
2110 );
2111 $array2 = array(
2112 'key1' => 'value1',
2113 'key3' => 'value3',
2114 );
2115 $expectedResult = array(
2116 'key2' => 'value2',
2117 );
2118 $actualResult = t3lib_div::arrayDiffAssocRecursive($array1, $array2);
2119 $this->assertEquals($expectedResult, $actualResult);
2120 }
2121
2122 /**
2123 * @test
2124 */
2125 public function arrayDiffAssocRecursiveHandlesMultiDimensionalArrays() {
2126 $array1 = array(
2127 'key1' => 'value1',
2128 'key2' => array(
2129 'key21' => 'value21',
2130 'key22' => 'value22',
2131 'key23' => array(
2132 'key231' => 'value231',
2133 'key232' => 'value232',
2134 ),
2135 ),
2136 );
2137 $array2 = array(
2138 'key1' => 'value1',
2139 'key2' => array(
2140 'key21' => 'value21',
2141 'key23' => array(
2142 'key231' => 'value231',
2143 ),
2144 ),
2145 );
2146 $expectedResult = array(
2147 'key2' => array(
2148 'key22' => 'value22',
2149 'key23' => array(
2150 'key232' => 'value232',
2151 ),
2152 ),
2153 );
2154 $actualResult = t3lib_div::arrayDiffAssocRecursive($array1, $array2);
2155 $this->assertEquals($expectedResult, $actualResult);
2156 }
2157
2158 /**
2159 * @test
2160 */
2161 public function arrayDiffAssocRecursiveHandlesMixedArrays() {
2162 $array1 = array(
2163 'key1' => array(
2164 'key11' => 'value11',
2165 'key12' => 'value12',
2166 ),
2167 'key2' => 'value2',
2168 'key3' => 'value3',
2169 );
2170 $array2 = array(
2171 'key1' => 'value1',
2172 'key2' => array(
2173 'key21' => 'value21',
2174 ),
2175 );
2176 $expectedResult = array(
2177 'key3' => 'value3',
2178 );
2179 $actualResult = t3lib_div::arrayDiffAssocRecursive($array1, $array2);
2180 $this->assertEquals($expectedResult, $actualResult);
2181 }
2182
2183
2184 //////////////////////////////////////
2185 // Tests concerning removeDotsFromTS
2186 //////////////////////////////////////
2187
2188 /**
2189 * @test
2190 */
2191 public function removeDotsFromTypoScriptSucceedsWithDottedArray() {
2192 $typoScript = array(
2193 'propertyA.' => array(
2194 'keyA.' => array(
2195 'valueA' => 1,
2196 ),
2197 'keyB' => 2,
2198 ),
2199 'propertyB' => 3,
2200 );
2201
2202 $expectedResult = array(
2203 'propertyA' => array(
2204 'keyA' => array(
2205 'valueA' => 1,
2206 ),
2207 'keyB' => 2,
2208 ),
2209 'propertyB' => 3,
2210 );
2211
2212 $this->assertEquals($expectedResult, t3lib_div::removeDotsFromTS($typoScript));
2213 }
2214
2215 /**
2216 * @test
2217 */
2218 public function removeDotsFromTypoScriptOverridesSubArray() {
2219 $typoScript = array(
2220 'propertyA.' => array(
2221 'keyA' => 'getsOverridden',
2222 'keyA.' => array(
2223 'valueA' => 1,
2224 ),
2225 'keyB' => 2,
2226 ),
2227 'propertyB' => 3,
2228 );
2229
2230 $expectedResult = array(
2231 'propertyA' => array(
2232 'keyA' => array(
2233 'valueA' => 1,
2234 ),
2235 'keyB' => 2,
2236 ),
2237 'propertyB' => 3,
2238 );
2239
2240 $this->assertEquals($expectedResult, t3lib_div::removeDotsFromTS($typoScript));
2241 }
2242
2243 /**
2244 * @test
2245 */
2246 public function removeDotsFromTypoScriptOverridesWithScalar() {
2247 $typoScript = array(
2248 'propertyA.' => array(
2249 'keyA.' => array(
2250 'valueA' => 1,
2251 ),
2252 'keyA' => 'willOverride',
2253 'keyB' => 2,
2254 ),
2255 'propertyB' => 3,
2256 );
2257
2258 $expectedResult = array(
2259 'propertyA' => array(
2260 'keyA' => 'willOverride',
2261 'keyB' => 2,
2262 ),
2263 'propertyB' => 3,
2264 );
2265
2266 $this->assertEquals($expectedResult, t3lib_div::removeDotsFromTS($typoScript));
2267 }
2268
2269 //////////////////////////////////////
2270 // Tests concerning naturalKeySortRecursive
2271 //////////////////////////////////////
2272
2273 /**
2274 * @test
2275 */
2276 public function naturalKeySortRecursiveReturnsFalseIfInputIsNotAnArray() {
2277 $testValues = array(
2278 1,
2279 'string',
2280 FALSE
2281 );
2282 foreach($testValues as $testValue) {
2283 $this->assertFalse(t3lib_div::naturalKeySortRecursive($testValue));
2284 }
2285 }
2286
2287 /**
2288 * @test
2289 */
2290 public function naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder() {
2291 $testArray = array(
2292 'bb' => 'bb',
2293 'ab' => 'ab',
2294 '123' => '123',
2295 'aaa' => 'aaa',
2296 'abc' => 'abc',
2297 '23' => '23',
2298 'ba' => 'ba',
2299 'bad' => 'bad',
2300 '2' => '2',
2301 'zap' => 'zap',
2302 '210' => '210'
2303 );
2304 $expectedResult = array(
2305 '2',
2306 '23',
2307 '123',
2308 '210',
2309 'aaa',
2310 'ab',
2311 'abc',
2312 'ba',
2313 'bad',
2314 'bb',
2315 'zap'
2316 );
2317 t3lib_div::naturalKeySortRecursive($testArray);
2318 $this->assertEquals($expectedResult, array_values($testArray));
2319 }
2320
2321 /**
2322 * @test
2323 */
2324 public function naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder() {
2325 $testArray = array(
2326 '2' => '2',
2327 'bb' => 'bb',
2328 'ab' => 'ab',
2329 '23' => '23',
2330 'aaa' => array(
2331 'bb' => 'bb',
2332 'ab' => 'ab',
2333 '123' => '123',
2334 'aaa' => 'aaa',
2335 '2' => '2',
2336 'abc' => 'abc',
2337 'ba' => 'ba',
2338 '23' => '23',
2339 'bad' => array(
2340 'bb' => 'bb',
2341 'ab' => 'ab',
2342 '123' => '123',
2343 'aaa' => 'aaa',
2344 'abc' => 'abc',
2345 '23' => '23',
2346 'ba' => 'ba',
2347 'bad' => 'bad',
2348 '2' => '2',
2349 'zap' => 'zap',
2350 '210' => '210'
2351 ),
2352 '210' => '210',
2353 'zap' => 'zap'
2354 ),
2355 'abc' => 'abc',
2356 'ba' => 'ba',
2357 '210' => '210',
2358 'bad' => 'bad',
2359 '123' => '123',
2360 'zap' => 'zap'
2361 );
2362
2363 $expectedResult = array(
2364 '2',
2365 '23',
2366 '123',
2367 '210',
2368 'aaa',
2369 'ab',
2370 'abc',
2371 'ba',
2372 'bad',
2373 'bb',
2374 'zap'
2375 );
2376 t3lib_div::naturalKeySortRecursive($testArray);
2377
2378 $this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa']['bad'])));
2379 $this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa'])));
2380 $this->assertEquals($expectedResult, array_values(array_keys($testArray)));
2381 }
2382
2383 //////////////////////////////////////
2384 // Tests concerning get_dirs
2385 //////////////////////////////////////
2386
2387 /**
2388 * @test
2389 */
2390 public function getDirsReturnsArrayOfDirectoriesFromGivenDirectory() {
2391 $path = PATH_t3lib;
2392 $directories = t3lib_div::get_dirs($path);
2393
2394 $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $directories);
2395 }
2396
2397 /**
2398 * @test
2399 */
2400 public function getDirsReturnsStringErrorOnPathFailure() {
2401 $path = 'foo';
2402 $result = t3lib_div::get_dirs($path);
2403 $expectedResult = 'error';
2404
2405 $this->assertEquals($expectedResult, $result);
2406 }
2407
2408
2409 //////////////////////////////////
2410 // Tests concerning hmac
2411 //////////////////////////////////
2412
2413 /**
2414 * @test
2415 */
2416 public function hmacReturnsHashOfProperLength() {
2417 $hmac = t3lib_div::hmac('message');
2418 $this->assertTrue(!empty($hmac) && is_string($hmac));
2419 $this->assertTrue(strlen($hmac) == 40);
2420 }
2421
2422 /**
2423 * @test
2424 */
2425 public function hmacReturnsEqualHashesForEqualInput() {
2426 $msg0 = 'message';
2427 $msg1 = 'message';
2428 $this->assertEquals(t3lib_div::hmac($msg0), t3lib_div::hmac($msg1));
2429 }
2430
2431 /**
2432 * @test
2433 */
2434 public function hmacReturnsNoEqualHashesForNonEqualInput() {
2435 $msg0 = 'message0';
2436 $msg1 = 'message1';
2437 $this->assertNotEquals(t3lib_div::hmac($msg0), t3lib_div::hmac($msg1));
2438 }
2439
2440
2441 //////////////////////////////////
2442 // Tests concerning quoteJSvalue
2443 //////////////////////////////////
2444
2445 /**
2446 * Data provider for quoteJSvalueTest.
2447 *
2448 * @return array
2449 */
2450 public function quoteJsValueDataProvider() {
2451 return array(
2452 'Immune characters are returned as is' => array(
2453 '._,',
2454 '._,',
2455 ),
2456 'Alphanumerical characters are returned as is' => array(
2457 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
2458 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
2459 ),
2460 'Angel brackets and ampersand are encoded' => array(
2461 '<>&',
2462 '\x3C\x3E\x26',
2463 ),
2464 'Quotes and slashes are encoded' => array(
2465 '"\'\\/',
2466 '\x22\x27\x5C\x2F',
2467 ),
2468 'Empty string stays empty' => array(
2469 '',
2470 '',
2471 ),
2472 'Exclamation mark and space are properly encoded' => array(
2473 'Hello World!',
2474 'Hello\x20World\x21',
2475 ),
2476 'Whitespaces are properly encoded' => array(
2477 TAB . LF . CR . ' ',
2478 '\x09\x0A\x0D\x20',
2479 ),
2480 'Null byte is properly encoded' => array(
2481 chr(0),
2482 '\x00',
2483 ),
2484 'Umlauts are properly encoded' => array(
2485 'ÜüÖöÄä',
2486 '\xDC\xFC\xD6\xF6\xC4\xE4',
2487 ),
2488 );
2489 }
2490
2491 /**
2492 * @test
2493 *
2494 * @param string $input
2495 * @param string $expected
2496 *
2497 * @dataProvider quoteJsValueDataProvider
2498 */
2499 public function quoteJsValueTest($input, $expected) {
2500 $this->assertSame(
2501 '\'' . $expected . '\'',
2502 t3lib_div::quoteJSvalue($input)
2503 );
2504 }
2505
2506
2507 //////////////////////////////////
2508 // Tests concerning readLLfile
2509 //////////////////////////////////
2510
2511 /**
2512 * @test
2513 */
2514 public function readLLfileHandlesLocallangXMLOverride() {
2515 $unique = uniqid('locallangXMLOverrideTest');
2516
2517 $xml = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
2518 <T3locallang>
2519 <data type="array">
2520 <languageKey index="default" type="array">
2521 <label index="buttons.logout">EXIT</label>
2522 </languageKey>
2523 </data>
2524 </T3locallang>';
2525
2526 $file = PATH_site . 'typo3temp/' . $unique . '.xml';
2527 t3lib_div::writeFileToTypo3tempDir($file, $xml);
2528
2529 // Make sure there is no cached version of the label
2530 $GLOBALS['typo3CacheManager']->getCache('t3lib_l10n')->flush();
2531
2532 // Get default value
2533 $defaultLL = t3lib_div::readLLfile('EXT:lang/locallang_core.xml', 'default');
2534
2535 // Clear language cache again
2536 $GLOBALS['typo3CacheManager']->getCache('t3lib_l10n')->flush();
2537
2538 // Set override file
2539 $GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:lang/locallang_core.xml'][$unique] = $file;
2540
2541 /** @var $store t3lib_l10n_Store */
2542 $store = t3lib_div::makeInstance('t3lib_l10n_Store');
2543 $store->flushData('EXT:lang/locallang_core.xml');
2544
2545 // Get override value
2546 $overrideLL = t3lib_div::readLLfile('EXT:lang/locallang_core.xml', 'default');
2547
2548 // Clean up again
2549 unlink($file);
2550
2551 $this->assertNotEquals($overrideLL['default']['buttons.logout'][0]['target'], '');
2552 $this->assertNotEquals($defaultLL['default']['buttons.logout'][0]['target'], $overrideLL['default']['buttons.logout'][0]['target']);
2553 $this->assertEquals($overrideLL['default']['buttons.logout'][0]['target'], 'EXIT');
2554 }
2555
2556
2557 ///////////////////////////////
2558 // Tests concerning _GETset()
2559 ///////////////////////////////
2560
2561 /**
2562 * @test
2563 */
2564 public function getSetWritesArrayToGetSystemVariable() {
2565 $_GET = array();
2566 $GLOBALS['HTTP_GET_VARS'] = array();
2567
2568 $getParameters = array('foo' => 'bar');
2569 t3lib_div::_GETset($getParameters);
2570 $this->assertSame($getParameters, $_GET);
2571 }
2572
2573 /**
2574 * @test
2575 */
2576 public function getSetWritesArrayToGlobalsHttpGetVars() {
2577 $_GET = array();
2578 $GLOBALS['HTTP_GET_VARS'] = array();
2579
2580 $getParameters = array('foo' => 'bar');
2581 t3lib_div::_GETset($getParameters);
2582 $this->assertSame($getParameters, $GLOBALS['HTTP_GET_VARS']);
2583 }
2584
2585 /**
2586 * @test
2587 */
2588 public function getSetForArrayDropsExistingValues() {
2589 $_GET = array();
2590 $GLOBALS['HTTP_GET_VARS'] = array();
2591
2592 t3lib_div::_GETset(array('foo' => 'bar'));
2593
2594 t3lib_div::_GETset(array('oneKey' => 'oneValue'));
2595
2596 $this->assertEquals(
2597 array('oneKey' => 'oneValue'),
2598 $GLOBALS['HTTP_GET_VARS']
2599 );
2600 }
2601
2602 /**
2603 * @test
2604 */
2605 public function getSetAssignsOneValueToOneKey() {
2606 $_GET = array();
2607 $GLOBALS['HTTP_GET_VARS'] = array();
2608
2609 t3lib_div::_GETset('oneValue', 'oneKey');
2610
2611 $this->assertEquals(
2612 'oneValue',
2613 $GLOBALS['HTTP_GET_VARS']['oneKey']
2614 );
2615 }
2616
2617 /**
2618 * @test
2619 */
2620 public function getSetForOneValueDoesNotDropUnrelatedValues() {
2621 $_GET = array();
2622 $GLOBALS['HTTP_GET_VARS'] = array();
2623
2624 t3lib_div::_GETset(array('foo' => 'bar'));
2625 t3lib_div::_GETset('oneValue', 'oneKey');
2626
2627 $this->assertEquals(
2628 array('foo' => 'bar', 'oneKey' => 'oneValue'),
2629 $GLOBALS['HTTP_GET_VARS']
2630 );
2631 }
2632
2633 /**
2634 * @test
2635 */
2636 public function getSetCanAssignsAnArrayToASpecificArrayElement() {
2637 $_GET = array();
2638 $GLOBALS['HTTP_GET_VARS'] = array();
2639
2640 t3lib_div::_GETset(array('childKey' => 'oneValue'), 'parentKey');
2641
2642 $this->assertEquals(
2643 array('parentKey' => array('childKey' => 'oneValue')),
2644 $GLOBALS['HTTP_GET_VARS']
2645 );
2646 }
2647
2648 /**
2649 * @test
2650 */
2651 public function getSetCanAssignAStringValueToASpecificArrayChildElement() {
2652 $_GET = array();
2653 $GLOBALS['HTTP_GET_VARS'] = array();
2654
2655 t3lib_div::_GETset('oneValue', 'parentKey|childKey');
2656
2657 $this->assertEquals(
2658 array('parentKey' => array('childKey' => 'oneValue')),
2659 $GLOBALS['HTTP_GET_VARS']
2660 );
2661 }
2662
2663 /**
2664 * @test
2665 */
2666 public function getSetCanAssignAnArrayToASpecificArrayChildElement() {
2667 $_GET = array();
2668 $GLOBALS['HTTP_GET_VARS'] = array();
2669
2670 t3lib_div::_GETset(
2671 array('key1' => 'value1', 'key2' => 'value2'),
2672 'parentKey|childKey'
2673 );
2674
2675 $this->assertEquals(
2676 array(
2677 'parentKey' => array(
2678 'childKey' => array('key1' => 'value1', 'key2' => 'value2')
2679 )
2680 ),
2681 $GLOBALS['HTTP_GET_VARS']
2682 );
2683 }
2684
2685 ///////////////////////////
2686 // Tests concerning minifyJavaScript
2687 ///////////////////////////
2688
2689 /**
2690 * @test
2691 */
2692 public function minifyJavaScriptReturnsInputStringIfNoHookIsRegistered() {
2693 unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript']);
2694 $testString = uniqid('string');
2695 $this->assertSame($testString, t3lib_div::minifyJavaScript($testString));
2696 }
2697
2698 /**
2699 * Create an own hook callback class, register as hook, and check
2700 * if given string to compress is given to hook method
2701 *
2702 * @test
2703 */
2704 public function minifyJavaScriptCallsRegisteredHookWithInputString() {
2705 $hookClassName = uniqid('tx_coretest');
2706 $minifyHookMock = $this->getMock(
2707 'stdClass',
2708 array('minify'),
2709 array(),
2710 $hookClassName
2711 );
2712
2713 $functionName = '&' . $hookClassName . '->minify';
2714 $GLOBALS['T3_VAR']['callUserFunction'][$functionName] = array();
2715 $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['obj'] = $minifyHookMock;
2716 $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['method'] = 'minify';
2717 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'][] = $functionName;
2718
2719 $minifyHookMock->expects($this->once())->method('minify')
2720 ->will($this->returnCallback(array($this, 'isMinifyJavaScriptHookCalledCallback')));
2721
2722 t3lib_div::minifyJavaScript('foo');
2723 }
2724
2725 /**
2726 * Callback function used in minifyJavaScriptCallsRegisteredHookWithInputString test
2727 *
2728 * @param array $params
2729 */
2730 public function isMinifyJavaScriptHookCalledCallback(array $params) {
2731 // We can not throw an exception here, because that would be caught by the
2732 // minifyJavaScript method under test itself. Thus, we just die if the
2733 // input string is not ok.
2734 if ($params['script'] !== 'foo') {
2735 die('broken');
2736 }
2737 }
2738
2739 /**
2740 * Create a hook callback, use callback to throw an exception and check
2741 * if the exception is given as error parameter to the calling method.
2742 *
2743 * @test
2744 */
2745 public function minifyJavaScriptReturnsErrorStringOfHookException() {
2746 $hookClassName = uniqid('tx_coretest');
2747 $minifyHookMock = $this->getMock(
2748 'stdClass',
2749 array('minify'),
2750 array(),
2751 $hookClassName
2752 );
2753
2754 $functionName = '&' . $hookClassName . '->minify';
2755 $GLOBALS['T3_VAR']['callUserFunction'][$functionName] = array();
2756 $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['obj'] = $minifyHookMock;
2757 $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['method'] = 'minify';
2758 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'][] = $functionName;
2759
2760 $minifyHookMock->expects($this->any())->method('minify')
2761 ->will($this->returnCallback(array($this, 'minifyJavaScriptErroneousCallback')));
2762
2763 $error = '';
2764 t3lib_div::minifyJavaScript('string to compress', $error);
2765 $this->assertSame('Error minifying java script: foo', $error);
2766 }
2767
2768 /**
2769 * Check if the error message that is returned by the hook callback
2770 * is logged to t3lib_div::devLog.
2771 *
2772 * @test
2773 */
2774 public function minifyJavaScriptWritesExceptionMessageToDevLog() {
2775 $t3libDivMock = uniqid('t3lib_div');
2776 eval(
2777 'class ' . $t3libDivMock . ' extends t3lib_div {' .
2778 ' public static function devLog($errorMessage) {' .
2779 ' if (!($errorMessage === \'Error minifying java script: foo\')) {' .
2780 ' throw new UnexpectedValue(\'broken\');' .
2781 ' }' .
2782 ' throw new RuntimeException();' .
2783 ' }' .
2784 '}'
2785 );
2786 $hookClassName = uniqid('tx_coretest');
2787 $minifyHookMock = $this->getMock(
2788 'stdClass',
2789 array('minify'),
2790 array(),
2791 $hookClassName
2792 );
2793
2794 $functionName = '&' . $hookClassName . '->minify';
2795 $GLOBALS['T3_VAR']['callUserFunction'][$functionName] = array();
2796 $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['obj'] = $minifyHookMock;
2797 $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['method'] = 'minify';
2798 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'][] = $functionName;
2799
2800 $minifyHookMock->expects($this->any())->method('minify')
2801 ->will($this->returnCallback(array($this, 'minifyJavaScriptErroneousCallback')));
2802
2803 $this->setExpectedException('RuntimeException');
2804 $t3libDivMock::minifyJavaScript('string to compress');
2805 }
2806
2807 /**
2808 * Callback function used in
2809 * minifyJavaScriptReturnsErrorStringOfHookException and
2810 * minifyJavaScriptWritesExceptionMessageToDevLog
2811 *
2812 * @throws RuntimeException
2813 */
2814 public function minifyJavaScriptErroneousCallback() {
2815 throw new RuntimeException('foo', 1344888548);
2816 }
2817
2818 ///////////////////////////
2819 // Tests concerning getUrl
2820 ///////////////////////////
2821
2822 /**
2823 * @test
2824 */
2825 public function getUrlWithAdditionalRequestHeadersProvidesHttpHeaderOnError() {
2826 $url = 'http://typo3.org/i-do-not-exist-' . time();
2827
2828 $report = array();
2829 t3lib_div::getUrl(
2830 $url,
2831 0,
2832 array(),
2833 $report
2834 );
2835 $this->assertContains(
2836 '404',
2837 $report['message']
2838 );
2839 }
2840
2841 /**
2842 * @test
2843 */
2844 public function getUrlProvidesWithoutAdditionalRequestHeadersHttpHeaderOnError() {
2845 $url = 'http://typo3.org/i-do-not-exist-' . time();
2846
2847 $report = array();
2848 t3lib_div::getUrl(
2849 $url,
2850 0,
2851 FALSE,
2852 $report
2853 );
2854 $this->assertContains(
2855 '404',
2856 $report['message'],
2857 'Did not provide the HTTP response header when requesting a failing URL.'
2858 );
2859 }
2860
2861
2862 ///////////////////////////////
2863 // Tests concerning fixPermissions
2864 ///////////////////////////////
2865
2866 /**
2867 * @test
2868 */
2869 public function fixPermissionsSetsGroup() {
2870 if (TYPO3_OS == 'WIN') {
2871 $this->markTestSkipped('fixPermissionsSetsGroup() tests not available on Windows');
2872 }
2873 if (!function_exists('posix_getegid')) {
2874 $this->markTestSkipped('Function posix_getegid() not available, fixPermissionsSetsGroup() tests skipped');
2875 }
2876 if (posix_getegid() === -1) {
2877 $this->markTestSkipped(
2878 'The fixPermissionsSetsGroup() is not available on Mac OS because posix_getegid() always returns -1 on Mac OS.'
2879 );
2880 }
2881
2882 // Create and prepare test file
2883 $filename = PATH_site . 'typo3temp/' . uniqid('test_');
2884 t3lib_div::writeFileToTypo3tempDir($filename, '42');
2885
2886 $currentGroupId = posix_getegid();
2887
2888 // Set target group and run method
2889 $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup'] = $currentGroupId;
2890 $fixPermissionsResult = t3lib_div::fixPermissions($filename);
2891
2892 clearstatcache();
2893 $resultFileGroup = filegroup($filename);
2894 unlink($filename);
2895
2896 $this->assertEquals($resultFileGroup, $currentGroupId);
2897 }
2898
2899 /**
2900 * @test
2901 */
2902 public function fixPermissionsSetsPermissionsToFile() {
2903 if (TYPO3_OS == 'WIN') {
2904 $this->markTestSkipped('fixPermissions() tests not available on Windows');
2905 }
2906
2907 // Create and prepare test file
2908 $filename = PATH_site . 'typo3temp/' . uniqid('test_');
2909 t3lib_div::writeFileToTypo3tempDir($filename, '42');
2910 chmod($filename, 0742);
2911
2912 // Set target permissions and run method
2913 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
2914 $fixPermissionsResult = t3lib_div::fixPermissions($filename);
2915
2916 // Get actual permissions and clean up
2917 clearstatcache();
2918 $resultFilePermissions = substr(decoct(fileperms($filename)), 2);
2919 unlink($filename);
2920
2921 // Test if everything was ok
2922 $this->assertTrue($fixPermissionsResult);
2923 $this->assertEquals($resultFilePermissions, '0660');
2924 }
2925
2926 /**
2927 * @test
2928 */
2929 public function fixPermissionsSetsPermissionsToHiddenFile() {
2930 if (TYPO3_OS == 'WIN') {
2931 $this->markTestSkipped('fixPermissions() tests not available on Windows');
2932 }
2933
2934 // Create and prepare test file
2935 $filename = PATH_site . 'typo3temp/' . uniqid('.test_');
2936 t3lib_div::writeFileToTypo3tempDir($filename, '42');
2937 chmod($filename, 0742);
2938
2939 // Set target permissions and run method
2940 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
2941 $fixPermissionsResult = t3lib_div::fixPermissions($filename);
2942
2943 // Get actual permissions and clean up
2944 clearstatcache();
2945 $resultFilePermissions = substr(decoct(fileperms($filename)), 2);
2946 unlink($filename);
2947
2948 // Test if everything was ok
2949 $this->assertTrue($fixPermissionsResult);
2950 $this->assertEquals($resultFilePermissions, '0660');
2951 }
2952
2953 /**
2954 * @test
2955 */
2956 public function fixPermissionsSetsPermissionsToDirectory() {
2957 if (TYPO3_OS == 'WIN') {
2958 $this->markTestSkipped('fixPermissions() tests not available on Windows');
2959 }
2960
2961 // Create and prepare test directory
2962 $directory = PATH_site . 'typo3temp/' . uniqid('test_');
2963 t3lib_div::mkdir($directory);
2964 chmod($directory, 1551);
2965
2966 // Set target permissions and run method
2967 $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
2968 $fixPermissionsResult = t3lib_div::fixPermissions($directory);
2969
2970 // Get actual permissions and clean up
2971 clearstatcache();
2972 $resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
2973 t3lib_div::rmdir($directory);
2974
2975 // Test if everything was ok
2976 $this->assertTrue($fixPermissionsResult);
2977 $this->assertEquals($resultDirectoryPermissions, '0770');
2978 }
2979
2980 /**
2981 * @test
2982 */
2983 public function fixPermissionsSetsPermissionsToDirectoryWithTrailingSlash() {
2984 if (TYPO3_OS == 'WIN') {
2985 $this->markTestSkipped('fixPermissions() tests not available on Windows');
2986 }
2987
2988 // Create and prepare test directory
2989 $directory = PATH_site . 'typo3temp/' . uniqid('test_');
2990 t3lib_div::mkdir($directory);
2991 chmod($directory, 1551);
2992
2993 // Set target permissions and run method
2994 $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
2995 $fixPermissionsResult = t3lib_div::fixPermissions($directory . '/');
2996
2997 // Get actual permissions and clean up
2998 clearstatcache();
2999 $resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
3000 t3lib_div::rmdir($directory);
3001
3002 // Test if everything was ok
3003 $this->assertTrue($fixPermissionsResult);
3004 $this->assertEquals($resultDirectoryPermissions, '0770');
3005 }
3006
3007 /**
3008 * @test
3009 */
3010 public function fixPermissionsSetsPermissionsToHiddenDirectory() {
3011 if (TYPO3_OS == 'WIN') {
3012 $this->markTestSkipped('fixPermissions() tests not available on Windows');
3013 }
3014
3015 // Create and prepare test directory
3016 $directory = PATH_site . 'typo3temp/' . uniqid('.test_');
3017 t3lib_div::mkdir($directory);
3018 chmod($directory, 1551);
3019
3020 // Set target permissions and run method
3021 $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
3022 $fixPermissionsResult = t3lib_div::fixPermissions($directory);
3023
3024 // Get actual permissions and clean up
3025 clearstatcache();
3026 $resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
3027 t3lib_div::rmdir($directory);
3028
3029 // Test if everything was ok
3030 $this->assertTrue($fixPermissionsResult);
3031 $this->assertEquals($resultDirectoryPermissions, '0770');
3032 }
3033
3034 /**
3035 * @test
3036 */
3037 public function fixPermissionsCorrectlySetsPermissionsRecursive() {
3038 if (TYPO3_OS == 'WIN') {
3039 $this->markTestSkipped('fixPermissions() tests not available on Windows');
3040 }
3041
3042 // Create and prepare test directory and file structure
3043 $baseDirectory = PATH_site . 'typo3temp/' . uniqid('test_');
3044 t3lib_div::mkdir($baseDirectory);
3045 chmod($baseDirectory, 1751);
3046 t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/file', '42');
3047 chmod($baseDirectory . '/file', 0742);
3048 t3lib_div::mkdir($baseDirectory . '/foo');
3049 chmod($baseDirectory . '/foo', 1751);
3050 t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/foo/file', '42');
3051 chmod($baseDirectory . '/foo/file', 0742);
3052 t3lib_div::mkdir($baseDirectory . '/.bar');
3053 chmod($baseDirectory . '/.bar', 1751);
3054 // Use this if writeFileToTypo3tempDir is fixed to create hidden files in subdirectories
3055 // t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/.bar/.file', '42');
3056 // t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/.bar/..file2', '42');
3057 touch($baseDirectory . '/.bar/.file', '42');
3058 chmod($baseDirectory . '/.bar/.file', 0742);
3059 touch($baseDirectory . '/.bar/..file2', '42');
3060 chmod($baseDirectory . '/.bar/..file2', 0742);
3061
3062 // Set target permissions and run method
3063 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
3064 $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
3065 $fixPermissionsResult = t3lib_div::fixPermissions($baseDirectory, TRUE);
3066
3067 // Get actual permissions
3068 clearstatcache();
3069 $resultBaseDirectoryPermissions = substr(decoct(fileperms($baseDirectory)), 1);
3070 $resultBaseFilePermissions = substr(decoct(fileperms($baseDirectory . '/file')), 2);
3071 $resultFooDirectoryPermissions = substr(decoct(fileperms($baseDirectory . '/foo')), 1);
3072 $resultFooFilePermissions = substr(decoct(fileperms($baseDirectory . '/foo/file')), 2);
3073 $resultBarDirectoryPermissions = substr(decoct(fileperms($baseDirectory . '/.bar')), 1);
3074 $resultBarFilePermissions = substr(decoct(fileperms($baseDirectory . '/.bar/.file')), 2);
3075 $resultBarFile2Permissions = substr(decoct(fileperms($baseDirectory . '/.bar/..file2')), 2);
3076
3077 // Clean up
3078 unlink($baseDirectory . '/file');
3079 unlink($baseDirectory . '/foo/file');
3080 unlink($baseDirectory . '/.bar/.file');
3081 unlink($baseDirectory . '/.bar/..file2');
3082 t3lib_div::rmdir($baseDirectory . '/foo');
3083 t3lib_div::rmdir($baseDirectory . '/.bar');
3084 t3lib_div::rmdir($baseDirectory);
3085
3086 // Test if everything was ok
3087 $this->assertTrue($fixPermissionsResult);
3088 $this->assertEquals($resultBaseDirectoryPermissions, '0770');
3089 $this->assertEquals($resultBaseFilePermissions, '0660');
3090 $this->assertEquals($resultFooDirectoryPermissions, '0770');
3091 $this->assertEquals($resultFooFilePermissions, '0660');
3092 $this->assertEquals($resultBarDirectoryPermissions, '0770');
3093 $this->assertEquals($resultBarFilePermissions, '0660');
3094 $this->assertEquals($resultBarFile2Permissions, '0660');
3095 }
3096
3097 /**
3098 * @test
3099 */
3100 public function fixPermissionsDoesNotSetPermissionsToNotAllowedPath() {
3101 if (TYPO3_OS == 'WIN') {
3102 $this->markTestSkipped('fixPermissions() tests not available on Windows');
3103 }
3104
3105 // Create and prepare test file
3106 $filename = PATH_site . 'typo3temp/../typo3temp/' . uniqid('test_');
3107 touch($filename);
3108 chmod($filename, 0742);
3109
3110 // Set target permissions and run method
3111 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
3112 $fixPermissionsResult = t3lib_div::fixPermissions($filename);
3113
3114 // Get actual permissions and clean up
3115 clearstatcache();
3116 $resultFilePermissions = substr(decoct(fileperms($filename)), 2);
3117 unlink($filename);
3118
3119 // Test if everything was ok
3120 $this->assertFalse($fixPermissionsResult);
3121 }
3122
3123 /**
3124 * @test
3125 */
3126 public function fixPermissionsSetsPermissionsWithRelativeFileReference() {
3127 if (TYPO3_OS == 'WIN') {
3128 $this->markTestSkipped('fixPermissions() tests not available on Windows');
3129 }
3130
3131 $filename = 'typo3temp/' . uniqid('test_');
3132 t3lib_div::writeFileToTypo3tempDir(PATH_site . $filename, '42');
3133 chmod(PATH_site . $filename, 0742);
3134
3135 // Set target permissions and run method
3136 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
3137 $fixPermissionsResult = t3lib_div::fixPermissions($filename);
3138
3139 // Get actual permissions and clean up
3140 clearstatcache();
3141 $resultFilePermissions = substr(decoct(fileperms(PATH_site . $filename)), 2);
3142 unlink(PATH_site . $filename);
3143
3144 // Test if everything was ok
3145 $this->assertTrue($fixPermissionsResult);
3146 $this->assertEquals($resultFilePermissions, '0660');
3147 }
3148
3149
3150 ///////////////////////////////
3151 // Tests concerning mkdir
3152 ///////////////////////////////
3153
3154 /**
3155 * @test
3156 */
3157 public function mkdirCreatesDirectory() {
3158 $directory = PATH_site . 'typo3temp/' . uniqid('test_');
3159 $mkdirResult = t3lib_div::mkdir($directory);
3160 clearstatcache();
3161 $directoryCreated = is_dir($directory);
3162 @rmdir($directory);
3163 $this->assertTrue($mkdirResult);
3164 $this->assertTrue($directoryCreated);
3165 }
3166
3167 /**
3168 * @test
3169 */
3170 public function mkdirCreatesHiddenDirectory() {
3171 $directory = PATH_site . 'typo3temp/' . uniqid('.test_');
3172 $mkdirResult = t3lib_div::mkdir($directory);
3173 clearstatcache();
3174 $directoryCreated = is_dir($directory);
3175 @rmdir($directory);
3176 $this->assertTrue($mkdirResult);
3177 $this->assertTrue($directoryCreated);
3178 }
3179
3180 /**
3181 * @test
3182 */
3183 public function mkdirCreatesDirectoryWithTrailingSlash() {
3184 $directory = PATH_site . 'typo3temp/' . uniqid('test_') . '/';
3185 $mkdirResult = t3lib_div::mkdir($directory);
3186 clearstatcache();
3187 $directoryCreated = is_dir($directory);
3188 @rmdir($directory);
3189 $this->assertTrue($mkdirResult);
3190 $this->assertTrue($directoryCreated);
3191 }
3192
3193 /**
3194 * @test
3195 */
3196 public function mkdirSetsPermissionsOfCreatedDirectory() {
3197 if (TYPO3_OS == 'WIN') {
3198 $this->markTestSkipped('mkdirSetsPermissionsOfCreatedDirectory() test not available on Windows');
3199 }
3200
3201 $directory = PATH_site . 'typo3temp/' . uniqid('test_');
3202 $oldUmask = umask(023);
3203 $GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0772';
3204 t3lib_div::mkdir($directory);
3205 clearstatcache();
3206 $resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
3207 umask($oldUmask);
3208 rmdir($directory);
3209 $this->assertEquals($resultDirectoryPermissions, '0772');
3210 }
3211
3212 /**
3213 * @test