Skip to content

Commit 20771dc

Browse files
committed
more test
1 parent 227c7b0 commit 20771dc

File tree

4 files changed

+376
-3
lines changed

4 files changed

+376
-3
lines changed

lib/tests/mock/mock_cache.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import { SyncCache } from "../../utils/cache/cache";
1+
import { SyncCache, AsyncCache } from "../../utils/cache/cache";
22
import { Maybe } from "../../utils/type";
33

44
type SyncCacheWithAddOn<T> = SyncCache<T> & {
55
size(): number;
66
getAll(): Map<string, T>;
77
};
88

9+
type AsyncCacheWithAddOn<T> = AsyncCache<T> & {
10+
size(): Promise<number>;
11+
getAll(): Promise<Map<string, T>>;
12+
};
13+
914
export const getMockSyncCache = <T>(): SyncCacheWithAddOn<T> => {
1015
const cache = {
1116
operation: 'sync' as const,
@@ -39,3 +44,36 @@ export const getMockSyncCache = <T>(): SyncCacheWithAddOn<T> => {
3944
return cache;
4045
};
4146

47+
48+
export const getMockAsyncCache = <T>(): AsyncCacheWithAddOn<T> => {
49+
const cache = {
50+
operation: 'async' as const,
51+
data: new Map<string, T>(),
52+
async remove(key: string): Promise<void> {
53+
this.data.delete(key);
54+
},
55+
async clear(): Promise<void> {
56+
this.data.clear();
57+
},
58+
async getKeys(): Promise<string[]> {
59+
return Array.from(this.data.keys());
60+
},
61+
async getAll(): Promise<Map<string, T>> {
62+
return this.data;
63+
},
64+
async getBatched(keys: string[]): Promise<Maybe<T>[]> {
65+
return Promise.all(keys.map((key) => this.get(key)));
66+
},
67+
async size(): Promise<number> {
68+
return this.data.size;
69+
},
70+
async get(key: string): Promise<Maybe<T>> {
71+
return this.data.get(key);
72+
},
73+
async set(key: string, value: T): Promise<void> {
74+
this.data.set(key, value);
75+
}
76+
}
77+
78+
return cache;
79+
};

lib/utils/cache/cache.spec.ts

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
import { describe, it, expect, beforeEach } from 'vitest';
2+
import { SyncPrefixCache, AsyncPrefixCache } from './cache';
3+
import { getMockSyncCache, getMockAsyncCache } from '../../tests/mock/mock_cache';
4+
5+
describe('SyncPrefixCache', () => {
6+
describe('set', () => {
7+
it('should add prefix to key when setting in the underlying cache', () => {
8+
const cache = getMockSyncCache<string>();
9+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
10+
prefixCache.set('key', 'value');
11+
expect(cache.get('prefix:key')).toEqual('value');
12+
});
13+
14+
it('should transform value when setting in the underlying cache', () => {
15+
const cache = getMockSyncCache<string>();
16+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v.toLowerCase(), (v) => v.toUpperCase());
17+
prefixCache.set('key', 'value');
18+
expect(cache.get('prefix:key')).toEqual('VALUE');
19+
});
20+
21+
it('should work correctly with empty prefix', () => {
22+
const cache = getMockSyncCache<string>();
23+
const prefixCache = new SyncPrefixCache(cache, '', (v) => v.toLowerCase(), (v) => v.toUpperCase());
24+
prefixCache.set('key', 'value');
25+
expect(cache.get('key')).toEqual('VALUE');
26+
});
27+
});
28+
29+
describe('get', () => {
30+
it('should remove prefix from key when getting from the underlying cache', () => {
31+
const cache = getMockSyncCache<string>();
32+
cache.set('prefix:key', 'value');
33+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
34+
expect(prefixCache.get('key')).toEqual('value');
35+
});
36+
37+
it('should transform value after getting from the underlying cache', () => {
38+
const cache = getMockSyncCache<string>();
39+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v.toLowerCase(), (v) => v.toUpperCase());
40+
cache.set('prefix:key', 'VALUE');
41+
expect(prefixCache.get('key')).toEqual('value');
42+
});
43+
44+
45+
it('should work correctly with empty prefix', () => {
46+
const cache = getMockSyncCache<string>();
47+
const prefixCache = new SyncPrefixCache(cache, '', (v) => v.toLowerCase(), (v) => v.toUpperCase());
48+
cache.set('key', 'VALUE');
49+
expect(prefixCache.get('key')).toEqual('value');
50+
});
51+
});
52+
53+
describe('remove', () => {
54+
it('should remove the correct value from the underlying cache', () => {
55+
const cache = getMockSyncCache<string>();
56+
cache.set('prefix:key', 'value');
57+
cache.set('key', 'value');
58+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
59+
prefixCache.remove('key');
60+
expect(cache.get('prefix:key')).toBeUndefined();
61+
expect(cache.get('key')).toEqual('value');
62+
});
63+
64+
it('should work with empty prefix', () => {
65+
const cache = getMockSyncCache<string>();
66+
cache.set('key', 'value');
67+
const prefixCache = new SyncPrefixCache(cache, '', (v) => v, (v) => v);
68+
prefixCache.remove('key');
69+
expect(cache.get('key')).toBeUndefined();
70+
});
71+
});
72+
73+
describe('clear', () => {
74+
it('should remove keys with correct prefix from the underlying cache', () => {
75+
const cache = getMockSyncCache<string>();
76+
cache.set('key1', 'value1');
77+
cache.set('key2', 'value2');
78+
cache.set('prefix:key1', 'value1');
79+
cache.set('prefix:key2', 'value2');
80+
81+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
82+
prefixCache.clear();
83+
84+
expect(cache.get('key1')).toEqual('value1');
85+
expect(cache.get('key2')).toEqual('value2');
86+
expect(cache.get('prefix:key1')).toBeUndefined();
87+
expect(cache.get('prefix:key2')).toBeUndefined();
88+
});
89+
90+
it('should work with empty prefix', () => {
91+
const cache = getMockSyncCache<string>();
92+
cache.set('key1', 'value1');
93+
cache.set('key2', 'value2');
94+
95+
const prefixCache = new SyncPrefixCache(cache, '', (v) => v, (v) => v);
96+
prefixCache.clear();
97+
98+
expect(cache.get('key1')).toBeUndefined();
99+
expect(cache.get('key2')).toBeUndefined();
100+
});
101+
});
102+
103+
describe('getKeys', () => {
104+
it('should return keys with correct prefix', () => {
105+
const cache = getMockSyncCache<string>();
106+
cache.set('key1', 'value1');
107+
cache.set('key2', 'value2');
108+
cache.set('prefix:key3', 'value1');
109+
cache.set('prefix:key4', 'value2');
110+
111+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
112+
113+
const keys = prefixCache.getKeys();
114+
expect(keys).toEqual(expect.arrayContaining(['key3', 'key4']));
115+
});
116+
117+
it('should work with empty prefix', () => {
118+
const cache = getMockSyncCache<string>();
119+
cache.set('key1', 'value1');
120+
cache.set('key2', 'value2');
121+
122+
const prefixCache = new SyncPrefixCache(cache, '', (v) => v, (v) => v);
123+
124+
const keys = prefixCache.getKeys();
125+
expect(keys).toEqual(expect.arrayContaining(['key1', 'key2']));
126+
});
127+
});
128+
129+
describe('getBatched', () => {
130+
it('should return values with correct prefix', () => {
131+
const cache = getMockSyncCache<string>();
132+
cache.set('key1', 'value1');
133+
cache.set('key2', 'value2');
134+
cache.set('key3', 'value3');
135+
cache.set('prefix:key1', 'prefix:value1');
136+
cache.set('prefix:key2', 'prefix:value2');
137+
138+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
139+
140+
const values = prefixCache.getBatched(['key1', 'key2', 'key3']);
141+
expect(values).toEqual(expect.arrayContaining(['prefix:value1', 'prefix:value2', undefined]));
142+
});
143+
144+
it('should transform values after getting from the underlying cache', () => {
145+
const cache = getMockSyncCache<string>();
146+
cache.set('key1', 'VALUE1');
147+
cache.set('key2', 'VALUE2');
148+
cache.set('key3', 'VALUE3');
149+
cache.set('prefix:key1', 'PREFIX:VALUE1');
150+
cache.set('prefix:key2', 'PREFIX:VALUE2');
151+
152+
const prefixCache = new SyncPrefixCache(cache, 'prefix:', (v) => v.toLocaleLowerCase(), (v) => v.toUpperCase());
153+
154+
const values = prefixCache.getBatched(['key1', 'key2', 'key3']);
155+
expect(values).toEqual(expect.arrayContaining(['prefix:value1', 'prefix:value2', undefined]));
156+
});
157+
158+
it('should work with empty prefix', () => {
159+
const cache = getMockSyncCache<string>();
160+
cache.set('key1', 'value1');
161+
cache.set('key2', 'value2');
162+
163+
const prefixCache = new SyncPrefixCache(cache, '', (v) => v, (v) => v);
164+
165+
const values = prefixCache.getBatched(['key1', 'key2']);
166+
expect(values).toEqual(expect.arrayContaining(['value1', 'value2']));
167+
});
168+
});
169+
});
170+
171+
describe('AsyncPrefixCache', () => {
172+
describe('set', () => {
173+
it('should add prefix to key when setting in the underlying cache', async () => {
174+
const cache = getMockAsyncCache<string>();
175+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
176+
await prefixCache.set('key', 'value');
177+
expect(await cache.get('prefix:key')).toEqual('value');
178+
});
179+
180+
it('should transform value when setting in the underlying cache', async () => {
181+
const cache = getMockAsyncCache<string>();
182+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v.toLowerCase(), (v) => v.toUpperCase());
183+
await prefixCache.set('key', 'value');
184+
expect(await cache.get('prefix:key')).toEqual('VALUE');
185+
});
186+
187+
it('should work correctly with empty prefix', async () => {
188+
const cache = getMockAsyncCache<string>();
189+
const prefixCache = new AsyncPrefixCache(cache, '', (v) => v.toLowerCase(), (v) => v.toUpperCase());
190+
await prefixCache.set('key', 'value');
191+
expect(await cache.get('key')).toEqual('VALUE');
192+
});
193+
});
194+
195+
describe('get', () => {
196+
it('should remove prefix from key when getting from the underlying cache', async () => {
197+
const cache = getMockAsyncCache<string>();
198+
await cache.set('prefix:key', 'value');
199+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
200+
expect(await prefixCache.get('key')).toEqual('value');
201+
});
202+
203+
it('should transform value after getting from the underlying cache', async () => {
204+
const cache = getMockAsyncCache<string>();
205+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v.toLowerCase(), (v) => v.toUpperCase());
206+
await cache.set('prefix:key', 'VALUE');
207+
expect(await prefixCache.get('key')).toEqual('value');
208+
});
209+
210+
211+
it('should work correctly with empty prefix', async () => {
212+
const cache = getMockAsyncCache<string>();
213+
const prefixCache = new AsyncPrefixCache(cache, '', (v) => v.toLowerCase(), (v) => v.toUpperCase());
214+
await cache.set('key', 'VALUE');
215+
expect(await prefixCache.get('key')).toEqual('value');
216+
});
217+
});
218+
219+
describe('remove', () => {
220+
it('should remove the correct value from the underlying cache', async () => {
221+
const cache = getMockAsyncCache<string>();
222+
cache.set('prefix:key', 'value');
223+
cache.set('key', 'value');
224+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
225+
await prefixCache.remove('key');
226+
expect(await cache.get('prefix:key')).toBeUndefined();
227+
expect(await cache.get('key')).toEqual('value');
228+
});
229+
230+
it('should work with empty prefix', async () => {
231+
const cache = getMockAsyncCache<string>();
232+
await cache.set('key', 'value');
233+
const prefixCache = new AsyncPrefixCache(cache, '', (v) => v, (v) => v);
234+
await prefixCache.remove('key');
235+
expect(await cache.get('key')).toBeUndefined();
236+
});
237+
});
238+
239+
describe('clear', () => {
240+
it('should remove keys with correct prefix from the underlying cache', async () => {
241+
const cache = getMockAsyncCache<string>();
242+
await cache.set('key1', 'value1');
243+
await cache.set('key2', 'value2');
244+
await cache.set('prefix:key1', 'value1');
245+
await cache.set('prefix:key2', 'value2');
246+
247+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
248+
await prefixCache.clear();
249+
250+
expect(await cache.get('key1')).toEqual('value1');
251+
expect(await cache.get('key2')).toEqual('value2');
252+
expect(await cache.get('prefix:key1')).toBeUndefined();
253+
expect(await cache.get('prefix:key2')).toBeUndefined();
254+
});
255+
256+
it('should work with empty prefix', async () => {
257+
const cache = getMockAsyncCache<string>();
258+
await cache.set('key1', 'value1');
259+
await cache.set('key2', 'value2');
260+
261+
const prefixCache = new AsyncPrefixCache(cache, '', (v) => v, (v) => v);
262+
await prefixCache.clear();
263+
264+
expect(await cache.get('key1')).toBeUndefined();
265+
expect(await cache.get('key2')).toBeUndefined();
266+
});
267+
});
268+
269+
describe('getKeys', () => {
270+
it('should return keys with correct prefix', async () => {
271+
const cache = getMockAsyncCache<string>();
272+
await cache.set('key1', 'value1');
273+
await cache.set('key2', 'value2');
274+
await cache.set('prefix:key3', 'value1');
275+
await cache.set('prefix:key4', 'value2');
276+
277+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
278+
279+
const keys = await prefixCache.getKeys();
280+
expect(keys).toEqual(expect.arrayContaining(['key3', 'key4']));
281+
});
282+
283+
it('should work with empty prefix', async () => {
284+
const cache = getMockAsyncCache<string>();
285+
await cache.set('key1', 'value1');
286+
await cache.set('key2', 'value2');
287+
288+
const prefixCache = new AsyncPrefixCache(cache, '', (v) => v, (v) => v);
289+
290+
const keys = await prefixCache.getKeys();
291+
expect(keys).toEqual(expect.arrayContaining(['key1', 'key2']));
292+
});
293+
});
294+
295+
describe('getBatched', () => {
296+
it('should return values with correct prefix', async () => {
297+
const cache = getMockAsyncCache<string>();
298+
await cache.set('key1', 'value1');
299+
await cache.set('key2', 'value2');
300+
await cache.set('key3', 'value3');
301+
await cache.set('prefix:key1', 'prefix:value1');
302+
await cache.set('prefix:key2', 'prefix:value2');
303+
304+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v, (v) => v);
305+
306+
const values = await prefixCache.getBatched(['key1', 'key2', 'key3']);
307+
expect(values).toEqual(expect.arrayContaining(['prefix:value1', 'prefix:value2', undefined]));
308+
});
309+
310+
it('should transform values after getting from the underlying cache', async () => {
311+
const cache = getMockAsyncCache<string>();
312+
await cache.set('key1', 'VALUE1');
313+
await cache.set('key2', 'VALUE2');
314+
await cache.set('key3', 'VALUE3');
315+
await cache.set('prefix:key1', 'PREFIX:VALUE1');
316+
await cache.set('prefix:key2', 'PREFIX:VALUE2');
317+
318+
const prefixCache = new AsyncPrefixCache(cache, 'prefix:', (v) => v.toLocaleLowerCase(), (v) => v.toUpperCase());
319+
320+
const values = await prefixCache.getBatched(['key1', 'key2', 'key3']);
321+
expect(values).toEqual(expect.arrayContaining(['prefix:value1', 'prefix:value2', undefined]));
322+
});
323+
324+
it('should work with empty prefix', async () => {
325+
const cache = getMockAsyncCache<string>();
326+
await cache.set('key1', 'value1');
327+
await cache.set('key2', 'value2');
328+
329+
const prefixCache = new AsyncPrefixCache(cache, '', (v) => v, (v) => v);
330+
331+
const values = await prefixCache.getBatched(['key1', 'key2']);
332+
expect(values).toEqual(expect.arrayContaining(['value1', 'value2']));
333+
});
334+
});
335+
});

0 commit comments

Comments
 (0)