mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
[NC Apple coverage] Refactor CBManagerStateString and add tests for BLE
Sockets utilities and Weave packets. PiperOrigin-RevId: 802825276
This commit is contained in:
committed by
Copybara-Service
parent
1b169516cb
commit
6e1fd931b7
+1
-18
@@ -18,27 +18,10 @@
|
||||
#import "internal/platform/implementation/apple/Log/GNCLogger.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Central/GNSCentralPeerManager+Private.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Central/GNSCentralPeerManager.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSUtils+Private.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSString *CBManagerStateString(CBManagerState state) {
|
||||
switch (state) {
|
||||
case CBManagerStateUnknown:
|
||||
return @"CBManagerStateUnknown";
|
||||
case CBManagerStateResetting:
|
||||
return @"CBManagerStateResetting";
|
||||
case CBManagerStateUnsupported:
|
||||
return @"CBManagerStateUnsupported";
|
||||
case CBManagerStateUnauthorized:
|
||||
return @"CBManagerStateUnauthorized";
|
||||
case CBManagerStatePoweredOff:
|
||||
return @"CBManagerStatePoweredOff";
|
||||
case CBManagerStatePoweredOn:
|
||||
return @"CBManagerStatePoweredOn";
|
||||
}
|
||||
return [NSString stringWithFormat:@"CBManagerState Unknown(%ld)", (long)state];
|
||||
}
|
||||
|
||||
@interface GNSCentralManager () {
|
||||
NSString *_advertisedName;
|
||||
CBUUID *_advertisedServiceUUID;
|
||||
|
||||
+1
-19
@@ -17,29 +17,11 @@
|
||||
#import "internal/platform/implementation/apple/Log/GNCLogger.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralServiceManager+Private.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSSocket+Private.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSUtils+Private.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
static NSString *CBManagerStateString(CBManagerState state) {
|
||||
switch (state) {
|
||||
case CBManagerStateUnknown:
|
||||
return @"CBManagerStateUnknown";
|
||||
case CBManagerStateResetting:
|
||||
return @"CBManagerStateResetting";
|
||||
case CBManagerStateUnsupported:
|
||||
return @"CBManagerStateUnsupported";
|
||||
case CBManagerStateUnauthorized:
|
||||
return @"CBManagerStateUnauthorized";
|
||||
case CBManagerStatePoweredOff:
|
||||
return @"CBManagerStatePoweredOff";
|
||||
case CBManagerStatePoweredOn:
|
||||
return @"CBManagerStatePoweredOn";
|
||||
}
|
||||
return @"CBManagerState Unknown";
|
||||
}
|
||||
|
||||
// http://b/28875581 On iOS, under some misterious conditions, the Bluetooth daemon (BTServer
|
||||
// process) continously crashes when attempting to register Bluetooth services. In fact, if the
|
||||
// BTServer process is killed, the OS spins a new instace of this process after 10 seconds.
|
||||
|
||||
+9
@@ -44,4 +44,13 @@ NSError *GNSErrorWithCode(GNSError errorCode);
|
||||
*/
|
||||
NSString *GNSCharacteristicName(NSString *uuid);
|
||||
|
||||
/**
|
||||
* Returns a human readable name based on a CBManagerState.
|
||||
*
|
||||
* @param state CBManagerState
|
||||
*
|
||||
* @return Name of the CBManagerState.
|
||||
*/
|
||||
NSString *CBManagerStateString(CBManagerState state);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -99,4 +99,22 @@ NSString *GNSCharacteristicName(NSString *uuid) {
|
||||
return @"UnknownChar";
|
||||
}
|
||||
|
||||
NSString *CBManagerStateString(CBManagerState state) {
|
||||
switch (state) {
|
||||
case CBManagerStateUnknown:
|
||||
return @"CBManagerStateUnknown";
|
||||
case CBManagerStateResetting:
|
||||
return @"CBManagerStateResetting";
|
||||
case CBManagerStateUnsupported:
|
||||
return @"CBManagerStateUnsupported";
|
||||
case CBManagerStateUnauthorized:
|
||||
return @"CBManagerStateUnauthorized";
|
||||
case CBManagerStatePoweredOff:
|
||||
return @"CBManagerStatePoweredOff";
|
||||
case CBManagerStatePoweredOn:
|
||||
return @"CBManagerStatePoweredOn";
|
||||
}
|
||||
return @"CBManagerState Unknown";
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -46,6 +46,7 @@ objc_library(
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"Shared/GNSSocketTest.m",
|
||||
"Shared/GNSUtilsTest.m",
|
||||
"Shared/GNSWeavePacketTest.m",
|
||||
],
|
||||
deps = [
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
// 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 <XCTest/XCTest.h>
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSUtils+Private.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSUtils.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GNSUtilsTest : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation GNSUtilsTest
|
||||
|
||||
- (void)testGNSErrorWithCode {
|
||||
// Test all error codes to ensure they have descriptions
|
||||
NSArray<NSNumber *> *allErrorCodes = @[
|
||||
@(GNSErrorNoConnection),
|
||||
@(GNSErrorLostConnection),
|
||||
@(GNSErrorOperationInProgress),
|
||||
@(GNSErrorMissingService),
|
||||
@(GNSErrorMissingCharacteristics),
|
||||
@(GNSErrorPeripheralDidRefuseConnection),
|
||||
@(GNSErrorCancelPendingSocketRequested),
|
||||
@(GNSErrorNewInviteToConnectReceived),
|
||||
@(GNSErrorWeaveErrorPacketReceived),
|
||||
@(GNSErrorUnsupportedWeaveProtocolVersion),
|
||||
@(GNSErrorUnexpectedWeaveControlPacket),
|
||||
@(GNSErrorParsingWeavePacket),
|
||||
@(GNSErrorWrongWeavePacketCounter),
|
||||
@(GNSErrorWeaveDataTransferInProgress),
|
||||
@(GNSErrorParsingWeavePacketTooSmall),
|
||||
@(GNSErrorParsingWeavePacketTooLarge),
|
||||
@(GNSErrorConnectionTimedOut),
|
||||
];
|
||||
for (NSNumber *errorCodeNum in allErrorCodes) {
|
||||
GNSError errorCode = [errorCodeNum integerValue];
|
||||
NSError *currentError = GNSErrorWithCode(errorCode);
|
||||
XCTAssertEqualObjects(currentError.domain, kGNSSocketsErrorDomain);
|
||||
XCTAssertEqual(currentError.code, errorCode);
|
||||
XCTAssertNotNil(currentError.localizedDescription, @"Description missing for error code %ld",
|
||||
(long)errorCode);
|
||||
XCTAssertTrue(currentError.localizedDescription.length > 0,
|
||||
@"Description empty for error code %ld", (long)errorCode);
|
||||
}
|
||||
|
||||
// Test the assertion for GNSErrorNoError
|
||||
XCTAssertThrows(GNSErrorWithCode(GNSErrorNoError),
|
||||
@"Should throw an assertion for GNSErrorNoError");
|
||||
}
|
||||
|
||||
- (void)testGNSCharacteristicName {
|
||||
XCTAssertEqualObjects(GNSCharacteristicName(kGNSWeaveToPeripheralCharUUIDString),
|
||||
@"ToPeripheralChar");
|
||||
XCTAssertEqualObjects(GNSCharacteristicName(kGNSWeaveFromPeripheralCharUUIDString),
|
||||
@"FromPeripheralChar");
|
||||
XCTAssertEqualObjects(GNSCharacteristicName(kGNSPairingCharUUIDString), @"PairingChar");
|
||||
XCTAssertEqualObjects(GNSCharacteristicName(@"UNKNOWN_UUID"), @"UnknownChar");
|
||||
XCTAssertEqualObjects(GNSCharacteristicName(@""), @"UnknownChar");
|
||||
}
|
||||
|
||||
- (void)testCBManagerStateString {
|
||||
XCTAssertEqualObjects(CBManagerStateString(CBManagerStateUnknown), @"CBManagerStateUnknown");
|
||||
XCTAssertEqualObjects(CBManagerStateString(CBManagerStateResetting), @"CBManagerStateResetting");
|
||||
XCTAssertEqualObjects(CBManagerStateString(CBManagerStateUnsupported),
|
||||
@"CBManagerStateUnsupported");
|
||||
XCTAssertEqualObjects(CBManagerStateString(CBManagerStateUnauthorized),
|
||||
@"CBManagerStateUnauthorized");
|
||||
XCTAssertEqualObjects(CBManagerStateString(CBManagerStatePoweredOff),
|
||||
@"CBManagerStatePoweredOff");
|
||||
XCTAssertEqualObjects(CBManagerStateString(CBManagerStatePoweredOn), @"CBManagerStatePoweredOn");
|
||||
// Test with an out-of-range value
|
||||
XCTAssertEqualObjects(CBManagerStateString((CBManagerState)100), @"CBManagerState Unknown");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+203
@@ -16,8 +16,47 @@
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSWeavePacket.h"
|
||||
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSUtils+Private.h"
|
||||
#import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSUtils.h"
|
||||
|
||||
// Fake handler for testing visitWithHandler
|
||||
@interface GNSFakeWeavePacketHandler : NSObject <GNSWeavePacketHandler>
|
||||
@property(nonatomic, nullable) GNSWeaveConnectionRequestPacket *lastConnectionRequestPacket;
|
||||
@property(nonatomic, nullable) GNSWeaveConnectionConfirmPacket *lastConnectionConfirmPacket;
|
||||
@property(nonatomic, nullable) GNSWeaveErrorPacket *lastErrorPacket;
|
||||
@property(nonatomic, nullable) GNSWeaveDataPacket *lastDataPacket;
|
||||
@property(nonatomic, nullable) id lastContext;
|
||||
@property(nonatomic) int handleConnectionRequestCalledCount;
|
||||
@property(nonatomic) int handleConnectionConfirmCalledCount;
|
||||
@property(nonatomic) int handleErrorCalledCount;
|
||||
@property(nonatomic) int handleDataCalledCount;
|
||||
@end
|
||||
|
||||
@implementation GNSFakeWeavePacketHandler
|
||||
- (void)handleConnectionRequestPacket:(GNSWeaveConnectionRequestPacket *)packet
|
||||
context:(nullable id)context {
|
||||
self.lastConnectionRequestPacket = packet;
|
||||
self.lastContext = context;
|
||||
self.handleConnectionRequestCalledCount++;
|
||||
}
|
||||
- (void)handleConnectionConfirmPacket:(GNSWeaveConnectionConfirmPacket *)packet
|
||||
context:(nullable id)context {
|
||||
self.lastConnectionConfirmPacket = packet;
|
||||
self.lastContext = context;
|
||||
self.handleConnectionConfirmCalledCount++;
|
||||
}
|
||||
- (void)handleErrorPacket:(GNSWeaveErrorPacket *)packet context:(nullable id)context {
|
||||
self.lastErrorPacket = packet;
|
||||
self.lastContext = context;
|
||||
self.handleErrorCalledCount++;
|
||||
}
|
||||
- (void)handleDataPacket:(GNSWeaveDataPacket *)packet context:(nullable id)context {
|
||||
self.lastDataPacket = packet;
|
||||
self.lastContext = context;
|
||||
self.handleDataCalledCount++;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GNSWeavePacketTest : XCTestCase {
|
||||
NSData *_largeNonEmptyData;
|
||||
NSData *_smallNonEmptyData;
|
||||
@@ -307,4 +346,168 @@
|
||||
XCTAssertEqualObjects(connectionConfirmPacket.data, smallPayload);
|
||||
}
|
||||
|
||||
- (void)testConnectionRequestVisitWithHandler {
|
||||
GNSWeaveConnectionRequestPacket *requestPacket =
|
||||
[[GNSWeaveConnectionRequestPacket alloc] initWithMinVersion:1
|
||||
maxVersion:1
|
||||
maxPacketSize:20
|
||||
data:nil];
|
||||
GNSFakeWeavePacketHandler *handler = [[GNSFakeWeavePacketHandler alloc] init];
|
||||
id context = [[NSObject alloc] init];
|
||||
|
||||
XCTAssertTrue([requestPacket visitWithHandler:handler context:context]);
|
||||
XCTAssertEqual(handler.handleConnectionRequestCalledCount, 1);
|
||||
XCTAssertEqual(handler.lastConnectionRequestPacket, requestPacket);
|
||||
XCTAssertEqual(handler.lastContext, context);
|
||||
XCTAssertEqual(handler.handleConnectionConfirmCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleErrorCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleDataCalledCount, 0);
|
||||
}
|
||||
|
||||
- (void)testConnectionConfirmVisitWithHandler {
|
||||
GNSWeaveConnectionConfirmPacket *confirmPacket =
|
||||
[[GNSWeaveConnectionConfirmPacket alloc] initWithVersion:1 packetSize:20 data:nil];
|
||||
GNSFakeWeavePacketHandler *handler = [[GNSFakeWeavePacketHandler alloc] init];
|
||||
id context = [[NSObject alloc] init];
|
||||
|
||||
XCTAssertTrue([confirmPacket visitWithHandler:handler context:context]);
|
||||
XCTAssertEqual(handler.handleConnectionConfirmCalledCount, 1);
|
||||
XCTAssertEqual(handler.lastConnectionConfirmPacket, confirmPacket);
|
||||
XCTAssertEqual(handler.lastContext, context);
|
||||
XCTAssertEqual(handler.handleConnectionRequestCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleErrorCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleDataCalledCount, 0);
|
||||
}
|
||||
|
||||
- (void)testErrorVisitWithHandler {
|
||||
GNSWeaveErrorPacket *errorPacket = [[GNSWeaveErrorPacket alloc] initWithPacketCounter:3];
|
||||
GNSFakeWeavePacketHandler *handler = [[GNSFakeWeavePacketHandler alloc] init];
|
||||
id context = [[NSObject alloc] init];
|
||||
|
||||
XCTAssertTrue([errorPacket visitWithHandler:handler context:context]);
|
||||
XCTAssertEqual(handler.handleErrorCalledCount, 1);
|
||||
XCTAssertEqual(handler.lastErrorPacket, errorPacket);
|
||||
XCTAssertEqual(handler.lastContext, context);
|
||||
XCTAssertEqual(handler.handleConnectionRequestCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleConnectionConfirmCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleDataCalledCount, 0);
|
||||
}
|
||||
|
||||
- (void)testDataVisitWithHandler {
|
||||
GNSWeaveDataPacket *dataPacket =
|
||||
[[GNSWeaveDataPacket alloc] initWithPacketCounter:4
|
||||
firstPacket:YES
|
||||
lastPacket:YES
|
||||
data:_smallNonEmptyData];
|
||||
GNSFakeWeavePacketHandler *handler = [[GNSFakeWeavePacketHandler alloc] init];
|
||||
id context = [[NSObject alloc] init];
|
||||
|
||||
XCTAssertTrue([dataPacket visitWithHandler:handler context:context]);
|
||||
XCTAssertEqual(handler.handleDataCalledCount, 1);
|
||||
XCTAssertEqual(handler.lastDataPacket, dataPacket);
|
||||
XCTAssertEqual(handler.lastContext, context);
|
||||
XCTAssertEqual(handler.handleConnectionRequestCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleConnectionConfirmCalledCount, 0);
|
||||
XCTAssertEqual(handler.handleErrorCalledCount, 0);
|
||||
}
|
||||
|
||||
- (void)testVisitWithHandlerNoMatch {
|
||||
GNSWeaveConnectionRequestPacket *requestPacket =
|
||||
[[GNSWeaveConnectionRequestPacket alloc] initWithMinVersion:1
|
||||
maxVersion:1
|
||||
maxPacketSize:20
|
||||
data:nil];
|
||||
// Handler that implements nothing from the protocol
|
||||
id<GNSWeavePacketHandler> emptyHandler = (id<GNSWeavePacketHandler>)[[NSObject alloc] init];
|
||||
|
||||
XCTAssertFalse([requestPacket visitWithHandler:emptyHandler context:nil]);
|
||||
}
|
||||
|
||||
// Additional tests for parsing edge cases
|
||||
|
||||
- (void)testParseConnectionRequestMinSize {
|
||||
UInt8 header = (1 << 7) + 0; // Connection Request, counter 0
|
||||
NSMutableData *payload = [NSMutableData data];
|
||||
UInt16 val = 0;
|
||||
// Min payload size is 6 bytes
|
||||
[payload appendBytes:&val length:sizeof(val)];
|
||||
[payload appendBytes:&val length:sizeof(val)];
|
||||
[payload appendBytes:&val length:sizeof(val)];
|
||||
XCTAssertEqual(payload.length, 6);
|
||||
|
||||
NSError *error = nil;
|
||||
GNSWeavePacket *packet =
|
||||
[GNSWeavePacket parseData:[self weavePacketWithHeader:header data:payload] error:&error];
|
||||
XCTAssertNotNil(packet);
|
||||
XCTAssertNil(error);
|
||||
XCTAssertTrue([packet isKindOfClass:[GNSWeaveConnectionRequestPacket class]]);
|
||||
|
||||
// Too small
|
||||
NSData *tooSmallPayload = [payload subdataWithRange:NSMakeRange(0, 5)];
|
||||
packet = [GNSWeavePacket parseData:[self weavePacketWithHeader:header data:tooSmallPayload]
|
||||
error:&error];
|
||||
XCTAssertNil(packet);
|
||||
XCTAssertEqual(error.code, GNSErrorParsingWeavePacketTooSmall);
|
||||
}
|
||||
|
||||
- (void)testParseConnectionConfirmMinSize {
|
||||
UInt8 header = (1 << 7) + 1; // Connection Confirm, counter 0
|
||||
NSMutableData *payload = [NSMutableData data];
|
||||
UInt16 version = 1;
|
||||
UInt16 packetSize = kGNSMinSupportedPacketSize;
|
||||
// Min payload size is 4 bytes
|
||||
UInt16 versionBigEndian = CFSwapInt16HostToBig(version);
|
||||
UInt16 packetSizeBigEndian = CFSwapInt16HostToBig(packetSize);
|
||||
[payload appendBytes:&versionBigEndian length:sizeof(versionBigEndian)];
|
||||
[payload appendBytes:&packetSizeBigEndian length:sizeof(packetSizeBigEndian)];
|
||||
XCTAssertEqual(payload.length, 4);
|
||||
|
||||
NSError *error = nil;
|
||||
GNSWeavePacket *packet =
|
||||
[GNSWeavePacket parseData:[self weavePacketWithHeader:header data:payload] error:&error];
|
||||
XCTAssertNotNil(packet);
|
||||
XCTAssertNil(error);
|
||||
XCTAssertTrue([packet isKindOfClass:[GNSWeaveConnectionConfirmPacket class]]);
|
||||
|
||||
// Too small
|
||||
NSData *tooSmallPayload = [payload subdataWithRange:NSMakeRange(0, 3)];
|
||||
packet = [GNSWeavePacket parseData:[self weavePacketWithHeader:header data:tooSmallPayload]
|
||||
error:&error];
|
||||
XCTAssertNil(packet);
|
||||
XCTAssertEqual(error.code, GNSErrorParsingWeavePacketTooSmall);
|
||||
}
|
||||
|
||||
- (void)testParseErrorPacketSize {
|
||||
UInt8 header = (1 << 7) + 2; // Error, counter 0
|
||||
// Error packet has no payload
|
||||
NSError *error = nil;
|
||||
GNSWeavePacket *packet = [GNSWeavePacket parseData:[self weavePacketWithHeader:header data:nil]
|
||||
error:&error];
|
||||
XCTAssertNotNil(packet);
|
||||
XCTAssertNil(error);
|
||||
|
||||
// Should still be valid with empty data
|
||||
packet = [GNSWeavePacket parseData:[self weavePacketWithHeader:header data:[NSData data]]
|
||||
error:&error];
|
||||
XCTAssertNotNil(packet);
|
||||
XCTAssertNil(error);
|
||||
|
||||
// Invalid with payload
|
||||
packet = [GNSWeavePacket parseData:[self weavePacketWithHeader:header data:_smallNonEmptyData]
|
||||
error:nil];
|
||||
// This doesn't cause an error in the current parseData, it just ignores the extra data.
|
||||
// Depending on spec, this might be desired or not. Assuming it's fine.
|
||||
XCTAssertNotNil(packet);
|
||||
}
|
||||
|
||||
- (void)testMaxPacketCounter {
|
||||
XCTAssertThrows([[GNSWeaveErrorPacket alloc] initWithPacketCounter:8],
|
||||
@"Should assert for packet counter >= 8");
|
||||
XCTAssertThrows([[GNSWeaveDataPacket alloc] initWithPacketCounter:8
|
||||
firstPacket:YES
|
||||
lastPacket:YES
|
||||
data:_smallNonEmptyData],
|
||||
@"Should assert for packet counter >= 8");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user