test: add missing coverage (#19)

* 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.
This commit is contained in:
Barrett Ruth 2026-02-24 22:33:13 -05:00 committed by GitHub
parent cfdffdadfe
commit 8e16744ebe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 68 additions and 0 deletions

View file

@ -128,4 +128,13 @@ describe('archive', function()
assert.is_true(descs['Keep pending']) assert.is_true(descs['Keep pending'])
assert.is_true(descs['Keep recent done']) assert.is_true(descs['Keep recent done'])
end) 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) end)

View file

@ -57,6 +57,28 @@ describe('diff', function()
assert.is_nil(result[2].id) assert.is_nil(result[2].id)
assert.are.equal('New task here', result[2].description) assert.are.equal('New task here', result[2].description)
end) 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) end)
describe('apply', function() describe('apply', function()
@ -107,6 +129,22 @@ describe('diff', function()
assert.are.equal('Renamed', task.description) assert.are.equal('Renamed', task.description)
end) 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() it('handles duplicate ids as copies', function()
store.add({ description = 'Original' }) store.add({ description = 'Original' })
store.save() store.save()

View file

@ -121,6 +121,27 @@ describe('store', function()
local updated = store.get(t.id) local updated = store.get(t.id)
assert.is_not_nil(updated['end']) assert.is_not_nil(updated['end'])
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) end)
describe('delete', function() describe('delete', function()