135 lines
4.7 KiB
Swift
135 lines
4.7 KiB
Swift
import Foundation
|
|
import MacSyncShared
|
|
import Testing
|
|
@testable import INoteSync
|
|
|
|
final class FakeNoteApplier: NoteApplying, @unchecked Sendable {
|
|
enum Call: Equatable {
|
|
case create(NoteSendPayload)
|
|
case update(NoteSendPayload)
|
|
case delete(NoteSendPayload)
|
|
}
|
|
|
|
private(set) var calls: [Call] = []
|
|
var nextResult: SendQueueApplyResult = .sent
|
|
|
|
func create(_ payload: NoteSendPayload) async -> SendQueueApplyResult {
|
|
calls.append(.create(payload))
|
|
return nextResult
|
|
}
|
|
|
|
func update(_ payload: NoteSendPayload) async -> SendQueueApplyResult {
|
|
calls.append(.update(payload))
|
|
return nextResult
|
|
}
|
|
|
|
func delete(_ payload: NoteSendPayload) async -> SendQueueApplyResult {
|
|
calls.append(.delete(payload))
|
|
return nextResult
|
|
}
|
|
}
|
|
|
|
@Suite("NoteSender dispatch")
|
|
@MainActor
|
|
struct SenderDispatchTests {
|
|
private func item(_ action: String, _ payload: NoteSendPayload = NoteSendPayload()) -> PendingNoteSend {
|
|
PendingNoteSend(id: "i-1", action: action, payload: payload, createdAt: "2026-05-13T00:00:00Z")
|
|
}
|
|
|
|
@Test("create_note dispatches to create")
|
|
func dispatchCreate() async {
|
|
let fake = FakeNoteApplier()
|
|
let sender = NoteSender(applier: fake)
|
|
let p = NoteSendPayload(folder: "Notes", name: "Hi", body: "<p>x</p>")
|
|
let result = await sender.apply(item("create_note", p))
|
|
guard case .sent = result else { Issue.record("expected .sent"); return }
|
|
#expect(fake.calls == [.create(p)])
|
|
}
|
|
|
|
@Test("update_note dispatches to update")
|
|
func dispatchUpdate() async {
|
|
let fake = FakeNoteApplier()
|
|
let sender = NoteSender(applier: fake)
|
|
let p = NoteSendPayload(noteIdentifier: "id-1", body: "<p>new</p>")
|
|
_ = await sender.apply(item("update_note", p))
|
|
#expect(fake.calls == [.update(p)])
|
|
}
|
|
|
|
@Test("delete_note dispatches to delete")
|
|
func dispatchDelete() async {
|
|
let fake = FakeNoteApplier()
|
|
let sender = NoteSender(applier: fake)
|
|
let p = NoteSendPayload(noteIdentifier: "id-1")
|
|
_ = await sender.apply(item("delete_note", p))
|
|
#expect(fake.calls == [.delete(p)])
|
|
}
|
|
|
|
@Test("unknown action returns .failed without invoking applier")
|
|
func unknownAction() async {
|
|
let fake = FakeNoteApplier()
|
|
let sender = NoteSender(applier: fake)
|
|
let result = await sender.apply(item("frobnicate"))
|
|
guard case .failed(let reason) = result else {
|
|
Issue.record("expected .failed")
|
|
return
|
|
}
|
|
#expect(reason.contains("unknown action"))
|
|
#expect(fake.calls.isEmpty)
|
|
}
|
|
|
|
@Test("propagates .failed from applier")
|
|
func propagatesFailure() async {
|
|
let fake = FakeNoteApplier()
|
|
fake.nextResult = .failed(reason: "boom")
|
|
let sender = NoteSender(applier: fake)
|
|
let result = await sender.apply(item("create_note", NoteSendPayload(name: "n")))
|
|
guard case .failed(let reason) = result else {
|
|
Issue.record("expected .failed")
|
|
return
|
|
}
|
|
#expect(reason == "boom")
|
|
}
|
|
}
|
|
|
|
@Suite("AppleScriptNoteApplier missing-field guards")
|
|
struct AppleScriptNoteApplierGuards {
|
|
@Test("create without name returns .failed")
|
|
func createMissingName() async {
|
|
let applier = AppleScriptNoteApplier()
|
|
let result = await applier.create(NoteSendPayload(body: "x"))
|
|
guard case .failed(let reason) = result else {
|
|
Issue.record("expected .failed"); return
|
|
}
|
|
#expect(reason.contains("name"))
|
|
}
|
|
|
|
@Test("update without noteIdentifier returns .failed")
|
|
func updateMissingId() async {
|
|
let applier = AppleScriptNoteApplier()
|
|
let result = await applier.update(NoteSendPayload(body: "x"))
|
|
guard case .failed(let reason) = result else {
|
|
Issue.record("expected .failed"); return
|
|
}
|
|
#expect(reason.contains("noteIdentifier"))
|
|
}
|
|
|
|
@Test("update with id but no fields returns .failed")
|
|
func updateNoFields() async {
|
|
let applier = AppleScriptNoteApplier()
|
|
let result = await applier.update(NoteSendPayload(noteIdentifier: "id-1"))
|
|
guard case .failed(let reason) = result else {
|
|
Issue.record("expected .failed"); return
|
|
}
|
|
#expect(reason.contains("no fields"))
|
|
}
|
|
|
|
@Test("delete without noteIdentifier returns .failed")
|
|
func deleteMissingId() async {
|
|
let applier = AppleScriptNoteApplier()
|
|
let result = await applier.delete(NoteSendPayload())
|
|
guard case .failed(let reason) = result else {
|
|
Issue.record("expected .failed"); return
|
|
}
|
|
#expect(reason.contains("noteIdentifier"))
|
|
}
|
|
}
|