GameViewedStoreTests.swift (2059B)
1 import Foundation 2 import Testing 3 4 @testable import Crossmate 5 6 @Suite("GameViewedStore") 7 @MainActor 8 struct GameViewedStoreTests { 9 10 private func makeStore() -> GameViewedStore { 11 // Fresh UserDefaults suite per test to avoid cross-test pollution. 12 let defaults = UserDefaults(suiteName: "test-\(UUID().uuidString)")! 13 return GameViewedStore(defaults: defaults) 14 } 15 16 private let gameID = UUID() 17 private let base = Date(timeIntervalSinceReferenceDate: 10_000) 18 19 @Test("A first open has no baseline") 20 func noBaselineInitially() { 21 #expect(makeStore().lastViewed(forGame: gameID) == nil) 22 } 23 24 @Test("advance sets the baseline, and moves it forward") 25 func advanceMovesForward() { 26 let store = makeStore() 27 store.advance(base, forGame: gameID) 28 #expect(store.lastViewed(forGame: gameID) == base) 29 30 let later = base.addingTimeInterval(60) 31 store.advance(later, forGame: gameID) 32 #expect(store.lastViewed(forGame: gameID) == later) 33 } 34 35 @Test("advance never regresses the baseline to an older value") 36 func advanceIsMonotonic() { 37 let store = makeStore() 38 store.advance(base, forGame: gameID) 39 // A laggy leave, or a stale value adopted from a sibling, must not pull 40 // the baseline back — already-seen changes would re-surface otherwise. 41 store.advance(base.addingTimeInterval(-300), forGame: gameID) 42 #expect(store.lastViewed(forGame: gameID) == base) 43 } 44 45 @Test("advance is scoped per game") 46 func advanceScopedPerGame() { 47 let store = makeStore() 48 let other = UUID() 49 store.advance(base, forGame: gameID) 50 #expect(store.lastViewed(forGame: other) == nil) 51 } 52 53 @Test("A synced SeenBaseline round-trips through JSON") 54 func seenBaselineRoundTrips() throws { 55 let encoded = try JSONEncoder().encode(SeenBaseline(viewedAt: base)) 56 let decoded = try JSONDecoder().decode(SeenBaseline.self, from: encoded) 57 #expect(decoded.viewedAt == base) 58 } 59 }