scratch – Rev
?pathlinks?
<?php
namespace Doctrine\Tests\Common\Cache;
use Doctrine\Common\Cache\Cache;
/**
* @group DCOM-101
*/
class FileCacheTest extends \Doctrine\Tests\DoctrineTestCase
{
/**
* @var \Doctrine\Common\Cache\FileCache
*/
private $driver;
protected function setUp()
{
$this->driver = $this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array(), '', false
);
}
public function testFilenameShouldCreateThePathWithOneSubDirectory()
{
$cache = $this->driver;
$method = new \ReflectionMethod($cache, 'getFilename');
$key = 'item-key';
$expectedDir = array(
'84',
);
$expectedDir = implode(DIRECTORY_SEPARATOR, $expectedDir);
$method->setAccessible(true);
$path = $method->invoke($cache, $key);
$dirname = pathinfo($path, PATHINFO_DIRNAME);
$this->assertEquals(DIRECTORY_SEPARATOR . $expectedDir, $dirname);
}
public function testFileExtensionCorrectlyEscaped()
{
$driver1 = $this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array(__DIR__, '.*')
);
$driver2 = $this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array(__DIR__, '.php')
);
$doGetStats = new \ReflectionMethod($driver1, 'doGetStats');
$doGetStats->setAccessible(true);
$stats1 = $doGetStats->invoke($driver1);
$stats2 = $doGetStats->invoke($driver2);
$this->assertSame(0, $stats1[Cache::STATS_MEMORY_USAGE]);
$this->assertGreaterThan(0, $stats2[Cache::STATS_MEMORY_USAGE]);
}
/**
* @group DCOM-266
*/
public function testFileExtensionSlashCorrectlyEscaped()
{
$driver = $this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array(__DIR__ . '/../', DIRECTORY_SEPARATOR . basename(__FILE__))
);
$doGetStats = new \ReflectionMethod($driver, 'doGetStats');
$doGetStats->setAccessible(true);
$stats = $doGetStats->invoke($driver);
$this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_USAGE]);
}
public function testNonIntUmaskThrowsInvalidArgumentException()
{
$this->setExpectedException('InvalidArgumentException');
$this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array('', '', 'invalid')
);
}
public function testGetDirectoryReturnsRealpathDirectoryString()
{
$directory = __DIR__ . '/../';
$driver = $this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array($directory)
);
$doGetDirectory = new \ReflectionMethod($driver, 'getDirectory');
$actualDirectory = $doGetDirectory->invoke($driver);
$expectedDirectory = realpath($directory);
$this->assertEquals($expectedDirectory, $actualDirectory);
}
public function testGetExtensionReturnsExtensionString()
{
$directory = __DIR__ . '/../';
$extension = DIRECTORY_SEPARATOR . basename(__FILE__);
$driver = $this->getMock(
'Doctrine\Common\Cache\FileCache',
array('doFetch', 'doContains', 'doSave'),
array($directory, $extension)
);
$doGetExtension = new \ReflectionMethod($driver, 'getExtension');
$actualExtension = $doGetExtension->invoke($driver);
$this->assertEquals($extension, $actualExtension);
}
const WIN_MAX_PATH_LEN = 258;
public static function getBasePathForWindowsPathLengthTests($pathLength)
{
// Not using __DIR__ because it can get screwed up when xdebug debugger is attached.
$basePath = realpath(sys_get_temp_dir()) . '/' . uniqid('doctrine-cache', true);
/** @noinspection MkdirRaceConditionInspection */
@mkdir($basePath);
$basePath = realpath($basePath);
// Test whether the desired path length is odd or even.
$desiredPathLengthIsOdd = ($pathLength % 2) == 1;
// If the cache key is not too long, the filecache codepath will add
// a slash and bin2hex($key). The length of the added portion will be an odd number.
// len(desired) = len(base path) + len(slash . bin2hex($key))
// odd = even + odd
// even = odd + odd
$basePathLengthShouldBeOdd = !$desiredPathLengthIsOdd;
$basePathLengthIsOdd = (strlen($basePath) % 2) == 1;
// If the base path needs to be odd or even where it is not, we add an odd number of
// characters as a pad. In this case, we're adding '\aa' (or '/aa' depending on platform)
// This is all to make it so that the key we're testing would result in
// a path that is exactly the length we want to test IF the path length limit
// were not in place in FileCache.
if ($basePathLengthIsOdd != $basePathLengthShouldBeOdd) {
$basePath .= DIRECTORY_SEPARATOR . "aa";
}
return $basePath;
}
/**
* @param int $length
* @param string $basePath
*
* @return array
*/
public static function getKeyAndPathFittingLength($length, $basePath)
{
$baseDirLength = strlen($basePath);
$extensionLength = strlen('.doctrine.cache');
$directoryLength = strlen(DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR);
$keyLength = $length - ($baseDirLength + $extensionLength + $directoryLength); // - 1 because of slash
$key = str_repeat('a', floor($keyLength / 2));
$keyHash = hash('sha256', $key);
$keyPath = $basePath
. DIRECTORY_SEPARATOR
. substr($keyHash, 0, 2)
. DIRECTORY_SEPARATOR
. bin2hex($key)
. '.doctrine.cache';
$hashedKeyPath = $basePath
. DIRECTORY_SEPARATOR
. substr($keyHash, 0, 2)
. DIRECTORY_SEPARATOR
. '_' . $keyHash
. '.doctrine.cache';
return array($key, $keyPath, $hashedKeyPath);
}
public function getPathLengthsToTest()
{
// Windows officially supports 260 bytes including null terminator
// 259 characters is too large due to PHP bug (https://bugs.php.net/bug.php?id=70943)
// 260 characters is too large - null terminator is included in allowable length
return array(
array(257, false),
array(258, false),
array(259, true),
array(260, true)
);
}
/**
* @runInSeparateProcess
* @dataProvider getPathLengthsToTest
*
* @covers \Doctrine\Common\Cache\FileCache::getFilename
*
* @param int $length
* @param bool $pathShouldBeHashed
*/
public function testWindowsPathLengthLimitationsAreCorrectlyRespected($length, $pathShouldBeHashed)
{
if (! defined('PHP_WINDOWS_VERSION_BUILD')) {
define('PHP_WINDOWS_VERSION_BUILD', 'Yes, this is the "usual suspect", with the usual limitations');
}
$basePath = self::getBasePathForWindowsPathLengthTests($length);
$fileCache = $this->getMockForAbstractClass(
'Doctrine\Common\Cache\FileCache',
array($basePath, '.doctrine.cache')
);
list($key, $keyPath, $hashedKeyPath) = self::getKeyAndPathFittingLength($length, $basePath);
$getFileName = new \ReflectionMethod($fileCache, 'getFilename');
$getFileName->setAccessible(true);
$this->assertEquals(
$length,
strlen($keyPath),
sprintf('Path expected to be %d characters long is %d characters long', $length, strlen($keyPath))
);
if ($pathShouldBeHashed) {
$keyPath = $hashedKeyPath;
}
if ($pathShouldBeHashed) {
$this->assertSame(
$hashedKeyPath,
$getFileName->invoke($fileCache, $key),
'Keys should be hashed correctly if they are over the limit.'
);
} else {
$this->assertSame(
$keyPath,
$getFileName->invoke($fileCache, $key),
'Keys below limit of the allowed length are used directly, unhashed'
);
}
}
}