Project

General

Profile

Bug #30311 » class.t3lib_divTest.php

Updated Testcases - David M., 2011-09-29 14:40

 
<?php
/***************************************************************
* Copyright notice
*
* (c) 2009-2011 Ingo Renner <ingo@typo3.org>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/

/**
* Testcase for class t3lib_div
*
* @author Ingo Renner <ingo@typo3.org>
* @author Oliver Klee <typo3-coding@oliverklee.de>
*
* @package TYPO3
* @subpackage t3lib
*/
class t3lib_divTest extends tx_phpunit_testcase {

/**
* Enable backup of global and system variables
*
* @var boolean
*/
protected $backupGlobals = TRUE;

/**
* Exclude TYPO3_DB from backup/ restore of $GLOBALS
* because resource types cannot be handled during serializing
*
* @var array
*/
protected $backupGlobalsBlacklist = array('TYPO3_DB');

public function tearDown() {
t3lib_div::purgeInstances();
}


///////////////////////////////
// Tests concerning gif_compress
///////////////////////////////

/**
* @test
*/
public function gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() test not available on Windows.');
}

if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] || !$GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']) {
$this->markTestSkipped('gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() test not available without imagemagick setup.');
}

$testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
$fixtureGifFile = $testFinder->getAbsoluteCoreTestsPath() . 't3lib/fixtures/clear.gif';

$GLOBALS['TYPO3_CONF_VARS']['GFX']['gif_compress'] = TRUE;

// Copy file to unique filename in typo3temp, set target permissions and run method
$testFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.gif';
@copy($fixtureGifFile, $testFilename);
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
t3lib_div::gif_compress($testFilename, 'IM');

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($testFilename)), 2);
t3lib_div::unlink_tempfile($testFilename);

$this->assertEquals($resultFilePermissions, '0777');
}

/**
* @test
*/
public function gifCompressFixesPermissionOfConvertedFileIfUsingGd() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('gifCompressFixesPermissionOfConvertedFileIfUsingImagemagick() test not available on Windows.');
}

$testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
$fixtureGifFile = $testFinder->getAbsoluteCoreTestsPath() . 't3lib/fixtures/clear.gif';

$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'] = TRUE;
$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] = FALSE;

// Copy file to unique filename in typo3temp, set target permissions and run method
$testFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.gif';
@copy($fixtureGifFile, $testFilename);
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
t3lib_div::gif_compress($testFilename, 'GD');

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($testFilename)), 2);
t3lib_div::unlink_tempfile($testFilename);

$this->assertEquals($resultFilePermissions, '0777');
}

///////////////////////////////
// Tests concerning png_to_gif_by_imagemagick
///////////////////////////////

/**
* @test
*/
public function pngToGifByImagemagickFixesPermissionsOfConvertedFile() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('pngToGifByImagemagickFixesPermissionsOfConvertedFile() test not available on Windows.');
}

if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] || !$GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']) {
$this->markTestSkipped('pngToGifByImagemagickFixesPermissionsOfConvertedFile() test not available without imagemagick setup.');
}

$testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
$fixturePngFile = $testFinder->getAbsoluteCoreTestsPath() . 't3lib/fixtures/clear.png';

$GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif'] = TRUE;

// Copy file to unique filename in typo3temp, set target permissions and run method
$testFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.png';
@copy($fixturePngFile, $testFilename);
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
$newGifFile = t3lib_div::png_to_gif_by_imagemagick($testFilename);

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($newGifFile)), 2);
t3lib_div::unlink_tempfile($newGifFile);

$this->assertEquals($resultFilePermissions, '0777');
}

///////////////////////////////
// Tests concerning read_png_gif
///////////////////////////////

/**
* @test
*/
public function readPngGifFixesPermissionsOfConvertedFile() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('readPngGifFixesPermissionsOfConvertedFile() test not available on Windows.');
}

if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
$this->markTestSkipped('readPngGifFixesPermissionsOfConvertedFile() test not available without imagemagick setup.');
}

$testFinder = t3lib_div::makeInstance('Tx_Phpunit_Service_TestFinder');
$testGifFile = $testFinder->getAbsoluteCoreTestsPath() . 't3lib/fixtures/clear.gif';

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';
$newPngFile = t3lib_div::read_png_gif($testGifFile, TRUE);

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($newPngFile)), 2);
t3lib_div::unlink_tempfile($newPngFile);

$this->assertEquals($resultFilePermissions, '0777');
}

///////////////////////////
// Tests concerning cmpIPv4
///////////////////////////

/**
* Data provider for cmpIPv4ReturnsTrueForMatchingAddress
*
* @return array Data sets
*/
public static function cmpIPv4DataProviderMatching() {
return array(
'host with full IP address' => array('127.0.0.1', '127.0.0.1'),
'host with two wildcards at the end' => array('127.0.0.1', '127.0.*.*'),
'host with wildcard at third octet' => array('127.0.0.1', '127.0.*.1'),
'host with wildcard at second octet' => array('127.0.0.1', '127.*.0.1'),
'/8 subnet' => array('127.0.0.1', '127.1.1.1/8'),
'/32 subnet (match only name)' => array('127.0.0.1', '127.0.0.1/32'),
'/30 subnet' => array('10.10.3.1', '10.10.3.3/30'),
'host with wildcard in list with IPv4/IPv6 addresses' => array('192.168.1.1', '127.0.0.1, 1234:5678::/126, 192.168.*'),
'host in list with IPv4/IPv6 addresses' => array('192.168.1.1', '::1, 1234:5678::/126, 192.168.1.1'),
);
}

/**
* @test
* @dataProvider cmpIPv4DataProviderMatching
*/
public function cmpIPv4ReturnsTrueForMatchingAddress($ip, $list) {
$this->assertTrue(t3lib_div::cmpIPv4($ip, $list));
}

/**
* Data provider for cmpIPv4ReturnsFalseForNotMatchingAddress
*
* @return array Data sets
*/
public static function cmpIPv4DataProviderNotMatching() {
return array(
'single host' => array('127.0.0.1', '127.0.0.2'),
'single host with wildcard' => array('127.0.0.1', '127.*.1.1'),
'single host with /32 subnet mask' => array('127.0.0.1', '127.0.0.2/32'),
'/31 subnet' => array('127.0.0.1', '127.0.0.2/31'),
'list with IPv4/IPv6 addresses' => array('127.0.0.1', '10.0.2.3, 192.168.1.1, ::1'),
'list with only IPv6 addresses' => array('10.20.30.40', '::1, 1234:5678::/127'),
);
}

/**
* @test
* @dataProvider cmpIPv4DataProviderNotMatching
*/
public function cmpIPv4ReturnsFalseForNotMatchingAddress($ip, $list) {
$this->assertFalse(t3lib_div::cmpIPv4($ip, $list));
}
///////////////////////////
// Tests concerning cmpIPv6
///////////////////////////

/**
* Data provider for cmpIPv6ReturnsTrueForMatchingAddress
*
* @return array Data sets
*/
public static function cmpIPv6DataProviderMatching() {
return array(
'empty address' => array('::', '::'),
'empty with netmask in list' => array('::', '::/0'),
'empty with netmask 0 and host-bits set in list' => array('::', '::123/0'),
'localhost' => array('::1', '::1'),
'localhost with leading zero blocks' => array('::1', '0:0::1'),
'host with submask /128' => array('::1', '0:0::1/128'),
'/16 subnet' => array('1234::1', '1234:5678::/16'),
'/126 subnet' => array('1234:5678::3', '1234:5678::/126'),
'/126 subnet with host-bits in list set' => array('1234:5678::3', '1234:5678::2/126'),
'list with IPv4/IPv6 addresses' => array('1234:5678::3', '::1, 127.0.0.1, 1234:5678::/126, 192.168.1.1'),
);
}

/**
* @test
* @dataProvider cmpIPv6DataProviderMatching
*/
public function cmpIPv6ReturnsTrueForMatchingAddress($ip, $list) {
$this->assertTrue(t3lib_div::cmpIPv6($ip, $list));
}

/**
* Data provider for cmpIPv6ReturnsFalseForNotMatchingAddress
*
* @return array Data sets
*/
public static function cmpIPv6DataProviderNotMatching() {
return array(
'empty against localhost' => array('::', '::1'),
'empty against localhost with /128 netmask' => array('::', '::1/128'),
'localhost against different host' => array('::1', '::2'),
'localhost against host with prior bits set' => array('::1', '::1:1'),
'host against different /17 subnet' => array('1234::1', '1234:f678::/17'),
'host against different /127 subnet' => array('1234:5678::3', '1234:5678::/127'),
'host against IPv4 address list' => array('1234:5678::3', '127.0.0.1, 192.168.1.1'),
'host against mixed list with IPv6 host in different subnet' => array('1234:5678::3', '::1, 1234:5678::/127'),
);
}

/**
* @test
* @dataProvider cmpIPv6DataProviderNotMatching
*/
public function cmpIPv6ReturnsFalseForNotMatchingAddress($ip, $list) {
$this->assertFalse(t3lib_div::cmpIPv6($ip, $list));
}

///////////////////////////////
// Tests concerning IPv6Hex2Bin
///////////////////////////////

/**
* Data provider for IPv6Hex2BinCorrect
*
* @return array Data sets
*/
public static function IPv6Hex2BinDataProviderCorrect() {
return array(
'empty 1' => array('::', str_pad('', 16, "\x00")),
'empty 2, already normalized' => array('0000:0000:0000:0000:0000:0000:0000:0000', str_pad('', 16, "\x00")),
'already normalized' => array('0102:0304:0000:0000:0000:0000:0506:0078', "\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78"),
'expansion in middle 1' => array('1::2', "\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02"),
'expansion in middle 2' => array('beef::fefa', "\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa"),
);
}

/**
* @test
* @dataProvider IPv6Hex2BinDataProviderCorrect
*/
public function IPv6Hex2BinCorrectlyConvertsAddresses($hex, $binary) {
$this->assertTrue(t3lib_div::IPv6Hex2Bin($hex) === $binary);
}

///////////////////////////////
// Tests concerning IPv6Bin2Hex
///////////////////////////////

/**
* Data provider for IPv6Bin2HexCorrect
*
* @return array Data sets
*/
public static function IPv6Bin2HexDataProviderCorrect() {
return array(
'empty' => array(str_pad('', 16, "\x00"), '::'),
'non-empty front' => array("\x01" . str_pad('', 15, "\x00"), '100::'),
'non-empty back' => array(str_pad('', 15, "\x00") . "\x01", '::1'),
'normalized' => array("\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78", '102:304::506:78'),
'expansion in middle 1' => array("\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02", '1::2'),
'expansion in middle 2' => array("\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa", 'beef::fefa'),
);
}

/**
* @test
* @dataProvider IPv6Bin2HexDataProviderCorrect
*/
public function IPv6Bin2HexCorrectlyConvertsAddresses($binary, $hex) {
$this->assertEquals(t3lib_div::IPv6Bin2Hex($binary), $hex);
}

////////////////////////////////////////////////
// Tests concerning normalizeIPv6 / compressIPv6
////////////////////////////////////////////////

/**
* Data provider for normalizeIPv6ReturnsCorrectlyNormalizedFormat
*
* @return array Data sets
*/
public static function normalizeCompressIPv6DataProviderCorrect() {
return array(
'empty' => array('::', '0000:0000:0000:0000:0000:0000:0000:0000'),
'localhost' => array('::1', '0000:0000:0000:0000:0000:0000:0000:0001'),
'some address on right side' => array('::f0f', '0000:0000:0000:0000:0000:0000:0000:0f0f'),
'expansion in middle 1' => array('1::2', '0001:0000:0000:0000:0000:0000:0000:0002'),
'expansion in middle 2' => array('1:2::3', '0001:0002:0000:0000:0000:0000:0000:0003'),
'expansion in middle 3' => array('1::2:3', '0001:0000:0000:0000:0000:0000:0002:0003'),
'expansion in middle 4' => array('1:2::3:4:5', '0001:0002:0000:0000:0000:0003:0004:0005'),
);
}

/**
* @test
* @dataProvider normalizeCompressIPv6DataProviderCorrect
*/
public function normalizeIPv6CorrectlyNormalizesAddresses($compressed, $normalized) {
$this->assertEquals(t3lib_div::normalizeIPv6($compressed), $normalized);
}

/**
* @test
* @dataProvider normalizeCompressIPv6DataProviderCorrect
*/
public function compressIPv6CorrectlyCompressesAdresses($compressed, $normalized) {
$this->assertEquals(t3lib_div::compressIPv6($normalized), $compressed);
}

///////////////////////////////
// Tests concerning validIP
///////////////////////////////

/**
* Data provider for checkValidIpReturnsTrueForValidIp
*
* @return array Data sets
*/
public static function validIpDataProvider() {
return array(
'0.0.0.0' => array('0.0.0.0'),
'private IPv4 class C' => array('192.168.0.1'),
'private IPv4 class A' => array('10.0.13.1'),
'private IPv6' => array('fe80::daa2:5eff:fe8b:7dfb'),
);
}

/**
* @test
* @dataProvider validIpDataProvider
*/
public function validIpReturnsTrueForValidIp($ip) {
$this->assertTrue(t3lib_div::validIP($ip));
}

/**
* Data provider for checkValidIpReturnsFalseForInvalidIp
*
* @return array Data sets
*/
public static function invalidIpDataProvider() {
return array(
'null' => array(NULL),
'zero' => array(0),
'string' => array('test'),
'string empty' => array(''),
'string NULL' => array('NULL'),
'out of bounds IPv4' => array('300.300.300.300'),
'dotted decimal notation with only two dots' => array('127.0.1'),
);
}

/**
* @test
* @dataProvider invalidIpDataProvider
*/
public function validIpReturnsFalseForInvalidIp($ip) {
$this->assertFalse(t3lib_div::validIP($ip));
}

///////////////////////////////
// Tests concerning cmpFQDN
///////////////////////////////

/**
* Data provider for cmpFqdnReturnsTrue
*
* @return array Data sets
*/
public static function cmpFqdnValidDataProvider() {
return array(
'localhost should usually resolve, IPv4' => array('127.0.0.1', '*'),
'localhost should usually resolve, IPv6' => array('::1', '*'),
// other testcases with resolving not possible since it would
// require a working IPv4/IPv6-connectivity
'aaa.bbb.ccc.ddd.eee, full' => array('aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.ddd.eee'),
'aaa.bbb.ccc.ddd.eee, wildcard first' => array('aaa.bbb.ccc.ddd.eee', '*.ccc.ddd.eee'),
'aaa.bbb.ccc.ddd.eee, wildcard last' => array('aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.*'),
'aaa.bbb.ccc.ddd.eee, wildcard middle' => array('aaa.bbb.ccc.ddd.eee', 'aaa.*.eee'),
'list-matches, 1' => array('aaa.bbb.ccc.ddd.eee', 'xxx, yyy, zzz, aaa.*.eee'),
'list-matches, 2' => array('aaa.bbb.ccc.ddd.eee', '127:0:0:1,,aaa.*.eee,::1'),
);
}

/**
* @test
* @dataProvider cmpFqdnValidDataProvider
*/
public function cmpFqdnReturnsTrue($baseHost, $list) {
$this->assertTrue(t3lib_div::cmpFQDN($baseHost, $list));
}

/**
* Data provider for cmpFqdnReturnsFalse
*
* @return array Data sets
*/
public static function cmpFqdnInvalidDataProvider() {
return array(
'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'),
'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'),
);
}

/**
* @test
* @dataProvider cmpFqdnInvalidDataProvider
*/
public function cmpFqdnReturnsFalse($baseHost, $list) {
$this->assertFalse(t3lib_div::cmpFQDN($baseHost, $list));
}


///////////////////////////////
// Tests concerning testInt
///////////////////////////////

/**
* Data provider for testIntReturnsTrue
*
* @return array Data sets
*/
public function functionTestIntValidDataProvider() {
return array(
'int' => array(32425),
'negative int' => array(-32425),
'largest int' => array(PHP_INT_MAX),
'int as string' => array('32425'),
'negative int as string' => array('-32425'),
'zero' => array(0),
'zero as string' => array('0'),
);
}

/**
* @test
* @dataProvider functionTestIntValidDataProvider
*/
public function testIntReturnsTrue($int) {
$this->assertTrue(t3lib_utility_Math::canBeInterpretedAsInteger($int));
}

/**
* Data provider for testIntReturnsFalse
*
* @return array Data sets
*/
public function functionTestIntInvalidDataProvider() {
return array(
'int as string with leading zero' => array('01234'),
'positive int as string with plus modifier' => array('+1234'),
'negative int as string with leading zero' => array('-01234'),
'largest int plus one' => array(PHP_INT_MAX + 1),
'string' => array('testInt'),
'empty string' => array(''),
'int in string' => array('5 times of testInt'),
'int as string with space after' => array('5 '),
'int as string with space before' => array(' 5'),
'int as string with many spaces before' => array(' 5'),
'float' => array(3.14159),
'float as string' => array('3.14159'),
'float as string only a dot' => array('10.'),
'float as string trailing zero would evaluate to int 10' => array('10.0'),
'float as string trailing zeros would evaluate to int 10' => array('10.00'),
'null' => array(NULL),
'empty array' => array(array()),
'int in array' => array(array(32425)),
'int as string in array' => array(array('32425')),
);
}

/**
* @test
* @dataProvider functionTestIntInvalidDataProvider
*/
public function testIntReturnsFalse($int) {
$this->assertFalse(t3lib_utility_Math::canBeInterpretedAsInteger($int));
}


///////////////////////////////
// Tests concerning isFirstPartOfStr
///////////////////////////////

/**
* Data provider for isFirstPartOfStrReturnsTrueForMatchingFirstParts
*
* @return array
*/
public function isFirstPartOfStrReturnsTrueForMatchingFirstPartDataProvider() {
return array(
'match first part of string' => array('hello world', 'hello'),
'match whole string' => array('hello', 'hello'),
'integer is part of string with same number' => array('24', 24),
'string is part of integer with same number' => array(24, '24'),
'integer is part of string starting with same number' => array('24 beer please', 24),
);
}

/**
* @test
* @dataProvider isFirstPartOfStrReturnsTrueForMatchingFirstPartDataProvider
*/
public function isFirstPartOfStrReturnsTrueForMatchingFirstPart($string, $part) {
$this->assertTrue(t3lib_div::isFirstPartOfStr($string, $part));
}

/**
* Data provider for checkIsFirstPartOfStrReturnsFalseForNotMatchingFirstParts
*
* @return array
*/
public function isFirstPartOfStrReturnsFalseForNotMatchingFirstPartDataProvider() {
return array(
'no string match' => array('hello', 'bye'),
'no case sensitive string match' => array('hello world', 'Hello'),
'array is not part of string' => array('string', array()),
'string is not part of array' => array(array(), 'string'),
'NULL is not part of string' => array('string', NULL),
'string is not part of array' => array(NULL, 'string'),
'NULL is not part of array' => array(array(), NULL),
'array is not part of string' => array(NULL, array()),
'empty string is not part of empty string' => array('', ''),
'NULL is not part of empty string' => array('', NULL),
'false is not part of empty string' => array('', FALSE),
'empty string is not part of NULL' => array(NULL, ''),
'empty string is not part of false' => array(FALSE, ''),
'empty string is not part of zero integer' => array(0, ''),
'zero integer is not part of NULL' => array(NULL, 0),
'zero integer is not part of empty string' => array('', 0),
);
}

/**
* @test
* @dataProvider isFirstPartOfStrReturnsFalseForNotMatchingFirstPartDataProvider
*/
public function isFirstPartOfStrReturnsFalseForNotMatchingFirstPart($string, $part) {
$this->assertFalse(t3lib_div::isFirstPartOfStr($string, $part));
}


///////////////////////////////
// Tests concerning splitCalc
///////////////////////////////

/**
* Data provider for splitCalc
*
* @return array expected values, arithmetic expression
*/
public function splitCalcDataProvider() {
return array(
'empty string returns empty array' => array(
array(),
'',
),
'number without operator returns array with plus and number' => array(
array(array('+', 42)),
'42',
),
'two numbers with asterisk return first number with plus and second number with asterisk' => array(
array(array('+', 42), array('*', 31)),
'42 * 31',
),
);
}

/**
* @test
* @dataProvider splitCalcDataProvider
*/
public function splitCalcCorrectlySplitsExpression($expected, $expression) {
$this->assertEquals($expected, t3lib_div::splitCalc($expression, '+-*/'));
}


//////////////////////////////////
// Tests concerning calcPriority
//////////////////////////////////

/**
* Data provider for calcPriority
*
* @return array expected values, arithmetic expression
*/
public function calcPriorityDataProvider() {
return array(
'add' => array(9, '6 + 3'),
'substract with positive result' => array(3, '6 - 3'),
'substract with negative result' => array(-3, '3 - 6'),
'multiply' => array(6, '2 * 3'),
'divide' => array(2.5, '5 / 2'),
'modulus' => array(1, '5 % 2'),
'power' => array(8, '2 ^ 3'),
'three operands with non integer result' => array(6.5, '5 + 3 / 2'),
'three operands with power' => array(14, '5 + 3 ^ 2'),
'three operads with modulus' => array(4, '5 % 2 + 3'),
'four operands' => array(3, '2 + 6 / 2 - 2'),
'division by zero when dividing' => array('ERROR: dividing by zero', '2 / 0'),
'division by zero with modulus' => array('ERROR: dividing by zero', '2 % 0')
);
}

/**
* @test
* @dataProvider calcPriorityDataProvider
*/
public function calcPriorityCorrectlyCalculatesExpression($expected, $expression) {
$this->assertEquals($expected, t3lib_div::calcPriority($expression));
}

//////////////////////////////////
// Tests concerning calcParenthesis
//////////////////////////////////

/**
* Data provider for calcParenthesis
*
* @return array expected values, arithmetic expression
*/
public function calcParenthesisDataProvider() {
return array(
'starts with parenthesis' => array(18, '(6 + 3) * 2'),
'ends with parenthesis' => array(6, '2 * (6 - 3)'),
'multiple parentheses' => array(-6, '(3 - 6) * (4 - 2)'),
'nested parentheses' => array(22, '2 * (3 + 2 + (3 * 2))'),
'parenthesis with division' => array(15, '5 / 2 * (3 * 2)'),
);
}

/**
* @test
* @dataProvider calcParenthesisDataProvider
*/
public function calcParenthesisCorrectlyCalculatesExpression($expected, $expression) {
$this->assertEquals($expected, t3lib_div::calcParenthesis($expression));
}

//////////////////////////////////
// Tests concerning calcPriority
//////////////////////////////////

/**
* Data provider for valid validEmail's
*
* @return array Valid email addresses
*/
public function validEmailValidDataProvider() {
return array(
'short mail address' => array('a@b.c'),
'simple mail address' => array('test@example.com'),
'uppercase characters' => array('QWERTYUIOPASDFGHJKLZXCVBNM@QWERTYUIOPASDFGHJKLZXCVBNM.NET'),
// 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
// 'equal sign in local part' => array('test=mail@example.com'),
'dash in local part' => array('test-mail@example.com'),
'plus in local part' => array('test+mail@example.com'),
// 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
// 'question mark in local part' => array('test?mail@example.com'),
'slash in local part' => array('foo/bar@example.com'),
'hash in local part' => array('foo#bar@example.com'),
// 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
// 'dot in local part' => array('firstname.lastname@employee.2something.com'),
// Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6, but not ok with 5.3.2
// 'dash as local part' => array('-@foo.com'),
'umlauts in local part' => array('äöüfoo@bar.com'),
'umlauts in domain part' => array('foo@äöüfoo.com'),
);
}

/**
* @test
* @dataProvider validEmailValidDataProvider
*/
public function validEmailReturnsTrueForValidMailAddress($address) {
$this->assertTrue(t3lib_div::validEmail($address));
}

/**
* Data provider for invalid validEmail's
*
* @return array Invalid email addresses
*/
public function validEmailInvalidDataProvider() {
return array(
'@ sign only' => array('@'),
'duplicate @' => array('test@@example.com'),
'duplicate @ combined with further special characters in local part' => array('test!.!@#$%^&*@example.com'),
'opening parenthesis in local part' => array('foo(bar@example.com'),
'closing parenthesis in local part' => array('foo)bar@example.com'),
'opening square bracket in local part' => array('foo[bar@example.com'),
'closing square bracket as local part' => array(']@example.com'),
// Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6, but not ok with 5.3.2
// 'top level domain only' => array('test@com'),
'dash as second level domain' => array('foo@-.com'),
'domain part starting with dash' => array('foo@-foo.com'),
'domain part ending with dash' => array('foo@foo-.com'),
'number as top level domain' => array('foo@bar.123'),
// Fix / change if TYPO3 php requirement changed: Address not ok with 5.2.6, but ok with 5.3.2 (?)
// 'dash as top level domain' => array('foo@bar.-'),
'dot at beginning of domain part' => array('test@.com'),
// Fix / change if TYPO3 php requirement changed: Address ok with 5.2.6, but not ok with 5.3.2
// 'local part ends with dot' => array('e.x.a.m.p.l.e.@example.com'),
'trailing whitespace' => array('test@example.com '),
'trailing carriage return' => array('test@example.com' . CR),
'trailing linefeed' => array('test@example.com' . LF),
'trailing carriage return linefeed' => array('test@example.com' . CRLF),
'trailing tab' => array('test@example.com' . TAB),
);
}

/**
* @test
* @dataProvider validEmailInvalidDataProvider
*/
public function validEmailReturnsFalseForInvalidMailAddress($address) {
$this->assertFalse(t3lib_div::validEmail($address));
}


//////////////////////////////////
// Tests concerning intExplode
//////////////////////////////////

/**
* @test
*/
public function intExplodeConvertsStringsToInteger() {
$testString = '1,foo,2';
$expectedArray = array(1, 0, 2);
$actualArray = t3lib_div::intExplode(',', $testString);

$this->assertEquals($expectedArray, $actualArray);
}

//////////////////////////////////
// Tests concerning intInRange
//////////////////////////////////
/**
* Data provider for intInRangeForcesIntegerIntoBoundaries
*
* @return array expected values, arithmetic expression
*/
public function intInRangeForcesIntegerIntoDefaultBoundariesDataProvider() {
return array(
'negativeValue' => array(0, -10),
'normalValue' => array(30, 30),
'veryHighValue' => array(2000000000, 3000000001),
'zeroValue' => array(0, 0),
'anotherNormalValue' => array(12309, 12309)
);
}

/**
* @test
* @dataProvider intInRangeForcesIntegerIntoDefaultBoundariesDataProvider
*/
public function intInRangeForcesIntegerIntoDefaultBoundaries($expected, $value) {
$this->assertEquals($expected, t3lib_div::intInRange($value, 0));
}

/**
* @test
*/
public function intInRangeSetsDefaultValueIfZeroValueIsGiven() {
$this->assertEquals(42, t3lib_div::intInRange('', 0, 2000000000, 42));
}

//////////////////////////////////
// Tests concerning intval_positive
//////////////////////////////////
/**
* @test
*/
public function intvalPositiveReturnsZeroForNegativeValues() {
$this->assertEquals(0, t3lib_div::intval_positive(-123));
}

/**
* @test
*/
public function intvalPositiveReturnsTheInputValueForPositiveValues() {
$this->assertEquals(123, t3lib_div::intval_positive(123));
}

//////////////////////////////////
// Tests concerning int_from_ver
//////////////////////////////////
/**
* Data Provider for intFromVerConvertsVersionNumbersToIntegersDataProvider
*
* return array
*/
public function intFromVerConvertsVersionNumbersToIntegersDataProvider() {
return array(
array('4003003', '4.3.3'),
array('4012003', '4.12.3'),
array('5000000', '5.0.0'),
array('3008001', '3.8.1'),
array('1012', '0.1.12')
);
}

/**
* @test
* @dataProvider intFromVerConvertsVersionNumbersToIntegersDataProvider
*/
public function intFromVerConvertsVersionNumbersToIntegers($expected, $version) {
$this->assertEquals($expected, t3lib_div::int_from_ver($version));
}

//////////////////////////////////
// Tests concerning revExplode
//////////////////////////////////

/**
* @test
*/
public function revExplodeExplodesString() {
$testString = 'my:words:here';
$expectedArray = array('my:words', 'here');
$actualArray = t3lib_div::revExplode(':', $testString, 2);

$this->assertEquals($expectedArray, $actualArray);
}


//////////////////////////////////
// Tests concerning trimExplode
//////////////////////////////////

/**
* @test
*/
public function checkTrimExplodeTrimsSpacesAtElementStartAndEnd() {
$testString = ' a , b , c ,d ,, e,f,';
$expectedArray = array('a', 'b', 'c', 'd', '', 'e', 'f', '');
$actualArray = t3lib_div::trimExplode(',', $testString);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeRemovesNewLines() {
$testString = ' a , b , ' . LF . ' ,d ,, e,f,';
$expectedArray = array('a', 'b', 'd', 'e', 'f');
$actualArray = t3lib_div::trimExplode(',', $testString, TRUE);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeRemovesEmptyElements() {
$testString = 'a , b , c , ,d ,, ,e,f,';
$expectedArray = array('a', 'b', 'c', 'd', 'e', 'f');
$actualArray = t3lib_div::trimExplode(',', $testString, TRUE);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeKeepsRemainingResultsWithEmptyItemsAfterReachingLimitWithPositiveParameter() {
$testString = ' a , b , c , , d,, ,e ';
$expectedArray = array('a', 'b', 'c,,d,,,e');
// Limiting returns the rest of the string as the last element
$actualArray = t3lib_div::trimExplode(',', $testString, FALSE, 3);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeKeepsRemainingResultsWithoutEmptyItemsAfterReachingLimitWithPositiveParameter() {
$testString = ' a , b , c , , d,, ,e ';
$expectedArray = array('a', 'b', 'c,d,e');
// Limiting returns the rest of the string as the last element
$actualArray = t3lib_div::trimExplode(',', $testString, TRUE, 3);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeKeepsRamainingResultsWithEmptyItemsAfterReachingLimitWithNegativeParameter() {
$testString = ' a , b , c , d, ,e, f , , ';
$expectedArray = array('a', 'b', 'c', 'd', '', 'e');
// limiting returns the rest of the string as the last element
$actualArray = t3lib_div::trimExplode(',', $testString, FALSE, -3);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeKeepsRamainingResultsWithoutEmptyItemsAfterReachingLimitWithNegativeParameter() {
$testString = ' a , b , c , d, ,e, f , , ';
$expectedArray = array('a', 'b', 'c');
// Limiting returns the rest of the string as the last element
$actualArray = t3lib_div::trimExplode(',', $testString, TRUE, -3);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeReturnsExactResultsWithoutReachingLimitWithPositiveParameter() {
$testString = ' a , b , , c , , , ';
$expectedArray = array('a', 'b', 'c');
// Limiting returns the rest of the string as the last element
$actualArray = t3lib_div::trimExplode(',', $testString, TRUE, 4);

$this->assertEquals($expectedArray, $actualArray);
}

/**
* @test
*/
public function checkTrimExplodeKeepsZeroAsString() {
$testString = 'a , b , c , ,d ,, ,e,f, 0 ,';
$expectedArray = array('a', 'b', 'c', 'd', 'e', 'f', '0');
$actualArray = t3lib_div::trimExplode(',', $testString, TRUE);

$this->assertEquals($expectedArray, $actualArray);
}


//////////////////////////////////
// Tests concerning removeArrayEntryByValue
//////////////////////////////////

/**
* @test
*/
public function checkRemoveArrayEntryByValueRemovesEntriesFromOneDimensionalArray() {
$inputArray = array(
'0' => 'test1',
'1' => 'test2',
'2' => 'test3',
'3' => 'test2',
);
$compareValue = 'test2';
$expectedResult = array(
'0' => 'test1',
'2' => 'test3',
);
$actualResult = t3lib_div::removeArrayEntryByValue($inputArray, $compareValue);
$this->assertEquals($expectedResult, $actualResult);
}

/**
* @test
*/
public function checkRemoveArrayEntryByValueRemovesEntriesFromMultiDimensionalArray() {
$inputArray = array(
'0' => 'foo',
'1' => array(
'10' => 'bar',
),
'2' => 'bar',
);
$compareValue = 'bar';
$expectedResult = array(
'0' => 'foo',
'1' => array(),
);
$actualResult = t3lib_div::removeArrayEntryByValue($inputArray, $compareValue);
$this->assertEquals($expectedResult, $actualResult);
}

/**
* @test
*/
public function checkRemoveArrayEntryByValueRemovesEntryWithEmptyString() {
$inputArray = array(
'0' => 'foo',
'1' => '',
'2' => 'bar',
);
$compareValue = '';
$expectedResult = array(
'0' => 'foo',
'2' => 'bar',
);
$actualResult = t3lib_div::removeArrayEntryByValue($inputArray, $compareValue);
$this->assertEquals($expectedResult, $actualResult);
}

//////////////////////////////////
// Tests concerning getBytesFromSizeMeasurement
//////////////////////////////////

/**
* Data provider for getBytesFromSizeMeasurement
*
* @return array expected value, input string
*/
public function getBytesFromSizeMeasurementDataProvider() {
return array(
'100 kilo Bytes' => array('102400', '100k'),
'100 mega Bytes' => array('104857600', '100m'),
'100 giga Bytes' => array('107374182400', '100g'),
);
}

/**
* @test
* @dataProvider getBytesFromSizeMeasurementDataProvider
*/
public function getBytesFromSizeMeasurementCalculatesCorrectByteValue($expected, $byteString) {
$this->assertEquals($expected, t3lib_div::getBytesFromSizeMeasurement($byteString));
}


//////////////////////////////////
// Tests concerning getIndpEnv
//////////////////////////////////

/**
* @test
*/
public function getIndpEnvTypo3SitePathReturnNonEmptyString() {
$this->assertTrue(strlen(t3lib_div::getIndpEnv('TYPO3_SITE_PATH')) >= 1);
}

/**
* @test
*/
public function getIndpEnvTypo3SitePathReturnsStringStartingWithSlash() {
$result = t3lib_div::getIndpEnv('TYPO3_SITE_PATH');
$this->assertEquals('/', $result[0]);
}

/**
* @test
*/
public function getIndpEnvTypo3SitePathReturnsStringEndingWithSlash() {
$result = t3lib_div::getIndpEnv('TYPO3_SITE_PATH');
$this->assertEquals('/', $result[strlen($result) - 1]);
}

/**
* @return array
*/
public static function hostnameAndPortDataProvider() {
return array(
'localhost ipv4 without port' => array('127.0.0.1', '127.0.0.1', ''),
'localhost ipv4 with port' => array('127.0.0.1:81', '127.0.0.1', '81'),
'localhost ipv6 without port' => array('[::1]', '[::1]', ''),
'localhost ipv6 with port' => array('[::1]:81', '[::1]', '81'),
'ipv6 without port' => array('[2001:DB8::1]', '[2001:DB8::1]', ''),
'ipv6 with port' => array('[2001:DB8::1]:81', '[2001:DB8::1]', '81'),
'hostname without port' => array('lolli.did.this', 'lolli.did.this', ''),
'hostname with port' => array('lolli.did.this:42', 'lolli.did.this', '42'),
);
}

/**
* @test
* @dataProvider hostnameAndPortDataProvider
*/
public function getIndpEnvTypo3HostOnlyParsesHostnamesAndIpAdresses($httpHost, $expectedIp) {
$_SERVER['HTTP_HOST'] = $httpHost;
$this->assertEquals($expectedIp, t3lib_div::getIndpEnv('TYPO3_HOST_ONLY'));
}

/**
* @test
* @dataProvider hostnameAndPortDataProvider
*/
public function getIndpEnvTypo3PortParsesHostnamesAndIpAdresses($httpHost, $dummy, $expectedPort) {
$_SERVER['HTTP_HOST'] = $httpHost;
$this->assertEquals($expectedPort, t3lib_div::getIndpEnv('TYPO3_PORT'));
}


//////////////////////////////////
// Tests concerning underscoredToUpperCamelCase
//////////////////////////////////

/**
* Data provider for underscoredToUpperCamelCase
*
* @return array expected, input string
*/
public function underscoredToUpperCamelCaseDataProvider() {
return array(
'single word' => array('Blogexample', 'blogexample'),
'multiple words' => array('BlogExample', 'blog_example'),
);
}

/**
* @test
* @dataProvider underscoredToUpperCamelCaseDataProvider
*/
public function underscoredToUpperCamelCase($expected, $inputString) {
$this->assertEquals($expected, t3lib_div::underscoredToUpperCamelCase($inputString));
}


//////////////////////////////////
// Tests concerning underscoredToLowerCamelCase
//////////////////////////////////

/**
* Data provider for underscoredToLowerCamelCase
*
* @return array expected, input string
*/
public function underscoredToLowerCamelCaseDataProvider() {
return array(
'single word' => array('minimalvalue', 'minimalvalue'),
'multiple words' => array('minimalValue', 'minimal_value'),
);
}

/**
* @test
* @dataProvider underscoredToLowerCamelCaseDataProvider
*/
public function underscoredToLowerCamelCase($expected, $inputString) {
$this->assertEquals($expected, t3lib_div::underscoredToLowerCamelCase($inputString));
}

//////////////////////////////////
// Tests concerning camelCaseToLowerCaseUnderscored
//////////////////////////////////

/**
* Data provider for camelCaseToLowerCaseUnderscored
*
* @return array expected, input string
*/
public function camelCaseToLowerCaseUnderscoredDataProvider() {
return array(
'single word' => array('blogexample', 'blogexample'),
'single word starting upper case' => array('blogexample', 'Blogexample'),
'two words starting lower case' => array('minimal_value', 'minimalValue'),
'two words starting upper case' => array('blog_example', 'BlogExample'),
);
}

/**
* @test
* @dataProvider camelCaseToLowerCaseUnderscoredDataProvider
*/
public function camelCaseToLowerCaseUnderscored($expected, $inputString) {
$this->assertEquals($expected, t3lib_div::camelCaseToLowerCaseUnderscored($inputString));
}


//////////////////////////////////
// Tests concerning lcFirst
//////////////////////////////////

/**
* Data provider for lcFirst
*
* @return array expected, input string
*/
public function lcfirstDataProvider() {
return array(
'single word' => array('blogexample', 'blogexample'),
'single Word starting upper case' => array('blogexample', 'Blogexample'),
'two words' => array('blogExample', 'BlogExample'),
);
}

/**
* @test
* @dataProvider lcfirstDataProvider
*/
public function lcFirst($expected, $inputString) {
$this->assertEquals($expected, t3lib_div::lcfirst($inputString));
}


//////////////////////////////////
// Tests concerning encodeHeader
//////////////////////////////////

/**
* @test
*/
public function encodeHeaderEncodesWhitespacesInQuotedPrintableMailHeader() {
$this->assertEquals(
'=?utf-8?Q?We_test_whether_the_copyright_character_=C2=A9_is_encoded_correctly?=',
t3lib_div::encodeHeader(
"We test whether the copyright character \xc2\xa9 is encoded correctly",
'quoted-printable',
'utf-8'
)
);
}

/**
* @test
*/
public function encodeHeaderEncodesQuestionmarksInQuotedPrintableMailHeader() {
$this->assertEquals(
'=?utf-8?Q?Is_the_copyright_character_=C2=A9_really_encoded_correctly=3F_Really=3F?=',
t3lib_div::encodeHeader(
"Is the copyright character \xc2\xa9 really encoded correctly? Really?",
'quoted-printable',
'utf-8'
)
);
}


//////////////////////////////////
// Tests concerning isValidUrl
//////////////////////////////////

/**
* Data provider for valid isValidUrl's
*
* @return array Valid ressource
*/
public function validUrlValidRessourceDataProvider() {
return array(
'http' => array('http://www.example.org/'),
'http without trailing slash' => array('http://qwe'),
'http directory with trailing slash' => array('http://www.example/img/dir/'),
'http directory without trailing slash' => array('http://www.example/img/dir'),
'http index.html' => array('http://example.com/index.html'),
'http index.php' => array('http://www.example.com/index.php'),
'http test.png' => array('http://www.example/img/test.png'),
'http username password querystring and ancher' => array('https://user:pw@www.example.org:80/path?arg=value#fragment'),
'file' => array('file:///tmp/test.c'),
'file directory' => array('file://foo/bar'),
'ftp directory' => array('ftp://ftp.example.com/tmp/'),
'mailto' => array('mailto:foo@bar.com'),
'news' => array('news:news.php.net'),
'telnet'=> array('telnet://192.0.2.16:80/'),
'ldap' => array('ldap://[2001:db8::7]/c=GB?objectClass?one'),
'http umlauts' => array('http://www.öbb.at'),
'http subdomain umlauts' => array('http://öh.öbb.at'),
'http directory umlauts' => array('http://www.oebb.at/öäü/'),
);
}

/**
* @test
* @dataProvider validUrlValidRessourceDataProvider
*/
public function validURLReturnsTrueForValidRessource($url) {
$this->assertTrue(t3lib_div::isValidUrl($url));
}

/**
* Data provider for invalid isValidUrl's
*
* @return array Invalid ressource
*/
public function isValidUrlInvalidRessourceDataProvider() {
return array(
'http missing colon' => array('http//www.example/wrong/url/'),
'http missing slash' => array('http:/www.example'),
'hostname only' => array('www.example.org/'),
'file missing protocol specification' => array('/tmp/test.c'),
'slash only' => array('/'),
'string http://' => array('http://'),
'string http:/' => array('http:/'),
'string http:' => array('http:'),
'string http' => array('http'),
'empty string' => array(''),
'string -1' => array('-1'),
'string array()' => array('array()'),
'random string' => array('qwe'),
);
}

/**
* @test
* @dataProvider isValidUrlInvalidRessourceDataProvider
*/
public function validURLReturnsFalseForInvalidRessoure($url) {
$this->assertFalse(t3lib_div::isValidUrl($url));
}


//////////////////////////////////
// Tests concerning isOnCurrentHost
//////////////////////////////////

/**
* @test
*/
public function isOnCurrentHostReturnsTrueWithCurrentHost() {
$testUrl = t3lib_div::getIndpEnv('TYPO3_REQUEST_URL');
$this->assertTrue(t3lib_div::isOnCurrentHost($testUrl));
}

/**
* Data provider for invalid isOnCurrentHost's
*
* @return array Invalid Hosts
*/
public function checkisOnCurrentHostInvalidHosts() {
return array(
'empty string' => array(''),
'arbitrary string' => array('arbitrary string'),
'localhost IP' => array('127.0.0.1'),
'relative path' => array('./relpath/file.txt'),
'absolute path' => array('/abspath/file.txt?arg=value'),
'differnt host' => array(t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST') . '.example.org'),
);
}


////////////////////////////////////////
// Tests concerning sanitizeLocalUrl
////////////////////////////////////////

/**
* Data provider for valid sanitizeLocalUrl's
*
* @return array Valid url
*/
public function sanitizeLocalUrlValidUrlDataProvider() {
$subDirectory = t3lib_div::getIndpEnv('TYPO3_SITE_PATH');
$typo3SiteUrl = t3lib_div::getIndpEnv('TYPO3_SITE_URL');
$typo3RequestHost = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST');

return array(
'alt_intro.php' => array('alt_intro.php'),
'alt_intro.php?foo=1&bar=2' => array('alt_intro.php?foo=1&bar=2'),
$subDirectory . 'typo3/alt_intro.php' => array($subDirectory . 'typo3/alt_intro.php'),
$subDirectory . 'index.php' => array($subDirectory . 'index.php'),
'../index.php' => array('../index.php'),
'../typo3/alt_intro.php' => array('../typo3/alt_intro.php'),
'../~userDirectory/index.php' => array('../~userDirectory/index.php'),
'../typo3/mod.php?var1=test-case&var2=~user' => array('../typo3/mod.php?var1=test-case&var2=~user'),
PATH_site . 'typo3/alt_intro.php' => array(PATH_site . 'typo3/alt_intro.php'),
$typo3SiteUrl . 'typo3/alt_intro.php' => array($typo3SiteUrl . 'typo3/alt_intro.php'),
$typo3RequestHost . $subDirectory . '/index.php' => array($typo3RequestHost . $subDirectory . '/index.php'),
);
}

/**
* @test
* @dataProvider sanitizeLocalUrlValidUrlDataProvider
*/
public function sanitizeLocalUrlAcceptsNotEncodedValidUrls($url) {
$this->assertEquals($url, t3lib_div::sanitizeLocalUrl($url));
}

/**
* @test
* @dataProvider sanitizeLocalUrlValidUrlDataProvider
*/
public function sanitizeLocalUrlAcceptsEncodedValidUrls($url) {
$this->assertEquals(rawurlencode($url), t3lib_div::sanitizeLocalUrl(rawurlencode($url)));
}

/**
* Data provider for invalid sanitizeLocalUrl's
*
* @return array Valid url
*/
public function sanitizeLocalUrlInvalidDataProvider() {
return array(
'empty string' => array(''),
'http domain' => array('http://www.google.de/'),
'https domain' => array('https://www.google.de/'),
'relative path with XSS' => array('../typo3/whatever.php?argument=javascript:alert(0)'),
);
}

/**
* @test
* @dataProvider sanitizeLocalUrlInvalidDataProvider
*/
public function sanitizeLocalUrlDeniesPlainInvalidUrls($url) {
$this->assertEquals('', t3lib_div::sanitizeLocalUrl($url));
}

/**
* @test
* @dataProvider sanitizeLocalUrlInvalidDataProvider
*/
public function sanitizeLocalUrlDeniesEncodedInvalidUrls($url) {
$this->assertEquals('', t3lib_div::sanitizeLocalUrl(rawurlencode($url)));
}


//////////////////////////////////////
// Tests concerning addSlashesOnArray
//////////////////////////////////////

/**
* @test
*/
public function addSlashesOnArrayAddsSlashesRecursive() {
$inputArray = array(
'key1' => array(
'key11' => "val'ue1",
'key12' => 'val"ue2',
),
'key2' => 'val\ue3',
);
$expectedResult = array(
'key1' => array(
'key11' => "val\'ue1",
'key12' => 'val\"ue2',
),
'key2' => 'val\\\\ue3',
);
t3lib_div::addSlashesOnArray($inputArray);
$this->assertEquals(
$expectedResult,
$inputArray
);
}


//////////////////////////////////////
// Tests concerning addSlashesOnArray
//////////////////////////////////////

/**
* @test
*/
public function stripSlashesOnArrayStripsSlashesRecursive() {
$inputArray = array(
'key1' => array(
'key11' => "val\'ue1",
'key12' => 'val\"ue2',
),
'key2' => 'val\\\\ue3',
);
$expectedResult = array(
'key1' => array(
'key11' => "val'ue1",
'key12' => 'val"ue2',
),
'key2' => 'val\ue3',
);
t3lib_div::stripSlashesOnArray($inputArray);
$this->assertEquals(
$expectedResult,
$inputArray
);
}


//////////////////////////////////////
// Tests concerning arrayDiffAssocRecursive
//////////////////////////////////////

/**
* @test
*/
public function arrayDiffAssocRecursiveHandlesOneDimensionalArrays() {
$array1 = array(
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
);
$array2 = array(
'key1' => 'value1',
'key3' => 'value3',
);
$expectedResult = array(
'key2' => 'value2',
);
$actualResult = t3lib_div::arrayDiffAssocRecursive($array1, $array2);
$this->assertEquals($expectedResult, $actualResult);
}

/**
* @test
*/
public function arrayDiffAssocRecursiveHandlesMultiDimensionalArrays() {
$array1 = array(
'key1' => 'value1',
'key2' => array(
'key21' => 'value21',
'key22' => 'value22',
'key23' => array(
'key231' => 'value231',
'key232' => 'value232',
),
),
);
$array2 = array(
'key1' => 'value1',
'key2' => array(
'key21' => 'value21',
'key23' => array(
'key231' => 'value231',
),
),
);
$expectedResult = array(
'key2' => array(
'key22' => 'value22',
'key23' => array(
'key232' => 'value232',
),
),
);
$actualResult = t3lib_div::arrayDiffAssocRecursive($array1, $array2);
$this->assertEquals($expectedResult, $actualResult);
}

/**
* @test
*/
public function arrayDiffAssocRecursiveHandlesMixedArrays() {
$array1 = array(
'key1' => array(
'key11' => 'value11',
'key12' => 'value12',
),
'key2' => 'value2',
'key3' => 'value3',
);
$array2 = array(
'key1' => 'value1',
'key2' => array(
'key21' => 'value21',
),
);
$expectedResult = array(
'key3' => 'value3',
);
$actualResult = t3lib_div::arrayDiffAssocRecursive($array1, $array2);
$this->assertEquals($expectedResult, $actualResult);
}


//////////////////////////////////////
// Tests concerning removeDotsFromTS
//////////////////////////////////////

/**
* @test
*/
public function removeDotsFromTypoScriptSucceedsWithDottedArray() {
$typoScript = array(
'propertyA.' => array(
'keyA.' => array(
'valueA' => 1,
),
'keyB' => 2,
),
'propertyB' => 3,
);

$expectedResult = array(
'propertyA' => array(
'keyA' => array(
'valueA' => 1,
),
'keyB' => 2,
),
'propertyB' => 3,
);

$this->assertEquals($expectedResult, t3lib_div::removeDotsFromTS($typoScript));
}

/**
* @test
*/
public function removeDotsFromTypoScriptOverridesSubArray() {
$typoScript = array(
'propertyA.' => array(
'keyA' => 'getsOverridden',
'keyA.' => array(
'valueA' => 1,
),
'keyB' => 2,
),
'propertyB' => 3,
);

$expectedResult = array(
'propertyA' => array(
'keyA' => array(
'valueA' => 1,
),
'keyB' => 2,
),
'propertyB' => 3,
);

$this->assertEquals($expectedResult, t3lib_div::removeDotsFromTS($typoScript));
}

/**
* @test
*/
public function removeDotsFromTypoScriptOverridesWithScalar() {
$typoScript = array(
'propertyA.' => array(
'keyA.' => array(
'valueA' => 1,
),
'keyA' => 'willOverride',
'keyB' => 2,
),
'propertyB' => 3,
);

$expectedResult = array(
'propertyA' => array(
'keyA' => 'willOverride',
'keyB' => 2,
),
'propertyB' => 3,
);

$this->assertEquals($expectedResult, t3lib_div::removeDotsFromTS($typoScript));
}

//////////////////////////////////////
// Tests concerning naturalKeySortRecursive
//////////////////////////////////////

/**
* @test
*/
public function naturalKeySortRecursiveReturnsFalseIfInputIsNotAnArray() {
$testValues = array(
1,
'string',
FALSE
);
foreach($testValues as $testValue) {
$this->assertFalse(t3lib_div::naturalKeySortRecursive($testValue));
}
}

/**
* @test
*/
public function naturalKeySortRecursiveSortsOneDimensionalArrayByNaturalOrder() {
$testArray = array(
'bb' => 'bb',
'ab' => 'ab',
'123' => '123',
'aaa' => 'aaa',
'abc' => 'abc',
'23' => '23',
'ba' => 'ba',
'bad' => 'bad',
'2' => '2',
'zap' => 'zap',
'210' => '210'
);
$expectedResult = array(
'2',
'23',
'123',
'210',
'aaa',
'ab',
'abc',
'ba',
'bad',
'bb',
'zap'
);
t3lib_div::naturalKeySortRecursive($testArray);
$this->assertEquals($expectedResult, array_values($testArray));
}

/**
* @test
*/
public function naturalKeySortRecursiveSortsMultiDimensionalArrayByNaturalOrder() {
$testArray = array(
'2' => '2',
'bb' => 'bb',
'ab' => 'ab',
'23' => '23',
'aaa' => array(
'bb' => 'bb',
'ab' => 'ab',
'123' => '123',
'aaa' => 'aaa',
'2' => '2',
'abc' => 'abc',
'ba' => 'ba',
'23' => '23',
'bad' => array(
'bb' => 'bb',
'ab' => 'ab',
'123' => '123',
'aaa' => 'aaa',
'abc' => 'abc',
'23' => '23',
'ba' => 'ba',
'bad' => 'bad',
'2' => '2',
'zap' => 'zap',
'210' => '210'
),
'210' => '210',
'zap' => 'zap'
),
'abc' => 'abc',
'ba' => 'ba',
'210' => '210',
'bad' => 'bad',
'123' => '123',
'zap' => 'zap'
);

$expectedResult = array(
'2',
'23',
'123',
'210',
'aaa',
'ab',
'abc',
'ba',
'bad',
'bb',
'zap'
);
t3lib_div::naturalKeySortRecursive($testArray);

$this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa']['bad'])));
$this->assertEquals($expectedResult, array_values(array_keys($testArray['aaa'])));
$this->assertEquals($expectedResult, array_values(array_keys($testArray)));
}

//////////////////////////////////////
// Tests concerning get_dirs
//////////////////////////////////////

/**
* @test
*/
public function getDirsReturnsArrayOfDirectoriesFromGivenDirectory() {
$path = PATH_t3lib;
$directories = t3lib_div::get_dirs($path);

$this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $directories);
}

/**
* @test
*/
public function getDirsReturnsStringErrorOnPathFailure() {
$path = 'foo';
$result = t3lib_div::get_dirs($path);
$expectedResult = 'error';

$this->assertEquals($expectedResult, $result);
}


//////////////////////////////////
// Tests concerning hmac
//////////////////////////////////

/**
* @test
*/
public function hmacReturnsHashOfProperLength() {
$hmac = t3lib_div::hmac('message');
$this->assertTrue(!empty($hmac) && is_string($hmac));
$this->assertTrue(strlen($hmac) == 40);
}

/**
* @test
*/
public function hmacReturnsEqualHashesForEqualInput() {
$msg0 = 'message';
$msg1 = 'message';
$this->assertEquals(t3lib_div::hmac($msg0), t3lib_div::hmac($msg1));
}

/**
* @test
*/
public function hmacReturnsNoEqualHashesForNonEqualInput() {
$msg0 = 'message0';
$msg1 = 'message1';
$this->assertNotEquals(t3lib_div::hmac($msg0), t3lib_div::hmac($msg1));
}


//////////////////////////////////
// Tests concerning quoteJSvalue
//////////////////////////////////

/**
* @test
*/
public function quoteJSvalueHtmlspecialcharsDataByDefault() {
$this->assertContains(
'&gt;',
t3lib_div::quoteJSvalue('>')
);
}

/**
* @test
*/
public function quoteJSvaluetHtmlspecialcharsDataWithinCDataSetToFalse() {
$this->assertContains(
'&gt;',
t3lib_div::quoteJSvalue('>', FALSE)
);
}

/**
* @test
*/
public function quoteJSvaluetNotHtmlspecialcharsDataWithinCDataSetToTrue() {
$this->assertContains(
'>',
t3lib_div::quoteJSvalue('>', TRUE)
);
}

/**
* @test
*/
public function quoteJSvalueReturnsEmptyStringQuotedInSingleQuotes() {
$this->assertEquals(
"''",
t3lib_div::quoteJSvalue("", TRUE)
);
}

/**
* @test
*/
public function quoteJSvalueNotModifiesStringWithoutSpecialCharacters() {
$this->assertEquals(
"'Hello world!'",
t3lib_div::quoteJSvalue("Hello world!", TRUE)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesSingleQuote() {
$this->assertEquals(
"'\\''",
t3lib_div::quoteJSvalue("'", TRUE)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesDoubleQuoteWithinCDataSetToTrue() {
$this->assertEquals(
"'\\\"'",
t3lib_div::quoteJSvalue('"', TRUE)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesAndHtmlspecialcharsDoubleQuoteWithinCDataSetToFalse() {
$this->assertEquals(
"'\\&quot;'",
t3lib_div::quoteJSvalue('"', FALSE)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesTab() {
$this->assertEquals(
"'" . '\t' . "'",
t3lib_div::quoteJSvalue(TAB)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesLinefeed() {
$this->assertEquals(
"'" . '\n' . "'",
t3lib_div::quoteJSvalue(LF)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesCarriageReturn() {
$this->assertEquals(
"'" . '\r' . "'",
t3lib_div::quoteJSvalue(CR)
);
}

/**
* @test
*/
public function quoteJSvalueEscapesBackslah() {
$this->assertEquals(
"'\\\\'",
t3lib_div::quoteJSvalue('\\')
);
}

//////////////////////////////////
// Tests concerning readLLfile
//////////////////////////////////

/**
* @test
*/
public function readLLfileHandlesLocallangXMLOverride() {
$unique = uniqid('locallangXMLOverrideTest');

$xml = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3locallang>
<data type="array">
<languageKey index="default" type="array">
<label index="buttons.logout">EXIT</label>
</languageKey>
</data>
</T3locallang>';

$file = PATH_site . 'typo3temp/' . $unique . '.xml';
t3lib_div::writeFileToTypo3tempDir($file, $xml);

// Make sure there is no cached version of the label
$GLOBALS['typo3CacheManager']->getCache('t3lib_l10n')->flush();

// Get default value
$defaultLL = t3lib_div::readLLfile('EXT:lang/locallang_core.xml', 'default');

// Clear language cache again
$GLOBALS['typo3CacheManager']->getCache('t3lib_l10n')->flush();

// Set override file
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:lang/locallang_core.xml'][$unique] = $file;

/** @var $store t3lib_l10n_Store */
$store = t3lib_div::makeInstance('t3lib_l10n_Store');
$store->flushData('EXT:lang/locallang_core.xml');

// Get override value
$overrideLL = t3lib_div::readLLfile('EXT:lang/locallang_core.xml', 'default');

// Clean up again
unlink($file);

$this->assertNotEquals($overrideLL['default']['buttons.logout'][0]['target'], '');
$this->assertNotEquals($defaultLL['default']['buttons.logout'][0]['target'], $overrideLL['default']['buttons.logout'][0]['target']);
$this->assertEquals($overrideLL['default']['buttons.logout'][0]['target'], 'EXIT');
}


///////////////////////////////
// Tests concerning _GETset()
///////////////////////////////

/**
* @test
*/
public function getSetWritesArrayToGetSystemVariable() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

$getParameters = array('foo' => 'bar');
t3lib_div::_GETset($getParameters);
$this->assertSame($getParameters, $_GET);
}

/**
* @test
*/
public function getSetWritesArrayToGlobalsHttpGetVars() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

$getParameters = array('foo' => 'bar');
t3lib_div::_GETset($getParameters);
$this->assertSame($getParameters, $GLOBALS['HTTP_GET_VARS']);
}

/**
* @test
*/
public function getSetForArrayDropsExistingValues() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

t3lib_div::_GETset(array('foo' => 'bar'));

t3lib_div::_GETset(array('oneKey' => 'oneValue'));

$this->assertEquals(
array('oneKey' => 'oneValue'),
$GLOBALS['HTTP_GET_VARS']
);
}

/**
* @test
*/
public function getSetAssignsOneValueToOneKey() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

t3lib_div::_GETset('oneValue', 'oneKey');

$this->assertEquals(
'oneValue',
$GLOBALS['HTTP_GET_VARS']['oneKey']
);
}

/**
* @test
*/
public function getSetForOneValueDoesNotDropUnrelatedValues() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

t3lib_div::_GETset(array('foo' => 'bar'));
t3lib_div::_GETset('oneValue', 'oneKey');

$this->assertEquals(
array('foo' => 'bar', 'oneKey' => 'oneValue'),
$GLOBALS['HTTP_GET_VARS']
);
}

/**
* @test
*/
public function getSetCanAssignsAnArrayToASpecificArrayElement() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

t3lib_div::_GETset(array('childKey' => 'oneValue'), 'parentKey');

$this->assertEquals(
array('parentKey' => array('childKey' => 'oneValue')),
$GLOBALS['HTTP_GET_VARS']
);
}

/**
* @test
*/
public function getSetCanAssignAStringValueToASpecificArrayChildElement() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

t3lib_div::_GETset('oneValue', 'parentKey|childKey');

$this->assertEquals(
array('parentKey' => array('childKey' => 'oneValue')),
$GLOBALS['HTTP_GET_VARS']
);
}

/**
* @test
*/
public function getSetCanAssignAnArrayToASpecificArrayChildElement() {
$_GET = array();
$GLOBALS['HTTP_GET_VARS'] = array();

t3lib_div::_GETset(
array('key1' => 'value1', 'key2' => 'value2'),
'parentKey|childKey'
);

$this->assertEquals(
array(
'parentKey' => array(
'childKey' => array('key1' => 'value1', 'key2' => 'value2')
)
),
$GLOBALS['HTTP_GET_VARS']
);
}


///////////////////////////////
// Tests concerning fixPermissions
///////////////////////////////

/**
* @test
*/
public function fixPermissionsSetsGroup() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissionsSetsGroup() tests not available on Windows');
}
if (!function_exists('posix_getegid')) {
$this->markTestSkipped('Function posix_getegid() not available, fixPermissionsSetsGroup() tests skipped');
}
if (posix_getegid() === -1) {
$this->markTestSkipped(
'The fixPermissionsSetsGroup() is not available on Mac OS because posix_getegid() always returns -1 on Mac OS.'
);
}

// Create and prepare test file
$filename = PATH_site . 'typo3temp/' . uniqid('test_');
t3lib_div::writeFileToTypo3tempDir($filename, '42');

$currentGroupId = posix_getegid();

// Set target group and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup'] = $currentGroupId;
$fixPermissionsResult = t3lib_div::fixPermissions($filename);

clearstatcache();
$resultFileGroup = filegroup($filename);
unlink($filename);

$this->assertEquals($resultFileGroup, $currentGroupId);
}

/**
* @test
*/
public function fixPermissionsSetsPermissionsToFile() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test file
$filename = PATH_site . 'typo3temp/' . uniqid('test_');
t3lib_div::writeFileToTypo3tempDir($filename, '42');
chmod($filename, 0742);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
$fixPermissionsResult = t3lib_div::fixPermissions($filename);

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($filename)), 2);
unlink($filename);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultFilePermissions, '0660');
}

/**
* @test
*/
public function fixPermissionsSetsPermissionsToHiddenFile() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test file
$filename = PATH_site . 'typo3temp/' . uniqid('.test_');
t3lib_div::writeFileToTypo3tempDir($filename, '42');
chmod($filename, 0742);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
$fixPermissionsResult = t3lib_div::fixPermissions($filename);

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($filename)), 2);
unlink($filename);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultFilePermissions, '0660');
}

/**
* @test
*/
public function fixPermissionsSetsPermissionsToDirectory() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test directory
$directory = PATH_site . 'typo3temp/' . uniqid('test_');
t3lib_div::mkdir($directory);
chmod($directory, 1551);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
$fixPermissionsResult = t3lib_div::fixPermissions($directory);

// Get actual permissions and clean up
clearstatcache();
$resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
t3lib_div::rmdir($directory);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultDirectoryPermissions, '0770');
}

/**
* @test
*/
public function fixPermissionsSetsPermissionsToDirectoryWithTrailingSlash() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test directory
$directory = PATH_site . 'typo3temp/' . uniqid('test_');
t3lib_div::mkdir($directory);
chmod($directory, 1551);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
$fixPermissionsResult = t3lib_div::fixPermissions($directory . '/');

// Get actual permissions and clean up
clearstatcache();
$resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
t3lib_div::rmdir($directory);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultDirectoryPermissions, '0770');
}

/**
* @test
*/
public function fixPermissionsSetsPermissionsToHiddenDirectory() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test directory
$directory = PATH_site . 'typo3temp/' . uniqid('.test_');
t3lib_div::mkdir($directory);
chmod($directory, 1551);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
$fixPermissionsResult = t3lib_div::fixPermissions($directory);

// Get actual permissions and clean up
clearstatcache();
$resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
t3lib_div::rmdir($directory);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultDirectoryPermissions, '0770');
}

/**
* @test
*/
public function fixPermissionsCorrectlySetsPermissionsRecursive() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test directory and file structure
$baseDirectory = PATH_site . 'typo3temp/' . uniqid('test_');
t3lib_div::mkdir($baseDirectory);
chmod($baseDirectory, 1751);
t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/file', '42');
chmod($baseDirectory . '/file', 0742);
t3lib_div::mkdir($baseDirectory . '/foo');
chmod($baseDirectory . '/foo', 1751);
t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/foo/file', '42');
chmod($baseDirectory . '/foo/file', 0742);
t3lib_div::mkdir($baseDirectory . '/.bar');
chmod($baseDirectory . '/.bar', 1751);
// Use this if writeFileToTypo3tempDir is fixed to create hidden files in subdirectories
// t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/.bar/.file', '42');
// t3lib_div::writeFileToTypo3tempDir($baseDirectory . '/.bar/..file2', '42');
touch($baseDirectory . '/.bar/.file', '42');
chmod($baseDirectory . '/.bar/.file', 0742);
touch($baseDirectory . '/.bar/..file2', '42');
chmod($baseDirectory . '/.bar/..file2', 0742);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
$GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
$fixPermissionsResult = t3lib_div::fixPermissions($baseDirectory, TRUE);

// Get actual permissions
clearstatcache();
$resultBaseDirectoryPermissions = substr(decoct(fileperms($baseDirectory)), 1);
$resultBaseFilePermissions = substr(decoct(fileperms($baseDirectory . '/file')), 2);
$resultFooDirectoryPermissions = substr(decoct(fileperms($baseDirectory . '/foo')), 1);
$resultFooFilePermissions = substr(decoct(fileperms($baseDirectory . '/foo/file')), 2);
$resultBarDirectoryPermissions = substr(decoct(fileperms($baseDirectory . '/.bar')), 1);
$resultBarFilePermissions = substr(decoct(fileperms($baseDirectory . '/.bar/.file')), 2);
$resultBarFile2Permissions = substr(decoct(fileperms($baseDirectory . '/.bar/..file2')), 2);

// Clean up
unlink($baseDirectory . '/file');
unlink($baseDirectory . '/foo/file');
unlink($baseDirectory . '/.bar/.file');
unlink($baseDirectory . '/.bar/..file2');
t3lib_div::rmdir($baseDirectory . '/foo');
t3lib_div::rmdir($baseDirectory . '/.bar');
t3lib_div::rmdir($baseDirectory);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultBaseDirectoryPermissions, '0770');
$this->assertEquals($resultBaseFilePermissions, '0660');
$this->assertEquals($resultFooDirectoryPermissions, '0770');
$this->assertEquals($resultFooFilePermissions, '0660');
$this->assertEquals($resultBarDirectoryPermissions, '0770');
$this->assertEquals($resultBarFilePermissions, '0660');
$this->assertEquals($resultBarFile2Permissions, '0660');
}

/**
* @test
*/
public function fixPermissionsDoesNotSetPermissionsToNotAllowedPath() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

// Create and prepare test file
$filename = PATH_site . 'typo3temp/../typo3temp/' . uniqid('test_');
touch($filename);
chmod($filename, 0742);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
$fixPermissionsResult = t3lib_div::fixPermissions($filename);

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($filename)), 2);
unlink($filename);

// Test if everything was ok
$this->assertFalse($fixPermissionsResult);
}

/**
* @test
*/
public function fixPermissionsSetsPermissionsWithRelativeFileReference() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('fixPermissions() tests not available on Windows');
}

$filename = 'typo3temp/' . uniqid('test_');
t3lib_div::writeFileToTypo3tempDir(PATH_site . $filename, '42');
chmod(PATH_site . $filename, 0742);

// Set target permissions and run method
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0660';
$fixPermissionsResult = t3lib_div::fixPermissions($filename);

// Get actual permissions and clean up
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms(PATH_site . $filename)), 2);
unlink(PATH_site . $filename);

// Test if everything was ok
$this->assertTrue($fixPermissionsResult);
$this->assertEquals($resultFilePermissions, '0660');
}


///////////////////////////////
// Tests concerning mkdir
///////////////////////////////

/**
* @test
*/
public function mkdirCreatesDirectory() {
$directory = PATH_site . 'typo3temp/' . uniqid('test_');
$mkdirResult = t3lib_div::mkdir($directory);
clearstatcache();
$directoryCreated = is_dir($directory);
@rmdir($directory);
$this->assertTrue($mkdirResult);
$this->assertTrue($directoryCreated);
}

/**
* @test
*/
public function mkdirCreatesHiddenDirectory() {
$directory = PATH_site . 'typo3temp/' . uniqid('.test_');
$mkdirResult = t3lib_div::mkdir($directory);
clearstatcache();
$directoryCreated = is_dir($directory);
@rmdir($directory);
$this->assertTrue($mkdirResult);
$this->assertTrue($directoryCreated);
}

/**
* @test
*/
public function mkdirCreatesDirectoryWithTrailingSlash() {
$directory = PATH_site . 'typo3temp/' . uniqid('test_') . '/';
$mkdirResult = t3lib_div::mkdir($directory);
clearstatcache();
$directoryCreated = is_dir($directory);
@rmdir($directory);
$this->assertTrue($mkdirResult);
$this->assertTrue($directoryCreated);
}

/**
* @test
*/
public function mkdirSetsPermissionsOfCreatedDirectory() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('mkdirSetsPermissionsOfCreatedDirectory() test not available on Windows');
}

$directory = PATH_site . 'typo3temp/' . uniqid('test_');
$GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0770';
t3lib_div::mkdir($directory);
clearstatcache();
$resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
rmdir($directory);
$this->assertEquals($resultDirectoryPermissions, '0770');
}


///////////////////////////////
// Tests concerning mkdir_deep
///////////////////////////////

/**
* @test
*/
public function mkdirDeepCreatesDirectory() {
$directory = 'typo3temp/' . uniqid('test_');
t3lib_div::mkdir_deep(PATH_site, $directory);
$isDirectoryCreated = is_dir(PATH_site . $directory);
rmdir(PATH_site . $directory);
$this->assertTrue($isDirectoryCreated);
}

/**
* @test
*/
public function mkdirDeepCreatesSubdirectoriesRecursive() {
$directory = 'typo3temp/' . uniqid('test_');
$subDirectory = $directory . '/foo';
t3lib_div::mkdir_deep(PATH_site, $subDirectory);
$isDirectoryCreated = is_dir(PATH_site . $subDirectory);
rmdir(PATH_site . $subDirectory);
rmdir(PATH_site . $directory);
$this->assertTrue($isDirectoryCreated);
}

/**
* @test
*/
public function mkdirDeepFixesPermissionsOnNewDirectory() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('mkdirDeepFixesPermissionsOnNewDirectory() test not available on Windows.');
}

$directory = uniqid('mkdirdeeptest_');
$GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'] = '0750';
t3lib_div::mkdir_deep(PATH_site . 'typo3temp/', $directory);
clearstatcache();
$resultDirectoryPermissions = substr(decoct(fileperms(PATH_site . 'typo3temp/' . $directory)), -3, 3);
@rmdir(PATH_site . 'typo3temp/' . $directory);
$this->assertEquals($resultDirectoryPermissions, '750');
}

/**
* @test
*/
public function mkdirDeepDoesNotChangePermissionsOfExistingSubDirectories() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('mkdirDeepDoesNotChangePermissionsOfExistingSubDirectories() test not available on Windows.');
}

$baseDirectory = PATH_site . 'typo3temp/';
$existingDirectory = uniqid('test_existing_') . '/';
$newSubDirectory = uniqid('test_new_');
@mkdir($baseDirectory . $existingDirectory);
chmod($baseDirectory . $existingDirectory, 0742);
t3lib_div::mkdir_deep($baseDirectory, $existingDirectory . $newSubDirectory);
$resultExistingDirectoryPermissions = substr(decoct(fileperms($baseDirectory . $existingDirectory)), 2);
@rmdir($baseDirectory, $existingDirectory . $newSubDirectory);
@rmdir($baseDirectory, $existingDirectory);
$this->assertEquals($resultExistingDirectoryPermissions, '0742');
}

/**
* @test
*/
public function mkdirDeepCreatesDirectoryInVfsStream() {
if (!class_exists('\vfsStreamWrapper')) {
$this->markTestSkipped('mkdirDeepCreatesDirectoryInVfsStream() test not available with this phpunit version.');
}

\vfsStreamWrapper::register();
$baseDirectory = uniqid('test_');
\vfsStreamWrapper::setRoot(new \vfsStreamDirectory($baseDirectory));
t3lib_div::mkdir_deep('vfs://' . $baseDirectory . '/', 'sub');
$this->assertTrue(is_dir('vfs://' . $baseDirectory . '/sub'));
}

/**
* @test
* @expectedException \RuntimeException
*/
public function mkdirDeepThrowsExceptionIfDirectoryCreationFails() {
t3lib_div::mkdir_deep('http://localhost');
}

/**
* @test
* @expectedException \InvalidArgumentException
*/
public function mkdirDeepThrowsExceptionIfBaseDirectoryIsNotOfTypeString() {
t3lib_div::mkdir_deep(array());
}

/**
* @test
* @expectedException \InvalidArgumentException
*/
public function mkdirDeepThrowsExceptionIfDeepDirectoryIsNotOfTypeString() {
t3lib_div::mkdir_deep(PATH_site . 'typo3temp/foo', array());
}


///////////////////////////////
// Tests concerning unQuoteFilenames
///////////////////////////////

/**
* Data provider for ImageMagick shell commands
* @see explodeAndUnquoteImageMagickCommands
*/
public function imageMagickCommandsDataProvider() {
return array(
// Some theoretical tests first
array(
'aa bb "cc" "dd"',
array('aa', 'bb', '"cc"', '"dd"'),
array('aa', 'bb', 'cc', 'dd'),
),
array(
'aa bb "cc dd"',
array('aa', 'bb', '"cc dd"'),
array('aa', 'bb', 'cc dd'),
),
array(
'\'aa bb\' "cc dd"',
array('\'aa bb\'', '"cc dd"'),
array('aa bb', 'cc dd'),
),
array(
'\'aa bb\' cc "dd"',
array('\'aa bb\'', 'cc', '"dd"'),
array('aa bb', 'cc', 'dd'),
),
// Now test against some real world examples
array(
'/opt/local/bin/gm.exe convert +profile \'*\' -geometry 170x136! -negate "C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
array(
'/opt/local/bin/gm.exe',
'convert',
'+profile',
'\'*\'',
'-geometry',
'170x136!',
'-negate',
'"C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
'"C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
),
array(
'/opt/local/bin/gm.exe',
'convert',
'+profile',
'*',
'-geometry',
'170x136!',
'-negate',
'C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
'C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
),
),
array(
'C:/opt/local/bin/gm.exe convert +profile \'*\' -geometry 170x136! -negate "C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
array(
'C:/opt/local/bin/gm.exe',
'convert',
'+profile',
'\'*\'',
'-geometry',
'170x136!',
'-negate',
'"C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
'"C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
),
array(
'C:/opt/local/bin/gm.exe',
'convert',
'+profile',
'*',
'-geometry',
'170x136!',
'-negate',
'C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
'C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
),
),
array(
'/usr/bin/gm convert +profile \'*\' -geometry 170x136! -negate "/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
array(
'/usr/bin/gm',
'convert',
'+profile',
'\'*\'',
'-geometry',
'170x136!',
'-negate',
'"/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
'"/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
),
array(
'/usr/bin/gm',
'convert',
'+profile',
'*',
'-geometry',
'170x136!',
'-negate',
'/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
'/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
),
),
array(
'/usr/bin/gm convert +profile \'*\' -geometry 170x136! -negate "/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
array(
'/usr/bin/gm',
'convert',
'+profile',
'\'*\'',
'-geometry',
'170x136!',
'-negate',
'"/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
'"/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
),
array(
'/usr/bin/gm',
'convert',
'+profile',
'*',
'-geometry',
'170x136!',
'-negate',
'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
),
),
array(
'/usr/bin/gm convert +profile \'*\' -geometry 170x136! -negate \'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]\' \'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif\'',
array(
'/usr/bin/gm',
'convert',
'+profile',
'\'*\'',
'-geometry',
'170x136!',
'-negate',
'\'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]\'',
'\'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif\''
),
array(
'/usr/bin/gm',
'convert',
'+profile',
'*',
'-geometry',
'170x136!',
'-negate',
'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
),
),
);
}

/**
* Tests if the commands are exploded and unquoted correctly
*
* @dataProvider imageMagickCommandsDataProvider
* @test
*/
public function explodeAndUnquoteImageMagickCommands($source, $expectedQuoted, $expectedUnquoted) {
$actualQuoted = t3lib_div::unQuoteFilenames($source);
$acutalUnquoted = t3lib_div::unQuoteFilenames($source, TRUE);

$this->assertEquals($expectedQuoted, $actualQuoted, 'The exploded command does not match the expected');
$this->assertEquals($expectedUnquoted, $acutalUnquoted, 'The exploded and unquoted command does not match the expected');
}


///////////////////////////////
// Tests concerning split_fileref
///////////////////////////////

/**
* @test
*/
public function splitFileRefReturnsFileTypeNotForFolders(){
$directoryName = uniqid('test_') . '.com';
$directoryPath = PATH_site . 'typo3temp/';
$directory = $directoryPath . $directoryName;
mkdir($directory, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']));

$fileInfo = t3lib_div::split_fileref($directory);

$directoryCreated = is_dir($directory);
rmdir($directory);

$this->assertTrue($directoryCreated);
$this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $fileInfo);
$this->assertEquals($directoryPath, $fileInfo['path']);
$this->assertEquals($directoryName, $fileInfo['file']);
$this->assertEquals($directoryName, $fileInfo['filebody']);
$this->assertEquals('', $fileInfo['fileext']);
$this->assertArrayNotHasKey('realFileext', $fileInfo);
}

/**
* @test
*/
public function splitFileRefReturnsFileTypeForFilesWithoutPathSite() {
$testFile = 'fileadmin/media/someFile.png';

$fileInfo = t3lib_div::split_fileref($testFile);
$this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $fileInfo);
$this->assertEquals('fileadmin/media/', $fileInfo['path']);
$this->assertEquals('someFile.png', $fileInfo['file']);
$this->assertEquals('someFile', $fileInfo['filebody']);
$this->assertEquals('png', $fileInfo['fileext']);
}


/////////////////////////////
// Tests concerning dirname
/////////////////////////////

/**
* @see dirnameWithDataProvider
*
* @return array<array>
*/
public function dirnameDataProvider() {
return array(
'absolute path with multiple part and file' => array('/dir1/dir2/script.php', '/dir1/dir2'),
'absolute path with one part' => array('/dir1/', '/dir1'),
'absolute path to file without extension' => array('/dir1/something', '/dir1'),
'relative path with one part and file' => array('dir1/script.php', 'dir1'),
'relative one-character path with one part and file' => array('d/script.php', 'd'),
'absolute zero-part path with file' => array('/script.php', ''),
'empty string' => array('', ''),
);
}

/**
* @test
*
* @dataProvider dirnameDataProvider
*
* @param string $input the input for dirname
* @param string $expectedValue the expected return value expected from dirname
*/
public function dirnameWithDataProvider($input, $expectedValue) {
$this->assertEquals(
$expectedValue,
t3lib_div::dirname($input)
);
}


/////////////////////////////////////
// Tests concerning resolveBackPath
/////////////////////////////////////

/**
* @see resolveBackPathWithDataProvider
*
* @return array<array>
*/
public function resolveBackPathDataProvider() {
return array(
'empty path' => array('', ''),
'this directory' => array('./', './'),
'relative directory without ..' => array('dir1/dir2/dir3/', 'dir1/dir2/dir3/'),
'relative path without ..' => array('dir1/dir2/script.php', 'dir1/dir2/script.php'),
'absolute directory without ..' => array('/dir1/dir2/dir3/', '/dir1/dir2/dir3/'),
'absolute path without ..' => array('/dir1/dir2/script.php', '/dir1/dir2/script.php'),
'only one directory upwards without trailing slash' => array('..', '..'),
'only one directory upwards with trailing slash' => array('../', '../'),
'one level with trailing ..' => array('dir1/..', ''),
'one level with trailing ../' => array('dir1/../', ''),
'two levels with trailing ..' => array('dir1/dir2/..', 'dir1'),
'two levels with trailing ../' => array('dir1/dir2/../', 'dir1/'),
'leading ../ without trailing /' => array('../dir1', '../dir1'),
'leading ../ with trailing /' => array('../dir1/', '../dir1/'),
'leading ../ and inside path' => array('../dir1/dir2/../dir3/', '../dir1/dir3/'),
'one times ../ in relative directory' => array('dir1/../dir2/', 'dir2/'),
'one times ../ in absolute directory' => array('/dir1/../dir2/', '/dir2/'),
'one times ../ in relative path' => array('dir1/../dir2/script.php', 'dir2/script.php'),
'one times ../ in absolute path' => array('/dir1/../dir2/script.php', '/dir2/script.php'),
'consecutive ../' => array('dir1/dir2/dir3/../../../dir4', 'dir4'),
'distrubuted ../ with trailing /' => array('dir1/../dir2/dir3/../', 'dir2/'),
'distributed ../ without trailing /' => array('dir1/../dir2/dir3/..', 'dir2'),
'multiple distributed and consecutive ../ together' => array('dir1/dir2/dir3/dir4/../../dir5/dir6/dir7/../dir8/', 'dir1/dir2/dir5/dir6/dir8/'),
'multiple distributed and consecutive ../ together' => array('dir1/dir2/dir3/dir4/../../dir5/dir6/dir7/../dir8/', 'dir1/dir2/dir5/dir6/dir8/'),
'dirname with leading ..' => array('dir1/..dir2/dir3/', 'dir1/..dir2/dir3/'),
'dirname with trailing ..' => array('dir1/dir2../dir3/', 'dir1/dir2../dir3/'),
'more times upwards than downwards in directory' => array('dir1/../../', '../'),
'more times upwards than downwards in path' => array('dir1/../../script.php', '../script.php'),
);
}

/**
* @test
*
* @dataProvider resolveBackPathDataProvider
*
* @param string $input the input for resolveBackPath
* @param $expectedValue the expected return value from resolveBackPath
*/
public function resolveBackPathWithDataProvider($input, $expectedValue) {
$this->assertEquals(
$expectedValue,
t3lib_div::resolveBackPath($input)
);
}


/////////////////////////////////////////////////////////////////////////////////////
// Tests concerning makeInstance, setSingletonInstance, addInstance, purgeInstances
/////////////////////////////////////////////////////////////////////////////////////

/**
* @test
* @expectedException InvalidArgumentException
*/
public function makeInstanceWithEmptyClassNameThrowsException() {
t3lib_div::makeInstance('');
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function makeInstanceWithNullClassNameThrowsException() {
t3lib_div::makeInstance(NULL);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function makeInstanceWithZeroStringClassNameThrowsException() {
t3lib_div::makeInstance(0);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function makeInstanceWithEmptyArrayThrowsException() {
t3lib_div::makeInstance(array());
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function makeInstanceWithNonEmptyArrayThrowsException() {
t3lib_div::makeInstance(array('foo'));
}

/**
* @test
*/
public function makeInstanceReturnsClassInstance() {
$className = get_class($this->getMock('foo'));

$this->assertTrue(
t3lib_div::makeInstance($className) instanceof $className
);
}

/**
* @test
*/
public function makeInstancePassesParametersToConstructor() {
$className = 'testingClass' . uniqid();
if (!class_exists($className, FALSE)) {
eval(
'class ' . $className . ' {' .
' public $constructorParameter1;' .
' public $constructorParameter2;' .
' public function __construct($parameter1, $parameter2) {' .
' $this->constructorParameter1 = $parameter1;' .
' $this->constructorParameter2 = $parameter2;' .
' }' .
'}'
);
}

$instance = t3lib_div::makeInstance($className, 'one parameter', 'another parameter');

$this->assertEquals(
'one parameter',
$instance->constructorParameter1,
'The first constructor parameter has not been set.'
);
$this->assertEquals(
'another parameter',
$instance->constructorParameter2,
'The second constructor parameter has not been set.'
);
}

/**
* @test
*/
public function makeInstanceCalledTwoTimesForNonSingletonClassReturnsDifferentInstances() {
$className = get_class($this->getMock('foo'));

$this->assertNotSame(
t3lib_div::makeInstance($className),
t3lib_div::makeInstance($className)
);
}

/**
* @test
*/
public function makeInstanceCalledTwoTimesForSingletonClassReturnsSameInstance() {
$className = get_class($this->getMock('t3lib_Singleton'));

$this->assertSame(
t3lib_div::makeInstance($className),
t3lib_div::makeInstance($className)
);
}

/**
* @test
*/
public function makeInstanceCalledTwoTimesForSingletonClassWithPurgeInstancesInbetweenReturnsDifferentInstances() {
$className = get_class($this->getMock('t3lib_Singleton'));

$instance = t3lib_div::makeInstance($className);
t3lib_div::purgeInstances();

$this->assertNotSame(
$instance,
t3lib_div::makeInstance($className)
);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function setSingletonInstanceForEmptyClassNameThrowsException() {
$instance = $this->getMock('t3lib_Singleton');

t3lib_div::setSingletonInstance('', $instance);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function setSingletonInstanceForClassThatIsNoSubclassOfProvidedClassThrowsException() {
$instance = $this->getMock('t3lib_Singleton', array('foo'));
$singletonClassName = get_class($this->getMock('t3lib_Singleton'));

t3lib_div::setSingletonInstance($singletonClassName, $instance);
}

/**
* @test
*/
public function setSingletonInstanceMakesMakeInstanceReturnThatInstance() {
$instance = $this->getMock('t3lib_Singleton');
$singletonClassName = get_class($instance);

t3lib_div::setSingletonInstance($singletonClassName, $instance);

$this->assertSame(
$instance,
t3lib_div::makeInstance($singletonClassName)
);
}

/**
* @test
*/
public function setSingletonInstanceCalledTwoTimesMakesMakeInstanceReturnLastSetInstance() {
$instance1 = $this->getMock('t3lib_Singleton');
$singletonClassName = get_class($instance1);
$instance2 = new $singletonClassName();

t3lib_div::setSingletonInstance($singletonClassName, $instance1);
t3lib_div::setSingletonInstance($singletonClassName, $instance2);

$this->assertSame(
$instance2,
t3lib_div::makeInstance($singletonClassName)
);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function addInstanceForEmptyClassNameThrowsException() {
$instance = $this->getMock('foo');

t3lib_div::addInstance('', $instance);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function addInstanceForClassThatIsNoSubclassOfProvidedClassThrowsException() {
$instance = $this->getMock('foo', array('bar'));
$singletonClassName = get_class($this->getMock('foo'));

t3lib_div::addInstance($singletonClassName, $instance);
}

/**
* @test
* @expectedException InvalidArgumentException
*/
public function addInstanceWithSingletonInstanceThrowsException() {
$instance = $this->getMock('t3lib_Singleton');

t3lib_div::addInstance(get_class($instance), $instance);
}

/**
* @test
*/
public function addInstanceMakesMakeInstanceReturnThatInstance() {
$instance = $this->getMock('foo');
$className = get_class($instance);

t3lib_div::addInstance($className, $instance);

$this->assertSame(
$instance,
t3lib_div::makeInstance($className)
);
}

/**
* @test
*/
public function makeInstanceCalledTwoTimesAfterAddInstanceReturnTwoDifferentInstances() {
$instance = $this->getMock('foo');
$className = get_class($instance);

t3lib_div::addInstance($className, $instance);

$this->assertNotSame(
t3lib_div::makeInstance($className),
t3lib_div::makeInstance($className)
);
}

/**
* @test
*/
public function addInstanceCalledTwoTimesMakesMakeInstanceReturnBothInstancesInAddingOrder() {
$instance1 = $this->getMock('foo');
$className = get_class($instance1);
t3lib_div::addInstance($className, $instance1);

$instance2 = new $className();
t3lib_div::addInstance($className, $instance2);

$this->assertSame(
$instance1,
t3lib_div::makeInstance($className),
'The first returned instance does not match the first added instance.'
);
$this->assertSame(
$instance2,
t3lib_div::makeInstance($className),
'The second returned instance does not match the second added instance.'
);
}

/**
* @test
*/
public function purgeInstancesDropsAddedInstance() {
$instance = $this->getMock('foo');
$className = get_class($instance);

t3lib_div::addInstance($className, $instance);
t3lib_div::purgeInstances();

$this->assertNotSame(
$instance,
t3lib_div::makeInstance($className)
);
}

/**
* Data provider for validPathStrDetectsInvalidCharacters.
*
* @return array
*/
public function validPathStrInvalidCharactersDataProvider() {
return array(
'double slash in path' => array('path//path'),
'backslash in path' => array('path\\path'),
'directory up in path' => array('path/../path'),
'directory up at the beginning' => array('../path'),
'NUL character in path' => array("path\x00path"),
'BS character in path' => array("path\x08path"),
);
}

/**
* Tests whether invalid characters are detected.
*
* @param string $path
* @dataProvider validPathStrInvalidCharactersDataProvider
* @test
*/
public function validPathStrDetectsInvalidCharacters($path) {
$this->assertNull(t3lib_div::validPathStr($path));
}

/**
* Tests whether verifyFilenameAgainstDenyPattern detects the NULL character.
*
* @test
*/
public function verifyFilenameAgainstDenyPatternDetectsNullCharacter() {
$this->assertFalse(t3lib_div::verifyFilenameAgainstDenyPattern("image\x00.gif"));
}


/////////////////////////////////////////////////////////////////////////////////////
// Tests concerning sysLog
/////////////////////////////////////////////////////////////////////////////////////

/**
* @test
*/
public function syslogFixesPermissionsOnFileIfUsingFileLogging() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('syslogFixesPermissionsOnFileIfUsingFileLogging() test not available on Windows.');
}

// Fake all required settings
$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] = 0;
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit'] = TRUE;
unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog']);
$testLogFilename = PATH_site . 'typo3temp/' . uniqid('test_') . '.txt';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog'] = 'file,' . $testLogFilename . ',0';
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';

// Call method, get actual permissions and clean up
t3lib_div::syslog('testLog', 'test', 1);
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($testLogFilename)), 2);
t3lib_div::unlink_tempfile($testLogFilename);

$this->assertEquals($resultFilePermissions, '0777');
}

/**
* @test
*/
public function deprecationLogFixesPermissionsOnLogFile() {
if (TYPO3_OS == 'WIN') {
$this->markTestSkipped('deprecationLogFixesPermissionsOnLogFile() test not available on Windows.');
}

// Fake all required settings and get an unique logfilename
$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = uniqid('test_');
$deprecationLogFilename = t3lib_div::getDeprecationLogFileName();
$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog'] = TRUE;
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777';

// Call method, get actual permissions and clean up
t3lib_div::deprecationLog('foo');
clearstatcache();
$resultFilePermissions = substr(decoct(fileperms($deprecationLogFilename)), 2);
@unlink($deprecationLogFilename);

$this->assertEquals($resultFilePermissions, '0777');
}

///////////////////////////////////////////////////
// Tests concerning hasValidClassPrefix
///////////////////////////////////////////////////

/**
* @return array
*/
public function validClassPrefixDataProvider() {
return array(
'normal prefix' => array('tx_foo'),
'normal long prefix' => array('tx_foo_bar'),
'extbase named prefix' => array('Tx_foo'),
'user func named prefix' => array('user_foo'),
);
}

/**
* @test
* @dataProvider validClassPrefixDataProvider
* @param string $className Class name to test
*/
public function hasValidClassPrefixAcceptsValidPrefixes($className) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['additionalAllowedClassPrefixes'] = 'foo_';
$this->assertTrue(
t3lib_div::hasValidClassPrefix($className)
);
}

/**
* @return array
*/
public function invalidClassPrefixDataProvider() {
return array(
array('ab_c'),
array('txfoo'),
array('Txfoo'),
array('userfoo'),
array('aser_foo'),
);
}

/**
* @test
* @dataProvider invalidClassPrefixDataProvider
* @param string $className Class name to test
*/
public function hasValidClassPrefixRefusesInvalidPrefixes($className) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['additionalAllowedClassPrefixes'] = 'foo_';
$this->assertFalse(
t3lib_div::hasValidClassPrefix($className)
);
}

/**
* @test
*/
public function hasValidClassPrefixReturnsFalseIfEmptyClassNameGiven() {
$this->assertFalse(
t3lib_div::hasValidClassPrefix('')
);
}

/**
* @return array
*/
public function invalidClassReferenceDataTypeDataProvider() {
return array(
'array' => array(array('someClassArray')),
'integer' => array(123),
'boolean' => array(TRUE),
'object' => array(new stdClass()),
);
}

/**
* @test
* @dataProvider invalidClassReferenceDataTypeDataProvider
* @param string $className Class name to test
* @expectedException \InvalidArgumentException
*/
public function hasValidClassPrefixThrowsExceptionForInvalidClassReferenceDataType($className) {
t3lib_div::hasValidClassPrefix($className);
}

/**
* @test
* @dataProvider invalidClassPrefixDataProvider
* @param string $className Class name to test
*/
public function hasValidClassPrefixAllowsEmptyPrefix($className) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['additionalAllowedClassPrefixes'] = '';
$this->assertTrue(
t3lib_div::hasValidClassPrefix($className)
);
}

/**
* @return array
*/
public function getValidClassPrefixesReturnsListOfValidClassPrefixesDataProvider() {
return array(
array('user_'),
array('User_'),
array('Tx_'),
array('tx_'),
array('foo_'),
array('bar_'),
array('BAZ_')
);
}

/**
* @test
* @dataProvider getValidClassPrefixesReturnsListOfValidClassPrefixesDataProvider
* @param string $prefix prefix to test
*/
public function getValidClassPrefixesReturnsListOfValidClassPrefixes($prefix) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['additionalAllowedClassPrefixes'] = 'foo_,bar_,BAZ_';
$this->assertTrue(in_array($prefix, t3lib_div::getValidClassPrefixes()));
}

/**
* @test
*/
public function hasValidClassPrefixAcceptsAdditionalPrefixes() {
$this->assertTrue(
t3lib_div::hasValidClassPrefix('customPrefix_foo', array('customPrefix_'))
);
}
}
?>
(1-1/2)