ItemStoreTests.swift (6377B)
1 import Foundation 2 import Testing 3 4 #if os(macOS) 5 @testable import Listless 6 #else 7 @testable import Listless_iOS 8 #endif 9 10 @Suite("ItemStore CRUD Operations", .serialized) 11 @MainActor 12 struct ItemStoreTests { 13 14 // MARK: - Creation Tests 15 16 @Test("Create item with empty title") 17 func createItemWithEmptyTitle() async throws { 18 let store = makeTestStore() 19 20 let item = try store.createItem() 21 22 #expect(item.title == "") 23 #expect(item.id != UUID(uuidString: "00000000-0000-0000-0000-000000000000")!) 24 #expect(item.isCompleted == false) 25 #expect(item.createdAt.timeIntervalSinceNow > -1.0) 26 } 27 28 @Test("Create item with title") 29 func createItemWithTitle() async throws { 30 let store = makeTestStore() 31 32 let item = try store.createItem(title: "Buy groceries") 33 34 #expect(item.title == "Buy groceries") 35 #expect(item.id != UUID(uuidString: "00000000-0000-0000-0000-000000000000")!) 36 } 37 38 @Test("Create multiple items with unique IDs") 39 func createMultipleItemsWithUniqueIDs() async throws { 40 let store = makeTestStore() 41 42 let item1 = try store.createItem(title: "Item 1") 43 let item2 = try store.createItem(title: "Item 2") 44 let item3 = try store.createItem(title: "Item 3") 45 46 #expect(item1.id != item2.id) 47 #expect(item2.id != item3.id) 48 #expect(item1.id != item3.id) 49 } 50 51 @Test("Created item has timestamps") 52 func createdItemHasTimestamps() async throws { 53 let store = makeTestStore() 54 55 let beforeCreate = Date() 56 let item = try store.createItem(title: "Test") 57 let afterCreate = Date() 58 59 #expect(item.createdAt >= beforeCreate) 60 #expect(item.createdAt <= afterCreate) 61 #expect(item.updatedAt >= beforeCreate) 62 #expect(item.updatedAt <= afterCreate) 63 } 64 65 @Test("Create item at beginning prepends to active items") 66 func createItemAtBeginningPrepends() async throws { 67 let store = makeTestStore() 68 69 let first = try store.createItem(title: "First") 70 let second = try store.createItem(title: "Second") 71 let prepended = try store.createItem(title: "Prepended", atBeginning: true) 72 73 let items = try store.fetchItems().filter { !$0.isCompleted } 74 75 #expect(items.map(\.title) == ["Prepended", "First", "Second"]) 76 #expect(prepended.sortOrder < first.sortOrder) 77 #expect(first.sortOrder < second.sortOrder) 78 } 79 80 // MARK: - Fetch Tests 81 82 @Test("Fetch items from empty store") 83 func fetchItemsFromEmptyStore() async throws { 84 let store = makeTestStore() 85 86 let items = try store.fetchItems() 87 88 #expect(items.isEmpty) 89 } 90 91 @Test("Fetch items returns created items") 92 func fetchItemsReturnsCreatedItems() async throws { 93 let store = makeTestStore() 94 _ = try store.createItem(title: "Item 1") 95 _ = try store.createItem(title: "Item 2") 96 97 let items = try store.fetchItems() 98 99 #expect(items.count == 2) 100 #expect(items[0].title == "Item 1") 101 #expect(items[1].title == "Item 2") 102 } 103 104 // MARK: - Update Tests 105 106 @Test("Update item title") 107 func updateItemTitle() async throws { 108 let store = makeTestStore() 109 let item = try store.createItem(title: "Original") 110 111 try store.update(itemID: item.id, title: "Updated") 112 113 let items = try store.fetchItems() 114 #expect(items.first?.title == "Updated") 115 } 116 117 @Test("Update item title without saving") 118 func updateItemTitleWithoutSaving() async throws { 119 let store = makeTestStore() 120 let item = try store.createItem(title: "Original") 121 122 try store.updateWithoutSaving(itemID: item.id, title: "Updated") 123 124 let items = try store.fetchItems() 125 #expect(items.first?.title == "Updated") 126 } 127 128 @Test("Update with invalid ID does nothing") 129 func updateWithInvalidIDDoesNothing() async throws { 130 let store = makeTestStore() 131 _ = try store.createItem(title: "Item 1") 132 let invalidID = UUID() 133 134 try store.update(itemID: invalidID, title: "Should not exist") 135 136 let items = try store.fetchItems() 137 #expect(items.count == 1) 138 #expect(items.first?.title == "Item 1") 139 } 140 141 // MARK: - Delete Tests 142 143 @Test("Delete item") 144 func deleteItem() async throws { 145 let store = makeTestStore() 146 let item1 = try store.createItem(title: "Item 1") 147 let item2 = try store.createItem(title: "Item 2") 148 149 try store.delete(itemID: item1.id) 150 151 let items = try store.fetchItems() 152 #expect(items.count == 1) 153 #expect(items.first?.id == item2.id) 154 } 155 156 @Test("Delete all items") 157 func deleteAllItems() async throws { 158 let store = makeTestStore() 159 let item1 = try store.createItem(title: "Item 1") 160 let item2 = try store.createItem(title: "Item 2") 161 162 try store.delete(itemID: item1.id) 163 try store.delete(itemID: item2.id) 164 165 let items = try store.fetchItems() 166 #expect(items.isEmpty) 167 } 168 169 @Test("Delete with invalid ID does nothing") 170 func deleteWithInvalidIDDoesNothing() async throws { 171 let store = makeTestStore() 172 _ = try store.createItem(title: "Item 1") 173 let invalidID = UUID() 174 175 try store.delete(itemID: invalidID) 176 177 let items = try store.fetchItems() 178 #expect(items.count == 1) 179 } 180 181 // MARK: - Edge Cases 182 183 @Test("Task IDs persist across fetches") 184 func itemIDsPersistAcrossFetches() async throws { 185 let store = makeTestStore() 186 let item = try store.createItem(title: "Test") 187 let originalID = item.id 188 189 let fetchedItems = try store.fetchItems() 190 let fetchedID = fetchedItems.first?.id 191 192 #expect(fetchedID == originalID) 193 } 194 195 @Test("Create item increments sortOrder") 196 func createItemIncrementsSortOrder() async throws { 197 let store = makeTestStore() 198 199 let item1 = try store.createItem(title: "Item 1") 200 let item2 = try store.createItem(title: "Item 2") 201 let item3 = try store.createItem(title: "Item 3") 202 203 #expect(item2.sortOrder > item1.sortOrder) 204 #expect(item3.sortOrder > item2.sortOrder) 205 #expect(item2.sortOrder - item1.sortOrder == 1000) 206 #expect(item3.sortOrder - item2.sortOrder == 1000) 207 } 208 }