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