Completed
Push — master ( 3f89cd...b2545f )
by Divine Niiquaye
02:08
created

CacheItemPoolTest::testSerialization()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of BiuradPHP opensource projects.
7
 *
8
 * PHP version 7.1 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace BiuradPHP\Cache\Tests;
19
20
use __PHP_Incomplete_Class;
21
use BadMethodCallException;
22
use BiuradPHP\Cache\CacheItem;
23
use BiuradPHP\Cache\CacheItemPool;
24
use BiuradPHP\Cache\Exceptions\InvalidArgumentException;
25
use BiuradPHP\Cache\SimpleCache;
26
use DateInterval;
27
use DateTime;
28
use Doctrine\Common\Cache\ArrayCache;
29
use Doctrine\Common\Cache\PhpFileCache;
30
use Generator;
31
use PHPUnit\Framework\TestCase;
32
use Psr\Cache\CacheItemInterface;
33
use Psr\Cache\CacheItemPoolInterface;
34
use ReflectionProperty;
35
36
/**
37
 * @internal
38
 */
39
class CacheItemPoolTest extends TestCase
40
{
41
    /** @var CacheItemPool */
42
    private $cache;
43
44
    protected function setUp(): void
45
    {
46
        parent::setUp();
47
48
        $adapter        = new ArrayCache();
49
        $this->cache    = new CacheItemPool(new SimpleCache($adapter));
50
    }
51
52
    /**
53
     * @throws \Psr\Cache\InvalidArgumentException
54
     */
55
    public function testProvider(): void
56
    {
57
        $pool = $this->cache;
58
59
        self::assertInstanceOf(CacheItemPoolInterface::class, $pool);
60
        $key = 'pool';
61
62
        self::assertTrue($pool->deleteItem($key));
63
        self::assertFalse($pool->hasItem($key));
64
65
        $item = $pool->getItem($key);
66
        $item->set('bar');
67
        self::assertTrue($pool->save($item));
68
        self::assertTrue($pool->hasItem($key));
69
        self::assertSame('bar', $pool->getItem($key)->get());
70
71
        self::assertTrue($pool->deleteItem($key));
72
        self::assertNull($pool->getItem($key)->get());
73
74
        $item = $pool->getItem($key);
75
        $item->set('bar');
76
        $pool->save($item);
77
        self::assertTrue($pool->getItem($key)->isHit());
78
79
        $pool->clear();
80
        self::assertNull($pool->getItem($key)->get());
81
        self::assertFalse($pool->hasItem($key));
82
    }
83
84
    /**
85
     * @throws \Psr\Cache\InvalidArgumentException
86
     */
87
    public function testInvalidKey(): void
88
    {
89
        $pool = $this->cache;
90
91
        $this->expectException(InvalidArgumentException::class);
92
        $this->expectExceptionMessage('Cache key "{}()/\@:" contains reserved characters "{}()/\@:');
93
        $pool->getItem(CacheItem::RESERVED_CHARACTERS);
94
    }
95
96
    /**
97
     * @throws \Psr\Cache\InvalidArgumentException
98
     */
99
    public function testCacheItems(): void
100
    {
101
        $pool = $this->cache;
102
103
        $i0  = $pool->getItem('i0');
104
        $i1  = $pool->getItem('i1');
105
        $i2  = $pool->getItem('i2');
106
        $i3  = $pool->getItem('i3');
107
        $foo = $pool->getItem('foo');
108
109
        $pool->save($i0);
110
        $pool->save($i1);
111
        $pool->save($i2);
112
        $pool->save($i3);
113
        $pool->save($foo);
114
115
        $pool->deleteItems(['i0', 'i2']);
116
117
        self::assertFalse($pool->getItem('i0')->isHit());
118
        self::assertTrue($pool->getItem('i1')->isHit());
119
        self::assertFalse($pool->getItem('i2')->isHit());
120
        self::assertTrue($pool->getItem('i3')->isHit());
121
        self::assertTrue($pool->getItem('foo')->isHit());
122
123
        $pool->deleteItems(['i1', 'i3']);
124
125
        self::assertFalse($pool->getItem('i1')->isHit());
126
        self::assertFalse($pool->getItem('i3')->isHit());
127
        self::assertTrue($pool->getItem('foo')->isHit());
128
129
        $anotherPoolInstance = $this->cache;
130
131
        self::assertFalse($anotherPoolInstance->getItem('i1')->isHit());
132
        self::assertFalse($anotherPoolInstance->getItem('i3')->isHit());
133
        self::assertTrue($anotherPoolInstance->getItem('foo')->isHit());
134
    }
135
136
    /**
137
     * @throws \Psr\Cache\InvalidArgumentException
138
     */
139
    public function testInvalidateCommits(): void
140
    {
141
        $pool = $this->cache;
142
143
        $foo = $pool->getItem('foo');
144
145
        $pool->saveDeferred($foo->set('foo'));
146
147
        // ??: This seems to contradict a bit logic in deleteItems,
148
        // ??: where it does unset($this->deferred[$key]); on key matches
149
150
        $foo = $pool->getItem('foo');
151
152
        self::assertTrue($foo->isHit());
153
154
        $pool->saveDeferred($foo);
155
        self::assertTrue($pool->hasItem('foo'));
156
        $pool->clear();
157
158
        $item = $pool->getItem('foo');
159
        $item->set(static function () {
160
            return 'value';
161
        });
162
        $pool->saveDeferred($item);
163
164
        $items = $pool->getItems(['foo', 'empty']);
165
166
        if ($items instanceof \Traversable) {
167
            $items = \iterator_to_array($items);
168
        }
169
170
        $key1 = $items['foo'];
171
        self::assertIsCallable($key1->get());
172
173
        $key2 = $items['empty'];
174
        self::assertFalse($key2->isHit());
175
    }
176
177
    /**
178
     * @throws \Psr\Cache\InvalidArgumentException
179
     */
180
    public function testMultiples(): void
181
    {
182
        $data = [
183
            'foo'      => 'baz',
184
            'pool'     => 'bar',
185
        ];
186
        $pool = $this->cache;
187
188
        self::assertTrue($pool->deleteItems(['foo', 'pool']));
189
        self::assertFalse($pool->hasItem('foo'));
190
        self::assertFalse($pool->hasItem('pool'));
191
192
        $item = $pool->getItem('foo');
193
        $item->set($data['foo']);
194
        $pool->save($item);
195
196
        $item = $pool->getItem('pool');
197
        $item->set($data['pool']);
198
        $pool->save($item);
199
200
        self::assertTrue($pool->hasItem('foo'));
201
        self::assertTrue($pool->hasItem('pool'));
202
203
        $foundItems = $pool->getItems(\array_keys($data));
204
        self::assertInstanceOf(Generator::class, $foundItems);
205
206
        if ($foundItems instanceof \Traversable) {
207
            $foundItems = \iterator_to_array($foundItems);
208
        }
209
210
        $items = [];
211
212
        foreach ($foundItems as $id => $item) {
213
            self::assertTrue($item->isHit());
214
            self::assertInstanceOf(CacheItemInterface::class, $item);
215
            $items[$id] = $item->get();
216
        }
217
        self::assertSame($data, $items);
218
219
        self::assertTrue($pool->deleteItems(\array_keys($data)));
220
221
        $foundItems = $pool->getItems(\array_keys($data));
222
223
        if ($foundItems instanceof \Traversable) {
224
            $foundItems = \iterator_to_array($foundItems);
225
        }
226
227
        foreach ($foundItems as $id => $item) {
228
            self::assertNull($item->get());
229
        }
230
231
        $pool->clear();
232
    }
233
234
    /**
235
     * @throws \Psr\Cache\InvalidArgumentException
236
     * @throws \ReflectionException
237
     */
238
    public function testDefaultLifeTime(): void
239
    {
240
        $pool = $this->cache;
241
242
        $item = $pool->getItem('key.dlt');
243
        $r    = new ReflectionProperty($item, 'defaultLifetime');
244
        $r->setAccessible(true);
245
        $r->setValue($item, 2);
246
247
        $item->expiresAfter(null);
248
        $pool->save($item);
249
        self::assertTrue($pool->getItem('key.dlt')->isHit());
250
251
        \sleep(3);
252
253
        self::assertFalse($pool->getItem('key.dlt')->isHit());
254
255
        $item = $pool->getItem('foo');
256
        $r    = new ReflectionProperty($item, 'defaultLifetime');
257
        $r->setAccessible(true);
258
        $r->setValue($item, 2);
259
260
        $item->expiresAt(null);
261
        $pool->save($item);
262
263
        \sleep(1);
264
265
        self::assertTrue($pool->getItem('foo')->isHit());
266
267
        \sleep(3);
268
269
        self::assertFalse($pool->getItem('foo')->isHit());
270
    }
271
272
    /**
273
     * @throws \Psr\Cache\InvalidArgumentException
274
     */
275
    public function testItemExpiry(): void
276
    {
277
        $pool = $this->cache;
278
279
        $item = $pool->getItem('foo');
280
        $item->expiresAfter(2);
281
282
        $pool->save($item);
283
        self::assertTrue($pool->getItem('foo')->isHit());
284
285
        \sleep(3);
286
287
        self::assertFalse($pool->getItem('foo')->isHit());
288
289
        $item = $pool->getItem('foo');
290
        $item->expiresAfter(DateInterval::createFromDateString('yesterday'));
291
292
        $pool->save($item);
293
        self::assertFalse($pool->getItem('foo')->isHit());
294
295
        $item = $pool->getItem('foo');
296
        $item->expiresAt(new DateTime('2 second'));
297
        $pool->save($item);
298
299
        \sleep(1);
300
301
        self::assertTrue($pool->getItem('foo')->isHit());
302
303
        \sleep(3);
304
305
        self::assertFalse($pool->getItem('foo')->isHit());
306
307
        $item = $pool->getItem('foo');
308
        $this->expectException(InvalidArgumentException::class);
309
        $this->expectExceptionMessage('Expiration date must be an integer, a DateInterval or null.');
310
        $item->expiresAfter('string');
0 ignored issues
show
Bug introduced by
'string' of type string is incompatible with the type DateInterval|integer|null expected by parameter $time of Psr\Cache\CacheItemInterface::expiresAfter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

310
        $item->expiresAfter(/** @scrutinizer ignore-type */ 'string');
Loading history...
311
    }
312
313
    /**
314
     * @throws \Psr\Cache\InvalidArgumentException
315
     */
316
    public function testNotUnserializableAndDeferred(): void
317
    {
318
        $pool = new CacheItemPool(new SimpleCache(new PhpFileCache(__DIR__ . '/caches')));
319
        $pool->clear();
320
321
        $item = $pool->getItem('foo');
322
        $item->set(new Fixtures\NotUnserializableTest());
323
        $pool->save($item);
324
        self::assertNull($pool->getItem('foo')->get());
325
326
        $pool->clear();
327
328
        self::assertTrue($pool->deleteItems(['foo']));
329
330
        $item = $pool->getItem('foo');
331
        $item->set(new Fixtures\NotUnserializableTest());
332
        $pool->saveDeferred($item);
333
334
        self::assertTrue($pool->deleteItem('foo'));
335
336
        $pool->clear();
337
    }
338
339
    public function testSerialization(): void
340
    {
341
        $this->expectException(BadMethodCallException::class);
342
        $pool = \serialize($this->cache);
343
        self::assertInstanceOf(__PHP_Incomplete_Class::class, $pool);
344
        self::assertInstanceOf(CacheItemPool::class, \unserialize($pool));
345
    }
346
}
347