listless

A simple list app for Apple platforms
Log | Files | Refs | README | LICENSE

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 }