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