import { describe, it, expect } from 'vitest'; import { planEdit } from '../pending_changes.js'; // planEdit is the pure core of applyOne's edit splice. These tests pin the // idempotency guards that stop the "block stamped 2-3x" corruption: applying the // same queued edit more than once must be a no-op, never a duplicate. describe('planEdit — normal application', () => { it('applies a unique exact edit', () => { const content = 'a\nfoo\nb\n'; const plan = planEdit(content, 'foo', 'bar'); expect(plan).toEqual({ kind: 'apply', updated: 'a\nbar\nb\n' }); }); it('reports ambiguous when old_string occurs more than once', () => { const content = 'foo\nx\nfoo\n'; const plan = planEdit(content, 'foo', 'bar'); expect(plan).toEqual({ kind: 'ambiguous', count: 2 }); }); it('reports not_found when old_string is absent and new is not present', () => { const content = 'alpha\nbeta\n'; const plan = planEdit(content, 'gamma that is clearly nowhere', 'delta'); expect(plan).toEqual({ kind: 'not_found' }); }); }); describe('planEdit — idempotency (the corruption guard)', () => { it('treats a re-applied anchored insert as already-applied (no duplicate)', () => { // The exact mechanism that tripled `const recordFormats` in settings.html: // an anchored insert (old=anchor, new=anchor+block) where the anchor still // matches uniquely after the first apply. const oldStr = '\n'; const first = planEdit(before, oldStr, newStr); expect(first.kind).toBe('apply'); const after = first.kind === 'apply' ? first.updated : ''; expect((after.match(/const recordFormats/g) || []).length).toBe(1); // Re-applying the identical edit to the already-edited content is a no-op. const second = planEdit(after, oldStr, newStr); expect(second).toEqual({ kind: 'noop', reason: 'already-applied' }); }); it('treats an edit whose old_string is gone but new_string is present as already-applied', () => { const content = 'const total = sum + tax;\n'; const plan = planEdit(content, 'const subtotal = sum;', 'const total = sum + tax;'); expect(plan).toEqual({ kind: 'noop', reason: 'already-applied' }); }); it('treats a no-change splice as a noop', () => { const content = 'a\nfoo\nb\n'; const plan = planEdit(content, 'foo', 'foo'); expect(plan).toEqual({ kind: 'noop', reason: 'identical' }); }); it('does not duplicate across three repeated applications', () => { const oldStr = 'function f() {'; const newStr = 'function f() {\n const x = 1;'; let content = 'function f() {\n return x;\n}\n'; for (let i = 0; i < 3; i++) { const plan = planEdit(content, oldStr, newStr); if (plan.kind === 'apply') content = plan.updated; } expect((content.match(/const x = 1;/g) || []).length).toBe(1); }); });