Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,25 @@ let package = Package(
.macOS(.v10_15), .iOS(.v13),
],
products: [
.library(name: "BLECombineKit", targets: ["BLECombineKit"])
.library(name: "BLECombineKit", targets: ["BLECombineKit"]),
.library(name: "BLECombineKitMocks", targets: ["BLECombineKitMocks"]),
],
targets: [
.target(
name: "BLECombineKit",
dependencies: [],
path: "Sources/BLECombineKit"
),
.target(
name: "BLECombineKitMocks",
dependencies: ["BLECombineKit"],
path: "Sources/BLECombineKitMocks"
),
.testTarget(
name: "BLECombineKitTests",
dependencies: [
"BLECombineKit"
"BLECombineKit",
"BLECombineKitMocks",
],
path: "Tests"
),
Expand Down
167 changes: 167 additions & 0 deletions Sources/BLECombineKitMocks/MockBLECentralManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//
// MockBLECentralManager.swift
// BLECombineKitMocks
//
// Created by Henry Javier Serrano Echeverria on 10/1/26.
//

import BLECombineKit
import Combine
import CoreBluetooth
import Foundation

/// A mock implementation of `BLECentralManager` for testing purposes.
open class MockBLECentralManager: BLECentralManager, @unchecked Sendable {

public init() {}

/// Subject to control the state of the central manager.
public var stateSubject = CurrentValueSubject<CBManagerState, Never>(.unknown)

/// Publisher for the state of the central manager.
public var state: AnyPublisher<CBManagerState, Never> {
stateSubject.eraseToAnyPublisher()
}

/// The associated central manager wrapper.
public var associatedCentralManager: CBCentralManagerWrapper = MockCBCentralManagerWrapper()

/// Flag to control the `isScanning` property.
public var isScanningValue: Bool = false
public var isScanning: Bool {
isScanningValue
}

/// Return value for `retrievePeripherals(withIdentifiers:)`.
public var retrievePeripheralsReturnValue: AnyPublisher<BLEPeripheral, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `retrievePeripherals(withIdentifiers:)` was called.
public var retrievePeripheralsWasCalledCount = 0
/// The identifiers passed to the last call of `retrievePeripherals(withIdentifiers:)`.
public var retrievePeripheralsIdentifiers = [UUID]()

/// Mocks the retrieval of peripherals with specified identifiers.
public func retrievePeripherals(withIdentifiers identifiers: [UUID]) -> AnyPublisher<
BLEPeripheral, BLEError
> {
retrievePeripheralsWasCalledCount += 1
retrievePeripheralsIdentifiers = identifiers
return retrievePeripheralsReturnValue
}

/// Return value for `retrieveConnectedPeripherals(withServices:)`.
public var retrieveConnectedPeripheralsReturnValue: AnyPublisher<BLEPeripheral, BLEError> =
Empty().eraseToAnyPublisher()
/// Count of how many times `retrieveConnectedPeripherals(withServices:)` was called.
public var retrieveConnectedPeripheralsWasCalledCount = 0
/// The service UUIDs passed to the last call of `retrieveConnectedPeripherals(withServices:)`.
public var retrieveConnectedPeripheralsServiceUUIDs = [CBUUID]()

/// Mocks the retrieval of connected peripherals with specified service UUIDs.
public func retrieveConnectedPeripherals(withServices serviceUUIDs: [CBUUID]) -> AnyPublisher<
BLEPeripheral, BLEError
> {
retrieveConnectedPeripheralsWasCalledCount += 1
retrieveConnectedPeripheralsServiceUUIDs = serviceUUIDs
return retrieveConnectedPeripheralsReturnValue
}

/// Return value for `scanForPeripherals(withServices:options:)`.
public var scanForPeripheralsReturnValue: AnyPublisher<BLEScanResult, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `scanForPeripherals(withServices:options:)` was called.
public var scanForPeripheralsWasCalledCount = 0
/// The services passed to the last call of `scanForPeripherals(withServices:options:)`.
public var scanForPeripheralsServices: [CBUUID]?
/// The options passed to the last call of `scanForPeripherals(withServices:options:)`.
public var scanForPeripheralsOptions: [String: Any]?

/// Mocks scanning for peripherals.
public func scanForPeripherals(withServices services: [CBUUID]?, options: [String: Any]?)
-> AnyPublisher<BLEScanResult, BLEError>
{
scanForPeripheralsWasCalledCount += 1
scanForPeripheralsServices = services
scanForPeripheralsOptions = options
return scanForPeripheralsReturnValue
}

/// Count of how many times `stopScan()` was called.
public var stopScanWasCalledCount = 0

/// Mocks stopping the peripheral scan.
public func stopScan() {
stopScanWasCalledCount += 1
}

/// Return value for `connect(peripheral:options:)`.
public var connectReturnValue: AnyPublisher<BLEPeripheral, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `connect(peripheral:options:)` was called.
public var connectWasCalledCount = 0
/// The peripheral passed to the last call of `connect(peripheral:options:)`.
public var connectPeripheral: BLEPeripheral?
/// The options passed to the last call of `connect(peripheral:options:)`.
public var connectOptions: [String: Any]?

/// Mocks connecting to a peripheral.
public func connect(peripheral: BLEPeripheral, options: [String: Any]?) -> AnyPublisher<
BLEPeripheral, BLEError
> {
connectWasCalledCount += 1
connectPeripheral = peripheral
connectOptions = options
return connectReturnValue
}

/// Return value for `cancelPeripheralConnection(_:)`.
public var cancelPeripheralConnectionReturnValue: AnyPublisher<Never, Never> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `cancelPeripheralConnection(_:)` was called.
public var cancelPeripheralConnectionWasCalledCount = 0
/// The peripheral passed to the last call of `cancelPeripheralConnection(_:)`.
public var cancelPeripheralConnectionPeripheral: BLEPeripheral?

/// Mocks cancelling a peripheral connection.
public func cancelPeripheralConnection(_ peripheral: BLEPeripheral) -> AnyPublisher<Never, Never>
{
cancelPeripheralConnectionWasCalledCount += 1
cancelPeripheralConnectionPeripheral = peripheral
return cancelPeripheralConnectionReturnValue
}

/// Count of how many times `registerForConnectionEvents(options:)` was called.
public var registerForConnectionEventsWasCalledCount = 0
/// The options passed to the last call of `registerForConnectionEvents(options:)`.
public var registerForConnectionEventsOptions: [CBConnectionEventMatchingOption: Any]?

/// Mocks registering for connection events.
public func registerForConnectionEvents(options: [CBConnectionEventMatchingOption: Any]?) {
registerForConnectionEventsWasCalledCount += 1
registerForConnectionEventsOptions = options
}

/// Return value for `observeWillRestoreState()`.
public var observeWillRestoreStateReturnValue: AnyPublisher<[String: Any], Never> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `observeWillRestoreState()` was called.
public var observeWillRestoreStateWasCalledCount = 0

/// Mocks observing state restoration.
public func observeWillRestoreState() -> AnyPublisher<[String: Any], Never> {
observeWillRestoreStateWasCalledCount += 1
return observeWillRestoreStateReturnValue
}

/// Return value for `observeDidUpdateANCSAuthorization()`.
public var observeDidUpdateANCSAuthorizationReturnValue: AnyPublisher<BLEPeripheral, Never> =
Empty().eraseToAnyPublisher()
/// Count of how many times `observeDidUpdateANCSAuthorization()` was called.
public var observeDidUpdateANCSAuthorizationWasCalledCount = 0

/// Mocks observing ANCS authorization updates.
public func observeDidUpdateANCSAuthorization() -> AnyPublisher<BLEPeripheral, Never> {
observeDidUpdateANCSAuthorizationWasCalledCount += 1
return observeDidUpdateANCSAuthorizationReturnValue
}
}
200 changes: 200 additions & 0 deletions Sources/BLECombineKitMocks/MockBLEPeripheral.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
//
// MockBLEPeripheral.swift
// BLECombineKitMocks
//
// Created by Henry Javier Serrano Echeverria on 10/1/26.
//

import BLECombineKit
import Combine
import CoreBluetooth
import Foundation

/// A mock implementation of `BLEPeripheral` for testing purposes.
open class MockBLEPeripheral: BLEPeripheral, @unchecked Sendable {

public init() {}

/// The associated peripheral wrapper.
public var associatedPeripheral: CBPeripheralWrapper = MockCBPeripheralWrapper()

/// Return value for `observeConnectionState()`.
public var observeConnectionStateReturnValue: AnyPublisher<Bool, Never> = Just(true)
.eraseToAnyPublisher()
/// Count of how many times `observeConnectionState()` was called.
public var observeConnectionStateWasCalledCount = 0

/// Mocks observing the connection state.
public func observeConnectionState() -> AnyPublisher<Bool, Never> {
observeConnectionStateWasCalledCount += 1
return observeConnectionStateReturnValue
}

/// Return value for `connect(with:)`.
public var connectReturnValue: AnyPublisher<BLEPeripheral, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `connect(with:)` was called.
public var connectWasCalledCount = 0
/// The options passed to the last call of `connect(with:)`.
public var connectOptions: [String: Any]?

/// Mocks connecting to the peripheral.
public func connect(with options: [String: Any]?) -> AnyPublisher<BLEPeripheral, BLEError> {
connectWasCalledCount += 1
connectOptions = options
return connectReturnValue
}

/// Return value for `disconnect()`.
public var disconnectReturnValue: AnyPublisher<Never, BLEError> = Empty().eraseToAnyPublisher()
/// Count of how many times `disconnect()` was called.
public var disconnectWasCalledCount = 0

/// Mocks disconnecting from the peripheral.
public func disconnect() -> AnyPublisher<Never, BLEError> {
disconnectWasCalledCount += 1
return disconnectReturnValue
}

/// Return value for `observeNameValue()`.
public var observeNameValueReturnValue: AnyPublisher<String, Never> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `observeNameValue()` was called.
public var observeNameValueWasCalledCount = 0

/// Mocks observing the peripheral name.
public func observeNameValue() -> AnyPublisher<String, Never> {
observeNameValueWasCalledCount += 1
return observeNameValueReturnValue
}

/// Return value for `observeRSSIValue()`.
public var observeRSSIValueReturnValue: AnyPublisher<NSNumber, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `observeRSSIValue()` was called.
public var observeRSSIValueWasCalledCount = 0

/// Mocks observing the RSSI value.
public func observeRSSIValue() -> AnyPublisher<NSNumber, BLEError> {
observeRSSIValueWasCalledCount += 1
return observeRSSIValueReturnValue
}

/// Return value for `discoverServices(serviceUUIDs:)`.
public var discoverServicesReturnValue: AnyPublisher<BLEService, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `discoverServices(serviceUUIDs:)` was called.
public var discoverServicesWasCalledCount = 0
/// The UUIDs passed to the last call of `discoverServices(serviceUUIDs:)`.
public var discoverServicesUUIDs: [CBUUID]?

/// Mocks discovering services.
public func discoverServices(serviceUUIDs: [CBUUID]?) -> AnyPublisher<BLEService, BLEError> {
discoverServicesWasCalledCount += 1
discoverServicesUUIDs = serviceUUIDs
return discoverServicesReturnValue
}

/// Return value for `discoverCharacteristics(characteristicUUIDs:for:)`.
public var discoverCharacteristicsReturnValue: AnyPublisher<BLECharacteristic, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `discoverCharacteristics(characteristicUUIDs:for:)` was called.
public var discoverCharacteristicsWasCalledCount = 0
/// The characterisic UUIDs passed to the last call of `discoverCharacteristics(characteristicUUIDs:for:)`.
public var discoverCharacteristicsUUIDs: [CBUUID]?
/// The service passed to the last call of `discoverCharacteristics(characteristicUUIDs:for:)`.
public var discoverCharacteristicsService: CBService?

/// Mocks discovering characteristics for a service.
public func discoverCharacteristics(characteristicUUIDs: [CBUUID]?, for service: CBService)
-> AnyPublisher<BLECharacteristic, BLEError>
{
discoverCharacteristicsWasCalledCount += 1
discoverCharacteristicsUUIDs = characteristicUUIDs
discoverCharacteristicsService = service
return discoverCharacteristicsReturnValue
}

/// Return value for `readValue(for:)`.
public var readValueReturnValue: AnyPublisher<BLEData, BLEError> = Empty().eraseToAnyPublisher()
/// Count of how many times `readValue(for:)` was called.
public var readValueWasCalledCount = 0
/// The characteristic passed to the last call of `readValue(for:)`.
public var readValueCharacteristic: CBCharacteristic?

/// Mocks reading a value for a characteristic.
public func readValue(for characteristic: CBCharacteristic) -> AnyPublisher<BLEData, BLEError> {
readValueWasCalledCount += 1
readValueCharacteristic = characteristic
return readValueReturnValue
}

/// Return value for `observeValue(for:)`.
public var observeValueReturnValue: AnyPublisher<BLEData, BLEError> = Empty()
.eraseToAnyPublisher()
/// Count of how many times `observeValue(for:)` was called.
public var observeValueWasCalledCount = 0
/// The characteristic passed to the last call of `observeValue(for:)`.
public var observeValueCharacteristic: CBCharacteristic?

/// Mocks observing value updates for a characteristic.
public func observeValue(for characteristic: CBCharacteristic) -> AnyPublisher<BLEData, BLEError>
{
observeValueWasCalledCount += 1
observeValueCharacteristic = characteristic
return observeValueReturnValue
}

/// Return value for `observeValueUpdateAndSetNotification(for:)`.
public var observeValueUpdateAndSetNotificationReturnValue: AnyPublisher<BLEData, BLEError> =
Empty().eraseToAnyPublisher()
/// Count of how many times `observeValueUpdateAndSetNotification(for:)` was called.
public var observeValueUpdateAndSetNotificationWasCalledCount = 0
/// The characteristic passed to the last call of `observeValueUpdateAndSetNotification(for:)`.
public var observeValueUpdateAndSetNotificationCharacteristic: CBCharacteristic?

/// Mocks observing value updates and setting notifications for a characteristic.
public func observeValueUpdateAndSetNotification(for characteristic: CBCharacteristic)
-> AnyPublisher<BLEData, BLEError>
{
observeValueUpdateAndSetNotificationWasCalledCount += 1
observeValueUpdateAndSetNotificationCharacteristic = characteristic
return observeValueUpdateAndSetNotificationReturnValue
}

/// Count of how many times `setNotifyValue(_:for:)` was called.
public var setNotifyValueWasCalledCount = 0
/// The enabled state passed to the last call of `setNotifyValue(_:for:)`.
public var setNotifyValueEnabled: Bool?
/// The characteristic passed to the last call of `setNotifyValue(_:for:)`.
public var setNotifyValueCharacteristic: CBCharacteristic?

/// Mocks setting notifications for a characteristic.
public func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic) {
setNotifyValueWasCalledCount += 1
setNotifyValueEnabled = enabled
setNotifyValueCharacteristic = characteristic
}

/// Return value for `writeValue(_:for:type:)`.
public var writeValueReturnValue: AnyPublisher<Never, BLEError> = Empty().eraseToAnyPublisher()
/// Count of how many times `writeValue(_:for:type:)` was called.
public var writeValueWasCalledCount = 0
/// The data passed to the last call of `writeValue(_:for:type:)`.
public var writeValueData: Data?
/// The characteristic passed to the last call of `writeValue(_:for:type:)`.
public var writeValueCharacteristic: CBCharacteristic?
/// The write type passed to the last call of `writeValue(_:for:type:)`.
public var writeValueType: CBCharacteristicWriteType?

/// Mocks writing a value to a characteristic.
public func writeValue(
_ data: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType
) -> AnyPublisher<Never, BLEError> {
writeValueWasCalledCount += 1
writeValueData = data
writeValueCharacteristic = characteristic
writeValueType = type
return writeValueReturnValue
}
}
Loading
Loading