import XCTest @testable import LChatCore // 🤖 The notification-tap resolution ladder (NotificationRoute): parked key → // snapshot scan → only-space. The silent-drop bug this pins: a stale or // missing SharedThreadKeys park used to strand the tap on the chat list. final class NotificationRouteTests: XCTestCase { private func inst(_ origin: String, archived: Bool = false) -> SavedInstance { var i = SavedInstance(origin: origin, deviceToken: "t", screenName: "s", userPub: "pub", userPriv: "priv") i.archived = archived return i } func testParkedKeyWins() { let a = inst("https://a.example"), b = inst("https://b.example") let r = NotificationRoute.resolve( threadID: "th1", instances: [a, b], entryOrigin: { _ in "https://b.example" }, snapshotHasThread: { _, _ in XCTFail("snapshot consulted despite park"); return false }) guard case .parkedKey(let hit) = r else { return XCTFail("\(r)") } XCTAssertEqual(hit.origin, b.origin) } func testStaleParkFallsBackToSnapshot() { // The park points at an origin that's no longer signed in (re-added // space) — the snapshot scan must still find the thread's real home. let a = inst("https://a.example"), b = inst("https://b.example") let r = NotificationRoute.resolve( threadID: "th1", instances: [a, b], entryOrigin: { _ in "https://gone.example" }, snapshotHasThread: { origin, thread in origin == "https://b.example" && thread == "th1" }) guard case .snapshot(let hit) = r else { return XCTFail("\(r)") } XCTAssertEqual(hit.origin, b.origin) } func testMissingParkFallsBackToSnapshot() { let a = inst("https://a.example"), b = inst("https://b.example") let r = NotificationRoute.resolve( threadID: "th1", instances: [a, b], entryOrigin: { _ in nil }, snapshotHasThread: { origin, _ in origin == "https://a.example" }) guard case .snapshot(let hit) = r else { return XCTFail("\(r)") } XCTAssertEqual(hit.origin, a.origin) } func testSingleSpaceAlwaysResolves() { // Nothing recorded anywhere (wiped keychain, brand-new thread): with // one signed-in space the tap still routes there. let a = inst("https://a.example") let r = NotificationRoute.resolve( threadID: "new-thread", instances: [a], entryOrigin: { _ in nil }, snapshotHasThread: { _, _ in false }) guard case .onlySpace(let hit) = r else { return XCTFail("\(r)") } XCTAssertEqual(hit.origin, a.origin) } func testSingleActiveSpaceSkipsArchived() { let live = inst("https://live.example") let parked = inst("https://old.example", archived: true) let r = NotificationRoute.resolve( threadID: "th1", instances: [live, parked], entryOrigin: { _ in nil }, snapshotHasThread: { _, _ in false }) guard case .onlySpace(let hit) = r else { return XCTFail("\(r)") } XCTAssertEqual(hit.origin, live.origin) } func testMultiSpaceUnknownThreadStaysUnresolved() { let a = inst("https://a.example"), b = inst("https://b.example") let r = NotificationRoute.resolve( threadID: "th1", instances: [a, b], entryOrigin: { _ in nil }, snapshotHasThread: { _, _ in false }) guard case .unresolved = r else { return XCTFail("\(r)") } } }