meld
Version:
Meld: A template language for LLM prompts
205 lines (181 loc) • 7.06 kB
text/typescript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as debugTransformModule from './debug-transform.js';
import { container } from 'tsyringe';
import { StateService } from '@services/state/StateService/StateService.js';
import { FileSystemService } from '@services/fs/FileSystemService/FileSystemService.js';
import { ParserService } from '@services/pipeline/ParserService/ParserService.js';
import { DirectiveService } from '@services/pipeline/DirectiveService/DirectiveService.js';
import { InterpreterService } from '@services/pipeline/InterpreterService/InterpreterService.js';
import { PathOperationsService } from '@services/fs/FileSystemService/PathOperationsService.js';
import { NodeFileSystem } from '@services/fs/FileSystemService/NodeFileSystem.js';
import { StateEventService } from '@services/state/StateEventService/StateEventService.js';
// Mock the services
vi.mock('@services/state/StateService/StateService.js');
vi.mock('@services/fs/FileSystemService/FileSystemService.js');
vi.mock('@services/pipeline/ParserService/ParserService.js');
vi.mock('@services/pipeline/DirectiveService/DirectiveService.js');
vi.mock('@services/pipeline/InterpreterService/InterpreterService.js');
vi.mock('@services/fs/FileSystemService/PathOperationsService.js');
vi.mock('@services/fs/FileSystemService/NodeFileSystem.js');
vi.mock('@services/state/StateEventService/StateEventService.js');
// Mock fs
vi.mock('fs/promises', () => ({
readFile: vi.fn().mockResolvedValue('Test content'),
writeFile: vi.fn().mockResolvedValue(undefined)
}));
// Save original console methods
const originalConsoleLog = console.log;
const originalConsoleError = console.error;
describe('debugTransformCommand', () => {
let mockStateService;
let mockFileSystemService;
let mockParserService;
let mockDirectiveService;
let mockInterpreterService;
beforeEach(() => {
vi.resetAllMocks();
// Create mock services
mockStateService = {
getState: vi.fn().mockReturnValue({
variables: {
text: { greeting: 'Hello' },
data: {}
}
}),
getTextVar: vi.fn().mockReturnValue('Hello'),
getDataVar: vi.fn().mockReturnValue({}),
getPathVar: vi.fn().mockReturnValue('/test/path'),
setTextVar: vi.fn(),
setDataVar: vi.fn(),
setPathVar: vi.fn(),
setCurrentFilePath: vi.fn(),
createState: vi.fn().mockReturnValue({
getId: vi.fn().mockReturnValue('test-state-id'),
setFilePath: vi.fn()
})
};
mockFileSystemService = {
readFile: vi.fn().mockResolvedValue('Test content'),
writeFile: vi.fn().mockResolvedValue(undefined),
exists: vi.fn().mockResolvedValue(true),
resolvePath: vi.fn().mockResolvedValue('/test/project/test.meld'),
initialize: vi.fn()
};
mockParserService = {
parse: vi.fn().mockReturnValue({
type: 'document',
children: [
{
type: 'directive',
name: 'text',
value: 'greeting = "Hello"',
location: { line: 1, column: 1 },
directive: { kind: 'text' }
}
]
}),
parseWithLocations: vi.fn().mockReturnValue([
{
type: 'directive',
name: 'text',
value: 'greeting = "Hello"',
location: { line: 1, column: 1, filePath: 'test.meld' },
directive: { kind: 'text' }
}
])
};
mockDirectiveService = {
processDirective: vi.fn().mockResolvedValue({
replacement: {
type: 'text',
value: 'Hello',
location: { line: 1, column: 1 },
transformed: true
}
}),
initialize: vi.fn()
};
mockInterpreterService = {
interpret: vi.fn().mockResolvedValue({
type: 'document',
children: [
{
type: 'text',
value: 'Hello',
location: { line: 1, column: 1 },
transformed: true,
interpreted: true
}
]
}),
canHandleTransformations: vi.fn().mockReturnValue(true)
};
// Mock needed dependencies
const mockPathOps = {
isAbsolute: vi.fn().mockReturnValue(true),
join: vi.fn().mockImplementation((...args) => args.join('/')),
resolve: vi.fn().mockImplementation((...args) => args.join('/'))
};
const mockNodeFs = {
readFile: vi.fn().mockResolvedValue('Test content'),
writeFile: vi.fn().mockResolvedValue(undefined),
exists: vi.fn().mockResolvedValue(true)
};
// Register mock services with the container
container.register('StateService', { useValue: mockStateService });
container.register('FileSystemService', { useValue: mockFileSystemService });
container.register('ParserService', { useValue: mockParserService });
container.register('DirectiveService', { useValue: mockDirectiveService });
container.register('InterpreterService', { useValue: mockInterpreterService });
container.register('PathOperationsService', { useValue: mockPathOps });
container.register('NodeFileSystem', { useValue: mockNodeFs });
// Mock console methods
console.log = vi.fn();
console.error = vi.fn();
});
afterEach(() => {
// Restore console methods
console.log = originalConsoleLog;
console.error = originalConsoleError;
// Clear container
container.clearInstances();
});
it('should debug transformations for a file', async () => {
// Call the command
await debugTransformModule.debugTransformCommand({
filePath: 'test.meld',
outputFormat: 'json',
includeContent: true
});
// Verify services were called
expect(mockFileSystemService.readFile).toHaveBeenCalledWith('test.meld');
expect(mockParserService.parse).toHaveBeenCalled();
expect(mockInterpreterService.interpret).toHaveBeenCalled();
// Verify output was generated
expect(console.log).toHaveBeenCalled();
});
it('should filter by directive type when specified', async () => {
// Call the command with directive type filter
await debugTransformModule.debugTransformCommand({
filePath: 'test.meld',
outputFormat: 'json',
includeContent: true,
directiveType: 'text'
});
// Verify output was generated with filter
expect(console.log).toHaveBeenCalled();
});
it('should handle errors gracefully', async () => {
// Make the interpreter not support transformations
mockInterpreterService.canHandleTransformations.mockReturnValue(false);
// Call the command
await debugTransformModule.debugTransformCommand({
filePath: 'test.meld',
outputFormat: 'json'
});
// Verify error was logged
expect(console.error).toHaveBeenCalled();
const errorOutput = vi.mocked(console.error).mock.calls.flat().join('\n');
expect(errorOutput).toContain('This interpreter does not support transformations');
});
});