Tests/Unit/ItemStoreTests.swift (6377B)
1import Foundation
2import 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
12struct ItemStoreTests {
13
14
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
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
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
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
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}