mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
Implement GNCPeripheralManagerMultiplexer.
PiperOrigin-RevId: 881707256
This commit is contained in:
committed by
Copybara-Service
parent
a2249dc07a
commit
c00d7ae485
@@ -39,6 +39,7 @@ objc_library(
|
||||
"GNCMConnection.m",
|
||||
"GNCPeripheral.m",
|
||||
"GNCPeripheralManager.m",
|
||||
"GNCPeripheralManagerMultiplexer.m",
|
||||
"NSData+GNCBase85.mm",
|
||||
"NSData+GNCWebSafeBase64.m",
|
||||
],
|
||||
@@ -59,6 +60,7 @@ objc_library(
|
||||
"GNCMConnection.h",
|
||||
"GNCPeripheral.h",
|
||||
"GNCPeripheralManager.h",
|
||||
"GNCPeripheralManagerMultiplexer.h",
|
||||
"NSData+GNCBase85.h",
|
||||
"NSData+GNCWebSafeBase64.h",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* A multiplexer that forwards @c CBPeripheralManagerDelegate and @c GNCPeripheralManagerDelegate
|
||||
*/
|
||||
@interface GNCPeripheralManagerMultiplexer : NSObject <GNCPeripheralManagerDelegate>
|
||||
|
||||
/**
|
||||
* Initializes the multiplexer.
|
||||
*
|
||||
* @param callbackQueue The queue to use for forwarding delegate callbacks.
|
||||
*/
|
||||
- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Adds a listener to the multiplexer. Listeners are held weakly.
|
||||
*
|
||||
* @param listener The listener to add.
|
||||
*/
|
||||
- (void)addListener:(id<GNCPeripheralManagerDelegate>)listener;
|
||||
|
||||
/**
|
||||
* Removes a listener from the multiplexer.
|
||||
*
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
- (void)removeListener:(id<GNCPeripheralManagerDelegate>)listener;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,194 @@
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h"
|
||||
|
||||
#import <CoreBluetooth/CoreBluetooth.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation GNCPeripheralManagerMultiplexer {
|
||||
NSHashTable<id<GNCPeripheralManagerDelegate>> *_listeners;
|
||||
dispatch_queue_t _callbackQueue;
|
||||
dispatch_queue_t _syncQueue;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_listeners = [NSHashTable weakObjectsHashTable];
|
||||
_callbackQueue = callbackQueue;
|
||||
_syncQueue = dispatch_queue_create("com.google.nearby.GNCPeripheralManagerMultiplexerSync",
|
||||
DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
}
|
||||
|
||||
- (void)addListener:(id<GNCPeripheralManagerDelegate>)listener {
|
||||
dispatch_async(_syncQueue, ^{
|
||||
[self->_listeners addObject:listener];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)removeListener:(id<GNCPeripheralManagerDelegate>)listener {
|
||||
dispatch_async(_syncQueue, ^{
|
||||
[self->_listeners removeObject:listener];
|
||||
});
|
||||
}
|
||||
|
||||
- (NSArray<id<GNCPeripheralManagerDelegate>> *)allListeners {
|
||||
__block NSArray<id<GNCPeripheralManagerDelegate>> *listeners;
|
||||
dispatch_sync(_syncQueue, ^{
|
||||
listeners = [self->_listeners allObjects];
|
||||
});
|
||||
return listeners;
|
||||
}
|
||||
|
||||
#pragma mark - GNCPeripheralManagerDelegate
|
||||
|
||||
- (void)gnc_peripheralManagerDidUpdateState:(id<GNCPeripheralManager>)peripheral {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
[listener gnc_peripheralManagerDidUpdateState:peripheral];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManagerDidStartAdvertising:(id<GNCPeripheralManager>)peripheral
|
||||
error:(nullable NSError *)error {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
if ([listener respondsToSelector:@selector(gnc_peripheralManagerDidStartAdvertising:error:)]) {
|
||||
[listener gnc_peripheralManagerDidStartAdvertising:peripheral error:error];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didAddService:(CBService *)service
|
||||
error:(nullable NSError *)error {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didAddService:error:)]) {
|
||||
[listener gnc_peripheralManager:peripheral didAddService:service error:error];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didReceiveReadRequest:(CBATTRequest *)request {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didReceiveReadRequest:)]) {
|
||||
[listener gnc_peripheralManager:peripheral didReceiveReadRequest:request];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didPublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(nullable NSError *)error {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didPublishL2CAPChannel:error:)]) {
|
||||
[listener gnc_peripheralManager:peripheral didPublishL2CAPChannel:PSM error:error];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(NSError *)error {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didUnpublishL2CAPChannel:error:)]) {
|
||||
[listener gnc_peripheralManager:peripheral didUnpublishL2CAPChannel:PSM error:error];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel
|
||||
error:(nullable NSError *)error {
|
||||
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
|
||||
dispatch_async(_callbackQueue, ^{
|
||||
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
|
||||
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didOpenL2CAPChannel:error:)]) {
|
||||
[listener gnc_peripheralManager:peripheral didOpenL2CAPChannel:channel error:error];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - CBPeripheralManagerDelegate
|
||||
|
||||
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
|
||||
[self gnc_peripheralManagerDidUpdateState:peripheral];
|
||||
}
|
||||
|
||||
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
|
||||
error:(nullable NSError *)error {
|
||||
[self gnc_peripheralManagerDidStartAdvertising:peripheral error:error];
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didAddService:(CBService *)service
|
||||
error:(nullable NSError *)error {
|
||||
[self gnc_peripheralManager:peripheral didAddService:service error:error];
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didReceiveReadRequest:(CBATTRequest *)request {
|
||||
[self gnc_peripheralManager:peripheral didReceiveReadRequest:request];
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didPublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(nullable NSError *)error {
|
||||
[self gnc_peripheralManager:peripheral didPublishL2CAPChannel:PSM error:error];
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(nullable NSError *)error {
|
||||
[self gnc_peripheralManager:peripheral didUnpublishL2CAPChannel:PSM error:error];
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel
|
||||
error:(nullable NSError *)error {
|
||||
[self gnc_peripheralManager:peripheral didOpenL2CAPChannel:channel error:error];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -44,6 +44,7 @@ objc_library(
|
||||
"GNCMBleUtilsTest.m",
|
||||
"GNCMConnectionsTest.m",
|
||||
"GNCMFakeConnection.mm",
|
||||
"GNCPeripheralManagerMultiplexerTest.m",
|
||||
"GNCPeripheralManagerTest.m",
|
||||
"GNCPeripheralTest.m",
|
||||
"NSData+GNCBase85Test.m",
|
||||
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h"
|
||||
|
||||
#import <CoreBluetooth/CoreBluetooth.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h"
|
||||
|
||||
@interface GNCPeripheralManagerMultiplexerTest : XCTestCase
|
||||
@end
|
||||
|
||||
@interface FakePeripheralManagerDelegate : NSObject <GNCPeripheralManagerDelegate>
|
||||
@property(nonatomic) XCTestExpectation *expectation;
|
||||
@property(nonatomic) BOOL didUpdateStateCalled;
|
||||
@property(nonatomic) CBManagerState state;
|
||||
|
||||
@property(nonatomic) BOOL didStartAdvertisingCalled;
|
||||
@property(nonatomic) NSError *startAdvertisingError;
|
||||
|
||||
@property(nonatomic) BOOL didAddServiceCalled;
|
||||
@property(nonatomic) CBService *addedService;
|
||||
@property(nonatomic) NSError *addServiceError;
|
||||
|
||||
@property(nonatomic) BOOL didReceiveReadRequestCalled;
|
||||
@property(nonatomic) CBATTRequest *readRequest;
|
||||
|
||||
@property(nonatomic) BOOL didPublishL2CAPChannelCalled;
|
||||
@property(nonatomic) CBL2CAPPSM publishedPSM;
|
||||
@property(nonatomic) NSError *publishL2CAPChannelError;
|
||||
|
||||
@property(nonatomic) BOOL didUnpublishL2CAPChannelCalled;
|
||||
@property(nonatomic) CBL2CAPPSM unpublishedPSM;
|
||||
@property(nonatomic) NSError *unpublishL2CAPChannelError;
|
||||
|
||||
@property(nonatomic) BOOL didOpenL2CAPChannelCalled;
|
||||
@property(nonatomic) CBL2CAPChannel *openedChannel;
|
||||
@property(nonatomic) NSError *openL2CAPChannelError;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FakePeripheralManagerDelegate
|
||||
|
||||
- (void)gnc_peripheralManagerDidUpdateState:(id<GNCPeripheralManager>)peripheral {
|
||||
_didUpdateStateCalled = YES;
|
||||
_state = peripheral.state;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManagerDidStartAdvertising:(id<GNCPeripheralManager>)peripheral
|
||||
error:(nullable NSError *)error {
|
||||
_didStartAdvertisingCalled = YES;
|
||||
_startAdvertisingError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didAddService:(CBService *)service
|
||||
error:(nullable NSError *)error {
|
||||
_didAddServiceCalled = YES;
|
||||
_addedService = service;
|
||||
_addServiceError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didReceiveReadRequest:(CBATTRequest *)request {
|
||||
_didReceiveReadRequestCalled = YES;
|
||||
_readRequest = request;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didPublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(nullable NSError *)error {
|
||||
_didPublishL2CAPChannelCalled = YES;
|
||||
_publishedPSM = PSM;
|
||||
_publishL2CAPChannelError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(NSError *)error {
|
||||
_didUnpublishL2CAPChannelCalled = YES;
|
||||
_unpublishedPSM = PSM;
|
||||
_unpublishL2CAPChannelError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
|
||||
didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel
|
||||
error:(nullable NSError *)error {
|
||||
_didOpenL2CAPChannelCalled = YES;
|
||||
_openedChannel = channel;
|
||||
_openL2CAPChannelError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManagerDidUpdateState:(nonnull CBPeripheralManager *)peripheral {
|
||||
_didUpdateStateCalled = YES;
|
||||
_state = peripheral.state;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
|
||||
error:(nullable NSError *)error {
|
||||
_didStartAdvertisingCalled = YES;
|
||||
_startAdvertisingError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didAddService:(CBService *)service
|
||||
error:(nullable NSError *)error {
|
||||
_didAddServiceCalled = YES;
|
||||
_addedService = service;
|
||||
_addServiceError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didReceiveReadRequest:(CBATTRequest *)request {
|
||||
_didReceiveReadRequestCalled = YES;
|
||||
_readRequest = request;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didPublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(nullable NSError *)error {
|
||||
_didPublishL2CAPChannelCalled = YES;
|
||||
_publishedPSM = PSM;
|
||||
_publishL2CAPChannelError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM
|
||||
error:(nullable NSError *)error {
|
||||
_didUnpublishL2CAPChannelCalled = YES;
|
||||
_unpublishedPSM = PSM;
|
||||
_unpublishL2CAPChannelError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)peripheralManager:(CBPeripheralManager *)peripheral
|
||||
didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel
|
||||
error:(nullable NSError *)error {
|
||||
_didOpenL2CAPChannelCalled = YES;
|
||||
_openedChannel = channel;
|
||||
_openL2CAPChannelError = error;
|
||||
if (_expectation) {
|
||||
[_expectation fulfill];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCPeripheralManagerMultiplexerTest
|
||||
|
||||
- (void)testMultiplexerForwardsCallbacks {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate1 = [[FakePeripheralManagerDelegate alloc] init];
|
||||
FakePeripheralManagerDelegate *delegate2 = [[FakePeripheralManagerDelegate alloc] init];
|
||||
|
||||
delegate1.expectation = [self expectationWithDescription:@"Delegate 1 called"];
|
||||
delegate2.expectation = [self expectationWithDescription:@"Delegate 2 called"];
|
||||
|
||||
[multiplexer addListener:delegate1];
|
||||
[multiplexer addListener:delegate2];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
fakeManager.state = CBManagerStatePoweredOn;
|
||||
|
||||
[multiplexer gnc_peripheralManagerDidUpdateState:fakeManager];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
|
||||
XCTAssertTrue(delegate1.didUpdateStateCalled);
|
||||
XCTAssertTrue(delegate2.didUpdateStateCalled);
|
||||
XCTAssertEqual(delegate1.state, CBManagerStatePoweredOn);
|
||||
XCTAssertEqual(delegate2.state, CBManagerStatePoweredOn);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerRemovesListener {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate1 = [[FakePeripheralManagerDelegate alloc] init];
|
||||
|
||||
delegate1.expectation = [self expectationWithDescription:@"Delegate 1 called"];
|
||||
|
||||
[multiplexer addListener:delegate1];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
fakeManager.state = CBManagerStatePoweredOn;
|
||||
|
||||
[multiplexer removeListener:delegate1];
|
||||
[multiplexer gnc_peripheralManagerDidUpdateState:fakeManager];
|
||||
|
||||
// We expect delegate1 NOT to be called.
|
||||
// Since removals are async, we wait a bit to ensure it had a chance (or didn't).
|
||||
XCTWaiterResult result = [XCTWaiter waitForExpectations:@[ delegate1.expectation ] timeout:0.5];
|
||||
XCTAssertEqual(result, XCTWaiterResultTimedOut);
|
||||
XCTAssertFalse(delegate1.didUpdateStateCalled);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerForwardsDidStartAdvertising {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:1 userInfo:nil];
|
||||
|
||||
[multiplexer gnc_peripheralManagerDidStartAdvertising:fakeManager error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didStartAdvertisingCalled);
|
||||
XCTAssertEqualObjects(delegate.startAdvertisingError, error);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerForwardsDidAddService {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
CBMutableService *service =
|
||||
[[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"180D"] primary:YES];
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:2 userInfo:nil];
|
||||
|
||||
[multiplexer gnc_peripheralManager:fakeManager didAddService:service error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didAddServiceCalled);
|
||||
XCTAssertEqualObjects(delegate.addedService, service);
|
||||
XCTAssertEqualObjects(delegate.addServiceError, error);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerForwardsDidReceiveReadRequest {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
id request = [NSNull null]; // Use NSNull or any object as placeholder since we can't create
|
||||
// CBATTRequest
|
||||
|
||||
[multiplexer gnc_peripheralManager:fakeManager didReceiveReadRequest:request];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didReceiveReadRequestCalled);
|
||||
XCTAssertEqual(delegate.readRequest, request);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerForwardsDidPublishL2CAPChannel {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
CBL2CAPPSM psm = 42;
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:3 userInfo:nil];
|
||||
|
||||
[multiplexer gnc_peripheralManager:fakeManager didPublishL2CAPChannel:psm error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didPublishL2CAPChannelCalled);
|
||||
XCTAssertEqual(delegate.publishedPSM, psm);
|
||||
XCTAssertEqualObjects(delegate.publishL2CAPChannelError, error);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerForwardsDidUnpublishL2CAPChannel {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
CBL2CAPPSM psm = 42;
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:4 userInfo:nil];
|
||||
|
||||
[multiplexer gnc_peripheralManager:fakeManager didUnpublishL2CAPChannel:psm error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didUnpublishL2CAPChannelCalled);
|
||||
XCTAssertEqual(delegate.unpublishedPSM, psm);
|
||||
XCTAssertEqualObjects(delegate.unpublishL2CAPChannelError, error);
|
||||
}
|
||||
|
||||
- (void)testMultiplexerForwardsDidOpenL2CAPChannel {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
id channel = [NSNull null]; // Placeholder
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:5 userInfo:nil];
|
||||
|
||||
[multiplexer gnc_peripheralManager:fakeManager didOpenL2CAPChannel:channel error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didOpenL2CAPChannelCalled);
|
||||
XCTAssertEqual(delegate.openedChannel, channel);
|
||||
XCTAssertEqualObjects(delegate.openL2CAPChannelError, error);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidUpdateState {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
fakeManager.state = CBManagerStatePoweredOn;
|
||||
|
||||
[multiplexer peripheralManagerDidUpdateState:(CBPeripheralManager *)fakeManager];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didUpdateStateCalled);
|
||||
XCTAssertEqual(delegate.state, CBManagerStatePoweredOn);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidStartAdvertising {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:10 userInfo:nil];
|
||||
|
||||
[multiplexer peripheralManagerDidStartAdvertising:(CBPeripheralManager *)fakeManager error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didStartAdvertisingCalled);
|
||||
XCTAssertEqualObjects(delegate.startAdvertisingError, error);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidAddService {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
CBMutableService *service =
|
||||
[[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"180F"] primary:YES];
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:11 userInfo:nil];
|
||||
|
||||
[multiplexer peripheralManager:(CBPeripheralManager *)fakeManager didAddService:service error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didAddServiceCalled);
|
||||
XCTAssertEqualObjects(delegate.addedService, service);
|
||||
XCTAssertEqualObjects(delegate.addServiceError, error);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidReceiveReadRequest {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
id request = [NSNull null];
|
||||
|
||||
[multiplexer peripheralManager:(CBPeripheralManager *)fakeManager didReceiveReadRequest:request];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didReceiveReadRequestCalled);
|
||||
XCTAssertEqual(delegate.readRequest, request);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidPublishL2CAPChannel {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
CBL2CAPPSM psm = 100;
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:13 userInfo:nil];
|
||||
|
||||
[multiplexer peripheralManager:(CBPeripheralManager *)fakeManager
|
||||
didPublishL2CAPChannel:psm
|
||||
error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didPublishL2CAPChannelCalled);
|
||||
XCTAssertEqual(delegate.publishedPSM, psm);
|
||||
XCTAssertEqualObjects(delegate.publishL2CAPChannelError, error);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidUnpublishL2CAPChannel {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
CBL2CAPPSM psm = 101;
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:14 userInfo:nil];
|
||||
|
||||
[multiplexer peripheralManager:(CBPeripheralManager *)fakeManager
|
||||
didUnpublishL2CAPChannel:psm
|
||||
error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didUnpublishL2CAPChannelCalled);
|
||||
XCTAssertEqual(delegate.unpublishedPSM, psm);
|
||||
XCTAssertEqualObjects(delegate.unpublishL2CAPChannelError, error);
|
||||
}
|
||||
|
||||
- (void)testCBPeripheralManagerDelegateDidOpenL2CAPChannel {
|
||||
GNCPeripheralManagerMultiplexer *multiplexer =
|
||||
[[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()];
|
||||
FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init];
|
||||
delegate.expectation = [self expectationWithDescription:@"Delegate called"];
|
||||
[multiplexer addListener:delegate];
|
||||
|
||||
GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init];
|
||||
id channel = [NSNull null];
|
||||
NSError *error = [NSError errorWithDomain:@"test" code:15 userInfo:nil];
|
||||
|
||||
[multiplexer peripheralManager:(CBPeripheralManager *)fakeManager
|
||||
didOpenL2CAPChannel:channel
|
||||
error:error];
|
||||
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
XCTAssertTrue(delegate.didOpenL2CAPChannelCalled);
|
||||
XCTAssertEqual(delegate.openedChannel, channel);
|
||||
XCTAssertEqualObjects(delegate.openL2CAPChannelError, error);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user