import { beforeEach, describe, expect, it, mock } from 'bun:test'; import { CacheFactory, createNamespacedCache } from '../src/cache-factory'; import { generateKey } from '../src/key-generator'; import type { ICache } from '../src/types'; describe('CacheFactory', () => { it('should create null cache when no config provided', () => { const cache = CacheFactory.create(null as any, 'test'); expect(cache).toBeDefined(); expect(cache.type).toBe('null'); }); it('should create cache with namespace', () => { const mockConfig = { cache: { provider: 'memory', redis: { host: 'localhost', port: 6379 }, }, }; const cache = CacheFactory.create(mockConfig as any, 'test-namespace'); expect(cache).toBeDefined(); }); }); describe('NamespacedCache', () => { let mockCache: ICache; beforeEach(() => { mockCache = { type: 'mock', get: mock(() => Promise.resolve(null)), set: mock(() => Promise.resolve()), del: mock(() => Promise.resolve()), clear: mock(() => Promise.resolve()), exists: mock(() => Promise.resolve(false)), ttl: mock(() => Promise.resolve(-1)), keys: mock(() => Promise.resolve([])), mget: mock(() => Promise.resolve([])), mset: mock(() => Promise.resolve()), mdel: mock(() => Promise.resolve()), size: mock(() => Promise.resolve(0)), flush: mock(() => Promise.resolve()), ping: mock(() => Promise.resolve(true)), disconnect: mock(() => Promise.resolve()), isConnected: mock(() => true), }; }); it('should create namespaced cache', () => { const nsCache = createNamespacedCache(mockCache, 'sub-namespace'); expect(nsCache).toBeDefined(); expect(nsCache).toHaveProperty('get'); expect(nsCache).toHaveProperty('set'); }); it('should prefix keys with namespace', async () => { const nsCache = createNamespacedCache(mockCache, 'test'); await nsCache.set('key', 'value'); expect(mockCache.set).toHaveBeenCalledWith('test:key', 'value', undefined); }); it('should handle null cache gracefully', async () => { const nsCache = createNamespacedCache(null, 'test'); expect(nsCache).toBeDefined(); // Should return null for get operations const value = await nsCache.get('key'); expect(value).toBeNull(); }); it('should prefix multiple operations', async () => { const nsCache = createNamespacedCache(mockCache, 'prefix'); await nsCache.get('key1'); expect(mockCache.get).toHaveBeenCalledWith('prefix:key1'); await nsCache.del('key2'); expect(mockCache.del).toHaveBeenCalledWith('prefix:key2'); await nsCache.exists('key3'); expect(mockCache.exists).toHaveBeenCalledWith('prefix:key3'); }); it('should handle pattern operations', async () => { const nsCache = createNamespacedCache(mockCache, 'ns'); mockCache.keys = mock(() => Promise.resolve(['ns:key1', 'ns:key2', 'other:key'])); const keys = await nsCache.keys('*'); expect(mockCache.keys).toHaveBeenCalledWith('ns:*'); expect(keys).toEqual(['key1', 'key2']); }); }); describe('KeyGenerator', () => { it('should generate key from parts', () => { const key = generateKey('part1', 'part2', 'part3'); expect(key).toBe('part1:part2:part3'); }); it('should handle empty parts', () => { const key = generateKey(); expect(key).toBe(''); }); it('should skip undefined parts', () => { const key = generateKey('part1', undefined, 'part3'); expect(key).toBe('part1:part3'); }); it('should convert non-string parts', () => { const key = generateKey('prefix', 123, true); expect(key).toBe('prefix:123:true'); }); });