const assert = require("node:assert/strict"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const test = require("node:test"); const { archiveTask, createTask, getTask, listTasks, updateTask, } = require("../.test-build/lib/tasks.js"); const { closeDatabaseForTests } = require("../.test-build/lib/db.js"); function useThrowawayDatabase(t) { const directory = fs.mkdtempSync(path.join(os.tmpdir(), "planner-tests-")); const databasePath = path.join(directory, "tasks.sqlite"); process.env.TASKS_DB_PATH = databasePath; t.after(() => { closeDatabaseForTests(); delete process.env.TASKS_DB_PATH; fs.rmSync(directory, { recursive: true, force: true }); }); return databasePath; } test("creating a task persists all four required fields", (t) => { useThrowawayDatabase(t); const created = createTask({ title: "Finish Lab 1", description: "Wire the planner to SQLite", dueDate: "2026-08-20", topic: "Academic", }); const reloaded = getTask(created.id); assert.equal(reloaded.title, "Finish Lab 1"); assert.equal(reloaded.description, "Wire the planner to SQLite"); assert.equal(reloaded.dueDate, "2026-08-20"); assert.equal(reloaded.topic, "Academic"); assert.equal(reloaded.status, "Todo"); assert.equal(reloaded.archivedAt, null); }); test("editing a task persists the changed fields and status", (t) => { useThrowawayDatabase(t); const created = createTask({ title: "Draft notes", description: "Initial wording", dueDate: "2026-08-21", topic: "Academic", }); const edited = updateTask(created.id, { title: "Submit notes", description: "Final wording", dueDate: "2026-08-22", topic: "Work", status: "In-Progress", }); const reloaded = getTask(created.id); assert.equal(edited.title, "Submit notes"); assert.equal(reloaded.description, "Final wording"); assert.equal(reloaded.dueDate, "2026-08-22"); assert.equal(reloaded.topic, "Work"); assert.equal(reloaded.status, "In-Progress"); }); test("archiving marks a task archived without deleting it", (t) => { useThrowawayDatabase(t); const created = createTask({ title: "Old task", description: "Keep for records", dueDate: "2026-08-23", topic: "Personal", }); const archived = archiveTask(created.id); const activeTasks = listTasks(); const allTasks = listTasks({ includeArchived: true }); assert.equal(typeof archived.archivedAt, "string"); assert.equal(getTask(created.id).id, created.id); assert.equal(activeTasks.some((task) => task.id === created.id), false); assert.equal(allTasks.some((task) => task.id === created.id), true); }); test("overdue is derived from due date and is not stored as a status", (t) => { useThrowawayDatabase(t); const overdue = createTask({ title: "Past task", description: "This date has passed", dueDate: "2000-01-01", topic: "Work", }); const future = createTask({ title: "Future task", description: "This date has not passed", dueDate: "2999-01-01", topic: "Work", }); const completed = updateTask(overdue.id, { status: "Complete" }); assert.equal(overdue.status, "Todo"); assert.equal(overdue.isOverdue, true); assert.equal(future.isOverdue, false); assert.equal(completed.status, "Complete"); assert.equal(completed.isOverdue, false); assert.notEqual(completed.status, "Overdue"); }); test("sorting by topic, status, and due date is deterministic", (t) => { useThrowawayDatabase(t); const work = createTask({ title: "Work item", description: "Second topic alphabetically", dueDate: "2026-09-03", topic: "Work", }); const academic = createTask({ title: "Academic item", description: "First topic alphabetically", dueDate: "2026-09-02", topic: "Academic", }); const personal = createTask({ title: "Personal item", description: "Earliest due date", dueDate: "2026-09-01", topic: "Personal", }); updateTask(work.id, { status: "Complete" }); updateTask(academic.id, { status: "In-Progress" }); assert.deepEqual( listTasks({ sort: "topic" }).map((task) => task.topic), ["Academic", "Personal", "Work"] ); assert.deepEqual( listTasks({ sort: "status" }).map((task) => task.status), ["Todo", "In-Progress", "Complete"] ); assert.deepEqual( listTasks({ sort: "dueDate" }).map((task) => task.id), [personal.id, academic.id, work.id] ); });