FakeReachability

@ObjCName(name = "ReachableFakeReachability", swiftName = "FakeReachability")
class FakeReachability(initial: ReachabilityStatus = ReachabilityStatus.Unknown) : StateFlowReachability

Scriptable fake Reachability for tests.

Drives status / reachable / dataMetered through the same StateFlowReachability base class as the production Apple / Android implementations, so tests exercise the same conflation and close-after-emit semantics consumers see in production.

Driving state

val fake = FakeReachability(
initial = ReachabilityStatus(
isReachable = true,
transport = Transport.Wifi,
isDataMetered = false,
),
)
fake.emit(ReachabilityStatus.Unknown)
fake.setReachable(false)
fake.setTransport(Transport.Cellular)
fake.setDataMetered(true)

The convenience setters compose with the current value — setReachable(false) leaves transport and isDataMetered alone. They publish via the same internal publish path so StateFlow conflation rules apply.

Observing close

Unlike the production singleton (which is wrapped in NonClosingReachability and no-ops close()), this fake honours close() and counts every call. Tests can assert assertEquals(0, fake.closeCallCount) to verify the unit under test does not try to close Reachability.shared, or assert a positive count to verify a use { } block did teardown properly.

Installing as Reachability.shared

Use withFakeReachability — it constructs a fake, installs it as the shared singleton via Reachability.installForTesting, runs your test block, then uninstalls and closes the fake in finally.

Renames cleanly across the Swift bridge: in Swift the class reads as FakeReachability, with emit(status:), setReachable(_:), setTransport(_:), setDataMetered(_:), reset(), closeCallCount, wasClosed.

Parameters

initial

Seed ReachabilityStatus. Defaults to ReachabilityStatus.Unknown to match the production StateFlow seed — supplying any other value publishes it during construction so that late-joining collectors immediately observe it instead of seeing Unknown → initial.

Constructors

Link copied to clipboard
constructor(initial: ReachabilityStatus = ReachabilityStatus.Unknown)

Properties

Link copied to clipboard

Total number of times close has been invoked on this fake, including redundant ones. The base class collapses repeated closes into a single onClose() (idempotent close-once contract), but the counter is the call count — useful for asserting that callers tried to close at all.

Link copied to clipboard
override val dataMetered: StateFlow<Boolean>
Link copied to clipboard
override val isDataMetered: Boolean
Link copied to clipboard
override val isReachable: Boolean
Link copied to clipboard
override val reachable: StateFlow<Boolean>
Link copied to clipboard
override val status: StateFlow<ReachabilityStatus>
Link copied to clipboard

true once close has been called at least once.

Functions

Link copied to clipboard
override fun close()
Link copied to clipboard
@ObjCName(swiftName = "emit")
fun emit(status: ReachabilityStatus)

Publish status to all collectors of Reachability.status. Public counterpart to the protected base-class publish; the rename on the base class (emit → publish) is what lets the fake expose the natural emit(...) driver name without a visibility-widening collision.

Link copied to clipboard
fun reset()

Reset to ReachabilityStatus.Unknown. Useful between assertion blocks.

Link copied to clipboard
@ObjCName(name = "setDataMetered")
fun setDataMetered(isDataMetered: Boolean)

Flip the data-metered boolean; keep reachable and transport. Equivalent to emit(status.value.copy(isDataMetered = isDataMetered)).

Link copied to clipboard
@ObjCName(name = "setReachable")
fun setReachable(isReachable: Boolean)

Flip the reachable boolean; keep current transport and metering. Equivalent to emit(status.value.copy(isReachable = isReachable)).

Link copied to clipboard
@ObjCName(name = "setTransport")
fun setTransport(transport: Transport)

Swap transport; keep reachable and metering. Equivalent to emit(status.value.copy(transport = transport)).