mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
- 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>
121 lines
4.6 KiB
TypeScript
121 lines
4.6 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { createSymbolTable, type SymbolTable } from '../../src/core/ingestion/symbol-table.js';
|
|
|
|
describe('SymbolTable', () => {
|
|
let table: SymbolTable;
|
|
|
|
beforeEach(() => {
|
|
table = createSymbolTable();
|
|
});
|
|
|
|
describe('add', () => {
|
|
it('registers a symbol in the table', () => {
|
|
table.add('src/index.ts', 'main', 'func:main', 'Function');
|
|
expect(table.getStats().globalSymbolCount).toBe(1);
|
|
expect(table.getStats().fileCount).toBe(1);
|
|
});
|
|
|
|
it('handles multiple symbols in the same file', () => {
|
|
table.add('src/index.ts', 'main', 'func:main', 'Function');
|
|
table.add('src/index.ts', 'helper', 'func:helper', 'Function');
|
|
expect(table.getStats().fileCount).toBe(1);
|
|
expect(table.getStats().globalSymbolCount).toBe(2);
|
|
});
|
|
|
|
it('handles same name in different files', () => {
|
|
table.add('src/a.ts', 'init', 'func:a:init', 'Function');
|
|
table.add('src/b.ts', 'init', 'func:b:init', 'Function');
|
|
expect(table.getStats().fileCount).toBe(2);
|
|
// Global index groups by name, so 'init' has one entry with two definitions
|
|
expect(table.getStats().globalSymbolCount).toBe(1);
|
|
});
|
|
|
|
it('allows duplicate adds for same file and name', () => {
|
|
table.add('src/a.ts', 'foo', 'func:foo:1', 'Function');
|
|
table.add('src/a.ts', 'foo', 'func:foo:2', 'Function');
|
|
// File index overwrites: last wins
|
|
expect(table.lookupExact('src/a.ts', 'foo')).toBe('func:foo:2');
|
|
// Global index appends
|
|
expect(table.lookupFuzzy('foo')).toHaveLength(2);
|
|
});
|
|
});
|
|
|
|
describe('lookupExact', () => {
|
|
it('finds a symbol by file path and name', () => {
|
|
table.add('src/index.ts', 'main', 'func:main', 'Function');
|
|
expect(table.lookupExact('src/index.ts', 'main')).toBe('func:main');
|
|
});
|
|
|
|
it('returns undefined for unknown file', () => {
|
|
table.add('src/index.ts', 'main', 'func:main', 'Function');
|
|
expect(table.lookupExact('src/other.ts', 'main')).toBeUndefined();
|
|
});
|
|
|
|
it('returns undefined for unknown symbol name', () => {
|
|
table.add('src/index.ts', 'main', 'func:main', 'Function');
|
|
expect(table.lookupExact('src/index.ts', 'notExist')).toBeUndefined();
|
|
});
|
|
|
|
it('returns undefined for empty table', () => {
|
|
expect(table.lookupExact('src/index.ts', 'main')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('lookupFuzzy', () => {
|
|
it('finds all definitions of a symbol across files', () => {
|
|
table.add('src/a.ts', 'render', 'func:a:render', 'Function');
|
|
table.add('src/b.ts', 'render', 'func:b:render', 'Method');
|
|
const results = table.lookupFuzzy('render');
|
|
expect(results).toHaveLength(2);
|
|
expect(results[0]).toEqual({ nodeId: 'func:a:render', filePath: 'src/a.ts', type: 'Function' });
|
|
expect(results[1]).toEqual({ nodeId: 'func:b:render', filePath: 'src/b.ts', type: 'Method' });
|
|
});
|
|
|
|
it('returns empty array for unknown symbol', () => {
|
|
expect(table.lookupFuzzy('nonexistent')).toEqual([]);
|
|
});
|
|
|
|
it('returns empty array for empty table', () => {
|
|
expect(table.lookupFuzzy('anything')).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('getStats', () => {
|
|
it('returns zero counts for empty table', () => {
|
|
expect(table.getStats()).toEqual({ fileCount: 0, globalSymbolCount: 0 });
|
|
});
|
|
|
|
it('tracks unique file count correctly', () => {
|
|
table.add('src/a.ts', 'foo', 'func:foo', 'Function');
|
|
table.add('src/a.ts', 'bar', 'func:bar', 'Function');
|
|
table.add('src/b.ts', 'baz', 'func:baz', 'Function');
|
|
expect(table.getStats().fileCount).toBe(2);
|
|
});
|
|
|
|
it('tracks unique global symbol names', () => {
|
|
table.add('src/a.ts', 'foo', 'func:a:foo', 'Function');
|
|
table.add('src/b.ts', 'foo', 'func:b:foo', 'Function');
|
|
table.add('src/a.ts', 'bar', 'func:a:bar', 'Function');
|
|
// 'foo' and 'bar' are 2 unique global names
|
|
expect(table.getStats().globalSymbolCount).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('clear', () => {
|
|
it('resets all state', () => {
|
|
table.add('src/a.ts', 'foo', 'func:foo', 'Function');
|
|
table.add('src/b.ts', 'bar', 'func:bar', 'Function');
|
|
table.clear();
|
|
expect(table.getStats()).toEqual({ fileCount: 0, globalSymbolCount: 0 });
|
|
expect(table.lookupExact('src/a.ts', 'foo')).toBeUndefined();
|
|
expect(table.lookupFuzzy('foo')).toEqual([]);
|
|
});
|
|
|
|
it('allows re-adding after clear', () => {
|
|
table.add('src/a.ts', 'foo', 'func:foo', 'Function');
|
|
table.clear();
|
|
table.add('src/b.ts', 'bar', 'func:bar', 'Function');
|
|
expect(table.getStats()).toEqual({ fileCount: 1, globalSymbolCount: 1 });
|
|
});
|
|
});
|
|
});
|