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