crossmate

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

TestHelpers.swift (2378B)


      1 import Foundation
      2 import Testing
      3 
      4 @testable import Crossmate
      5 
      6 /// Creates a fresh PersistenceController with in-memory storage for isolated testing.
      7 @MainActor
      8 func makeTestPersistence() -> PersistenceController {
      9     PersistenceController(inMemory: true)
     10 }
     11 
     12 /// Builds a `GameStore` wired with no-op collaborators for tests that don't
     13 /// exercise the sync/identity/updater paths. Override only what the test needs.
     14 @MainActor
     15 func makeTestStore(
     16     persistence: PersistenceController,
     17     movesUpdater: MovesUpdater? = nil,
     18     authorIDProvider: @escaping @MainActor () -> String? = { nil },
     19     onGameCreated: @escaping (String) -> Void = { _ in },
     20     onGameUpdated: @escaping (String) -> Void = { _ in },
     21     onGameDeleted: @escaping (GameCloudDeletion) -> Void = { _ in }
     22 ) -> GameStore {
     23     let updater = movesUpdater ?? MovesUpdater(
     24         persistence: persistence,
     25         writerAuthorIDProvider: { nil },
     26         sink: { _ in }
     27     )
     28     return GameStore(
     29         persistence: persistence,
     30         movesUpdater: updater,
     31         authorIDProvider: authorIDProvider,
     32         onGameCreated: onGameCreated,
     33         onGameUpdated: onGameUpdated,
     34         onGameDeleted: onGameDeleted
     35     )
     36 }
     37 
     38 /// Creates a Game, GameEntity, and GameMutator backed by an in-memory store.
     39 /// The puzzle is a minimal 3x3 grid with a single block at (1,1).
     40 /// `movesUpdater` is nil — tests that need emission verify via MovesUpdater's own suite.
     41 @MainActor
     42 func makeTestGame() throws -> (Game, GameMutator, GameEntity, PersistenceController) {
     43     let persistence = makeTestPersistence()
     44     let context = persistence.viewContext
     45 
     46     let source = """
     47     Title: Test Puzzle
     48     Author: Test
     49 
     50 
     51     ABC
     52     D#E
     53     FGH
     54 
     55 
     56     A1. Across 1 ~ ABC
     57     A4. Across 4 ~ DE
     58     A5. Across 5 ~ FGH
     59     D1. Down 1 ~ ADF
     60     D2. Down 2 ~ BG
     61     D3. Down 3 ~ CEH
     62     """
     63 
     64     let xd = try XD.parse(source)
     65     let puzzle = Puzzle(xd: xd)
     66     let game = Game(puzzle: puzzle)
     67 
     68     let gameID = UUID()
     69     let entity = GameEntity(context: context)
     70     entity.id = gameID
     71     entity.title = puzzle.title
     72     entity.puzzleSource = source
     73     entity.createdAt = Date()
     74     entity.updatedAt = Date()
     75     entity.ckRecordName = "game-\(gameID.uuidString)"
     76 
     77     try context.save()
     78 
     79     let mutator = GameMutator(game: game, gameID: gameID, movesUpdater: nil)
     80     return (game, mutator, entity, persistence)
     81 }