macsync/@packages/ical/Tests/ICalSyncTests/SenderTests.swift

193 lines
6.8 KiB
Swift

import EventKit
import Foundation
import MacSyncShared
import Testing
@testable import ICalSync
@MainActor
final class FakeApplier: CalendarEventApplying {
var calendars: [String: EKCalendar] = [:]
var events: [String: EKEvent] = [:]
private(set) var savedCount = 0
private(set) var removedCount = 0
private(set) var lastSavedEvent: EKEvent?
private(set) var lastRemovedEvent: EKEvent?
var saveError: Error?
var removeError: Error?
let store = EKEventStore()
func calendar(withIdentifier id: String) -> EKCalendar? { calendars[id] }
func event(withIdentifier id: String) -> EKEvent? { events[id] }
func makeEvent() -> EKEvent { EKEvent(eventStore: store) }
func save(_ event: EKEvent, span: EKSpan) throws {
if let e = saveError { throw e }
savedCount += 1
lastSavedEvent = event
}
func remove(_ event: EKEvent, span: EKSpan) throws {
if let e = removeError { throw e }
removedCount += 1
lastRemovedEvent = event
}
}
@Suite("CalendarSender")
@MainActor
struct CalendarSenderTests {
private func makeItem(action: String, payload: CalendarSendPayload) -> PendingCalendarSend {
PendingCalendarSend(id: "item-1", action: action, payload: payload, createdAt: "2026-05-13T00:00:00Z")
}
@Test("create_event with valid fields returns .sent")
func createValid() async {
let fake = FakeApplier()
// Seed a calendar
let cal = EKCalendar(for: .event, eventStore: fake.store)
fake.calendars["cal-1"] = cal
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "create_event", payload: CalendarSendPayload(
calendarIdentifier: "cal-1",
title: "Test",
startDate: "2026-05-13T10:00:00Z",
endDate: "2026-05-13T11:00:00Z"
))
let result = await sender.apply(item)
guard case .sent = result else {
Issue.record("expected .sent, got \(result)")
return
}
#expect(fake.savedCount == 1)
#expect(fake.lastSavedEvent?.title == "Test")
}
@Test("create_event missing calendarIdentifier returns .failed")
func createMissingCalendar() async {
let fake = FakeApplier()
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "create_event", payload: CalendarSendPayload(
title: "Test",
startDate: "2026-05-13T10:00:00Z",
endDate: "2026-05-13T11:00:00Z"
))
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("missing calendarIdentifier"))
#expect(fake.savedCount == 0)
}
@Test("create_event with unknown calendar returns .failed")
func createUnknownCalendar() async {
let fake = FakeApplier()
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "create_event", payload: CalendarSendPayload(
calendarIdentifier: "missing",
title: "Test",
startDate: "2026-05-13T10:00:00Z",
endDate: "2026-05-13T11:00:00Z"
))
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("calendar not found"))
}
@Test("create_event with invalid startDate returns .failed")
func createInvalidDate() async {
let fake = FakeApplier()
let cal = EKCalendar(for: .event, eventStore: fake.store)
fake.calendars["cal-1"] = cal
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "create_event", payload: CalendarSendPayload(
calendarIdentifier: "cal-1",
title: "Test",
startDate: "not-a-date",
endDate: "2026-05-13T11:00:00Z"
))
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("invalid startDate"))
}
@Test("update_event with no eventIdentifier returns .failed")
func updateMissingId() async {
let fake = FakeApplier()
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "update_event", payload: CalendarSendPayload(title: "Renamed"))
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("missing eventIdentifier"))
}
@Test("update_event with unknown event returns .failed")
func updateUnknown() async {
let fake = FakeApplier()
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "update_event", payload: CalendarSendPayload(
eventIdentifier: "ghost",
title: "Renamed"
))
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("event not found"))
}
@Test("delete_event with no eventIdentifier returns .failed")
func deleteMissingId() async {
let fake = FakeApplier()
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "delete_event", payload: CalendarSendPayload())
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("missing eventIdentifier"))
}
@Test("delete_event happy path calls remove")
func deleteHappy() async {
let fake = FakeApplier()
let ev = EKEvent(eventStore: fake.store)
fake.events["ev-1"] = ev
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "delete_event", payload: CalendarSendPayload(eventIdentifier: "ev-1"))
let result = await sender.apply(item)
guard case .sent = result else {
Issue.record("expected .sent, got \(result)")
return
}
#expect(fake.removedCount == 1)
}
@Test("unknown action returns .failed")
func unknownAction() async {
let fake = FakeApplier()
let sender = CalendarSender(applier: fake)
let item = makeItem(action: "bogus", payload: CalendarSendPayload())
let result = await sender.apply(item)
guard case .failed(let reason) = result else {
Issue.record("expected .failed")
return
}
#expect(reason.contains("unknown action"))
}
}