| 1 | import XCTest |
| 2 | |
| 3 | @testable import CallsKit |
| 4 | |
| 5 | /// The rules about when someone waiting is worth interrupting for. All of |
| 6 | /// them live in KnockWatch precisely so they can be held here, without a |
| 7 | /// notification centre or an app bundle. |
| 8 | final class KnockWatchTests: XCTestCase { |
| 9 | private func peer(_ id: String, _ name: String) -> RosterPeer { |
| 10 | let json = #"{"peer":"\#(id)","name":"\#(name)","kind":"guest","gen":null}"# |
| 11 | return try! JSONDecoder().decode(RosterPeer.self, from: Data(json.utf8)) |
| 12 | } |
| 13 | |
| 14 | @MainActor func testSomeoneArrivingWhileAwayIsAnnouncedExactlyOnce() { |
| 15 | let watch = KnockWatch() |
| 16 | let bea = peer("p1", "Bea") |
| 17 | XCTAssertEqual(watch.arrivals(waiting: [bea], visible: false).map(\.name), ["Bea"]) |
| 18 | // The same roster arriving again is the same person still waiting, |
| 19 | // not a second knock. State events repeat constantly. |
| 20 | XCTAssertTrue(watch.arrivals(waiting: [bea], visible: false).isEmpty) |
| 21 | XCTAssertTrue(watch.arrivals(waiting: [bea], visible: false).isEmpty) |
| 22 | } |
| 23 | |
| 24 | @MainActor func testNobodyIsAnnouncedWhileTheQueueIsOnScreen() { |
| 25 | let watch = KnockWatch() |
| 26 | XCTAssertTrue(watch.arrivals(waiting: [peer("p1", "Bea")], visible: true).isEmpty) |
| 27 | } |
| 28 | |
| 29 | @MainActor func testPeopleWhoArrivedWhileLookingAreNotAnnouncedOnTabbingAway() { |
| 30 | // The rule that makes the feature bearable. Someone watching the call |
| 31 | // sees the queue; tabbing away afterwards must not then produce a |
| 32 | // pile of notifications about people who have been there for a while. |
| 33 | // Only an arrival *during* the absence is news. |
| 34 | let watch = KnockWatch() |
| 35 | let bea = peer("p1", "Bea") |
| 36 | _ = watch.arrivals(waiting: [bea], visible: true) |
| 37 | XCTAssertTrue( |
| 38 | watch.arrivals(waiting: [bea], visible: false).isEmpty, |
| 39 | "someone seen while the app was in front must not be announced later") |
| 40 | let cass = peer("p2", "Cass") |
| 41 | XCTAssertEqual( |
| 42 | watch.arrivals(waiting: [bea, cass], visible: false).map(\.name), ["Cass"], |
| 43 | "the person who arrived while away is the only news") |
| 44 | } |
| 45 | |
| 46 | @MainActor func testLeavingTheQueueAndKnockingAgainIsHeardAgain() { |
| 47 | // Someone let in, or who gave up and came back, is a new knock. A set |
| 48 | // that only ever grew would swallow the second one in silence. |
| 49 | let watch = KnockWatch() |
| 50 | let bea = peer("p1", "Bea") |
| 51 | XCTAssertEqual(watch.arrivals(waiting: [bea], visible: false).count, 1) |
| 52 | XCTAssertTrue(watch.arrivals(waiting: [], visible: false).isEmpty) |
| 53 | XCTAssertEqual( |
| 54 | watch.arrivals(waiting: [bea], visible: false).map(\.name), ["Bea"], |
| 55 | "a second knock from the same person must be heard") |
| 56 | } |
| 57 | |
| 58 | @MainActor func testOnePersonSwappedForAnotherIsStillOneAnnouncement() { |
| 59 | // A count would read this as "still one waiting" and say nothing. The |
| 60 | // set is what makes the swap visible. |
| 61 | let watch = KnockWatch() |
| 62 | _ = watch.arrivals(waiting: [peer("p1", "Bea")], visible: false) |
| 63 | XCTAssertEqual( |
| 64 | watch.arrivals(waiting: [peer("p2", "Cass")], visible: false).map(\.name), ["Cass"]) |
| 65 | } |
| 66 | |
| 67 | @MainActor func testSeveralArrivingAtOnceAreAllAnnounced() { |
| 68 | let watch = KnockWatch() |
| 69 | let names = watch.arrivals( |
| 70 | waiting: [peer("p1", "Bea"), peer("p2", "Cass")], visible: false |
| 71 | ).map(\.name) |
| 72 | XCTAssertEqual(names, ["Bea", "Cass"]) |
| 73 | } |
| 74 | |
| 75 | @MainActor func testEndingACallForgetsItsQueue() { |
| 76 | let watch = KnockWatch() |
| 77 | let bea = peer("p1", "Bea") |
| 78 | _ = watch.arrivals(waiting: [bea], visible: false) |
| 79 | watch.reset() |
| 80 | XCTAssertEqual( |
| 81 | watch.arrivals(waiting: [bea], visible: false).map(\.name), ["Bea"], |
| 82 | "a queue from a finished meeting says nothing about the next one") |
| 83 | } |
| 84 | } |
| 85 | |