Skip to content

Commit

Permalink
Keep delegate method passthrough on same thread, add tests for checki…
Browse files Browse the repository at this point in the history
…ng delegate thread
  • Loading branch information
exPHAT committed Dec 29, 2023
1 parent 826d568 commit f4ad0e2
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,48 @@ class CentralManagerDelegateWrapper: NSObject, CBCentralManagerDelegate {
// MARK: - CBCentralManagerDelegate conformance
func centralManagerDidUpdateState(_ central: CBCentralManager) {
guard let parent = self.parent else { return }

parent.delegate?.centralManagerDidUpdateState(parent)

parent.eventQueue.async {
parent.eventSubscriptions.recieve(.stateUpdated(parent.state))
parent.delegate?.centralManagerDidUpdateState(parent)
}
}

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
guard let parent = parent else { return }
let peripheral = parent.peripheral(peripheral)

parent.connectedPeripherals.insert(peripheral)
parent.delegate?.centralManager(parent, didConnect: peripheral)

parent.eventQueue.async {
parent.connectedPeripherals.insert(peripheral)
parent.eventSubscriptions.recieve(.connected(peripheral))
parent.delegate?.centralManager(parent, didConnect: peripheral)
}
}

func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
guard let parent = parent else { return }
let peripheral = parent.peripheral(peripheral)

parent.connectedPeripherals.remove(peripheral)
parent.delegate?.centralManager(parent, didDisconnectPeripheral: peripheral, error: error)
parent.removePeripheral(peripheral.cbPeripheral)

parent.eventQueue.async {
parent.connectedPeripherals.remove(peripheral)
parent.eventSubscriptions.recieve(.disconnected(peripheral, error))
peripheral.eventSubscriptions.recieve(.didDisconnect(error))
parent.delegate?.centralManager(parent, didDisconnectPeripheral: peripheral, error: error)

parent.removePeripheral(peripheral.cbPeripheral)
}
}

func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
guard let parent = parent else { return }
let peripheral = parent.peripheral(peripheral)

parent.delegate?.centralManager(parent, didFailToConnect: peripheral, error: error)

parent.eventQueue.async {
parent.eventSubscriptions.recieve(.failToConnect(peripheral, error))
parent.delegate?.centralManager(parent, didFailToConnect: peripheral, error: error)
}
}

Expand All @@ -57,18 +61,20 @@ class CentralManagerDelegateWrapper: NSObject, CBCentralManagerDelegate {
let peripheral = parent.peripheral(peripheral)
peripheral.discovery = .init(rssi: RSSI, advertisementData: advertisementData)

parent.delegate?.centralManager(parent, didDiscover: peripheral, advertisementData: advertisementData, rssi: RSSI)

Check warning on line 64 in Sources/SwiftBluetooth/CentralManager/CentralManagerDelegateWrapper.swift

View workflow job for this annotation

GitHub Actions / lint

Line Length Violation: Line should be 120 characters or less; currently it has 122 characters (line_length)

parent.eventQueue.async {
parent.eventSubscriptions.recieve(.discovered(peripheral, advertisementData, RSSI))
parent.delegate?.centralManager(parent, didDiscover: peripheral, advertisementData: advertisementData, rssi: RSSI)
}
}

func centralManager(_ central: CBCentralManager, willRestoreState dict: [String: Any]) {
guard let parent = parent else { return }

parent.delegate?.centralManager(parent, willRestoreState: dict)

parent.eventQueue.async {
parent.eventSubscriptions.recieve(.restoreState(dict))
parent.delegate?.centralManager(parent, willRestoreState: dict)
}
}

Expand All @@ -77,18 +83,14 @@ class CentralManagerDelegateWrapper: NSObject, CBCentralManagerDelegate {
guard let parent = parent else { return }
let peripheral = parent.peripheral(peripheral)

parent.eventQueue.async {
parent.delegate?.centralManager(parent, connectionEventDidOccur: event, for: peripheral)
}
parent.delegate?.centralManager(parent, connectionEventDidOccur: event, for: peripheral)
}

func centralManager(_ central: CBCentralManager, didUpdateANCSAuthorizationFor peripheral: CBPeripheral) {
guard let parent = parent else { return }
let peripheral = parent.peripheral(peripheral)

parent.eventQueue.async {
parent.delegate?.centralManager(parent, didUpdateANCSAuthorizationFor: peripheral)
}
parent.delegate?.centralManager(parent, didUpdateANCSAuthorizationFor: peripheral)
}
#endif
}
105 changes: 103 additions & 2 deletions Tests/SwiftBluetoothTests/CentralPeripheralTestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,112 @@ import XCTest
@testable import CoreBluetoothMock
@testable import SwiftBluetoothMock

fileprivate final class CentralManagerDelegateThreadChecker: CentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CentralManager) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, didConnect peripheral: Peripheral) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, didDisconnectPeripheral peripheral: Peripheral, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, didFailToConnect peripheral: Peripheral, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, connectionEventDidOccur event: CBConnectionEvent, for peripheral: Peripheral) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, didDiscover peripheral: Peripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, willRestoreState dict: [String: Any]) {
XCTAssert(Thread.isMainThread)
}

func centralManager(_ central: CentralManager, didUpdateANCSAuthorizationFor peripheral: Peripheral) {
XCTAssert(Thread.isMainThread)
}
}

fileprivate final class PeripheralDelegateThreadChecker: PeripheralDelegate {
func peripheral(_ peripheral: Peripheral, didDiscoverServices error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didDiscoverIncludedServicesFor service: CBService, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didModifyServices services: [CBService]) {
XCTAssert(Thread.isMainThread)
}

func peripheral(_ peripheral: Peripheral, didOpen channel: CBL2CAPChannel?, error: Error?) {
XCTAssert(Thread.isMainThread)
}

func peripheralDidUpdateName(_ peripheral: Peripheral) {
XCTAssert(Thread.isMainThread)
}
}

class CentralPeripheralTestCase: XCTestCase {
let connectionTimeout: TimeInterval = 2

var central: CentralManager!
var peripheral: Peripheral!
private let centralDelegate = CentralManagerDelegateThreadChecker()
private let peripheralDelegate = PeripheralDelegateThreadChecker()

var central: CentralManager! {
didSet {
guard let central else { return }
central.delegate = centralDelegate
}
}
var peripheral: Peripheral! {
didSet {
guard let peripheral else { return }
peripheral.delegate = peripheralDelegate
}
}

override func setUp() {
mockPeripheral.connectionDelegate?.reset()
Expand Down

0 comments on commit f4ad0e2

Please sign in to comment.