| 1 | import Foundation |
| 2 | import RastrilloNative |
| 3 | import XCTest |
| 4 | |
| 5 | private func summary(_ lanes: [String: (pending: Int, held: Int, inFlight: Int)], hold: Hold.Reason? = nil) -> OutboxSummary { |
| 6 | var summary = OutboxSummary() |
| 7 | for (name, counts) in lanes { |
| 8 | var lane = OutboxSummary.Lane() |
| 9 | lane.pending = counts.pending; lane.held = counts.held; lane.inFlight = counts.inFlight |
| 10 | if counts.held > 0 { lane.firstHold = hold ?? .accessLost } |
| 11 | summary.lanes[name] = lane |
| 12 | } |
| 13 | return summary |
| 14 | } |
| 15 | |
| 16 | final class SyncStatusTests: XCTestCase { |
| 17 | func testPriorityOrder() { |
| 18 | let pending = summary(["doc:a": (2, 0, 0), "doc:b": (1, 0, 0)]) |
| 19 | let held = summary(["doc:a": (1, 1, 0)], hold: .tooLarge) |
| 20 | let flying = summary(["doc:a": (2, 0, 1)]) |
| 21 | |
| 22 | // 1. A hold beats everything, even an ended session. |
| 23 | XCTAssertEqual(SyncStatus(summary: held, sending: true, sessionEnded: true, offline: true, backingOff: true), |
| 24 | .failed(pending: 1, reason: .held(.tooLarge))) |
| 25 | // A local failure is failed too. |
| 26 | XCTAssertEqual(SyncStatus(summary: pending, sending: false, sessionEnded: false, offline: false, backingOff: false, localFailure: .cannotSaveOnDevice), |
| 27 | .failed(pending: 2, reason: .cannotSaveOnDevice)) |
| 28 | // 2. Session ended. |
| 29 | XCTAssertEqual(SyncStatus(summary: pending, sending: false, sessionEnded: true, offline: true, backingOff: true), .needsSignIn(pending: 2)) |
| 30 | // 3. Nothing to send. |
| 31 | XCTAssertEqual(SyncStatus(summary: OutboxSummary(), sending: false, sessionEnded: false, offline: false, backingOff: false), .saved) |
| 32 | // 4. In flight. |
| 33 | XCTAssertEqual(SyncStatus(summary: flying, sending: true, sessionEnded: false, offline: true, backingOff: false), .saving) |
| 34 | // 5. Offline. |
| 35 | XCTAssertEqual(SyncStatus(summary: pending, sending: false, sessionEnded: false, offline: true, backingOff: true), .offline(pending: 2)) |
| 36 | // 6. Backing off. |
| 37 | XCTAssertEqual(SyncStatus(summary: pending, sending: false, sessionEnded: false, offline: false, backingOff: true), .retrying(pending: 2)) |
| 38 | // Sendable, online, not yet started: about to save, never "saved". |
| 39 | XCTAssertEqual(SyncStatus(summary: pending, sending: false, sessionEnded: false, offline: false, backingOff: false), .saving) |
| 40 | } |
| 41 | |
| 42 | func testOfflineWithNothingPendingIsSilentlySaved() { |
| 43 | let status = SyncStatus(summary: OutboxSummary(), sending: false, sessionEnded: false, offline: true, backingOff: false) |
| 44 | XCTAssertEqual(status, .saved, "\"Offline · 0 pending\" must never appear") |
| 45 | XCTAssertEqual(SyncStatus(summary: OutboxSummary(), sending: false, sessionEnded: true, offline: true, backingOff: false), .needsSignIn(pending: 0), |
| 46 | "Session-ended has priority over an empty outbox (spec 3.4)") |
| 47 | } |
| 48 | |
| 49 | func testNCountsLanesByDefaultAndWhatTheAppChooses() { |
| 50 | let lanes = summary(["doc:a": (5, 0, 0), "doc:b": (1, 0, 0)]) |
| 51 | XCTAssertEqual(SyncStatus(summary: lanes, sending: false, sessionEnded: false, offline: true, backingOff: false), .offline(pending: 2)) |
| 52 | XCTAssertEqual(SyncStatus(summary: lanes, sending: false, sessionEnded: false, offline: true, backingOff: false, count: { $0.pending }), |
| 53 | .offline(pending: 6)) |
| 54 | } |
| 55 | |
| 56 | func testSaveStateMappingStickinessAndAnnouncements() { |
| 57 | XCTAssertEqual(SyncStatus.saved.saveState, .saved) |
| 58 | XCTAssertEqual(SyncStatus.saving.saveState, .saving) |
| 59 | XCTAssertEqual(SyncStatus.offline(pending: 1).saveState, .retrying, "The Slides precedent: offline is retrying") |
| 60 | XCTAssertEqual(SyncStatus.retrying(pending: 1).saveState, .retrying) |
| 61 | XCTAssertEqual(SyncStatus.needsSignIn(pending: 1).saveState, .failed) |
| 62 | XCTAssertEqual(SyncStatus.failed(pending: 1, reason: .tooManyUnsent).saveState, .failed) |
| 63 | XCTAssertTrue(SyncStatus.needsSignIn(pending: 1).isSticky) |
| 64 | XCTAssertTrue(SyncStatus.failed(pending: 1, reason: .cannotSaveOnDevice).isSticky) |
| 65 | XCTAssertFalse(SyncStatus.offline(pending: 1).isSticky) |
| 66 | XCTAssertFalse(SyncStatus.saving.isAnnounced, "A saving flicker is never announced") |
| 67 | XCTAssertTrue(SyncStatus.offline(pending: 1).isAnnounced) |
| 68 | XCTAssertTrue(SyncStatus.needsSignIn(pending: 1).isAnnounced) |
| 69 | XCTAssertTrue(SyncStatus.failed(pending: 1, reason: .tooManyUnsent).isAnnounced) |
| 70 | } |
| 71 | } |
| 72 | |