FakeCalendarBridge.swift 72 lignes · 2640 octets
import Foundation
@testable import Card2vcf

/// In-memory fake `CalendarBridge` (no EventKit) to test the calendar↔store bridge.
final class FakeCalendarBridge: CalendarBridge {
    private var calendars: [String: Int64] = [:]
    private var events: [Int64: [Int64: CalendarEventSnapshot]] = [:]
    private var nextCalendarId: Int64 = 1
    private var nextEventId: Int64 = 1
    var deletedEventIds: [Int64] = []
    var deletedCalendarIds: [Int64] = []

    /// Simulates a revoked Calendar permission: `deleteCalendar` throws this when non-nil.
    var deleteCalendarFailure: Error? = nil

    /// Simulates iCloud Calendar hiding the local source when set to false.
    var hasLocalSourceValue = true

    func hasLocalSource() -> Bool { hasLocalSourceValue }

    @discardableResult
    func ensureLocalCalendar(displayName: String) throws -> Int64 {
        if let existing = calendars[displayName] { return existing }
        let id = nextCalendarId
        nextCalendarId += 1
        calendars[displayName] = id
        return id
    }

    func deleteCalendar(calendarId: Int64) throws {
        if let deleteCalendarFailure { throw deleteCalendarFailure }
        deletedCalendarIds.append(calendarId)
        calendars = calendars.filter { $0.value != calendarId }
        events.removeValue(forKey: calendarId)
    }

    func listEvents(calendarId: Int64) throws -> [CalendarEventSnapshot] {
        guard let calendarEvents = events[calendarId] else { return [] }
        return calendarEvents.keys.sorted().compactMap { calendarEvents[$0] }
    }

    @discardableResult
    func upsertEvent(calendarId: Int64, snap: CalendarEventSnapshot) throws -> Int64 {
        var calendarEvents = events[calendarId] ?? [:]
        let eventId: Int64
        if let existing = snap.eventId {
            eventId = existing
        } else {
            eventId = nextEventId
            nextEventId += 1
        }
        var stored = snap
        stored.eventId = eventId
        calendarEvents[eventId] = stored
        events[calendarId] = calendarEvents
        return eventId
    }

    func deleteEvent(eventId: Int64) throws {
        deletedEventIds.append(eventId)
        for (calendarId, var calendarEvents) in events {
            calendarEvents.removeValue(forKey: eventId)
            events[calendarId] = calendarEvents
        }
    }

    /// Simulates an event already present in the system calendar app (added outside `upsertEvent`).
    @discardableResult
    func seedEvent(calendarId: Int64, snap: CalendarEventSnapshot) -> Int64 {
        (try? upsertEvent(calendarId: calendarId, snap: snap)) ?? -1
    }
}