Security update for Core, with self-updated composer
[yaffs-website] / vendor / doctrine / cache / tests / Doctrine / Tests / Common / Cache / CacheTest.php
1 <?php
2
3 namespace Doctrine\Tests\Common\Cache;
4
5 use Doctrine\Common\Cache\Cache;
6 use ArrayObject;
7
8 abstract class CacheTest extends \Doctrine\Tests\DoctrineTestCase
9 {
10     /**
11      * @dataProvider provideDataToCache
12      */
13     public function testSetContainsFetchDelete($value)
14     {
15         $cache = $this->_getCacheDriver();
16
17         // Test saving a value, checking if it exists, and fetching it back
18         $this->assertTrue($cache->save('key', $value));
19         $this->assertTrue($cache->contains('key'));
20         if (is_object($value)) {
21             $this->assertEquals($value, $cache->fetch('key'), 'Objects retrieved from the cache must be equal but not necessarily the same reference');
22         } else {
23             $this->assertSame($value, $cache->fetch('key'), 'Scalar and array data retrieved from the cache must be the same as the original, e.g. same type');
24         }
25
26         // Test deleting a value
27         $this->assertTrue($cache->delete('key'));
28         $this->assertFalse($cache->contains('key'));
29         $this->assertFalse($cache->fetch('key'));
30     }
31
32     /**
33      * @dataProvider provideDataToCache
34      */
35     public function testUpdateExistingEntry($value)
36     {
37         $cache = $this->_getCacheDriver();
38
39         $this->assertTrue($cache->save('key', 'old-value'));
40         $this->assertTrue($cache->contains('key'));
41
42         $this->assertTrue($cache->save('key', $value));
43         $this->assertTrue($cache->contains('key'));
44         if (is_object($value)) {
45             $this->assertEquals($value, $cache->fetch('key'), 'Objects retrieved from the cache must be equal but not necessarily the same reference');
46         } else {
47             $this->assertSame($value, $cache->fetch('key'), 'Scalar and array data retrieved from the cache must be the same as the original, e.g. same type');
48         }
49     }
50
51     public function testCacheKeyIsCaseSensitive()
52     {
53         $cache = $this->_getCacheDriver();
54
55         $this->assertTrue($cache->save('key', 'value'));
56         $this->assertTrue($cache->contains('key'));
57         $this->assertSame('value', $cache->fetch('key'));
58
59         $this->assertFalse($cache->contains('KEY'));
60         $this->assertFalse($cache->fetch('KEY'));
61
62         $cache->delete('KEY');
63         $this->assertTrue($cache->contains('key', 'Deleting cache item with different case must not affect other cache item'));
64     }
65
66     public function testFetchMultiple()
67     {
68         $cache  = $this->_getCacheDriver();
69         $values = $this->provideDataToCache();
70         $saved  = array();
71
72         foreach ($values as $key => $value) {
73             $cache->save($key, $value[0]);
74
75             $saved[$key] = $value[0];
76         }
77
78         $keys = array_keys($saved);
79
80         $this->assertEquals(
81             $saved,
82             $cache->fetchMultiple($keys),
83             'Testing fetchMultiple with different data types'
84         );
85         $this->assertEquals(
86             array_slice($saved, 0, 1),
87             $cache->fetchMultiple(array_slice($keys, 0, 1)),
88             'Testing fetchMultiple with a single key'
89         );
90
91         $keysWithNonExisting = array();
92         $keysWithNonExisting[] = 'non_existing1';
93         $keysWithNonExisting[] = $keys[0];
94         $keysWithNonExisting[] = 'non_existing2';
95         $keysWithNonExisting[] = $keys[1];
96         $keysWithNonExisting[] = 'non_existing3';
97
98         $this->assertEquals(
99             array_slice($saved, 0, 2),
100             $cache->fetchMultiple($keysWithNonExisting),
101             'Testing fetchMultiple with a subset of keys and mixed with non-existing ones'
102         );
103     }
104
105     public function testFetchMultipleWithNoKeys()
106     {
107         $cache = $this->_getCacheDriver();
108
109         $this->assertSame(array(), $cache->fetchMultiple(array()));
110     }
111
112     public function testSaveMultiple()
113     {
114         $cache = $this->_getCacheDriver();
115         $cache->deleteAll();
116
117         $data = array_map(function ($value) {
118             return $value[0];
119         }, $this->provideDataToCache());
120
121         $this->assertTrue($cache->saveMultiple($data));
122
123         $keys = array_keys($data);
124
125         $this->assertEquals($data, $cache->fetchMultiple($keys));
126     }
127
128     public function provideDataToCache()
129     {
130         $obj = new \stdClass();
131         $obj->foo = 'bar';
132         $obj2 = new \stdClass();
133         $obj2->bar = 'foo';
134         $obj2->obj = $obj;
135         $obj->obj2 = $obj2;
136
137         return array(
138             'array' => array(array('one', 2, 3.01)),
139             'string' => array('value'),
140             'string_invalid_utf8' => array("\xc3\x28"),
141             'string_null_byte' => array('with'."\0".'null char'),
142             'integer' => array(1),
143             'float' => array(1.5),
144             'object' => array(new ArrayObject(array('one', 2, 3.01))),
145             'object_recursive' => array($obj),
146             'true' => array(true),
147             // the following are considered FALSE in boolean context, but caches should still recognize their existence
148             'null' => array(null),
149             'false' => array(false),
150             'array_empty' => array(array()),
151             'string_zero' => array('0'),
152             'integer_zero' => array(0),
153             'float_zero' => array(0.0),
154             'string_empty' => array(''),
155         );
156     }
157
158     public function testDeleteIsSuccessfulWhenKeyDoesNotExist()
159     {
160         $cache = $this->_getCacheDriver();
161
162         $cache->delete('key');
163         $this->assertFalse($cache->contains('key'));
164         $this->assertTrue($cache->delete('key'));
165     }
166
167     public function testDeleteAll()
168     {
169         $cache = $this->_getCacheDriver();
170
171         $this->assertTrue($cache->save('key1', 1));
172         $this->assertTrue($cache->save('key2', 2));
173         $this->assertTrue($cache->deleteAll());
174         $this->assertFalse($cache->contains('key1'));
175         $this->assertFalse($cache->contains('key2'));
176     }
177
178     /**
179      * @dataProvider provideCacheIds
180      */
181     public function testCanHandleSpecialCacheIds($id)
182     {
183         $cache = $this->_getCacheDriver();
184
185         $this->assertTrue($cache->save($id, 'value'));
186         $this->assertTrue($cache->contains($id));
187         $this->assertEquals('value', $cache->fetch($id));
188
189         $this->assertTrue($cache->delete($id));
190         $this->assertFalse($cache->contains($id));
191         $this->assertFalse($cache->fetch($id));
192     }
193
194     public function testNoCacheIdCollisions()
195     {
196         $cache = $this->_getCacheDriver();
197
198         $ids = $this->provideCacheIds();
199
200         // fill cache with each id having a different value
201         foreach ($ids as $index => $id) {
202             $cache->save($id[0], $index);
203         }
204
205         // then check value of each cache id
206         foreach ($ids as $index => $id) {
207             $value = $cache->fetch($id[0]);
208             $this->assertNotFalse($value, sprintf('Failed to retrieve data for cache id "%s".', $id[0]));
209             if ($index !== $value) {
210                 $this->fail(sprintf('Cache id "%s" collides with id "%s".', $id[0], $ids[$value][0]));
211             }
212         }
213     }
214
215     /**
216      * Returns cache ids with special characters that should still work.
217      *
218      * For example, the characters :\/<>"*?| are not valid in Windows filenames. So they must be encoded properly.
219      * Each cache id should be considered different from the others.
220      *
221      * @return array
222      */
223     public function provideCacheIds()
224     {
225         return array(
226             array(':'),
227             array('\\'),
228             array('/'),
229             array('<'),
230             array('>'),
231             array('"'),
232             array('*'),
233             array('?'),
234             array('|'),
235             array('['),
236             array(']'),
237             array('ä'),
238             array('a'),
239             array('é'),
240             array('e'),
241             array('.'), // directory traversal
242             array('..'), // directory traversal
243             array('-'),
244             array('_'),
245             array('$'),
246             array('%'),
247             array(' '),
248             array("\0"),
249             array(''),
250             array(str_repeat('a', 300)), // long key
251             array(str_repeat('a', 113)),
252         );
253     }
254
255     public function testLifetime()
256     {
257         $cache = $this->_getCacheDriver();
258         $cache->save('expire', 'value', 1);
259         $this->assertTrue($cache->contains('expire'), 'Data should not be expired yet');
260         // @TODO should more TTL-based tests pop up, so then we should mock the `time` API instead
261         sleep(2);
262         $this->assertFalse($cache->contains('expire'), 'Data should be expired');
263     }
264
265     public function testNoExpire()
266     {
267         $cache = $this->_getCacheDriver();
268         $cache->save('noexpire', 'value', 0);
269         // @TODO should more TTL-based tests pop up, so then we should mock the `time` API instead
270         sleep(1);
271         $this->assertTrue($cache->contains('noexpire'), 'Data with lifetime of zero should not expire');
272     }
273
274     public function testLongLifetime()
275     {
276         $cache = $this->_getCacheDriver();
277         $cache->save('longlifetime', 'value', 30 * 24 * 3600 + 1);
278         $this->assertTrue($cache->contains('longlifetime'), 'Data with lifetime > 30 days should be accepted');
279     }
280
281     public function testDeleteAllAndNamespaceVersioningBetweenCaches()
282     {
283         if ( ! $this->isSharedStorage()) {
284             $this->markTestSkipped('The cache storage needs to be shared.');
285         }
286
287         $cache1 = $this->_getCacheDriver();
288         $cache2 = $this->_getCacheDriver();
289
290         $this->assertTrue($cache1->save('key1', 1));
291         $this->assertTrue($cache2->save('key2', 2));
292
293         /* Both providers are initialized with the same namespace version, so
294          * they can see entries set by each other.
295          */
296         $this->assertTrue($cache1->contains('key1'));
297         $this->assertTrue($cache1->contains('key2'));
298         $this->assertTrue($cache2->contains('key1'));
299         $this->assertTrue($cache2->contains('key2'));
300
301         /* Deleting all entries through one provider will only increment the
302          * namespace version on that object (and in the cache itself, which new
303          * instances will use to initialize). The second provider will retain
304          * its original version and still see stale data.
305          */
306         $this->assertTrue($cache1->deleteAll());
307         $this->assertFalse($cache1->contains('key1'));
308         $this->assertFalse($cache1->contains('key2'));
309         $this->assertTrue($cache2->contains('key1'));
310         $this->assertTrue($cache2->contains('key2'));
311
312         /* A new cache provider should not see the deleted entries, since its
313          * namespace version will be initialized.
314          */
315         $cache3 = $this->_getCacheDriver();
316         $this->assertFalse($cache3->contains('key1'));
317         $this->assertFalse($cache3->contains('key2'));
318     }
319
320     public function testFlushAll()
321     {
322         $cache = $this->_getCacheDriver();
323
324         $this->assertTrue($cache->save('key1', 1));
325         $this->assertTrue($cache->save('key2', 2));
326         $this->assertTrue($cache->flushAll());
327         $this->assertFalse($cache->contains('key1'));
328         $this->assertFalse($cache->contains('key2'));
329     }
330
331     public function testFlushAllAndNamespaceVersioningBetweenCaches()
332     {
333         if ( ! $this->isSharedStorage()) {
334             $this->markTestSkipped('The cache storage needs to be shared.');
335         }
336
337         $cache1 = $this->_getCacheDriver();
338         $cache2 = $this->_getCacheDriver();
339
340         /* Deleting all elements from the first provider should increment its
341          * namespace version before saving the first entry.
342          */
343         $cache1->deleteAll();
344         $this->assertTrue($cache1->save('key1', 1));
345
346         /* The second provider will be initialized with the same namespace
347          * version upon its first save operation.
348          */
349         $this->assertTrue($cache2->save('key2', 2));
350
351         /* Both providers have the same namespace version and can see entries
352          * set by each other.
353          */
354         $this->assertTrue($cache1->contains('key1'));
355         $this->assertTrue($cache1->contains('key2'));
356         $this->assertTrue($cache2->contains('key1'));
357         $this->assertTrue($cache2->contains('key2'));
358
359         /* Flushing all entries through one cache will remove all entries from
360          * the cache but leave their namespace version as-is.
361          */
362         $this->assertTrue($cache1->flushAll());
363         $this->assertFalse($cache1->contains('key1'));
364         $this->assertFalse($cache1->contains('key2'));
365         $this->assertFalse($cache2->contains('key1'));
366         $this->assertFalse($cache2->contains('key2'));
367
368         /* Inserting a new entry will use the same, incremented namespace
369          * version, and it will be visible to both providers.
370          */
371         $this->assertTrue($cache1->save('key1', 1));
372         $this->assertTrue($cache1->contains('key1'));
373         $this->assertTrue($cache2->contains('key1'));
374
375         /* A new cache provider will be initialized with the original namespace
376          * version and not share any visibility with the first two providers.
377          */
378         $cache3 = $this->_getCacheDriver();
379         $this->assertFalse($cache3->contains('key1'));
380         $this->assertFalse($cache3->contains('key2'));
381         $this->assertTrue($cache3->save('key3', 3));
382         $this->assertTrue($cache3->contains('key3'));
383     }
384
385     public function testNamespace()
386     {
387         $cache = $this->_getCacheDriver();
388
389         $cache->setNamespace('ns1_');
390
391         $this->assertTrue($cache->save('key1', 1));
392         $this->assertTrue($cache->contains('key1'));
393
394         $cache->setNamespace('ns2_');
395
396         $this->assertFalse($cache->contains('key1'));
397     }
398
399     public function testDeleteAllNamespace()
400     {
401         $cache = $this->_getCacheDriver();
402
403         $cache->setNamespace('ns1');
404         $this->assertFalse($cache->contains('key1'));
405         $cache->save('key1', 'test');
406         $this->assertTrue($cache->contains('key1'));
407
408         $cache->setNamespace('ns2');
409         $this->assertFalse($cache->contains('key1'));
410         $cache->save('key1', 'test');
411         $this->assertTrue($cache->contains('key1'));
412
413         $cache->setNamespace('ns1');
414         $this->assertTrue($cache->contains('key1'));
415         $cache->deleteAll();
416         $this->assertFalse($cache->contains('key1'));
417
418         $cache->setNamespace('ns2');
419         $this->assertTrue($cache->contains('key1'));
420         $cache->deleteAll();
421         $this->assertFalse($cache->contains('key1'));
422     }
423
424     /**
425      * @group DCOM-43
426      */
427     public function testGetStats()
428     {
429         $cache = $this->_getCacheDriver();
430         $stats = $cache->getStats();
431
432         $this->assertArrayHasKey(Cache::STATS_HITS, $stats);
433         $this->assertArrayHasKey(Cache::STATS_MISSES, $stats);
434         $this->assertArrayHasKey(Cache::STATS_UPTIME, $stats);
435         $this->assertArrayHasKey(Cache::STATS_MEMORY_USAGE, $stats);
436         $this->assertArrayHasKey(Cache::STATS_MEMORY_AVAILABLE, $stats);
437     }
438
439     public function testSaveReturnsTrueWithAndWithoutTTlSet()
440     {
441         $cache = $this->_getCacheDriver();
442         $cache->deleteAll();
443         $this->assertTrue($cache->save('without_ttl', 'without_ttl'));
444         $this->assertTrue($cache->save('with_ttl', 'with_ttl', 3600));
445     }
446
447     public function testValueThatIsFalseBooleanIsProperlyRetrieved()
448     {
449         $cache = $this->_getCacheDriver();
450         $cache->deleteAll();
451
452         $this->assertTrue($cache->save('key1', false));
453         $this->assertTrue($cache->contains('key1'));
454         $this->assertFalse($cache->fetch('key1'));
455     }
456
457     /**
458      * Return whether multiple cache providers share the same storage.
459      *
460      * This is used for skipping certain tests for shared storage behavior.
461      *
462      * @return bool
463      */
464     protected function isSharedStorage()
465     {
466         return true;
467     }
468
469     /**
470      * @return \Doctrine\Common\Cache\CacheProvider
471      */
472     abstract protected function _getCacheDriver();
473 }