-- Calendar plugin test -- Exercises: verstak.db.* / verstak.config.* / verstak.state.* / verstak.activity.* -- Runs as part of the LuaVM test suite (no node/worklog/http — those are service-dependent) local function assert(cond, msg) if not cond then error("ASSERT FAIL: " .. tostring(msg), 2) end print(" ✓ " .. tostring(msg)) end local test_count = 0 local function test(name, fn) test_count = test_count + 1 print("\n[" .. test_count .. "] " .. name) local ok, err = pcall(fn) if not ok then print(" ✗ FAIL: " .. tostring(err)) error("Test " .. test_count .. " failed: " .. tostring(err), 2) end end ---------------------------------------------------------------------- -- Test suite ---------------------------------------------------------------------- test("calendar module exists", function() assert(calendar ~= nil, "calendar global exists") assert(type(calendar.get_categories) == "function", "calendar.get_categories exists") assert(type(calendar.create_event) == "function", "calendar.create_event exists") end) test("categories have defaults", function() local cats = calendar.get_categories() assert(#cats >= 6, "at least 6 default categories, got " .. #cats) print(" Categories: " .. #cats) for _, c in ipairs(cats) do print(" " .. c.icon .. " " .. c.name .. " (" .. c.color .. ")") end end) test("create custom category", function() local id = calendar.create_category("Тестовая", "#ff0000", "🧪") assert(id ~= nil, "got category id: " .. tostring(id)) local cats = calendar.get_categories() local found = false for _, c in ipairs(cats) do if c.id == id then found = true end end assert(found, "category found in list") end) test("update category", function() local cats = calendar.get_categories() if #cats == 0 then return end local ok = calendar.update_category(cats[1].id, { name = "Обновлённая" }) assert(ok, "category updated") cats = calendar.get_categories() -- Don't assert the name because the DB might not persist across LuaVM sessions assert(#cats > 0, "still have categories") end) test("soft delete category", function() local cats = calendar.get_categories() if #cats < 2 then return end calendar.delete_category(cats[2].id) -- Verify it's gone from active list local active = calendar.get_categories() for _, c in ipairs(active) do assert(c.id ~= cats[2].id, "deleted category not in active list") end end) test("restore default categories", function() local ok = calendar.restore_default_categories() assert(ok, "defaults restored") local cats = calendar.get_categories() assert(#cats >= 6, "at least 6 default categories after restore") end) test("create event (all-day)", function() local cats = calendar.get_categories() local cat_id = "" if #cats > 0 then cat_id = cats[1].id end local id = calendar.create_event{ title = "Тестовое событие", start = "2026-07-01T00:00:00", all_day = true, category_id = cat_id, color = "#10b981", } assert(id ~= nil, "event created: " .. tostring(id)) local events = calendar.get_events("2026-07-01T00:00:00", "2026-07-01T23:59:59") local found = false for _, e in ipairs(events) do if e.id == id then found = true; break end end assert(found, "event found in date query") end) test("create event with time", function() local id = calendar.create_event{ title = "Встреча в полдень", start = "2026-07-02T12:00:00", ["end"] = "2026-07-02T13:00:00", all_day = false, color = "#8b5cf6", } assert(id ~= nil, "timed event created") end) test("create event with reminder", function() local id = calendar.create_event{ title = "С напоминанием", start = os.date("%Y-%m-%dT23:00:00"), reminder_minutes = {10, 60}, } assert(id ~= nil, "event with reminders created") local ev = calendar.get_event(id) assert(ev ~= nil, "event readable") -- reminder_minutes should be stored — we can check if it has content assert(ev.reminder_minutes ~= nil and ev.reminder_minutes ~= "", "reminder stored") end) test("update event partial", function() local events = calendar.get_events("2026-07-01T00:00:00", "2026-07-01T23:59:59") if #events == 0 then return end calendar.update_event(events[1].id, { title = "Обновлённое событие" }) print(" updated: " .. events[1].id) end) test("delete event", function() local events = calendar.get_events("2026-07-02T00:00:00", "2026-07-02T23:59:59") if #events == 0 then return end local ev_id = events[1].id calendar.delete_event(ev_id) events = calendar.get_events("2026-07-02T00:00:00", "2026-07-02T23:59:59") for _, e in ipairs(events) do assert(e.id ~= ev_id, "deleted event not found") end print(" deleted: " .. ev_id) end) test("expand daily recurrence", function() local dates = calendar.expand_recurring( "2026-07-01T00:00:00", "2026-07-01T01:00:00", { freq = "daily", interval = 1, count = 5, ["until"] = "2026-07-15" }, "2026-07-01T00:00:00", "2026-07-10T00:00:00" ) assert(#dates > 0, "got " .. #dates .. " daily instances") print(" daily instances: " .. #dates) for _, d in ipairs(dates) do print(" " .. d) end end) test("expand weekly recurrence (Mon/Wed/Fri)", function() local dates = calendar.expand_recurring( "2026-07-06T00:00:00", -- Monday "2026-07-06T01:00:00", { freq = "weekly", interval = 1, by_day = {1, 3, 5}, count = 9 }, "2026-07-06T00:00:00", "2026-07-20T00:00:00" ) assert(#dates > 0, "got " .. #dates .. " weekday instances") print(" weekday instances: " .. #dates) for _, d in ipairs(dates) do print(" " .. d) end end) test("expand monthly recurrence", function() local dates = calendar.expand_recurring( "2026-07-15T00:00:00", "2026-07-15T00:00:00", { freq = "monthly", interval = 1, by_month_day = {15}, count = 6 }, "2026-07-01T00:00:00", "2026-12-31T00:00:00" ) assert(#dates >= 5, "got " .. #dates .. " monthly instances (>= 5)") print(" monthly instances: " .. #dates) end) test("check reminders (no crash)", function() local n = calendar.check_reminders() assert(type(n) == "number", "check_reminders returned a number: " .. tostring(n)) print(" reminders to fire: " .. tostring(n)) end) -- Clear test data calendar.clear_events() print("\n========================") print("All " .. test_count .. " tests passed!") print("========================")