Refactor GATT/L2CAP servers to support shared peripheral manager

PiperOrigin-RevId: 882024313
This commit is contained in:
Edwin Wu
2026-06-13 16:52:26 +05:30
committed by Lasan Mahaliyana
parent 840d24896f
commit 2f6cff0f08
14 changed files with 1024 additions and 495 deletions
@@ -104,6 +104,10 @@ constexpr auto kMediumMaxAllowedReadBytes =
// Disable/Enable refactor of BLE/L2CAP in Nearby Connections SDK.
constexpr auto kRefactorBleL2cap =
flags::Flag<bool>(kConfigPackage, "45737079", false);
// Enable/Disable usage of shared CBPeripheralManager for GATT and L2CAP
// servers.
constexpr auto kEnableSharedPeripheralManager =
flags::Flag<bool>(kConfigPackage, "45770787", false);
// Set the safe-to-disconnect version.
// 0. Disabled all. 1. safe-to-disconnect 2. reserved 3. auto-reconnect
// 4. auto-resume 5. non-distance-constraint-recovery 6. payload_ack
@@ -29,4 +29,7 @@
/** Checks whether BLE L2CAP refactor is enabled in the Nearby Connections SDK. */
@property(nonatomic, class, readonly) BOOL refactorBleL2capEnabled;
/** Checks whether shared peripheral manager is enabled in the Nearby Connections SDK. */
@property(nonatomic, class, readonly) BOOL sharedPeripheralManagerEnabled;
@end
@@ -42,4 +42,10 @@
kRefactorBleL2cap);
}
+ (BOOL)sharedPeripheralManagerEnabled {
return nearby::NearbyFlags::GetInstance().GetBoolFlag(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager);
}
@end
@@ -34,6 +34,13 @@
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::kEnableBleL2cap,
false);
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
false);
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
false);
[super tearDown];
}
@@ -78,4 +85,34 @@
XCTAssertFalse([GNCFeatureFlags bleL2capEnabled]);
}
- (void)testRefactorBleL2capEnabled_WhenFlagIsTrue {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
YES);
XCTAssertTrue([GNCFeatureFlags refactorBleL2capEnabled]);
}
- (void)testRefactorBleL2capEnabled_WhenFlagIsFalse {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::kRefactorBleL2cap,
NO);
XCTAssertFalse([GNCFeatureFlags refactorBleL2capEnabled]);
}
- (void)testSharedPeripheralManagerEnabled_WhenFlagIsTrue {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
YES);
XCTAssertTrue([GNCFeatureFlags sharedPeripheralManagerEnabled]);
}
- (void)testSharedPeripheralManagerEnabled_WhenFlagIsFalse {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
NO);
XCTAssertFalse([GNCFeatureFlags sharedPeripheralManagerEnabled]);
}
@end
@@ -15,6 +15,8 @@
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
@class GNCBLEGATTCharacteristic;
NS_ASSUME_NONNULL_BEGIN
@@ -57,7 +59,18 @@ typedef void (^GNCStopAdvertisingCompletionHandler)(NSError *_Nullable error);
*
* @note The public APIs of this class are thread safe.
*/
@interface GNCBLEGATTServer : NSObject
@interface GNCBLEGATTServer : NSObject <GNCPeripheralManagerDelegate>
/**
* Initializes the GATT server.
*
* @param peripheralManager The peripheral manager to use.
* @param queue The queue to use for delegate callbacks and internal operations.
*/
- (instancetype)initWithPeripheralManager:(nullable id<GNCPeripheralManager>)peripheralManager
queue:(nullable dispatch_queue_t)queue;
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a characteristic and adds it to the GATT server.
@@ -59,30 +59,33 @@ static const int kMaxAdvertisementLengthOnIOS = 23;
NSDictionary<NSString *, id> *_advertisementData;
}
- (instancetype)init {
- (instancetype)initWithPeripheralManager:(nullable id<GNCPeripheralManager>)peripheralManager
queue:(nullable dispatch_queue_t)queue {
self = [super init];
if (self) {
_queue = dispatch_queue_create(kGNCBLEGATTServerQueueLabel, DISPATCH_QUEUE_SERIAL);
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil queue:_queue];
// Set for @c GNCPeripheralManager to be able to forward callbacks.
_peripheralManager.peripheralDelegate = self;
_services = [[NSMutableDictionary alloc] init];
_pendingCharacteristics = [[NSMutableDictionary alloc] init];
_characteristicValues = [[NSMutableDictionary alloc] init];
_advertisementData = nil;
}
return self;
}
_queue = queue ?: dispatch_queue_create(kGNCBLEGATTServerQueueLabel, DISPATCH_QUEUE_SERIAL);
if (GNCFeatureFlags.sharedPeripheralManagerEnabled) {
if (!peripheralManager) {
// In shared mode, the peripheral manager must be injected.
[NSException raise:NSInvalidArgumentException
format:@"Peripheral manager cannot be nil when shared manager is enabled."];
}
_peripheralManager = peripheralManager;
// In shared mode, do NOT set the delegate. The Multiplexer handles callbacks.
} else {
// Legacy mode: Create a new manager if one isn't provided.
if (!peripheralManager) {
peripheralManager = [[CBPeripheralManager alloc]
initWithDelegate:self
queue:_queue
options:@{CBPeripheralManagerOptionShowPowerAlertKey : @NO}];
}
_peripheralManager = peripheralManager;
// In legacy mode, we own the manager (or use the injected one as if we own it) and set the
// delegate.
_peripheralManager.peripheralDelegate = self;
}
// This is private and should only be used for tests. The provided peripheral manager must call
// delegate methods on the main queue.
- (instancetype)initWithPeripheralManager:(nullable id<GNCPeripheralManager>)peripheralManager {
self = [super init];
if (self) {
_queue = dispatch_get_main_queue();
_peripheralManager = peripheralManager;
// Set for @c GNCPeripheralManager to be able to forward callbacks.
_peripheralManager.peripheralDelegate = self;
_services = [[NSMutableDictionary alloc] init];
_pendingCharacteristics = [[NSMutableDictionary alloc] init];
_characteristicValues = [[NSMutableDictionary alloc] init];
@@ -342,6 +345,12 @@ static const int kMaxAdvertisementLengthOnIOS = 23;
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
didReceiveReadRequest:(CBATTRequest *)request {
dispatch_assert_queue(_queue);
if (!_services[request.characteristic.service.UUID]) {
// This server does not own the requested service. Ignore the request to allow other listeners
// (or future listeners) to handle it.
return;
}
NSData *value =
_characteristicValues[request.characteristic.service.UUID][request.characteristic.UUID];
if (!value) {
@@ -15,6 +15,8 @@
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
@class GNCBLEL2CAPStream;
@protocol GNCPeripheralManager;
@@ -42,7 +44,7 @@ typedef void (^GNCOpenL2CAPServerChannelOpendCompletionHandler)(GNCBLEL2CAPStrea
*
* @note The public APIs of this class are thread safe.
*/
@interface GNCBLEL2CAPServer : NSObject
@interface GNCBLEL2CAPServer : NSObject <GNCPeripheralManagerDelegate>
// Represents a PSM (Protocol/Service Multiplexer) value for an L2CAP channel.
@property(atomic, readonly) CBL2CAPPSM PSM;
@@ -57,6 +59,8 @@ typedef void (^GNCOpenL2CAPServerChannelOpendCompletionHandler)(GNCBLEL2CAPStrea
- (instancetype)initWithPeripheralManager:(nullable id<GNCPeripheralManager>)peripheralManager
queue:(nullable dispatch_queue_t)queue;
- (instancetype)init NS_UNAVAILABLE;
/**
* Starts listening for an L2CAP channel.
*
@@ -17,6 +17,7 @@
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h"
#import "internal/platform/implementation/apple/Log/GNCLogger.h"
#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEError.h"
#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPStream.h"
@@ -43,21 +44,25 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP
BOOL _alreadyStartedWhenPeripheralPoweredOff;
}
- (instancetype)init {
return [self initWithPeripheralManager:nil queue:nil];
}
// This is private and should only be used for tests. The provided peripheral manager must call
// delegate methods on the main queue.
- (instancetype)initWithPeripheralManager:(nullable id<GNCPeripheralManager>)peripheralManager
queue:(nullable dispatch_queue_t)queue {
self = [super init];
if (self) {
_queue = queue ?: dispatch_queue_create(kGNCBLEL2CAPServerQueueLabel, DISPATCH_QUEUE_SERIAL);
if (peripheralManager) {
if (GNCFeatureFlags.sharedPeripheralManagerEnabled) {
if (!peripheralManager) {
// In shared mode, the peripheral manager must be injected.
[NSException raise:NSInvalidArgumentException
format:@"Peripheral manager cannot be nil when shared manager is enabled."];
}
_peripheralManager = peripheralManager;
// Set for @c GNCPeripheralManager to be able to forward callbacks.
_peripheralManager.peripheralDelegate = self;
// In shared mode, do NOT set the delegate. The Multiplexer handles callbacks.
} else {
if (peripheralManager) {
_peripheralManager = peripheralManager;
// Set for @c GNCPeripheralManager to be able to forward callbacks.
_peripheralManager.peripheralDelegate = self;
}
}
}
return self;
@@ -70,20 +75,36 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP
channelOpenedCompletionHandler {
_psmPublishedCompletionHandler = [psmPublishedCompletionHandler copy];
_channelOpenedCompletionHandler = [channelOpenedCompletionHandler copy];
if (!_queue) {
_psmPublishedCompletionHandler(0, [NSError errorWithDomain:GNCBLEErrorDomain
code:GNCBLEErrorL2CAPListeningOnQueueNil
userInfo:nil]);
return;
}
if (!_peripheralManager) {
// Lazy initialization to avoid system dialog on app startup before pairing.
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil
queue:_queue
options:nil];
if (GNCFeatureFlags.sharedPeripheralManagerEnabled) {
if (!_queue) {
if (_psmPublishedCompletionHandler) {
_psmPublishedCompletionHandler(0,
[NSError errorWithDomain:GNCBLEErrorDomain
code:GNCBLEErrorL2CAPListeningOnQueueNil
userInfo:nil]);
}
return;
}
if (!_peripheralManager) {
GNCLoggerError(@"[NEARBY] Peripheral manager must not be nil.");
return;
}
} else {
if (!_queue) {
_psmPublishedCompletionHandler(0, [NSError errorWithDomain:GNCBLEErrorDomain
code:GNCBLEErrorL2CAPListeningOnQueueNil
userInfo:nil]);
return;
}
if (!_peripheralManager) {
// Lazy initialization to avoid system dialog on app startup before pairing.
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil
queue:_queue
options:nil];
// Set for @c GNCPeripheralManager to be able to forward callbacks.
_peripheralManager.peripheralDelegate = self;
// Set for @c GNCPeripheralManager to be able to forward callbacks.
_peripheralManager.peripheralDelegate = self;
}
}
if (_peripheralManager.state == CBManagerStatePoweredOn) {
@@ -40,16 +40,6 @@ static NSError *AlreadyScanningError() {
return [NSError errorWithDomain:GNCBLEErrorDomain code:GNCBLEErrorAlreadyScanning userInfo:nil];
}
static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer(
id<GNCPeripheralManager> _Nullable peripheralManager) {
if (!peripheralManager) {
return [[GNCBLEL2CAPServer alloc] init];
} else {
return [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:peripheralManager
queue:dispatch_get_main_queue()];
}
}
@interface GNCBLEMedium () <GNCCentralManagerDelegate, CBCentralManagerDelegate>
@end
@@ -164,7 +154,16 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer(
completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler {
dispatch_async(_queue, ^{
if (!_server) {
_server = [[GNCBLEGATTServer alloc] init];
if (GNCFeatureFlags.sharedPeripheralManagerEnabled) {
// TODO (edwinwu): Implement shared peripheral manager.
// For now, raise an exception.
[NSException raise:NSInvalidArgumentException
format:@"Not implemented for shared manager is enabled."];
} else {
// In legacy mode, we pass nil (or a separate manager) and do NOT add to multiplexer.
// GNCBLEGATTServer will create its own internal manager.
_server = [[GNCBLEGATTServer alloc] initWithPeripheralManager:nil queue:nil];
}
}
[_server startAdvertisingData:serviceData completionHandler:completionHandler];
});
@@ -238,7 +237,14 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer(
(nullable GNCGATTServerCompletionHandler)completionHandler {
dispatch_async(_queue, ^{
if (!_server) {
_server = [[GNCBLEGATTServer alloc] init];
if (GNCFeatureFlags.sharedPeripheralManagerEnabled) {
// TODO (edwinwu): Implement shared peripheral manager.
// For now, raise an exception.
[NSException raise:NSInvalidArgumentException
format:@"Not implemented for shared manager is enabled."];
} else {
_server = [[GNCBLEGATTServer alloc] initWithPeripheralManager:nil queue:nil];
}
}
if (completionHandler) {
completionHandler(_server, nil);
@@ -284,7 +290,17 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer(
(nullable id<GNCPeripheralManager>)peripheralManager {
dispatch_async(_queue, ^{
if (!_l2capServer) {
_l2capServer = CreateL2CapServer(peripheralManager);
if (GNCFeatureFlags.sharedPeripheralManagerEnabled) {
// TODO (edwinwu): Implement shared peripheral manager.
// For now, raise an exception.
[NSException raise:NSInvalidArgumentException
format:@"Not implemented for shared manager is enabled."];
} else {
// Legacy mode
_l2capServer = [[GNCBLEL2CAPServer alloc]
initWithPeripheralManager:peripheralManager // Likely nil, so Server creates new one
queue:peripheralManager ? dispatch_get_main_queue() : nil];
}
}
[_l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:psmPublishedCompletionHandler
@@ -26,11 +26,11 @@ objc_library(
srcs = [
"GNCBLEGATTCharacteristicTest.mm",
"GNCBLEGATTClientTest.m",
"GNCBLEGATTServerTest.m",
"GNCBLEGATTServerTest.mm",
"GNCBLEL2CAPClientTest.m",
"GNCBLEL2CAPConnectionTest.m",
"GNCBLEL2CAPFakeInputOutputStream.m",
"GNCBLEL2CAPServerTest.m",
"GNCBLEL2CAPServerTest.mm",
"GNCBLEL2CAPStreamTest.m",
"GNCBLEMediumTest.m",
"GNCFakeBLEGATTServer.m",
@@ -66,6 +66,8 @@ objc_library(
"GNCMFakeConnection.h",
],
deps = [
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform/implementation/apple", # buildcleaner: keep
"//internal/platform/implementation/apple/Mediums/BLE",
"//internal/platform/implementation/apple/Mediums/BLE/Sockets:Shared",
@@ -22,6 +22,9 @@
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServer+Testing.h"
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "internal/flags/nearby_flags.h"
static NSString *const kServiceUUID1 = @"0000FEF3-0000-1000-8000-00805F9B34FB";
static NSString *const kServiceUUID2 = @"0000FEF4-0000-1000-8000-00805F9B34FB";
static NSString *const kCharacteristicUUID1 = @"00000000-0000-3000-8000-000000000000";
@@ -34,11 +37,60 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
#pragma mark - Create Characteristic
- (void)testCreateCharacteristic {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
- (void)tearDown {
nearby::NearbyFlags::GetInstance().ResetOverridedValues();
[super tearDown];
}
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
- (void)testInit_setsDelegateCorrectlyBasedOnFlag {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *server =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
// In shared mode, functionality is delegated to the multiplexer, so the server should NOT
// self-assign as delegate.
XCTAssertNil(fakePeripheralManager.peripheralDelegate);
} else {
// In legacy mode, the server owns the manager and sets itself as delegate.
XCTAssertEqual(fakePeripheralManager.peripheralDelegate, server);
}
}
}
- (void)testInit_throwsWithNilManagerWhenFlagEnabled {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
true);
XCTAssertThrowsSpecificNamed(
[[GNCBLEGATTServer alloc] initWithPeripheralManager:(id<GNCPeripheralManager>)nil
queue:dispatch_get_main_queue()],
NSException, NSInvalidArgumentException);
}
- (void)testCreateCharacteristic {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -62,13 +114,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testCreateMultipleCharacteristicsForOneService {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -105,13 +167,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
[self waitForExpectations:@[ expectation1, expectation2 ] timeout:3];
XCTAssertEqual(fakePeripheralManager.services.count, 1);
XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 2);
}
}
- (void)testCreateDuplicateCharacteristics {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -140,13 +212,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
[self waitForExpectations:@[ expectation ] timeout:3];
XCTAssertEqual(fakePeripheralManager.services.count, 1);
XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 1);
}
}
- (void)testCreateDuplicatePendingCharacteristics {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"Create characteristic."];
@@ -171,13 +253,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testCreateCharacteristicNotPoweredOn {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"Create characteristic."];
@@ -198,13 +290,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testCreateCharacteristicServiceFailure {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
fakePeripheralManager.didAddServiceError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -228,15 +330,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
#pragma mark - Read Request
- (void)testReadRequest {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -265,14 +377,24 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
characteristic:characteristicUUID];
[self waitForExpectations:@[ fakePeripheralManager.respondToRequestSuccessExpectation ]
timeout:0];
timeout:3];
}
}
- (void)testReadRequestInvalidService {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
- (void)testReadRequestInvalidCharacteristic {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -296,73 +418,106 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
[self waitForExpectations:@[ expectation ] timeout:3];
CBUUID *invalidCharacteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID2];
[fakePeripheralManager
simulatePeripheralManagerDidReceiveReadRequestForService:serviceUUID
characteristic:invalidCharacteristicUUID];
[self waitForExpectations:@[ fakePeripheralManager.respondToRequestErrorExpectation ] timeout:3];
}
}
- (void)testReadRequestInvalidService {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"Create characteristic."];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
[gattServer createCharacteristicWithServiceID:serviceUUID
characteristicUUID:characteristicUUID
permissions:CBAttributePermissionsReadable
properties:CBCharacteristicPropertyRead
completionHandler:^(GNCBLEGATTCharacteristic *characteristic,
NSError *error) {
[expectation fulfill];
}];
[self waitForExpectations:@[ expectation ] timeout:3];
CBUUID *invalidServiceUUID = [CBUUID UUIDWithString:kServiceUUID2];
// Expectation that we *should not* receive a response.
fakePeripheralManager.respondToRequestSuccessExpectation.inverted = YES;
fakePeripheralManager.respondToRequestErrorExpectation.inverted = YES;
[fakePeripheralManager
simulatePeripheralManagerDidReceiveReadRequestForService:invalidServiceUUID
characteristic:characteristicUUID];
[self waitForExpectations:@[ fakePeripheralManager.respondToRequestErrorExpectation ] timeout:0];
}
- (void)testReadRequestInvalidCharacteristic {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"Create and update characteristic."];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
[gattServer createCharacteristicWithServiceID:serviceUUID
characteristicUUID:characteristicUUID
permissions:CBAttributePermissionsReadable
properties:CBCharacteristicPropertyRead
completionHandler:^(GNCBLEGATTCharacteristic *characteristic,
NSError *error) {
[gattServer updateCharacteristic:characteristic
value:[NSData data]
completionHandler:^(NSError *error) {
[expectation fulfill];
}];
}];
[self waitForExpectations:@[ expectation ] timeout:3];
CBUUID *invalidCharacteristicUUID =
[CBUUID UUIDWithString:kCharacteristicUUID2];
[fakePeripheralManager
simulatePeripheralManagerDidReceiveReadRequestForService:serviceUUID
characteristic:invalidCharacteristicUUID];
[self waitForExpectations:@[ fakePeripheralManager.respondToRequestErrorExpectation ] timeout:0];
[self waitForExpectations:@[
fakePeripheralManager.respondToRequestSuccessExpectation,
fakePeripheralManager.respondToRequestErrorExpectation
]
timeout:3];
}
}
#pragma mark - Stop
- (void)testStop {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[gattServer stop];
[gattServer stop];
XCTAssertEqual(fakePeripheralManager.services.count, 0);
XCTAssertEqual(fakePeripheralManager.services.count, 0);
}
}
#pragma mark - Start Advertising
- (void)testStartAdvertisingNoServiceData {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -377,13 +532,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingEmptyServiceData {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -402,13 +567,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingShortServiceData {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -429,13 +604,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertising20ByteServiceData {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -457,13 +642,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingLongServiceData {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -482,13 +677,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingWithEmojiServiceData {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -510,13 +715,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingMultipleServices {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -536,13 +751,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingNotPoweredOn {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"Start advertising."];
@@ -556,13 +781,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingStartFailure {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
fakePeripheralManager.didStartAdvertisingError = [NSError errorWithDomain:@"fake"
code:0
@@ -581,13 +816,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartAdvertisingAlreadyAdvertising {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
fakePeripheralManager.didStartAdvertisingError = [NSError errorWithDomain:@"fake"
code:0
@@ -608,13 +853,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
- (void)testStartStopStartAdvertising {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager];
GNCBLEGATTServer *gattServer =
[[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = gattServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
@@ -648,6 +903,9 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
}];
[self waitForExpectations:@[ expectation ] timeout:3];
}
}
@end
@@ -1,329 +0,0 @@
// Copyright 2025 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/GNCBLEL2CAPServer.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServer+Testing.h"
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h"
static const NSTimeInterval kTestTimeout = 1.0;
@interface GNCBLEL2CAPServerTest : XCTestCase
@end
@implementation GNCBLEL2CAPServerTest
#pragma mark Tests
- (void)testInit {
GNCBLEL2CAPServer *l2capServer = [[GNCBLEL2CAPServer alloc] init];
XCTAssertNotNil(l2capServer);
XCTAssertNil([l2capServer valueForKey:@"_peripheralManager"]);
}
- (void)testPublishL2CAPChannelAndOpenChannelWhenStartListeningChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *psmPublishedExpectation =
[[XCTestExpectation alloc] initWithDescription:@"PSM published."];
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
[psmPublishedExpectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
XCTAssertNil(error);
XCTAssertNotNil(stream);
[channelOpenedexpectation fulfill];
}];
[self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ]
timeout:kTestTimeout];
XCTAssertNotNil([l2capServer valueForKey:@"l2CAPChannel"]);
XCTAssertNotNil([l2capServer valueForKey:@"l2CAPStream"]);
}
- (void)testFailedToPublishL2CAPChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
fakePeripheralManager.didPublishL2CAPChannelError = [NSError errorWithDomain:@"fake"
code:0
userInfo:nil];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *psmPublishedExpectation =
[[XCTestExpectation alloc] initWithDescription:@"PSM published with error."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, fakePeripheralManager.didPublishL2CAPChannelError);
XCTAssertEqual(PSM, 0);
[psmPublishedExpectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[self waitForExpectations:@[ psmPublishedExpectation ] timeout:kTestTimeout];
}
- (void)testPoweredOffUnpublishesChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOff];
[self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout];
}
- (void)testPeripheralManagerDidUpdateStatePoweredOffUnpublishesChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
fakePeripheralManager.state = CBManagerStatePoweredOn;
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
fakePeripheralManager.state = CBManagerStatePoweredOff;
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager];
[self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout];
}
- (void)testStartPeripheralManagerInitiallyOff {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *psmPublishedExpectation =
[[XCTestExpectation alloc] initWithDescription:@"PSM published."];
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
[psmPublishedExpectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
[channelOpenedexpectation fulfill];
}];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ]
timeout:kTestTimeout];
}
- (void)testClose {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[l2capServer close];
XCTAssertEqual([l2capServer PSM], 0);
}
- (void)testCloseDoesNotUnpublishesChannelIfNotConnected {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
fakePeripheralManager.unpublishExpectation.inverted = YES;
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
[l2capServer close];
[self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout];
}
- (void)testFailedToOpenL2CAPChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
fakePeripheralManager.didOpenL2CAPChannelError = [NSError errorWithDomain:@"fake"
code:0
userInfo:nil];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
XCTAssertNil(stream);
XCTAssertEqual(error, fakePeripheralManager.didOpenL2CAPChannelError);
[channelOpenedexpectation fulfill];
}];
[self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout];
XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]);
XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]);
}
- (void)testPeripheralManagerDidUnpublishL2CAPChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManager:(CBPeripheralManager *)fakePeripheralManager
didUnpublishL2CAPChannel:l2capServer.PSM
error:[NSError errorWithDomain:@"fake" code:0 userInfo:nil]];
XCTAssertEqual(l2capServer.PSM, 0);
}
- (void)testCloseL2CAPChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
[channelOpenedexpectation fulfill];
}];
[self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout];
[l2capServer closeL2CAPChannel];
XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]);
XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]);
}
- (void)testPeripheralManagerDidPublishL2CAPChannel {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"completion called"];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(PSM, 1);
XCTAssertNil(error);
[expectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManager:(CBPeripheralManager *)fakePeripheralManager
didPublishL2CAPChannel:1
error:nil];
[self waitForExpectations:@[ expectation ] timeout:kTestTimeout];
XCTAssertEqual(l2capServer.PSM, 1);
}
- (void)testPeripheralManagerDidPublishL2CAPChannelWithError {
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"completion called"];
NSError *publishError = [NSError errorWithDomain:@"test" code:0 userInfo:nil];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(PSM, 0);
XCTAssertEqualObjects(error, publishError);
[expectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManager:(CBPeripheralManager *)fakePeripheralManager
didPublishL2CAPChannel:0
error:publishError];
[self waitForExpectations:@[ expectation ] timeout:kTestTimeout];
XCTAssertEqual(l2capServer.PSM, 0);
}
@end
@@ -0,0 +1,485 @@
// Copyright 2025 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/GNCBLEL2CAPServer.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServer+Testing.h"
#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "internal/flags/nearby_flags.h"
static const NSTimeInterval kTestTimeout = 1.0;
@interface GNCBLEL2CAPServerTest : XCTestCase
@end
@implementation GNCBLEL2CAPServerTest
#pragma mark Tests
- (void)tearDown {
nearby::NearbyFlags::GetInstance().ResetOverridedValues();
[super tearDown];
}
- (void)testInit_setsDelegateCorrectlyBasedOnFlag {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *server =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
// In shared mode, functionality is delegated to the multiplexer, so the server should NOT
// self-assign as delegate.
XCTAssertNil(fakePeripheralManager.peripheralDelegate);
} else {
// In legacy mode, the server owns the manager and sets itself as delegate.
XCTAssertEqual(fakePeripheralManager.peripheralDelegate, server);
}
}
}
- (void)testInit_throwsWithNilManagerWhenFlagEnabled {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
true);
XCTAssertThrowsSpecificNamed(
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:(id<GNCPeripheralManager>)nil
queue:dispatch_get_main_queue()],
NSException, NSInvalidArgumentException);
}
- (void)testPublishL2CAPChannelAndOpenChannelWhenStartListeningChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *psmPublishedExpectation =
[[XCTestExpectation alloc] initWithDescription:@"PSM published."];
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
[psmPublishedExpectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
XCTAssertNil(error);
XCTAssertNotNil(stream);
[channelOpenedexpectation fulfill];
}];
[self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ]
timeout:kTestTimeout];
XCTAssertNotNil([l2capServer valueForKey:@"l2CAPChannel"]);
XCTAssertNotNil([l2capServer valueForKey:@"l2CAPStream"]);
}
}
- (void)testFailedToPublishL2CAPChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
fakePeripheralManager.didPublishL2CAPChannelError = [NSError errorWithDomain:@"fake"
code:0
userInfo:nil];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *psmPublishedExpectation =
[[XCTestExpectation alloc] initWithDescription:@"PSM published with error."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, fakePeripheralManager.didPublishL2CAPChannelError);
XCTAssertEqual(PSM, 0);
[psmPublishedExpectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[self waitForExpectations:@[ psmPublishedExpectation ] timeout:kTestTimeout];
}
}
- (void)testPoweredOffUnpublishesChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOff];
[self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout];
}
}
- (void)testPeripheralManagerDidUpdateStatePoweredOffUnpublishesChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
fakePeripheralManager.state = CBManagerStatePoweredOn;
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
fakePeripheralManager.state = CBManagerStatePoweredOff;
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager];
[self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout];
}
}
- (void)testStartPeripheralManagerInitiallyOff {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *psmPublishedExpectation =
[[XCTestExpectation alloc] initWithDescription:@"PSM published."];
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
[psmPublishedExpectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
[channelOpenedexpectation fulfill];
}];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ]
timeout:kTestTimeout];
}
}
- (void)testClose {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[l2capServer close];
XCTAssertEqual([l2capServer PSM], 0);
}
}
- (void)testCloseDoesNotUnpublishesChannelIfNotConnected {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
fakePeripheralManager.unpublishExpectation.inverted = YES;
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
[l2capServer close];
[self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout];
}
}
- (void)testFailedToOpenL2CAPChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
fakePeripheralManager.didOpenL2CAPChannelError = [NSError errorWithDomain:@"fake"
code:0
userInfo:nil];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(error, nil);
XCTAssertEqual(PSM, fakePeripheralManager.PSM);
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
XCTAssertNil(stream);
XCTAssertEqual(error, fakePeripheralManager.didOpenL2CAPChannelError);
[channelOpenedexpectation fulfill];
}];
[self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout];
XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]);
XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]);
}
}
- (void)testPeripheralManagerDidUnpublishL2CAPChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManager:(CBPeripheralManager *)fakePeripheralManager
didUnpublishL2CAPChannel:l2capServer.PSM
error:[NSError errorWithDomain:@"fake" code:0 userInfo:nil]];
XCTAssertEqual(l2capServer.PSM, 0);
}
}
- (void)testCloseL2CAPChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *channelOpenedexpectation =
[[XCTestExpectation alloc] initWithDescription:@"Channel opened."];
[fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error) {
[channelOpenedexpectation fulfill];
}];
[self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout];
[l2capServer closeL2CAPChannel];
XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]);
XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]);
}
}
- (void)testPeripheralManagerDidPublishL2CAPChannel {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"completion called"];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(PSM, 1);
XCTAssertNil(error);
[expectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManager:(CBPeripheralManager *)fakePeripheralManager
didPublishL2CAPChannel:1
error:nil];
[self waitForExpectations:@[ expectation ] timeout:kTestTimeout];
XCTAssertEqual(l2capServer.PSM, 1);
}
}
- (void)testPeripheralManagerDidPublishL2CAPChannelWithError {
for (NSNumber *enabled in @[ @NO, @YES ]) {
nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue(
nearby::connections::config_package_nearby::nearby_connections_feature::
kEnableSharedPeripheralManager,
enabled.boolValue);
GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init];
GNCBLEL2CAPServer *l2capServer =
[[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager
queue:dispatch_get_main_queue()];
if (enabled.boolValue) {
fakePeripheralManager.peripheralDelegate = l2capServer;
}
XCTestExpectation *expectation =
[[XCTestExpectation alloc] initWithDescription:@"completion called"];
NSError *publishError = [NSError errorWithDomain:@"test" code:0 userInfo:nil];
[l2capServer
startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM,
NSError *_Nullable error) {
XCTAssertEqual(PSM, 0);
XCTAssertEqualObjects(error, publishError);
[expectation fulfill];
}
channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream,
NSError *_Nullable error){
}];
[(id<CBPeripheralManagerDelegate>)l2capServer
peripheralManager:(CBPeripheralManager *)fakePeripheralManager
didPublishL2CAPChannel:0
error:publishError];
[self waitForExpectations:@[ expectation ] timeout:kTestTimeout];
XCTAssertEqual(l2capServer.PSM, 0);
}
}
@end
@@ -225,8 +225,8 @@ static const char *const kTestServiceID = "TestServiceID";
#pragma mark - GATT Server Tests
- (void)testStartGattServer_Success {
_fakeGNCBLEMedium.fakeGATTServer = [[GNCFakeBLEGATTServer alloc] init];
_fakeGNCBLEMedium.fakeGATTServer =
[[GNCFakeBLEGATTServer alloc] initWithPeripheralManager:nil queue:nil];
auto gatt_server = _medium->StartGattServer({});
XCTAssertNotEqual(gatt_server.get(), nullptr);