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 }