meld
Version:
Meld: A template language for LLM prompts
119 lines (97 loc) • 3.51 kB
text/typescript
import { describe, it, expect, beforeEach } from 'vitest';
import { CircularityService } from './CircularityService.js';
import { MeldImportError } from '@core/errors/MeldImportError.js';
describe('CircularityService', () => {
let service: CircularityService;
beforeEach(() => {
service = new CircularityService();
});
describe('Basic import tracking', () => {
it('should track imports in stack', () => {
service.beginImport('fileA.meld');
expect(service.isInStack('fileA.meld')).toBe(true);
expect(service.getImportStack()).toEqual(['fileA.meld']);
});
it('should remove imports from stack', () => {
service.beginImport('fileA.meld');
service.endImport('fileA.meld');
expect(service.isInStack('fileA.meld')).toBe(false);
expect(service.getImportStack()).toEqual([]);
});
it('should handle multiple imports in LIFO order', () => {
service.beginImport('fileA.meld');
service.beginImport('fileB.meld');
service.beginImport('fileC.meld');
expect(service.getImportStack()).toEqual([
'fileA.meld',
'fileB.meld',
'fileC.meld'
]);
service.endImport('fileC.meld');
expect(service.getImportStack()).toEqual([
'fileA.meld',
'fileB.meld'
]);
});
});
describe('Circular import detection', () => {
it('should detect direct circular imports', () => {
service.beginImport('fileA.meld');
expect(() => service.beginImport('fileA.meld'))
.toThrow(MeldImportError);
});
it('should detect indirect circular imports', () => {
service.beginImport('fileA.meld');
service.beginImport('fileB.meld');
expect(() => service.beginImport('fileA.meld'))
.toThrow(MeldImportError);
});
it('should include import chain in error', () => {
service.beginImport('fileA.meld');
service.beginImport('fileB.meld');
try {
service.beginImport('fileA.meld');
fail('Should have thrown');
} catch (error) {
expect(error).toBeInstanceOf(MeldImportError);
if (error instanceof MeldImportError) {
expect(error.details?.importChain).toEqual([
'fileA.meld',
'fileB.meld',
'fileA.meld'
]);
}
}
});
it('should allow reimporting after file is removed from stack', () => {
service.beginImport('fileA.meld');
service.endImport('fileA.meld');
expect(() => service.beginImport('fileA.meld'))
.not.toThrow();
});
});
describe('Stack management', () => {
it('should reset the stack', () => {
service.beginImport('fileA.meld');
service.beginImport('fileB.meld');
service.reset();
expect(service.getImportStack()).toEqual([]);
expect(service.isInStack('fileA.meld')).toBe(false);
expect(service.isInStack('fileB.meld')).toBe(false);
});
it('should handle ending import for file not in stack', () => {
expect(() => service.endImport('nonexistent.meld'))
.not.toThrow();
});
it('should maintain stack order when ending imports out of order', () => {
service.beginImport('fileA.meld');
service.beginImport('fileB.meld');
service.beginImport('fileC.meld');
service.endImport('fileB.meld');
expect(service.getImportStack()).toEqual([
'fileA.meld',
'fileC.meld'
]);
});
});
});