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