/** * Parser performance tests * Tests regex pre-compilation and format caching optimizations */ // Test the pre-compiled regex patterns directly by importing them from parser.js // We use dynamic import with mocking to avoid the SillyTavern dependency chain describe('Parser regex pre-compilation', () => { // Test that pre-compiled regex patterns produce correct results // These patterns are now module-level constants in parser.js test('emoji regex pattern works correctly', () => { const EMOJI_RE = /^[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F000}-\u{1F02F}\u{1F0A0}-\u{1F0FF}\u{1F100}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{1F910}-\u{1F96B}\u{1F980}-\u{1F9E0}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}]+/u; expect('😊 Hello'.match(EMOJI_RE)).toBeTruthy(); expect('Hello'.match(EMOJI_RE)).toBeNull(); }); test('thinking tag regex works correctly', () => { const THINKING_TAG_RE = /[\s\S]*?<\/think>/gi; const THINKING_TAG_ALT_RE = /[\s\S]*?<\/thinking>/gi; const text1 = 'thinking contentactual content'; const text2 = 'thinking contentactual content'; expect(text1.replace(THINKING_TAG_RE, '')).toBe('actual content'); expect(text2.replace(THINKING_TAG_ALT_RE, '')).toBe('actual content'); }); test('JSON block regex works correctly', () => { const JSON_BLOCK_RE = /```json\s*\n([\s\S]*?)```/g; const text = '```json\n{"key": "value"}\n```'; const matches = [...text.matchAll(JSON_BLOCK_RE)]; expect(matches.length).toBe(1); expect(matches[0][1].trim()).toBe('{"key": "value"}'); }); test('code block regex works correctly', () => { const CODE_BLOCK_RE = /```([^`]+)```/g; const text = '```Stats\n---\nHealth: 100%\n```'; const matches = [...text.matchAll(CODE_BLOCK_RE)]; expect(matches.length).toBe(1); expect(matches[0][1].trim()).toBe('Stats\n---\nHealth: 100%'); }); test('XML trackers regex works correctly', () => { const XML_TRACKERS_RE = /([\s\S]*?)<\/trackers>/i; const text = 'content here'; const match = text.match(XML_TRACKERS_RE); expect(match).toBeTruthy(); expect(match[1]).toBe('content here'); }); test('stats section detection regex works', () => { const STATS_SECTION_RE = /Stats\s*\n\s*---/i; expect('Stats\n---\nHealth: 100%'.match(STATS_SECTION_RE)).toBeTruthy(); expect('Info Box\n---\nDate: 2024'.match(STATS_SECTION_RE)).toBeNull(); }); test('info box section detection regex works', () => { const INFOBOX_SECTION_RE = /Info Box\s*\n\s*---/i; expect('Info Box\n---\nDate: 2024'.match(INFOBOX_SECTION_RE)).toBeTruthy(); expect('Stats\n---\nHealth: 100%'.match(INFOBOX_SECTION_RE)).toBeNull(); }); test('characters section detection regex works', () => { const CHARACTERS_SECTION_RE = /Present Characters\s*\n\s*---/i; expect('Present Characters\n---\nAlice'.match(CHARACTERS_SECTION_RE)).toBeTruthy(); expect('Stats\n---\nHealth: 100%'.match(CHARACTERS_SECTION_RE)).toBeNull(); }); test('RPG attribute regexes work', () => { const RPG_STR_RE = /STR:\s*(\d+)/i; const RPG_DEX_RE = /DEX:\s*(\d+)/i; const RPG_LVL_RE = /LVL:\s*(\d+)/i; expect('STR: 15'.match(RPG_STR_RE)?.[1]).toBe('15'); expect('DEX: 20'.match(RPG_DEX_RE)?.[1]).toBe('20'); expect('LVL: 10'.match(RPG_LVL_RE)?.[1]).toBe('10'); }); test('placeholder pattern regex works', () => { const PLACEHOLDER_PATTERN_RE = /\[([A-Za-z\s\/]+)\]/g; const text = '[Location] some text [Mood Emoji]'; const matches = [...text.matchAll(PLACEHOLDER_PATTERN_RE)]; expect(matches.length).toBe(2); }); test('format marker regex works', () => { const FORMAT_MARKER_RE = /FORMAT:\s*/gi; expect('FORMAT: some text'.replace(FORMAT_MARKER_RE, '')).toBe('some text'); }); }); describe('Format cache logic', () => { test('format cache hit threshold logic', () => { // Simulate the format caching logic from parser.js let lastDetectedFormat = null; let formatCacheHits = 0; const FORMAT_CACHE_HIT_THRESHOLD = 3; // Initially no cache expect(lastDetectedFormat).toBeNull(); expect(formatCacheHits).toBe(0); // First detection lastDetectedFormat = 'json'; formatCacheHits = 1; expect(formatCacheHits >= FORMAT_CACHE_HIT_THRESHOLD).toBe(false); // Second hit formatCacheHits++; expect(formatCacheHits >= FORMAT_CACHE_HIT_THRESHOLD).toBe(false); // Third hit - now cache is trusted formatCacheHits++; expect(formatCacheHits >= FORMAT_CACHE_HIT_THRESHOLD).toBe(true); // Cache clear lastDetectedFormat = null; formatCacheHits = 0; expect(lastDetectedFormat).toBeNull(); expect(formatCacheHits).toBe(0); }); }); describe('Regex performance verification', () => { test('pre-compiled regex is faster than re-compiling', () => { // Pre-compiled constant (module-level) const PRECOMPILED_RE = /```json\s*\n([\s\S]*?)```/g; // Simulate per-call compilation (old behavior) const compilePerCall = (text) => { const re = /```json\s*\n([\s\S]*?)```/g; return [...text.matchAll(re)]; }; // Pre-compiled usage (new behavior) const usePrecompiled = (text) => { // Reset lastIndex for global regex PRECOMPILED_RE.lastIndex = 0; return [...text.matchAll(PRECOMPILED_RE)]; }; const testText = '```json\n{"key": "value"}\n```'; // Both should produce the same result const compiled = compilePerCall(testText); const precompiled = usePrecompiled(testText); expect(compiled.length).toBe(precompiled.length); expect(compiled[0][1]).toBe(precompiled[0][1]); }); });