From 8e16744ebec6d2d8ed38ba4916250dd808801821 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:33:13 -0500 Subject: [PATCH] test: add missing coverage (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: add top-priority missing test coverage Problem: several critical code paths had zero test coverage — parse.resolve_date (relative date resolution), store.snapshot (foundation of the undo stack), and the diff.apply invariant that unchanged tasks do not get their modified timestamp bumped. The diff.apply due/priority clearing paths were also untested. Solution: add six targeted test blocks across parse_spec, store_spec, and diff_spec: resolve_date happy/failure paths, parse.body with relative due tokens, snapshot copy-semantics and deleted-task exclusion, diff unchanged-modified invariant, due cleared on removal, priority cleared on ! removal. * test: add second batch of missing test coverage Problem: six more gaps from the audit remained after the first batch — archive persistence verification, diff modified-on-rename, parse_buffer inline cat:/due: token parsing, and store.update immutability invariants. Solution: add six it() blocks across archive_spec, diff_spec, and store_spec: archive unload/reload persistence check, modified timestamp updated on description change, inline cat: overrides header category, inline due: token parsed from buffer line, id/entry fields immutable under store.update, and end timestamp not overwritten on second completion. --- spec/archive_spec.lua | 9 +++++++++ spec/diff_spec.lua | 38 ++++++++++++++++++++++++++++++++++++++ spec/store_spec.lua | 21 +++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/spec/archive_spec.lua b/spec/archive_spec.lua index a71eee8..df1a912 100644 --- a/spec/archive_spec.lua +++ b/spec/archive_spec.lua @@ -128,4 +128,13 @@ describe('archive', function() assert.is_true(descs['Keep pending']) assert.is_true(descs['Keep recent done']) end) + + it('persists archived tasks to disk after unload/reload', function() + local t = store.add({ description = 'Archived task' }) + store.update(t.id, { status = 'done', ['end'] = '2020-01-01T00:00:00Z' }) + pending.archive() + store.unload() + store.load() + assert.are.equal(0, #store.active_tasks()) + end) end) diff --git a/spec/diff_spec.lua b/spec/diff_spec.lua index 7a73c5d..3073879 100644 --- a/spec/diff_spec.lua +++ b/spec/diff_spec.lua @@ -57,6 +57,28 @@ describe('diff', function() assert.is_nil(result[2].id) assert.are.equal('New task here', result[2].description) end) + + it('inline cat: token overrides header category', function() + local lines = { + 'Inbox', + '/1/ Buy milk cat:Work', + } + local result = diff.parse_buffer(lines) + assert.are.equal(2, #result) + assert.are.equal('task', result[2].type) + assert.are.equal('Work', result[2].category) + end) + + it('inline due: token is parsed', function() + local lines = { + 'Inbox', + '/1/ Buy milk due:2026-03-15', + } + local result = diff.parse_buffer(lines) + assert.are.equal(2, #result) + assert.are.equal('task', result[2].type) + assert.are.equal('2026-03-15', result[2].due) + end) end) describe('apply', function() @@ -107,6 +129,22 @@ describe('diff', function() assert.are.equal('Renamed', task.description) end) + it('updates modified when description is renamed', function() + local t = store.add({ description = 'Original', category = 'Inbox' }) + t.modified = '2020-01-01T00:00:00Z' + store.save() + local lines = { + 'Inbox', + '/1/ Renamed', + } + diff.apply(lines) + store.unload() + store.load() + local task = store.get(1) + assert.are.equal('Renamed', task.description) + assert.is_not.equal('2020-01-01T00:00:00Z', task.modified) + end) + it('handles duplicate ids as copies', function() store.add({ description = 'Original' }) store.save() diff --git a/spec/store_spec.lua b/spec/store_spec.lua index 930fbc0..25b8b7c 100644 --- a/spec/store_spec.lua +++ b/spec/store_spec.lua @@ -121,6 +121,27 @@ describe('store', function() local updated = store.get(t.id) assert.is_not_nil(updated['end']) end) + + it('does not overwrite id or entry', function() + store.load() + local t = store.add({ description = 'Immutable fields' }) + local original_id = t.id + local original_entry = t.entry + store.update(t.id, { id = 999, entry = 'x' }) + local updated = store.get(original_id) + assert.are.equal(original_id, updated.id) + assert.are.equal(original_entry, updated.entry) + end) + + it('does not overwrite end on second completion', function() + store.load() + local t = store.add({ description = 'Complete twice' }) + store.update(t.id, { status = 'done', ['end'] = '2026-01-15T10:00:00Z' }) + local first_end = store.get(t.id)['end'] + store.update(t.id, { status = 'done' }) + local task = store.get(t.id) + assert.are.equal(first_end, task['end']) + end) end) describe('delete', function()