crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

AuthorIdentityTests.swift (3403B)


      1 import CloudKit
      2 import Foundation
      3 import Testing
      4 
      5 @testable import Crossmate
      6 
      7 @Suite("AuthorIdentity")
      8 @MainActor
      9 struct AuthorIdentityTests {
     10 
     11     private func makeIsolatedStorage() -> UserDefaults {
     12         UserDefaults(suiteName: "test-authoridentity-\(UUID().uuidString)")!
     13     }
     14 
     15     @Test("Before any account resolves, falls back to a device-local id")
     16     func initialStateUsesFallback() {
     17         let identity = AuthorIdentity(storage: makeIsolatedStorage())
     18         #expect(identity.isFallback)
     19         #expect(identity.currentID?.hasPrefix("local-") == true)
     20     }
     21 
     22     @Test("Fallback id is stable across instances sharing storage")
     23     func fallbackPersistsAcrossInstances() {
     24         let storage = makeIsolatedStorage()
     25         let first = AuthorIdentity(storage: storage).currentID
     26         let second = AuthorIdentity(storage: storage).currentID
     27         #expect(first?.hasPrefix("local-") == true)
     28         #expect(first == second)
     29     }
     30 
     31     @Test("Testing initializer seeds currentID")
     32     func testingInitializerSeedsValue() {
     33         let identity = AuthorIdentity(testing: "_abc")
     34         #expect(identity.currentID == "_abc")
     35         #expect(!identity.isFallback)
     36     }
     37 
     38     @Test("refresh with unavailable account leaves the fallback in place")
     39     func refreshFailurePreservesFallback() async {
     40         let identity = AuthorIdentity(storage: makeIsolatedStorage())
     41         let fallback = identity.currentID
     42         // The default CKContainer without a signed-in account fails the fetch.
     43         // The contract is: on failure, currentID is unchanged — still the
     44         // fallback — so offline writes keep a consistent author.
     45         let containerWithNoAccount = CloudContainer.container
     46         await identity.refresh(using: containerWithNoAccount)
     47         #expect(identity.currentID == fallback)
     48         #expect(identity.isFallback)
     49     }
     50 
     51     @Test("A resolved iCloud id takes precedence over the fallback")
     52     func resolvedIDPersistsAcrossInstances() {
     53         let storage = makeIsolatedStorage()
     54         storage.set("_persisted", forKey: "AuthorIdentity.currentID")
     55         let identity = AuthorIdentity(storage: storage)
     56         #expect(identity.currentID == "_persisted")
     57         #expect(!identity.isFallback)
     58     }
     59 }
     60 
     61 /// `AppServices.accountSwitchRequiresPurge` gates the local-store wipe on an
     62 /// account-change event. Only a switch between two *known, different* accounts
     63 /// should purge.
     64 @Suite("Account switch purge gate")
     65 @MainActor
     66 struct AccountSwitchPurgeTests {
     67 
     68     @Test("Switch to a different account purges")
     69     func differentAccountPurges() {
     70         #expect(AppServices.accountSwitchRequiresPurge(previousID: "_alice", newID: "_bob"))
     71     }
     72 
     73     @Test("Same account does not purge")
     74     func sameAccountKeeps() {
     75         #expect(!AppServices.accountSwitchRequiresPurge(previousID: "_alice", newID: "_alice"))
     76     }
     77 
     78     @Test("First sign-in (no previous ID) does not purge")
     79     func firstSignInKeeps() {
     80         #expect(!AppServices.accountSwitchRequiresPurge(previousID: nil, newID: "_bob"))
     81     }
     82 
     83     @Test("Transient sign-out (no new ID) does not purge")
     84     func signOutKeeps() {
     85         #expect(!AppServices.accountSwitchRequiresPurge(previousID: "_alice", newID: nil))
     86     }
     87 
     88     @Test("Both unknown does not purge")
     89     func bothUnknownKeeps() {
     90         #expect(!AppServices.accountSwitchRequiresPurge(previousID: nil, newID: nil))
     91     }
     92 }