test: add store, parse, and diff specs
Problem: need test coverage for core data operations, inline metadata parsing, and buffer diff algorithm. Solution: add busted specs for store CRUD, round-trip preservation, parse body/command_add with configurable date syntax, and diff create/delete/update/copy/move operations.
This commit is contained in:
parent
dfe09ef721
commit
8bd6bf8a6a
4 changed files with 483 additions and 0 deletions
189
spec/store_spec.lua
Normal file
189
spec/store_spec.lua
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
require('spec.helpers')
|
||||
|
||||
local config = require('todo.config')
|
||||
local store = require('todo.store')
|
||||
|
||||
describe('store', function()
|
||||
local tmpdir
|
||||
|
||||
before_each(function()
|
||||
tmpdir = vim.fn.tempname()
|
||||
vim.fn.mkdir(tmpdir, 'p')
|
||||
vim.g.todo = { data_path = tmpdir .. '/tasks.json' }
|
||||
config.reset()
|
||||
store.unload()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
vim.fn.delete(tmpdir, 'rf')
|
||||
vim.g.todo = nil
|
||||
config.reset()
|
||||
end)
|
||||
|
||||
describe('load', function()
|
||||
it('returns empty data when no file exists', function()
|
||||
local data = store.load()
|
||||
assert.are.equal(1, data.version)
|
||||
assert.are.equal(1, data.next_id)
|
||||
assert.are.same({}, data.tasks)
|
||||
end)
|
||||
|
||||
it('loads existing data', function()
|
||||
local path = config.get().data_path
|
||||
local f = io.open(path, 'w')
|
||||
f:write(vim.json.encode({
|
||||
version = 1,
|
||||
next_id = 3,
|
||||
tasks = {
|
||||
{
|
||||
id = 1,
|
||||
description = 'Todo one',
|
||||
status = 'pending',
|
||||
entry = '2026-01-01T00:00:00Z',
|
||||
modified = '2026-01-01T00:00:00Z',
|
||||
},
|
||||
{
|
||||
id = 2,
|
||||
description = 'Todo two',
|
||||
status = 'done',
|
||||
entry = '2026-01-01T00:00:00Z',
|
||||
modified = '2026-01-01T00:00:00Z',
|
||||
},
|
||||
},
|
||||
}))
|
||||
f:close()
|
||||
local data = store.load()
|
||||
assert.are.equal(3, data.next_id)
|
||||
assert.are.equal(2, #data.tasks)
|
||||
assert.are.equal('Todo one', data.tasks[1].description)
|
||||
assert.are.equal('done', data.tasks[2].status)
|
||||
end)
|
||||
|
||||
it('preserves unknown fields', function()
|
||||
local path = config.get().data_path
|
||||
local f = io.open(path, 'w')
|
||||
f:write(vim.json.encode({
|
||||
version = 1,
|
||||
next_id = 2,
|
||||
tasks = {
|
||||
{
|
||||
id = 1,
|
||||
description = 'Todo',
|
||||
status = 'pending',
|
||||
entry = '2026-01-01T00:00:00Z',
|
||||
modified = '2026-01-01T00:00:00Z',
|
||||
custom_field = 'hello',
|
||||
},
|
||||
},
|
||||
}))
|
||||
f:close()
|
||||
store.load()
|
||||
local task = store.get(1)
|
||||
assert.is_not_nil(task._extra)
|
||||
assert.are.equal('hello', task._extra.custom_field)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('add', function()
|
||||
it('creates a task with incremented id', function()
|
||||
store.load()
|
||||
local t1 = store.add({ description = 'First' })
|
||||
local t2 = store.add({ description = 'Second' })
|
||||
assert.are.equal(1, t1.id)
|
||||
assert.are.equal(2, t2.id)
|
||||
assert.are.equal('pending', t1.status)
|
||||
assert.are.equal('Inbox', t1.category)
|
||||
end)
|
||||
|
||||
it('uses provided category', function()
|
||||
store.load()
|
||||
local t = store.add({ description = 'Test', category = 'Work' })
|
||||
assert.are.equal('Work', t.category)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('update', function()
|
||||
it('updates fields and sets modified', function()
|
||||
store.load()
|
||||
local t = store.add({ description = 'Original' })
|
||||
local original_modified = t.modified
|
||||
store.update(t.id, { description = 'Updated' })
|
||||
local updated = store.get(t.id)
|
||||
assert.are.equal('Updated', updated.description)
|
||||
assert.is_not.equal(original_modified, updated.modified)
|
||||
end)
|
||||
|
||||
it('sets end timestamp on completion', function()
|
||||
store.load()
|
||||
local t = store.add({ description = 'Test' })
|
||||
assert.is_nil(t['end'])
|
||||
store.update(t.id, { status = 'done' })
|
||||
local updated = store.get(t.id)
|
||||
assert.is_not_nil(updated['end'])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('delete', function()
|
||||
it('marks task as deleted', function()
|
||||
store.load()
|
||||
local t = store.add({ description = 'To delete' })
|
||||
store.delete(t.id)
|
||||
local deleted = store.get(t.id)
|
||||
assert.are.equal('deleted', deleted.status)
|
||||
assert.is_not_nil(deleted['end'])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('save and round-trip', function()
|
||||
it('persists and reloads correctly', function()
|
||||
store.load()
|
||||
store.add({ description = 'Persisted', category = 'Work', priority = 1 })
|
||||
store.save()
|
||||
store.unload()
|
||||
store.load()
|
||||
local tasks = store.active_tasks()
|
||||
assert.are.equal(1, #tasks)
|
||||
assert.are.equal('Persisted', tasks[1].description)
|
||||
assert.are.equal('Work', tasks[1].category)
|
||||
assert.are.equal(1, tasks[1].priority)
|
||||
end)
|
||||
|
||||
it('round-trips unknown fields', function()
|
||||
local path = config.get().data_path
|
||||
local f = io.open(path, 'w')
|
||||
f:write(vim.json.encode({
|
||||
version = 1,
|
||||
next_id = 2,
|
||||
tasks = {
|
||||
{
|
||||
id = 1,
|
||||
description = 'Todo',
|
||||
status = 'pending',
|
||||
entry = '2026-01-01T00:00:00Z',
|
||||
modified = '2026-01-01T00:00:00Z',
|
||||
_gcal_event_id = 'abc123',
|
||||
},
|
||||
},
|
||||
}))
|
||||
f:close()
|
||||
store.load()
|
||||
store.save()
|
||||
store.unload()
|
||||
store.load()
|
||||
local task = store.get(1)
|
||||
assert.are.equal('abc123', task._extra._gcal_event_id)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('active_tasks', function()
|
||||
it('excludes deleted tasks', function()
|
||||
store.load()
|
||||
store.add({ description = 'Active' })
|
||||
local t2 = store.add({ description = 'To delete' })
|
||||
store.delete(t2.id)
|
||||
local active = store.active_tasks()
|
||||
assert.are.equal(1, #active)
|
||||
assert.are.equal('Active', active[1].description)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
Loading…
Add table
Add a link
Reference in a new issue