/** * Unit tests for DiffCache class. * * Tests TTL expiry, prefix invalidation, and env-var TTL configuration. */ import { describe, it, expect, vi, afterEach } from 'vitest'; import { DiffCache } from './diff-cache.js'; afterEach(() => { vi.restoreAllMocks(); }); describe('DiffCache', () => { it('returns undefined for a key that was never set', () => { const cache = new DiffCache(5000); expect(cache.get('nonexistent')).toBeUndefined(); }); it('returns value when entry has not expired', () => { vi.spyOn(Date, 'now').mockReturnValue(1000); const cache = new DiffCache(5000); cache.set('key', 'value'); vi.spyOn(Date, 'now').mockReturnValue(5999); // 4999ms elapsed, TTL=5000 expect(cache.get('key')).toBe('value'); }); it('returns undefined and deletes the entry when TTL has elapsed', () => { vi.spyOn(Date, 'now').mockReturnValue(1000); const cache = new DiffCache(5000); cache.set('key', 'value'); vi.spyOn(Date, 'now').mockReturnValue(6001); // 5001ms elapsed, TTL=5000 expect(cache.get('key')).toBeUndefined(); // Verify the key is no longer stored (second get also returns undefined) vi.spyOn(Date, 'now').mockReturnValue(6001); expect(cache.get('key')).toBeUndefined(); }); it('overwrites an existing entry and resets its TTL', () => { vi.spyOn(Date, 'now').mockReturnValue(1000); const cache = new DiffCache(5000); cache.set('key', 'first'); vi.spyOn(Date, 'now').mockReturnValue(4000); // overwrite before expiry cache.set('key', 'second'); vi.spyOn(Date, 'now').mockReturnValue(8999); // 4999ms after overwrite, TTL=5000 expect(cache.get('key')).toBe('second'); vi.spyOn(Date, 'now').mockReturnValue(9001); // 5001ms after overwrite expect(cache.get('key')).toBeUndefined(); }); it('invalidateByPrefix removes all matching keys and preserves others', () => { const cache = new DiffCache(60_000); cache.set('phase-1:abc', 'a'); cache.set('phase-1:abc:file.ts', 'b'); cache.set('phase-2:xyz', 'c'); cache.invalidateByPrefix('phase-1:'); expect(cache.get('phase-1:abc')).toBeUndefined(); expect(cache.get('phase-1:abc:file.ts')).toBeUndefined(); expect(cache.get('phase-2:xyz')).toBe('c'); }); it('singleton instances use REVIEW_DIFF_CACHE_TTL_MS env var for TTL', async () => { vi.resetModules(); vi.stubEnv('REVIEW_DIFF_CACHE_TTL_MS', '1000'); const { phaseMetaCache } = await import('./diff-cache.js'); vi.spyOn(Date, 'now').mockReturnValue(0); phaseMetaCache.set('key', {} as any); vi.spyOn(Date, 'now').mockReturnValue(999); expect(phaseMetaCache.get('key')).toBeDefined(); vi.spyOn(Date, 'now').mockReturnValue(1001); expect(phaseMetaCache.get('key')).toBeUndefined(); vi.unstubAllEnvs(); }); });