From 0e2c5ef11cc6c26b2ff800ed0bc2399fd5252fd8 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 26 Feb 2026 16:44:39 -0500 Subject: [PATCH] test(sync): add backend dispatch tests Problem: No test coverage for sync dispatch logic, config migration, or gcal module interface conformance. Solution: Add spec/sync_spec.lua with tests for: bare sync errors, empty backend errors, unknown backend errors, unknown action errors, default-to-sync routing, explicit sync/auth routing, legacy gcal config migration, explicit sync.gcal precedence, and gcal module interface fields (name, auth, sync, health). --- spec/sync_spec.lua | 174 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 spec/sync_spec.lua diff --git a/spec/sync_spec.lua b/spec/sync_spec.lua new file mode 100644 index 0000000..4d8a3dc --- /dev/null +++ b/spec/sync_spec.lua @@ -0,0 +1,174 @@ +require('spec.helpers') + +local config = require('pending.config') +local store = require('pending.store') + +describe('sync', function() + local tmpdir + local 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() + package.loaded['pending'] = nil + pending = require('pending') + end) + + after_each(function() + vim.fn.delete(tmpdir, 'rf') + vim.g.pending = nil + config.reset() + store.unload() + package.loaded['pending'] = nil + end) + + describe('dispatch', function() + it('errors on bare :Pending sync with no backend', function() + local msg + local orig = vim.notify + vim.notify = function(m, level) + if level == vim.log.levels.ERROR then + msg = m + end + end + pending.sync(nil) + vim.notify = orig + assert.are.equal('Usage: :Pending sync [action]', msg) + end) + + it('errors on empty backend string', function() + local msg + local orig = vim.notify + vim.notify = function(m, level) + if level == vim.log.levels.ERROR then + msg = m + end + end + pending.sync('') + vim.notify = orig + assert.are.equal('Usage: :Pending sync [action]', msg) + end) + + it('errors on unknown backend', function() + local msg + local orig = vim.notify + vim.notify = function(m, level) + if level == vim.log.levels.ERROR then + msg = m + end + end + pending.sync('notreal') + vim.notify = orig + assert.are.equal('Unknown sync backend: notreal', msg) + end) + + it('errors on unknown action for valid backend', function() + local msg + local orig = vim.notify + vim.notify = function(m, level) + if level == vim.log.levels.ERROR then + msg = m + end + end + pending.sync('gcal', 'notreal') + vim.notify = orig + assert.are.equal("gcal backend has no 'notreal' action", msg) + end) + + it('defaults to sync action when action is omitted', function() + local called = false + local gcal = require('pending.sync.gcal') + local orig_sync = gcal.sync + gcal.sync = function() + called = true + end + pending.sync('gcal') + gcal.sync = orig_sync + assert.is_true(called) + end) + + it('routes explicit sync action', function() + local called = false + local gcal = require('pending.sync.gcal') + local orig_sync = gcal.sync + gcal.sync = function() + called = true + end + pending.sync('gcal', 'sync') + gcal.sync = orig_sync + assert.is_true(called) + end) + + it('routes auth action', function() + local called = false + local gcal = require('pending.sync.gcal') + local orig_auth = gcal.auth + gcal.auth = function() + called = true + end + pending.sync('gcal', 'auth') + gcal.auth = orig_auth + assert.is_true(called) + end) + end) + + describe('config migration', function() + it('migrates legacy gcal to sync.gcal', function() + config.reset() + vim.g.pending = { + data_path = tmpdir .. '/tasks.json', + gcal = { calendar = 'MyCalendar' }, + } + local cfg = config.get() + assert.is_not_nil(cfg.sync) + assert.is_not_nil(cfg.sync.gcal) + assert.are.equal('MyCalendar', cfg.sync.gcal.calendar) + end) + + it('does not overwrite explicit sync.gcal with legacy gcal', function() + config.reset() + vim.g.pending = { + data_path = tmpdir .. '/tasks.json', + gcal = { calendar = 'Legacy' }, + sync = { gcal = { calendar = 'Explicit' } }, + } + local cfg = config.get() + assert.are.equal('Explicit', cfg.sync.gcal.calendar) + end) + + it('works with sync.gcal and no legacy gcal', function() + config.reset() + vim.g.pending = { + data_path = tmpdir .. '/tasks.json', + sync = { gcal = { calendar = 'NewStyle' } }, + } + local cfg = config.get() + assert.are.equal('NewStyle', cfg.sync.gcal.calendar) + end) + end) + + describe('gcal module', function() + it('has name field', function() + local gcal = require('pending.sync.gcal') + assert.are.equal('gcal', gcal.name) + end) + + it('has auth function', function() + local gcal = require('pending.sync.gcal') + assert.are.equal('function', type(gcal.auth)) + end) + + it('has sync function', function() + local gcal = require('pending.sync.gcal') + assert.are.equal('function', type(gcal.sync)) + end) + + it('has health function', function() + local gcal = require('pending.sync.gcal') + assert.are.equal('function', type(gcal.health)) + end) + end) +end)