GitNexus/gitnexus/test/unit/ast-cache.test.ts
abhigyanpatwari 8a100a76d3 test: add test suite with vitest (unit + integration + fixtures)
- 59 test files covering unit and integration tests
- vitest config with coverage thresholds and fork pooling
- Test fixtures (mini-repo + multi-language sample code)
- Add vitest + coverage-v8 to devDependencies
- Add test scripts (test, test:integration, test:all, test:watch, test:coverage)
- Move typescript to devDependencies where it belongs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:07:02 +05:30

86 lines
2.7 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import { createASTCache, type ASTCache } from '../../src/core/ingestion/ast-cache.js';
// Create a minimal mock tree object (mimics Parser.Tree interface)
function mockTree(id: string): any {
return { rootNode: { type: 'program', text: id }, delete: vi.fn() };
}
describe('ASTCache', () => {
let cache: ASTCache;
beforeEach(() => {
cache = createASTCache(3);
});
describe('get / set', () => {
it('returns undefined for cache miss', () => {
expect(cache.get('nonexistent.ts')).toBeUndefined();
});
it('returns cached tree on hit', () => {
const tree = mockTree('test');
cache.set('src/index.ts', tree);
expect(cache.get('src/index.ts')).toBe(tree);
});
it('overwrites existing entry for same key', () => {
const tree1 = mockTree('v1');
const tree2 = mockTree('v2');
cache.set('src/index.ts', tree1);
cache.set('src/index.ts', tree2);
expect(cache.get('src/index.ts')).toBe(tree2);
});
});
describe('LRU eviction', () => {
it('evicts least recently used when capacity exceeded', () => {
cache.set('a.ts', mockTree('a'));
cache.set('b.ts', mockTree('b'));
cache.set('c.ts', mockTree('c'));
// Cache is full (maxSize=3). Adding one more evicts 'a'
cache.set('d.ts', mockTree('d'));
expect(cache.get('a.ts')).toBeUndefined();
expect(cache.get('b.ts')).toBeDefined();
expect(cache.get('d.ts')).toBeDefined();
});
it('accessing an entry makes it recently used', () => {
cache.set('a.ts', mockTree('a'));
cache.set('b.ts', mockTree('b'));
cache.set('c.ts', mockTree('c'));
// Touch 'a' to make it recently used
cache.get('a.ts');
// Now 'b' is LRU
cache.set('d.ts', mockTree('d'));
expect(cache.get('a.ts')).toBeDefined();
expect(cache.get('b.ts')).toBeUndefined();
});
});
describe('clear', () => {
it('removes all entries', () => {
cache.set('a.ts', mockTree('a'));
cache.set('b.ts', mockTree('b'));
cache.clear();
expect(cache.get('a.ts')).toBeUndefined();
expect(cache.get('b.ts')).toBeUndefined();
expect(cache.stats().size).toBe(0);
});
});
describe('stats', () => {
it('reports size and maxSize', () => {
expect(cache.stats()).toEqual({ size: 0, maxSize: 3 });
cache.set('a.ts', mockTree('a'));
expect(cache.stats()).toEqual({ size: 1, maxSize: 3 });
cache.set('b.ts', mockTree('b'));
expect(cache.stats()).toEqual({ size: 2, maxSize: 3 });
});
it('uses default maxSize of 50', () => {
const defaultCache = createASTCache();
expect(defaultCache.stats().maxSize).toBe(50);
});
});
});