scratch – Blame information for rev 120
?pathlinks?
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 | } |