| 1 | #if os(macOS) |
| 2 | import XCTest |
| 3 | @testable import RastrilloMacUpdates |
| 4 | |
| 5 | final class QuietUpdateRulesTests: XCTestCase { |
| 6 | func testBusyDefersOnlyScheduledChecksAndRunsThemWhenIdle() { |
| 7 | var rules = QuietUpdateRules() |
| 8 | XCTAssertTrue(rules.mayPerform(.background)) |
| 9 | XCTAssertFalse(rules.setBusy(true)) |
| 10 | XCTAssertFalse(rules.mayPerform(.background)) |
| 11 | // Asked for by the person: never held back. |
| 12 | XCTAssertTrue(rules.mayPerform(.userInitiated)) |
| 13 | XCTAssertTrue(rules.mayPerform(.information)) |
| 14 | XCTAssertTrue(rules.setBusy(false), "the declined check runs when the call ends") |
| 15 | XCTAssertFalse(rules.setBusy(true)) |
| 16 | XCTAssertFalse(rules.setBusy(false), "and only once") |
| 17 | } |
| 18 | |
| 19 | func testNoDeferredCheckWhenNothingWasDeclined() { |
| 20 | var rules = QuietUpdateRules() |
| 21 | _ = rules.setBusy(true) |
| 22 | XCTAssertTrue(rules.mayPerform(.userInitiated)) |
| 23 | XCTAssertFalse(rules.setBusy(false)) |
| 24 | } |
| 25 | |
| 26 | func testStagedUpdateIsReadyButNotActionableWhileBusy() { |
| 27 | var rules = QuietUpdateRules() |
| 28 | XCTAssertFalse(rules.canInstall) |
| 29 | rules.staged(version: "0.3.5") |
| 30 | XCTAssertEqual(rules.pending, .ready(version: "0.3.5")) |
| 31 | XCTAssertTrue(rules.canInstall) |
| 32 | _ = rules.setBusy(true) |
| 33 | XCTAssertEqual(rules.pending, .ready(version: "0.3.5"), "busy hides the action, not the fact") |
| 34 | XCTAssertFalse(rules.canInstall) |
| 35 | _ = rules.setBusy(false) |
| 36 | XCTAssertTrue(rules.canInstall) |
| 37 | rules.clear() |
| 38 | XCTAssertEqual(rules.pending, .none) |
| 39 | XCTAssertFalse(rules.canInstall) |
| 40 | } |
| 41 | |
| 42 | func testGentleReminderDistinguishesDownloadedFromAvailable() { |
| 43 | var rules = QuietUpdateRules() |
| 44 | rules.found(version: "0.3.5", downloaded: false) |
| 45 | XCTAssertEqual(rules.pending, .available(version: "0.3.5")) |
| 46 | rules.found(version: "0.3.5", downloaded: true) |
| 47 | XCTAssertEqual(rules.pending, .ready(version: "0.3.5")) |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | @MainActor final class QuietUpdaterTests: XCTestCase { |
| 52 | /// Sparkle finds its optional delegate methods by selector. A Swift signature |
| 53 | /// that drifts from the header compiles without a word and turns quiet updates |
| 54 | /// back into Sparkle's alerts. |
| 55 | func testDelegateAnswersSparklesSelectors() { |
| 56 | let delegate = QuietUpdateDelegate() |
| 57 | for selector in [ |
| 58 | "updater:mayPerformUpdateCheck:error:", |
| 59 | "updater:willInstallUpdateOnQuit:immediateInstallationBlock:", |
| 60 | "updater:didFinishUpdateCycleForUpdateCheck:error:", |
| 61 | "supportsGentleScheduledUpdateReminders", |
| 62 | "standardUserDriverShouldHandleShowingScheduledUpdate:andInImmediateFocus:", |
| 63 | "standardUserDriverWillHandleShowingUpdate:forUpdate:state:", |
| 64 | "standardUserDriverDidReceiveUserAttentionForUpdate:", |
| 65 | "standardUserDriverWillFinishUpdateSession", |
| 66 | ] { |
| 67 | XCTAssertTrue(delegate.responds(to: NSSelectorFromString(selector)), selector) |
| 68 | } |
| 69 | XCTAssertTrue(delegate.supportsGentleScheduledUpdateReminders) |
| 70 | } |
| 71 | |
| 72 | func testQuietUpdaterDefersAndReplaysScheduledCheck() { |
| 73 | let updater = NativeUpdater(policy: .quiet) |
| 74 | var replayed = 0 |
| 75 | updater.runDeferredCheck = { replayed += 1 } |
| 76 | updater.isBusy = true |
| 77 | XCTAssertFalse(updater.mayPerform(.background)) |
| 78 | XCTAssertTrue(updater.mayPerform(.userInitiated)) |
| 79 | XCTAssertEqual(replayed, 0) |
| 80 | updater.isBusy = false |
| 81 | XCTAssertEqual(replayed, 1) |
| 82 | } |
| 83 | |
| 84 | func testStandardUpdaterNeverDefers() { |
| 85 | let updater = NativeUpdater() |
| 86 | XCTAssertEqual(updater.policy, .standard) |
| 87 | updater.isBusy = true |
| 88 | XCTAssertTrue(updater.mayPerform(.background)) |
| 89 | } |
| 90 | |
| 91 | func testRestartWaitsForIdleAndUsesSparklesInstallBlock() { |
| 92 | let updater = NativeUpdater(policy: .quiet) |
| 93 | var installs = 0 |
| 94 | updater.isBusy = true |
| 95 | updater.staged(version: "0.3.5") { installs += 1 } |
| 96 | XCTAssertEqual(updater.pendingUpdate, .ready(version: "0.3.5")) |
| 97 | XCTAssertFalse(updater.canInstallPendingUpdate) |
| 98 | updater.installPendingUpdate() |
| 99 | XCTAssertEqual(installs, 0, "never relaunch during a call") |
| 100 | updater.isBusy = false |
| 101 | XCTAssertTrue(updater.canInstallPendingUpdate) |
| 102 | updater.installPendingUpdate() |
| 103 | XCTAssertEqual(installs, 1) |
| 104 | } |
| 105 | |
| 106 | func testEndedSessionDropsNoticeAndInstallBlock() { |
| 107 | let updater = NativeUpdater(policy: .quiet) |
| 108 | var installs = 0 |
| 109 | updater.staged(version: "0.3.5") { installs += 1 } |
| 110 | updater.sessionEnded() |
| 111 | XCTAssertEqual(updater.pendingUpdate, .none) |
| 112 | updater.installPendingUpdate() |
| 113 | XCTAssertEqual(installs, 0) |
| 114 | } |
| 115 | |
| 116 | func testUnconfiguredBundleCannotTurnOnAutomaticInstalls() { |
| 117 | let updater = NativeUpdater(policy: .quiet) |
| 118 | XCTAssertFalse(updater.canInstallUpdatesAutomatically) |
| 119 | updater.automaticallyInstallsUpdates = true |
| 120 | XCTAssertFalse(updater.automaticallyInstallsUpdates) |
| 121 | } |
| 122 | } |
| 123 | #endif |
| 124 | |