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