Skip to content

Commit

Permalink
[Feature] Add BluetoothError error reasons (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
litso authored Dec 27, 2023
1 parent 857df0f commit 9ed2461
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
9 changes: 8 additions & 1 deletion Sources/Peripheral/BluetoothError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@

import Foundation

public enum BluetoothUnavailableReason {
case poweredOff
case unauthorized
case unsupported
case unknown
}

public enum BluetoothError: Error {
case bluetoothUnavailable
case bluetoothUnavailable(BluetoothUnavailableReason)
case connectingInProgress
case disconnectingInProgress
case cancelledConnectionToPeripheral
Expand Down
34 changes: 19 additions & 15 deletions Sources/Utils/CentralManagerUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,32 @@ struct CentralManagerUtils {
/// - Returns: success when `poweredOn`; failure when `unsupported`, `unauthorized` or `poweredOff`; and
/// nil for `unknown` or `resetting`.
static func isBluetoothReady(_ bluetoothState: CBManagerState) -> Result<Void, Error>? {
guard let isBluetoothReady: Bool = Self.isBluetoothReady(bluetoothState) else {
guard bluetoothState != .poweredOn else {
return .success(())
}

guard let reason = BluetoothUnavailableReason(bluetoothState) else {
return nil
}
return isBluetoothReady
? .success(())
: .failure(BluetoothError.bluetoothUnavailable)

return .failure(BluetoothError.bluetoothUnavailable(reason))
}

/// Whether Bluetooth is ready to be used or not given a bluetoothState.
/// - Returns: true when `poweredOn`; false when `unsupported`, `unauthorized` or `poweredOff`; and
/// nil for `unknown` or `resetting`.
private static func isBluetoothReady(_ bluetoothState: CBManagerState) -> Bool? {
}

private extension BluetoothUnavailableReason {
init?(_ bluetoothState: CBManagerState) {
switch bluetoothState {
case .poweredOn:
return true
case .unsupported, .unauthorized, .poweredOff:
return false
case .unknown, .resetting:
case .unauthorized:
self = .unauthorized
case .unsupported:
self = .unsupported
case .poweredOff:
self = .poweredOff
case .poweredOn, .unknown, .resetting:
return nil
@unknown default:
AsyncBluetooth.commonLogger.error("Unsupported CBManagerState received with raw value of \(bluetoothState.rawValue)")
return false
self = .unknown
}
}
}
45 changes: 45 additions & 0 deletions Tests/CentralManagerUtilsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Foundation
import XCTest
@testable import AsyncBluetooth

class CentralManagerUtilsTests: XCTestCase {
func testIsBluetoothReady() throws {
XCTAssertNotNil(
try CentralManagerUtils.isBluetoothReady(.poweredOn)?.get()
)

XCTAssertNil(CentralManagerUtils.isBluetoothReady(.resetting))

XCTAssertEqual(
CentralManagerUtils.isBluetoothReady(.poweredOff)?.error?.extractReason,
.poweredOff
)

XCTAssertEqual(
CentralManagerUtils.isBluetoothReady(.unauthorized)?.error?.extractReason,
.unauthorized
)
}
}

private extension Result<(), Error> {
var error: Error? {
switch self {
case .success: return nil
case .failure(let error): return error
}
}
}

private extension Error {
var extractReason: BluetoothUnavailableReason? {
guard let error = self as? BluetoothError else {
return nil
}

switch error {
case .bluetoothUnavailable(let reason): return reason
default: return nil
}
}
}

0 comments on commit 9ed2461

Please sign in to comment.