mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 03:45:21 +00:00
Isolate nearby notes settings in tests
This commit is contained in:
@@ -33,15 +33,25 @@ final class NearbyNotesCounter: ObservableObject {
|
||||
private let locationManager: LocationChannelManager
|
||||
private let managerFactory: @MainActor (String) -> LocationNotesManager
|
||||
private let releaseManager: @MainActor (LocationNotesManager?) -> Void
|
||||
private let locationNotesEnabled: @MainActor () -> Bool
|
||||
private let locationNotesSettingsPublisher: AnyPublisher<Void, Never>
|
||||
|
||||
init(
|
||||
locationManager: LocationChannelManager = .shared,
|
||||
managerFactory: @escaping @MainActor (String) -> LocationNotesManager = { LocationNotesPool.shared.acquire($0) },
|
||||
releaseManager: @escaping @MainActor (LocationNotesManager?) -> Void = { LocationNotesPool.shared.release($0) }
|
||||
releaseManager: @escaping @MainActor (LocationNotesManager?) -> Void = { LocationNotesPool.shared.release($0) },
|
||||
locationNotesEnabled: @escaping @MainActor () -> Bool = { LocationNotesSettings.enabled },
|
||||
locationNotesSettings: AnyPublisher<Void, Never>? = nil
|
||||
) {
|
||||
self.locationManager = locationManager
|
||||
self.managerFactory = managerFactory
|
||||
self.releaseManager = releaseManager
|
||||
self.locationNotesEnabled = locationNotesEnabled
|
||||
self.locationNotesSettingsPublisher = locationNotesSettings
|
||||
?? NotificationCenter.default
|
||||
.publisher(for: LocationNotesSettings.didChangeNotification)
|
||||
.map { _ in () }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Whether the empty-timeline "check for notes" hint should render.
|
||||
@@ -53,7 +63,7 @@ final class NearbyNotesCounter: ObservableObject {
|
||||
/// passes its own observed permission state so the hint re-renders when
|
||||
/// authorization changes.
|
||||
func offersRevealHint(permissionState: LocationChannelManager.PermissionState) -> Bool {
|
||||
!revealed && LocationNotesSettings.enabled && permissionState == .authorized
|
||||
!revealed && locationNotesEnabled() && permissionState == .authorized
|
||||
}
|
||||
|
||||
/// Marks the one explicit act that lets the counter subscribe. Sticky for
|
||||
@@ -83,8 +93,7 @@ final class NearbyNotesCounter: ObservableObject {
|
||||
.sink { [weak self] _ in self?.retarget() }
|
||||
// The app-info kill switch must take effect immediately, not on the
|
||||
// next location change or remount.
|
||||
settingCancellable = NotificationCenter.default
|
||||
.publisher(for: LocationNotesSettings.didChangeNotification)
|
||||
settingCancellable = locationNotesSettingsPublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.retarget() }
|
||||
retarget()
|
||||
@@ -105,7 +114,7 @@ final class NearbyNotesCounter: ObservableObject {
|
||||
private func retarget() {
|
||||
guard activeHolders > 0,
|
||||
revealed,
|
||||
LocationNotesSettings.enabled,
|
||||
locationNotesEnabled(),
|
||||
locationManager.permissionState == .authorized,
|
||||
let geohash = locationManager.availableChannels
|
||||
.first(where: { $0.level == .building })?.geohash
|
||||
|
||||
@@ -8,25 +8,9 @@ import XCTest
|
||||
/// the pooled subscription must come up exactly once and go down exactly once.
|
||||
@MainActor
|
||||
final class NearbyNotesCounterTests: XCTestCase {
|
||||
private var previousNotesEnabled: Any?
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
previousNotesEnabled = UserDefaults.standard.object(forKey: "locationNotes.enabled")
|
||||
UserDefaults.standard.set(true, forKey: "locationNotes.enabled")
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
if let previous = previousNotesEnabled as? Bool {
|
||||
UserDefaults.standard.set(previous, forKey: "locationNotes.enabled")
|
||||
} else {
|
||||
UserDefaults.standard.removeObject(forKey: "locationNotes.enabled")
|
||||
}
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func test_counterOnlySubscribesAfterReveal_countsUnexpiredNotes_andUnsubscribesOnDeactivate() async throws {
|
||||
let relays = SubscriptionRecorder()
|
||||
let settings = LocationNotesSettingsStub()
|
||||
let locationManager = try await makeAuthorizedLocationManager()
|
||||
let buildingGeohash = try XCTUnwrap(
|
||||
locationManager.availableChannels.first(where: { $0.level == .building })?.geohash
|
||||
@@ -35,7 +19,9 @@ final class NearbyNotesCounterTests: XCTestCase {
|
||||
let counter = NearbyNotesCounter(
|
||||
locationManager: locationManager,
|
||||
managerFactory: { LocationNotesManager(geohash: $0, dependencies: relays.dependencies) },
|
||||
releaseManager: { $0?.cancel() }
|
||||
releaseManager: { $0?.cancel() },
|
||||
locationNotesEnabled: { settings.enabled },
|
||||
locationNotesSettings: settings.changes
|
||||
)
|
||||
|
||||
counter.activate()
|
||||
@@ -93,11 +79,14 @@ final class NearbyNotesCounterTests: XCTestCase {
|
||||
|
||||
func test_permissionRevocation_releasesBuildingSubscriptionDespiteCachedChannels() async throws {
|
||||
let relays = SubscriptionRecorder()
|
||||
let settings = LocationNotesSettingsStub()
|
||||
let locationManager = try await makeAuthorizedLocationManager()
|
||||
let counter = NearbyNotesCounter(
|
||||
locationManager: locationManager,
|
||||
managerFactory: { LocationNotesManager(geohash: $0, dependencies: relays.dependencies) },
|
||||
releaseManager: { $0?.cancel() }
|
||||
releaseManager: { $0?.cancel() },
|
||||
locationNotesEnabled: { settings.enabled },
|
||||
locationNotesSettings: settings.changes
|
||||
)
|
||||
|
||||
counter.activate()
|
||||
@@ -122,24 +111,27 @@ final class NearbyNotesCounterTests: XCTestCase {
|
||||
|
||||
func test_locationNotesKillSwitch_releasesAndCanReacquireBuildingSubscription() async throws {
|
||||
let relays = SubscriptionRecorder()
|
||||
let settings = LocationNotesSettingsStub()
|
||||
let locationManager = try await makeAuthorizedLocationManager()
|
||||
let counter = NearbyNotesCounter(
|
||||
locationManager: locationManager,
|
||||
managerFactory: { LocationNotesManager(geohash: $0, dependencies: relays.dependencies) },
|
||||
releaseManager: { $0?.cancel() }
|
||||
releaseManager: { $0?.cancel() },
|
||||
locationNotesEnabled: { settings.enabled },
|
||||
locationNotesSettings: settings.changes
|
||||
)
|
||||
|
||||
counter.activate()
|
||||
counter.reveal()
|
||||
XCTAssertEqual(relays.subscribeCount, 1)
|
||||
|
||||
LocationNotesSettings.enabled = false
|
||||
settings.setEnabled(false)
|
||||
|
||||
let released = await waitUntil { relays.unsubscribeCount == 1 }
|
||||
XCTAssertTrue(released)
|
||||
XCTAssertEqual(counter.noteCount, 0)
|
||||
|
||||
LocationNotesSettings.enabled = true
|
||||
settings.setEnabled(true)
|
||||
|
||||
let reacquired = await waitUntil { relays.subscribeCount == 2 }
|
||||
XCTAssertTrue(reacquired)
|
||||
@@ -149,10 +141,13 @@ final class NearbyNotesCounterTests: XCTestCase {
|
||||
|
||||
func test_checkNotesHint_requiresAuthorizedLocationPermission() {
|
||||
let relays = SubscriptionRecorder()
|
||||
let settings = LocationNotesSettingsStub()
|
||||
let counter = NearbyNotesCounter(
|
||||
locationManager: makeBareLocationManager(),
|
||||
managerFactory: { LocationNotesManager(geohash: $0, dependencies: relays.dependencies) },
|
||||
releaseManager: { $0?.cancel() }
|
||||
releaseManager: { $0?.cancel() },
|
||||
locationNotesEnabled: { settings.enabled },
|
||||
locationNotesSettings: settings.changes
|
||||
)
|
||||
|
||||
// An unauthorized install must never see the hint: the tap can't
|
||||
@@ -164,9 +159,9 @@ final class NearbyNotesCounterTests: XCTestCase {
|
||||
XCTAssertTrue(counter.offersRevealHint(permissionState: .authorized))
|
||||
|
||||
// The app-info kill switch hides it too.
|
||||
LocationNotesSettings.enabled = false
|
||||
settings.setEnabled(false)
|
||||
XCTAssertFalse(counter.offersRevealHint(permissionState: .authorized))
|
||||
LocationNotesSettings.enabled = true
|
||||
settings.setEnabled(true)
|
||||
|
||||
// Once revealed, the hint yields to the live strip and count.
|
||||
counter.reveal()
|
||||
@@ -411,6 +406,21 @@ final class NearbyNotesCounterTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private final class LocationNotesSettingsStub {
|
||||
private let changesSubject = PassthroughSubject<Void, Never>()
|
||||
private(set) var enabled = true
|
||||
|
||||
var changes: AnyPublisher<Void, Never> {
|
||||
changesSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func setEnabled(_ enabled: Bool) {
|
||||
self.enabled = enabled
|
||||
changesSubject.send(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Stub relay layer: counts REQs, captures the last filter/handler, and never
|
||||
/// touches the network.
|
||||
@MainActor
|
||||
|
||||
Reference in New Issue
Block a user