UNPKG

meld

Version:

Meld: A template language for LLM prompts

225 lines (189 loc) 7.86 kB
import { describe, it, expect, beforeEach } from 'vitest'; import { StateFactory } from './StateFactory.js'; import type { StateNode } from './types.js'; describe('StateFactory', () => { let factory: StateFactory; beforeEach(() => { factory = new StateFactory(); }); describe('createState', () => { it('should create an empty state', () => { const state = factory.createState(); expect(state.variables.text.size).toBe(0); expect(state.variables.data.size).toBe(0); expect(state.variables.path.size).toBe(0); expect(state.imports.size).toBe(0); expect(state.nodes.length).toBe(0); expect(state.filePath).toBeUndefined(); expect(state.parentState).toBeUndefined(); }); it('should create state with options', () => { const parent = factory.createState(); const state = factory.createState({ parentState: parent, filePath: '/test/file.md', source: 'test' }); expect(state.parentState).toBe(parent); expect(state.filePath).toBe('/test/file.md'); }); it('should inherit parent state', () => { // Create parent with some state const parentBase = factory.createState(); const parent = factory.updateState(parentBase, { variables: { text: new Map([['inherited', 'value']]), data: new Map([['config', { inherited: true }]]), path: new Map([['root', '/parent']]) }, imports: new Set(['parent.md']), nodes: [{ type: 'text', value: 'parent' } as any] }); // Create child state const child = factory.createState({ parentState: parent }); // Verify inheritance expect(child.variables.text.get('inherited')).toBe('value'); expect(child.variables.data.get('config')).toEqual({ inherited: true }); expect(child.variables.path.get('root')).toBe('/parent'); expect(child.imports.has('parent.md')).toBe(true); expect(child.nodes[0].value).toBe('parent'); }); }); describe('createChildState', () => { it('should create child state with parent reference', () => { const parent = factory.createState(); const child = factory.createChildState(parent); expect(child.parentState).toBe(parent); }); it('should create empty child state that inherits parent values', () => { // Create parent with some state const parentBase = factory.createState(); const parent = factory.updateState(parentBase, { variables: { text: new Map([['text', 'parent']]), data: new Map([['data', { value: 'parent' }]]), path: new Map([['path', '/parent']]) } }); const child = factory.createChildState(parent); // Verify child inherits parent values expect(child.variables.text.get('text')).toBe('parent'); expect(child.variables.data.get('data')).toEqual({ value: 'parent' }); expect(child.variables.path.get('path')).toBe('/parent'); }); }); describe('mergeStates', () => { it('should merge variables from child to parent', () => { // Create parent state const parentBase = factory.createState(); const parent = factory.updateState(parentBase, { variables: { text: new Map([['parentText', 'parent']]), data: new Map([['parentData', { value: 'parent' }]]), path: new Map([['parentPath', '/parent']]) } }); // Create child state const childBase = factory.createState(); const child = factory.updateState(childBase, { variables: { text: new Map([['childText', 'child']]), data: new Map([['childData', { value: 'child' }]]), path: new Map([['childPath', '/child']]) } }); const merged = factory.mergeStates(parent, child); // Check merged variables expect(merged.variables.text.get('parentText')).toBe('parent'); expect(merged.variables.text.get('childText')).toBe('child'); expect(merged.variables.data.get('parentData')).toEqual({ value: 'parent' }); expect(merged.variables.data.get('childData')).toEqual({ value: 'child' }); expect(merged.variables.path.get('parentPath')).toBe('/parent'); expect(merged.variables.path.get('childPath')).toBe('/child'); }); it('should override parent variables with child values', () => { // Create parent state const parentBase = factory.createState(); const parent = factory.updateState(parentBase, { variables: { text: new Map([['text', 'parent']]) } }); // Create child state const childBase = factory.createState(); const child = factory.updateState(childBase, { variables: { text: new Map([['text', 'child']]) } }); const merged = factory.mergeStates(parent, child); expect(merged.variables.text.get('text')).toBe('child'); // Verify parent state wasn't modified expect(parent.variables.text.get('text')).toBe('parent'); }); it('should merge imports and nodes', () => { // Create parent state const parentBase = factory.createState(); const parent = factory.updateState(parentBase, { imports: new Set(['parent.md']), nodes: [{ type: 'text', value: 'parent' } as any] }); // Create child state const childBase = factory.createState(); const child = factory.updateState(childBase, { imports: new Set(['child.md']), nodes: [{ type: 'text', value: 'child' } as any] }); const merged = factory.mergeStates(parent, child); expect(merged.imports.has('parent.md')).toBe(true); expect(merged.imports.has('child.md')).toBe(true); expect(merged.nodes).toHaveLength(2); expect(merged.nodes[0].value).toBe('parent'); expect(merged.nodes[1].value).toBe('child'); // Verify original states weren't modified expect(parent.imports.size).toBe(1); expect(child.imports.size).toBe(1); expect(parent.nodes).toHaveLength(1); expect(child.nodes).toHaveLength(1); }); }); describe('updateState', () => { it('should update state with new values', () => { const initial = factory.createState(); const updates: Partial<StateNode> = { filePath: '/updated/file.md', variables: { text: new Map([['text', 'updated']]), data: new Map([['data', { value: 'updated' }]]), path: new Map([['path', '/updated']]) } }; const updated = factory.updateState(initial, updates); expect(updated.filePath).toBe('/updated/file.md'); expect(updated.variables.text.get('text')).toBe('updated'); expect(updated.variables.data.get('data')).toEqual({ value: 'updated' }); expect(updated.variables.path.get('path')).toBe('/updated'); // Verify original state wasn't modified expect(initial.variables.text.size).toBe(0); expect(initial.variables.data.size).toBe(0); expect(initial.variables.path.size).toBe(0); }); it('should preserve unmodified values', () => { // Create initial state with some values const baseState = factory.createState(); const initial = factory.updateState(baseState, { variables: { text: new Map([['preserved', 'value']]) } }); const updates: Partial<StateNode> = { filePath: '/updated/file.md' }; const updated = factory.updateState(initial, updates); expect(updated.filePath).toBe('/updated/file.md'); expect(updated.variables.text.get('preserved')).toBe('value'); // Verify values are copied, not referenced expect(updated.variables.text).not.toBe(initial.variables.text); }); }); });