import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import test from 'node:test'; import { RuntimeOptionsManager } from './runtime-options'; test('SM-012 runtime options path does not use JSON serialize-clone helpers', () => { const source = fs.readFileSync(path.join(process.cwd(), 'src/runtime-options.ts'), 'utf-8'); assert.equal(source.includes('JSON.parse(JSON.stringify('), false); }); test('RuntimeOptionsManager returns detached effective Anki config copies', () => { const baseConfig = { deck: 'Mining', note: 'Sentence', tags: ['SubMiner'], behavior: { autoUpdateNewCards: true, updateIntervalMs: 5000, }, fieldMapping: { sentence: 'Sentence', meaning: 'Meaning', audio: 'Audio', image: 'Image', context: 'Context', source: 'Source', definition: 'Definition', sequence: 'Sequence', contextSecondary: 'ContextSecondary', contextTertiary: 'ContextTertiary', primarySpelling: 'PrimarySpelling', primaryReading: 'PrimaryReading', wordSpelling: 'WordSpelling', wordReading: 'WordReading', }, duplicates: { mode: 'note' as const, scope: 'deck' as const, allowedFields: [], }, ai: { enabled: false, model: '', systemPrompt: '', }, }; const manager = new RuntimeOptionsManager(() => structuredClone(baseConfig), { applyAnkiPatch: () => undefined, onOptionsChanged: () => undefined, }); const effective = manager.getEffectiveAnkiConnectConfig(); effective.tags!.push('mutated'); effective.behavior!.autoUpdateNewCards = false; assert.deepEqual(baseConfig.tags, ['SubMiner']); assert.equal(baseConfig.behavior.autoUpdateNewCards, true); });