pending.nvim/spec/archive_spec.lua
Barrett Ruth 114048298b 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.
2026-02-24 22:33:13 -05:00

140 lines
4.6 KiB
Lua

require('spec.helpers')
local config = require('pending.config')
local store = require('pending.store')
describe('archive', function()
local tmpdir
local pending = require('pending')
before_each(function()
tmpdir = vim.fn.tempname()
vim.fn.mkdir(tmpdir, 'p')
vim.g.pending = { data_path = tmpdir .. '/tasks.json' }
config.reset()
store.unload()
store.load()
end)
after_each(function()
vim.fn.delete(tmpdir, 'rf')
vim.g.pending = nil
config.reset()
end)
it('removes done tasks completed more than 30 days ago', function()
local t = store.add({ description = 'Old done task' })
store.update(t.id, { status = 'done', ['end'] = '2020-01-01T00:00:00Z' })
pending.archive()
assert.are.equal(0, #store.active_tasks())
end)
it('keeps done tasks completed fewer than 30 days ago', function()
local recent_end = os.date('!%Y-%m-%dT%H:%M:%SZ', os.time() - (5 * 86400))
local t = store.add({ description = 'Recent done task' })
store.update(t.id, { status = 'done', ['end'] = recent_end })
pending.archive()
local active = store.active_tasks()
assert.are.equal(1, #active)
assert.are.equal('Recent done task', active[1].description)
end)
it('respects a custom day count', function()
local eight_days_ago = os.date('!%Y-%m-%dT%H:%M:%SZ', os.time() - (8 * 86400))
local t = store.add({ description = 'Old for 7 days' })
store.update(t.id, { status = 'done', ['end'] = eight_days_ago })
pending.archive(7)
assert.are.equal(0, #store.active_tasks())
end)
it('keeps tasks within the custom day cutoff', function()
local five_days_ago = os.date('!%Y-%m-%dT%H:%M:%SZ', os.time() - (5 * 86400))
local t = store.add({ description = 'Recent for 7 days' })
store.update(t.id, { status = 'done', ['end'] = five_days_ago })
pending.archive(7)
local active = store.active_tasks()
assert.are.equal(1, #active)
end)
it('never archives pending tasks regardless of age', function()
store.add({ description = 'Still pending' })
pending.archive()
local active = store.active_tasks()
assert.are.equal(1, #active)
assert.are.equal('pending', active[1].status)
end)
it('removes deleted tasks past the cutoff', function()
local t = store.add({ description = 'Old deleted task' })
store.update(t.id, { status = 'deleted', ['end'] = '2020-01-01T00:00:00Z' })
pending.archive()
local all = store.tasks()
assert.are.equal(0, #all)
end)
it('keeps deleted tasks within the cutoff', function()
local recent_end = os.date('!%Y-%m-%dT%H:%M:%SZ', os.time() - (5 * 86400))
local t = store.add({ description = 'Recent deleted' })
store.update(t.id, { status = 'deleted', ['end'] = recent_end })
pending.archive()
local all = store.tasks()
assert.are.equal(1, #all)
end)
it('reports the correct count in vim.notify', function()
local messages = {}
local orig_notify = vim.notify
vim.notify = function(msg, ...)
table.insert(messages, msg)
return orig_notify(msg, ...)
end
local t1 = store.add({ description = 'Old 1' })
local t2 = store.add({ description = 'Old 2' })
store.add({ description = 'Keep' })
store.update(t1.id, { status = 'done', ['end'] = '2020-01-01T00:00:00Z' })
store.update(t2.id, { status = 'done', ['end'] = '2020-01-01T00:00:00Z' })
pending.archive()
vim.notify = orig_notify
local found = false
for _, msg in ipairs(messages) do
if msg:find('Archived 2') then
found = true
break
end
end
assert.is_true(found)
end)
it('leaves only kept tasks in store.active_tasks after archive', function()
local t1 = store.add({ description = 'Old done' })
store.add({ description = 'Keep pending' })
local recent_end = os.date('!%Y-%m-%dT%H:%M:%SZ', os.time() - (5 * 86400))
local t3 = store.add({ description = 'Keep recent done' })
store.update(t1.id, { status = 'done', ['end'] = '2020-01-01T00:00:00Z' })
store.update(t3.id, { status = 'done', ['end'] = recent_end })
pending.archive()
local active = store.active_tasks()
assert.are.equal(2, #active)
local descs = {}
for _, task in ipairs(active) do
descs[task.description] = true
end
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)