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