scratch – Blame information for rev 120

Subversion Repositories:
Rev:
Rev Author Line No. Line
120 office 1 <?php
2  
3 namespace Doctrine\Tests\Common\Cache;
4  
5 use Doctrine\Common\Cache\Cache;
6  
7 /**
8 * @group DCOM-101
9 */
10 class FileCacheTest extends \Doctrine\Tests\DoctrineTestCase
11 {
12 /**
13 * @var \Doctrine\Common\Cache\FileCache
14 */
15 private $driver;
16  
17 protected function setUp()
18 {
19 $this->driver = $this->getMock(
20 'Doctrine\Common\Cache\FileCache',
21 array('doFetch', 'doContains', 'doSave'),
22 array(), '', false
23 );
24 }
25  
26 public function testFilenameShouldCreateThePathWithOneSubDirectory()
27 {
28 $cache = $this->driver;
29 $method = new \ReflectionMethod($cache, 'getFilename');
30 $key = 'item-key';
31 $expectedDir = array(
32 '84',
33 );
34 $expectedDir = implode(DIRECTORY_SEPARATOR, $expectedDir);
35  
36 $method->setAccessible(true);
37  
38 $path = $method->invoke($cache, $key);
39 $dirname = pathinfo($path, PATHINFO_DIRNAME);
40  
41 $this->assertEquals(DIRECTORY_SEPARATOR . $expectedDir, $dirname);
42 }
43  
44 public function testFileExtensionCorrectlyEscaped()
45 {
46 $driver1 = $this->getMock(
47 'Doctrine\Common\Cache\FileCache',
48 array('doFetch', 'doContains', 'doSave'),
49 array(__DIR__, '.*')
50 );
51 $driver2 = $this->getMock(
52 'Doctrine\Common\Cache\FileCache',
53 array('doFetch', 'doContains', 'doSave'),
54 array(__DIR__, '.php')
55 );
56  
57 $doGetStats = new \ReflectionMethod($driver1, 'doGetStats');
58  
59 $doGetStats->setAccessible(true);
60  
61 $stats1 = $doGetStats->invoke($driver1);
62 $stats2 = $doGetStats->invoke($driver2);
63  
64 $this->assertSame(0, $stats1[Cache::STATS_MEMORY_USAGE]);
65 $this->assertGreaterThan(0, $stats2[Cache::STATS_MEMORY_USAGE]);
66 }
67  
68 /**
69 * @group DCOM-266
70 */
71 public function testFileExtensionSlashCorrectlyEscaped()
72 {
73 $driver = $this->getMock(
74 'Doctrine\Common\Cache\FileCache',
75 array('doFetch', 'doContains', 'doSave'),
76 array(__DIR__ . '/../', DIRECTORY_SEPARATOR . basename(__FILE__))
77 );
78  
79 $doGetStats = new \ReflectionMethod($driver, 'doGetStats');
80  
81 $doGetStats->setAccessible(true);
82  
83 $stats = $doGetStats->invoke($driver);
84  
85 $this->assertGreaterThan(0, $stats[Cache::STATS_MEMORY_USAGE]);
86 }
87  
88 public function testNonIntUmaskThrowsInvalidArgumentException()
89 {
90 $this->setExpectedException('InvalidArgumentException');
91  
92 $this->getMock(
93 'Doctrine\Common\Cache\FileCache',
94 array('doFetch', 'doContains', 'doSave'),
95 array('', '', 'invalid')
96 );
97 }
98  
99 public function testGetDirectoryReturnsRealpathDirectoryString()
100 {
101 $directory = __DIR__ . '/../';
102 $driver = $this->getMock(
103 'Doctrine\Common\Cache\FileCache',
104 array('doFetch', 'doContains', 'doSave'),
105 array($directory)
106 );
107  
108 $doGetDirectory = new \ReflectionMethod($driver, 'getDirectory');
109  
110 $actualDirectory = $doGetDirectory->invoke($driver);
111 $expectedDirectory = realpath($directory);
112  
113 $this->assertEquals($expectedDirectory, $actualDirectory);
114 }
115  
116 public function testGetExtensionReturnsExtensionString()
117 {
118 $directory = __DIR__ . '/../';
119 $extension = DIRECTORY_SEPARATOR . basename(__FILE__);
120 $driver = $this->getMock(
121 'Doctrine\Common\Cache\FileCache',
122 array('doFetch', 'doContains', 'doSave'),
123 array($directory, $extension)
124 );
125  
126 $doGetExtension = new \ReflectionMethod($driver, 'getExtension');
127  
128 $actualExtension = $doGetExtension->invoke($driver);
129  
130 $this->assertEquals($extension, $actualExtension);
131 }
132  
133 const WIN_MAX_PATH_LEN = 258;
134  
135 public static function getBasePathForWindowsPathLengthTests($pathLength)
136 {
137 // Not using __DIR__ because it can get screwed up when xdebug debugger is attached.
138 $basePath = realpath(sys_get_temp_dir()) . '/' . uniqid('doctrine-cache', true);
139  
140 /** @noinspection MkdirRaceConditionInspection */
141 @mkdir($basePath);
142  
143 $basePath = realpath($basePath);
144  
145 // Test whether the desired path length is odd or even.
146 $desiredPathLengthIsOdd = ($pathLength % 2) == 1;
147  
148 // If the cache key is not too long, the filecache codepath will add
149 // a slash and bin2hex($key). The length of the added portion will be an odd number.
150 // len(desired) = len(base path) + len(slash . bin2hex($key))
151 // odd = even + odd
152 // even = odd + odd
153 $basePathLengthShouldBeOdd = !$desiredPathLengthIsOdd;
154  
155 $basePathLengthIsOdd = (strlen($basePath) % 2) == 1;
156  
157 // If the base path needs to be odd or even where it is not, we add an odd number of
158 // characters as a pad. In this case, we're adding '\aa' (or '/aa' depending on platform)
159 // This is all to make it so that the key we're testing would result in
160 // a path that is exactly the length we want to test IF the path length limit
161 // were not in place in FileCache.
162 if ($basePathLengthIsOdd != $basePathLengthShouldBeOdd) {
163 $basePath .= DIRECTORY_SEPARATOR . "aa";
164 }
165  
166 return $basePath;
167 }
168  
169 /**
170 * @param int $length
171 * @param string $basePath
172 *
173 * @return array
174 */
175 public static function getKeyAndPathFittingLength($length, $basePath)
176 {
177 $baseDirLength = strlen($basePath);
178 $extensionLength = strlen('.doctrine.cache');
179 $directoryLength = strlen(DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR);
180 $keyLength = $length - ($baseDirLength + $extensionLength + $directoryLength); // - 1 because of slash
181  
182 $key = str_repeat('a', floor($keyLength / 2));
183  
184 $keyHash = hash('sha256', $key);
185  
186 $keyPath = $basePath
187 . DIRECTORY_SEPARATOR
188 . substr($keyHash, 0, 2)
189 . DIRECTORY_SEPARATOR
190 . bin2hex($key)
191 . '.doctrine.cache';
192  
193 $hashedKeyPath = $basePath
194 . DIRECTORY_SEPARATOR
195 . substr($keyHash, 0, 2)
196 . DIRECTORY_SEPARATOR
197 . '_' . $keyHash
198 . '.doctrine.cache';
199  
200 return array($key, $keyPath, $hashedKeyPath);
201 }
202  
203 public function getPathLengthsToTest()
204 {
205 // Windows officially supports 260 bytes including null terminator
206 // 259 characters is too large due to PHP bug (https://bugs.php.net/bug.php?id=70943)
207 // 260 characters is too large - null terminator is included in allowable length
208 return array(
209 array(257, false),
210 array(258, false),
211 array(259, true),
212 array(260, true)
213 );
214 }
215  
216 /**
217 * @runInSeparateProcess
218 * @dataProvider getPathLengthsToTest
219 *
220 * @covers \Doctrine\Common\Cache\FileCache::getFilename
221 *
222 * @param int $length
223 * @param bool $pathShouldBeHashed
224 */
225 public function testWindowsPathLengthLimitationsAreCorrectlyRespected($length, $pathShouldBeHashed)
226 {
227 if (! defined('PHP_WINDOWS_VERSION_BUILD')) {
228 define('PHP_WINDOWS_VERSION_BUILD', 'Yes, this is the "usual suspect", with the usual limitations');
229 }
230  
231 $basePath = self::getBasePathForWindowsPathLengthTests($length);
232  
233 $fileCache = $this->getMockForAbstractClass(
234 'Doctrine\Common\Cache\FileCache',
235 array($basePath, '.doctrine.cache')
236 );
237  
238 list($key, $keyPath, $hashedKeyPath) = self::getKeyAndPathFittingLength($length, $basePath);
239  
240 $getFileName = new \ReflectionMethod($fileCache, 'getFilename');
241  
242 $getFileName->setAccessible(true);
243  
244 $this->assertEquals(
245 $length,
246 strlen($keyPath),
247 sprintf('Path expected to be %d characters long is %d characters long', $length, strlen($keyPath))
248 );
249  
250 if ($pathShouldBeHashed) {
251 $keyPath = $hashedKeyPath;
252 }
253  
254 if ($pathShouldBeHashed) {
255 $this->assertSame(
256 $hashedKeyPath,
257 $getFileName->invoke($fileCache, $key),
258 'Keys should be hashed correctly if they are over the limit.'
259 );
260 } else {
261 $this->assertSame(
262 $keyPath,
263 $getFileName->invoke($fileCache, $key),
264 'Keys below limit of the allowed length are used directly, unhashed'
265 );
266 }
267 }
268 }