crossmate

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

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 }