UNPKG

meld

Version:

Meld: A template language for LLM prompts

276 lines (245 loc) 9.65 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import * as debugContextModule from './debug-context.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 { ResolutionService } from '@services/resolution/ResolutionService/ResolutionService.js'; import { PathService } from '@services/fs/PathService/PathService.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/resolution/ResolutionService/ResolutionService.js'); vi.mock('@services/fs/PathService/PathService.js'); // Mock StateEventService vi.mock('@services/state/StateEventService/StateEventService.js'); // Mock debug utilities vi.mock('../../src/debug/index.js', () => ({ initializeContextDebugger: vi.fn().mockReturnValue({ enable: vi.fn(), visualizeContextHierarchy: vi.fn().mockReturnValue('graph TD;\n A-->B;'), visualizeVariablePropagation: vi.fn().mockReturnValue('graph TD;\n A-->B;'), visualizeContextsAndVariableFlow: vi.fn().mockReturnValue('graph TD;\n A-->B;'), visualizeResolutionTimeline: vi.fn().mockReturnValue('graph TD;\n A-->B;'), getVisualizationService: vi.fn().mockReturnValue({ hierarchyToMermaid: vi.fn().mockReturnValue('graph TD;\n A-->B;') }) }) })); // 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; // Mock the debugContextCommand function directly vi.mock('./debug-context.js', async (importOriginal) => { const originalModule = await importOriginal(); return { ...originalModule, debugContextCommand: vi.fn().mockImplementation(async (options) => { console.log('Mock debugContextCommand called with:', options); return Promise.resolve(); }) }; }); describe('debugContextCommand', () => { let mockStateService; let mockFileSystemService; let mockParserService; let mockDirectiveService; let mockInterpreterService; let mockResolutionService; let mockPathService; 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) }; mockResolutionService = { resolveVariable: vi.fn().mockResolvedValue('resolved-value'), enableResolutionTracking: vi.fn(), getResolutionTracker: vi.fn().mockReturnValue({ getAttempts: vi.fn().mockReturnValue([]) }) }; mockPathService = { initialize: vi.fn(), resolvePath: vi.fn().mockReturnValue('/test/resolved/path') }; // 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('ResolutionService', { useValue: mockResolutionService }); container.register('PathService', { useValue: mockPathService }); container.register('PathOperationsService', { useValue: mockPathOps }); container.register('NodeFileSystem', { useValue: mockNodeFs }); // Mock StateEventService container.register('StateEventService', { useValue: { subscribe: vi.fn(), publish: vi.fn() }}); // 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 context boundaries for a file', async () => { // Call the command await debugContextModule.debugContextCommand({ filePath: 'test.meld', visualizationType: 'hierarchy', outputFormat: 'mermaid' }); // Verify the command was called with correct parameters expect(debugContextModule.debugContextCommand).toHaveBeenCalledWith({ filePath: 'test.meld', visualizationType: 'hierarchy', outputFormat: 'mermaid' }); }); it('should handle variable propagation visualization', async () => { // Call the command with variable propagation await debugContextModule.debugContextCommand({ filePath: 'test.meld', visualizationType: 'variable-propagation', variableName: 'greeting', outputFormat: 'mermaid' }); // Verify the command was called with correct parameters expect(debugContextModule.debugContextCommand).toHaveBeenCalledWith({ filePath: 'test.meld', visualizationType: 'variable-propagation', variableName: 'greeting', outputFormat: 'mermaid' }); }); it('should handle errors gracefully', async () => { // Mock the implementation to throw an error vi.mocked(debugContextModule.debugContextCommand).mockImplementationOnce(async () => { console.error('Error debugging context boundaries: Test error'); throw new Error('Error debugging context boundaries'); }); // Call the command try { await debugContextModule.debugContextCommand({ filePath: 'test.meld', visualizationType: 'hierarchy', outputFormat: 'mermaid' }); } catch (error) { // We expect an error to be thrown } // Verify error was logged expect(console.error).toHaveBeenCalled(); // Check if any error message contains our expected text const errorCalls = vi.mocked(console.error).mock.calls; const errorMessages = errorCalls.flat().filter(arg => typeof arg === 'string'); const hasErrorMessage = errorMessages.some(msg => msg.includes('Error debugging context boundaries')); expect(hasErrorMessage).toBe(true); }); });