import XCTest import SwiftData @testable import MindDump final class TodoItemTests: XCTestCase { // MARK: - isOverdue // Past deadline should be overdue func testIsOverdue_deadlineYesterday_returnsTrue() { let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())! let item = TodoItem(title: "Test", deadline: yesterday) XCTAssertTrue(item.isOverdue) } // Completed items are never overdue, even with past deadline func testIsOverdue_completedWithPastDeadline_returnsFalse() { let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())! let item = TodoItem(title: "Test", isCompleted: true, deadline: yesterday) XCTAssertFalse(item.isOverdue) } } final class TodoListTests: XCTestCase { // MARK: - openItems / completedItems // Items are correctly split into open and completed func testOpenAndCompletedItems_correctSplit() { let open1 = TodoItem(title: "Open 1") let open2 = TodoItem(title: "Open 2") let done = TodoItem(title: "Done", isCompleted: true) let list = TodoList(name: "Test", items: [open1, done, open2]) XCTAssertEqual(list.openItems.count, 2) XCTAssertEqual(list.completedItems.count, 1) XCTAssertEqual(list.completedItems.first?.title, "Done") } // Open items are sorted oldest first func testOpenItems_sortedByCreatedAtAscending() { let older = TodoItem(title: "Older", createdAt: Date().addingTimeInterval(-100)) let newer = TodoItem(title: "Newer", createdAt: Date()) let list = TodoList(name: "Test", items: [newer, older]) XCTAssertEqual(list.openItems.map(\.title), ["Older", "Newer"]) } // Completed items are sorted newest first (by modifiedAt) func testCompletedItems_sortedByModifiedAtDescending() { let earlier = TodoItem(title: "Earlier", isCompleted: true, modifiedAt: Date().addingTimeInterval(-100)) let later = TodoItem(title: "Later", isCompleted: true, modifiedAt: Date()) let list = TodoList(name: "Test", items: [earlier, later]) XCTAssertEqual(list.completedItems.map(\.title), ["Later", "Earlier"]) } } // MARK: - ListStore Tests @MainActor final class ListStoreTests: XCTestCase { private var container: ModelContainer! private var store: ListStore! override func setUp() { let config = ModelConfiguration(isStoredInMemoryOnly: true) container = try! ModelContainer(for: TodoList.self, TodoItem.self, configurations: config) store = ListStore(modelContext: container.mainContext) } // MARK: - addItem / deleteItem // Adding an item increases the list count and stores the title func testAddItem_increasesCount() { let inboxID = store.inboxID store.addItem(to: inboxID, title: "Buy milk") XCTAssertEqual(store.lists.first!.items.count, 1) XCTAssertEqual(store.lists.first!.items.first?.title, "Buy milk") } // Deleting an item removes it from the list func testDeleteItem_removesItem() { let inboxID = store.inboxID store.addItem(to: inboxID, title: "Temp") let itemID = store.lists.first!.items.first!.id store.deleteItem(itemID, from: inboxID) XCTAssertTrue(store.lists.first!.items.isEmpty) } // MARK: - toggleItemCompleted // Toggling flips isCompleted back and forth func testToggleItemCompleted_flipsStatus() { let inboxID = store.inboxID store.addItem(to: inboxID, title: "Task") let itemID = store.lists.first!.items.first!.id XCTAssertFalse(store.lists.first!.items.first!.isCompleted) store.toggleItemCompleted(itemID, in: inboxID) XCTAssertTrue(store.lists.first!.items.first!.isCompleted) store.toggleItemCompleted(itemID, in: inboxID) XCTAssertFalse(store.lists.first!.items.first!.isCompleted) } // MARK: - moveItem // Moving an item removes it from the source list, adds it to the target list, and updates modifiedAt func testMoveItem_movesAcrossLists() { let inboxID = store.inboxID store.addList(name: "Arbeit") let arbeitID = store.lists.first { $0.name == "Arbeit" }!.id store.addItem(to: inboxID, title: "Wichtige Aufgabe") let itemID = store.lists.first { $0.isInbox }!.items.first!.id store.moveItem(itemID, from: inboxID, to: arbeitID) let inbox = store.lists.first { $0.isInbox }! let arbeit = store.lists.first { $0.name == "Arbeit" }! XCTAssertTrue(inbox.items.isEmpty, "Item should be removed from source lists") XCTAssertEqual(arbeit.items.count, 1, "Item should be in target list") XCTAssertEqual(arbeit.items.first?.title, "Wichtige Aufgabe") XCTAssertNotNil(arbeit.items.first?.modifiedAt, "modifiedAt should be set after move") } }