Passed
Push — main ( 624418...d73a9f )
by Dimitri
06:56 queued 03:19
created

MockCache   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 231
Duplicated Lines 0 %

Test Coverage

Coverage 22.73%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 61
c 2
b 1
f 0
dl 0
loc 231
ccs 10
cts 44
cp 0.2273
rs 9.76
wmc 33

14 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 5 2
A increment() 0 16 5
A assertMissing() 0 3 1
A set() 0 13 4
A clear() 0 6 1
A clearGroup() 0 3 1
A getMetaData() 0 13 4
A deleteMatching() 0 12 3
A bypass() 0 6 1
A info() 0 3 1
A delete() 0 11 2
A assertHas() 0 3 1
A decrement() 0 17 5
A assertHasValue() 0 10 2
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Spec\Mock;
13
14
use BlitzPHP\Cache\CacheInterface;
15
use BlitzPHP\Cache\Handlers\BaseHandler;
16
use BlitzPHP\Utilities\Date;
17
use DateInterval;
18
19
class MockCache extends BaseHandler implements CacheInterface
20
{
21
    /**
22
     * stockage des mocks de cache.
23
     *
24
     * @var array<string, mixed>
25
     */
26
    protected array $cache = [];
27
28
    /**
29
     * Temps d'expiration.
30
     *
31
     * @var int[]
32
     */
33
    protected array $expirations = [];
34
35
    /**
36
     * Si true, nous ne mettons aucune donnees en cache.
37
     */
38
    protected bool $bypass = false;
39
40
    /**
41
     * {@inheritDoc}
42
     *
43
     * @return bool|null
44
     */
45
    public function get(string $key, mixed $default = null): mixed
46
    {
47 10
        $key = $this->_key($key);
48
49 10
        return array_key_exists($key, $this->cache) ? $this->cache[$key] : null;
50
    }
51
52
    /**
53
     * {@inheritDoc}
54
     */
55
    public function set(string $key, mixed $value, null|DateInterval|int $ttl = null): bool
56
    {
57
        if ($this->bypass) {
58
            return false;
59
        }
60
61 2
        $key = $this->_key($key);
62 2
		$ttl = $ttl instanceof DateInterval ? $ttl->s : $ttl;
63
64 2
        $this->cache[$key]       = $value;
65 2
        $this->expirations[$key] = $ttl > 0 ? Date::now()->getTimestamp() + $ttl : null;
66
67 2
        return true;
68
    }
69
70
    /**
71
     * {@inheritDoc}
72
     */
73
    public function delete(string $key): bool
74
    {
75
        $key = $this->_key($key);
76
77
        if (! isset($this->cache[$key])) {
78
            return false;
79
        }
80
81
        unset($this->cache[$key], $this->expirations[$key]);
82
83
        return true;
84
    }
85
86
    /**
87
     * {@inheritDoc}
88
     *
89
     * @return int
90
     */
91
    public function deleteMatching(string $pattern)
92
    {
93
        $count = 0;
94
95
        foreach (array_keys($this->cache) as $key) {
96
            if (fnmatch($pattern, $key)) {
97
                $count++;
98
                unset($this->cache[$key], $this->expirations[$key]);
99
            }
100
        }
101
102
        return $count;
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     */
108
    public function increment(string $key, int $offset = 1)
109
    {
110
        $key  = $this->_key($key);
111
        $data = $this->cache[$key] ?: null;
112
113
        if ($data === null) {
114
            $data = 0;
115
        } elseif (! is_int($data)) {
116
            return false;
117
        }
118
119
		if (false !== $this->set($key, $increment = $data + $offset)) {
120
			return $increment;
121
		}
122
123
		return false;
124
    }
125
126
    /**
127
     * {@inheritDoc}
128
     */
129
    public function decrement(string $key, int $offset = 1)
130
    {
131
        $key = $this->_key($key);
132
133
        $data = $this->cache[$key] ?: null;
134
135
        if ($data === null) {
136
            $data = 0;
137
        } elseif (! is_int($data)) {
138
            return false;
139
        }
140
141
        if (false !== $this->set($key, $decrement = $data - $offset)) {
142
			return $decrement;
143
		}
144
145
		return false;
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151
    public function clear(): bool
152
    {
153 2
        $this->cache       = [];
154 2
        $this->expirations = [];
155
156 2
        return true;
157
    }
158
159
    /**
160
     * {@inheritDoc}
161
     */
162
    public function clearGroup(string $group): bool
163
    {
164
        return $this->deleteMatching($group) > 0;
165
    }
166
167
    /**
168
     * {@inheritDoc}
169
     *
170
     * @return string[] Keys currently present in the store
171
     */
172
    public function info(): array
173
    {
174
        return array_keys($this->cache);
175
    }
176
177
    /**
178
     * Renvoie des informations détaillées sur l'élément spécifique du cache.
179
     *
180
     * @return array|null Retourne null si l'élément n'existe pas, sinon array<string, mixed>
181
     *                    avec au moins la clé 'expire' pour une expiration absolue (ou null).
182
     */
183
    public function getMetaData(string $key): ?array
184
    {
185
        // n'existe pas, retourne null
186
        if (! array_key_exists($key, $this->expirations)) {
187
            return null;
188
        }
189
190
        //  Compter les elements périmés comme un manque
191
        if (is_int($this->expirations[$key]) && $this->expirations[$key] > Date::now()->getTimestamp()) {
192
            return null;
193
        }
194
195
        return ['expire' => $this->expirations[$key]];
196
    }
197
198
    // --------------------------------------------------------------------
199
    // Helpers de test
200
    // --------------------------------------------------------------------
201
202
    /**
203
     * Indique à la classe d'ignorer toutes les demandes de mise en cache d'un élément,
204
     * et de toujours "manquer" lorsqu'on vérifie la présence de données existantes.
205
     */
206
    public function bypass(bool $bypass = true): self
207
    {
208
        $this->clear();
209
        $this->bypass = $bypass;
210
211
        return $this;
212
    }
213
214
    // --------------------------------------------------------------------
215
    // Additional Assertions
216
    // --------------------------------------------------------------------
217
218
    /**
219
     * Affirme que le cache possède un élément nommé $key.
220
     * La valeur n'est pas vérifiée puisque le stockage de valeurs fausses ou nulles est valide.
221
     */
222
    public function assertHas(string $key): void
223
    {
224
        expect($this->get($key))->not->toBeNull();
225
        // Assert::assertNotNull($this->get($key), "Le cache n'a pas un élément nommé: `{$key}`");
226
    }
227
228
    /**
229
     * Affirme que le cache possède un élément nommé $key dont la valeur correspond à $value.
230
     */
231
    public function assertHasValue(string $key, mixed $value = null): void
232
    {
233
        $item = $this->get($key);
234
235
        // Laissez la fonction assertHas() gérer l'erreur de cohérence si la clé n'est pas trouvée.
236
        if ($item === null) {
237
            $this->assertHas($key);
238
        }
239
240
        expect($this->get($key))->toBe($value);
241
        // Assert::assertSame($value, $this->get($key), "L'élément `{$key}` du cache ne correspond pas à la valeur attendue. Trouvée: " . print_r($value, true));
242
    }
243
244
    /**
245
     * Affirme que le cache ne possède pas un élément nommé $key.
246
     */
247
    public function assertMissing(string $key): void
248
    {
249
        expect($this->cache)->not->toContainKey($key);
250
        // Assert::assertArrayNotHasKey($key, $this->cache, "L'élément en cache nommé `{$key}` existe.");
251
    }
252
}
253