diff --git a/Package.swift b/Package.swift index c55b3871..016f7d23 100644 --- a/Package.swift +++ b/Package.swift @@ -399,6 +399,7 @@ let package = Package( "internal/platform/implementation/apple/Flags/Tests", "internal/platform/implementation/apple/Log/Tests", "internal/platform/implementation/apple/Mediums/Ble/Sockets/Tests", + "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests", "internal/platform/implementation/windows", "third_party", "CONTRIBUTING.md", @@ -429,6 +430,7 @@ let package = Package( "internal/platform/implementation/apple/Log/BUILD", "internal/platform/implementation/apple/Mediums/BUILD", "internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD", + "internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD", "internal/platform/implementation/apple/Tests/BUILD", "internal/platform/implementation/apple/BUILD", "internal/platform/implementation/BUILD", diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index 7feba254..ca58ac8a 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -101,6 +101,7 @@ objc_library( "//internal/platform/implementation:platform", "//internal/platform/implementation:types", "//internal/platform/implementation/apple/Mediums", + "//internal/platform/implementation/apple/Mediums/WiFiCommon", "//internal/platform/implementation/shared:file", "//internal/platform/implementation/apple/Log:GNCLogger", "//internal/platform:cancellation_flag", @@ -190,7 +191,7 @@ objc_library( "//internal/platform:cancellation_flag", "//internal/platform/implementation:comm", "//internal/platform/implementation/apple/Log:GNCLogger", - "//internal/platform/implementation/apple/Mediums", + "//internal/platform/implementation/apple/Mediums/WiFiCommon", "@com_google_absl//absl/functional:any_invocable", ], ) diff --git a/internal/platform/implementation/apple/Mediums/BUILD b/internal/platform/implementation/apple/Mediums/BUILD index dbd7c14c..c8dfb77d 100644 --- a/internal/platform/implementation/apple/Mediums/BUILD +++ b/internal/platform/implementation/apple/Mediums/BUILD @@ -1,6 +1,6 @@ load("@rules_cc//cc:objc_library.bzl", "objc_library") -# Copyright 2020 Google LLC +# 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. @@ -45,13 +45,6 @@ objc_library( "GNCMConnection.m", "Hotspot/GNCHotspotMedium.m", "Hotspot/GNCHotspotSocket.m", - "WiFiCommon/GNCIPv4Address.m", - "WiFiCommon/GNCNWFramework.m", - "WiFiCommon/GNCNWFrameworkError.m", - "WiFiCommon/GNCNWFrameworkServerSocket.m", - "WiFiCommon/GNCNWFrameworkServerSocket+Internal.h", - "WiFiCommon/GNCNWFrameworkSocket.m", - "WiFiCommon/GNCNWParameters.m", ], hdrs = [ "BLEv2/GNCBLEError.h", @@ -73,12 +66,6 @@ objc_library( "GNCMConnection.h", "Hotspot/GNCHotspotMedium.h", "Hotspot/GNCHotspotSocket.h", - "WiFiCommon/GNCIPv4Address.h", - "WiFiCommon/GNCNWFramework.h", - "WiFiCommon/GNCNWFrameworkError.h", - "WiFiCommon/GNCNWFrameworkServerSocket.h", - "WiFiCommon/GNCNWFrameworkSocket.h", - "WiFiCommon/GNCNWParameters.h", ], deps = [ "//internal/encoding:base85", @@ -86,6 +73,7 @@ objc_library( "//internal/platform/implementation/apple/Flags", "//internal/platform/implementation/apple/Log:GNCLogger", "//internal/platform/implementation/apple/Mediums/Ble/Sockets:Shared", + "//internal/platform/implementation/apple/Mediums/WiFiCommon", "//proto/mediums:ble_frames_cc_proto", "//third_party/apple_frameworks:CoreBluetooth", "//third_party/apple_frameworks:CoreLocation", diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD b/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD new file mode 100644 index 00000000..6a398865 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD @@ -0,0 +1,57 @@ +# 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. + +load("@rules_cc//cc:objc_library.bzl", "objc_library") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS") +load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test") + +licenses(["notice"]) + +package(default_visibility = [ + "//internal/platform/implementation/apple:__subpackages__", +]) + +objc_library( + name = "WiFiCommon", + srcs = [ + "GNCIPv4Address.m", + "GNCNWFramework.m", + "GNCNWFrameworkError.m", + "GNCNWFrameworkServerSocket.m", + "GNCNWFrameworkSocket.m", + "GNCNWParameters.m", + ], + hdrs = [ + "GNCIPv4Address.h", + "GNCNWFramework.h", + "GNCNWFrameworkError.h", + "GNCNWFrameworkServerSocket.h", + "GNCNWFrameworkServerSocket+Internal.h", + "GNCNWFrameworkSocket.h", + "GNCNWParameters.h", + ], + deps = [ + "//internal/platform/implementation/apple/Log:GNCLogger", + "//third_party/apple_frameworks:Foundation", + "//third_party/apple_frameworks:Network", + "//third_party/apple_frameworks:Security", + ], +) + +swift_explicit_module_build_test( + name = "swift_explicit_module_build_test", + ignore_headerless_targets = True, + minimum_os_version = IOS_MINIMUM_OS, + platform_type = "ios", +) diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.m index 8e7dae73..1dd02e4a 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.m +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.m @@ -22,7 +22,8 @@ NS_ASSUME_NONNULL_BEGIN -BOOL GNCConfigureTLSOptions(sec_protocol_options_t options, NSData *PSK, NSData *identity) { +BOOL GNCConfigureTLSOptions(sec_protocol_options_t _Nullable options, NSData *PSK, + NSData *identity) { if (!options) { GNCLoggerError(@"[GNCNWParameters] Invalid parameter of options."); return NO; diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD new file mode 100644 index 00000000..2c812091 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD @@ -0,0 +1,45 @@ +# 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. + +load("@rules_apple//apple:ios.bzl", "ios_unit_test") +load("@rules_cc//cc:objc_library.bzl", "objc_library") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS") + +licenses(["notice"]) + +package(default_visibility = ["//:__subpackages__"]) + +objc_library( + name = "WiFiCommonTestsLib", + testonly = True, + srcs = [ + "GNCIPAddressTest.mm", + "GNCNWFrameworkServerSocketTest.m", + "GNCNWFrameworkSocketTest.m", + "GNCNWFrameworkTest.m", + "GNCNWParametersTest.m", + ], + deps = [ + "//internal/platform/implementation/apple/Mediums/WiFiCommon", + "//third_party/apple_frameworks:XCTest", + "//third_party/objective_c/ocmock/v3:OCMock", + ], +) + +ios_unit_test( + name = "WiFiCommonTests", + minimum_os_version = IOS_MINIMUM_OS, + runner = "//testing/utp/ios:IOS_LATEST", + deps = [":WiFiCommonTestsLib"], +) diff --git a/internal/platform/implementation/apple/Tests/GNCIPAddressTest.mm b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCIPAddressTest.mm similarity index 100% rename from internal/platform/implementation/apple/Tests/GNCIPAddressTest.mm rename to internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCIPAddressTest.mm diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkServerSocketTest.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkServerSocketTest.m new file mode 100644 index 00000000..87746d60 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkServerSocketTest.m @@ -0,0 +1,80 @@ +// 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 +#import +#import + +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket.h" +#import "third_party/objective_c/ocmock/v3/Source/OCMock/OCMock.h" + +@interface GNCNWFrameworkServerSocketTest : XCTestCase +@end + +@implementation GNCNWFrameworkServerSocketTest { + id _mockListener; +} + +- (void)setUp { + [super setUp]; + if (@available(iOS 13.0, *)) { + // This mock is not actually used by the code under test internally, as nw_listener_create is + // called directly. + _mockListener = OCMProtocolMock(@protocol(OS_nw_listener)); + } +} + +- (void)testInitAndProperties API_AVAILABLE(ios(13.0)) { + // Difficult to test initWithPort directly without mocking nw_listener_create. + // We can only test that it doesn't immediately crash. + // Consider refactoring GNCNWFrameworkServerSocket to inject the listener for testability. + NSInteger port = 0; // Use port 0 to let the system pick an available port + // This will call the real nw_listener_create, potentially failing in a test environment. + GNCNWFrameworkServerSocket *serverSocket = [[GNCNWFrameworkServerSocket alloc] initWithPort:port]; + XCTAssertNotNil(serverSocket, @"Failed to initialize GNCNWFrameworkServerSocket"); + + // We can't reliably check the port number as it's system-assigned, but we can check if it's + // non-negative. + XCTAssertGreaterThanOrEqual(serverSocket.port, 0, @"Port number should be non-negative"); + + [serverSocket close]; +} + +- (void)testGetIPAddress API_AVAILABLE(ios(13.0)) { + GNCNWFrameworkServerSocket *serverSocket = [[GNCNWFrameworkServerSocket alloc] initWithPort:0]; + XCTAssertNotNil(serverSocket, @"Failed to initialize GNCNWFrameworkServerSocket"); + // The IP address on a test runner can vary. We mainly check that it returns something non-nil. + // A more thorough test would require mocking network interfaces. + GNCIPv4Address *ipAddress = serverSocket.ipAddress; + XCTAssertNotNil(ipAddress, @"ipAddress should return a non-nil value"); + // We can't know the exact IP, but it should not be empty or null. + XCTAssertGreaterThan(ipAddress.dottedRepresentation.length, 0, + @"IP address string should not be empty"); + + [serverSocket close]; +} + +- (void)testCloseMultipleTimes API_AVAILABLE(ios(13.0)) { + GNCNWFrameworkServerSocket *serverSocket = [[GNCNWFrameworkServerSocket alloc] initWithPort:0]; + XCTAssertNotNil(serverSocket, @"Failed to initialize GNCNWFrameworkServerSocket"); + + [serverSocket close]; + // Test that closing a second time does not crash. + XCTAssertNoThrow([serverSocket close], @"Closing an already closed socket should not throw"); +} + +// Testing accept() is difficult without a client connection or extensive mocking of nw_connection. + +@end diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.m new file mode 100644 index 00000000..44ec9f91 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.m @@ -0,0 +1,41 @@ +// 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 +#import +#import + +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h" +#import "third_party/objective_c/ocmock/v3/Source/OCMock/OCMock.h" + +@interface GNCNWFrameworkSocketTest : XCTestCase +@end + +@implementation GNCNWFrameworkSocketTest { + id _mockConnection; +} + +- (void)setUp { + [super setUp]; + if (@available(iOS 13.0, *)) { + _mockConnection = OCMProtocolMock(@protocol(OS_nw_connection)); + } +} + +- (void)testInitWithConnection API_AVAILABLE(ios(13.0)) { + GNCNWFrameworkSocket *socket = [[GNCNWFrameworkSocket alloc] initWithConnection:_mockConnection]; + XCTAssertNotNil(socket); +} + +@end diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkTest.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkTest.m new file mode 100644 index 00000000..2519a313 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkTest.m @@ -0,0 +1,262 @@ +// 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/WiFiCommon/GNCNWFramework.h" + +#import +#import "third_party/objective_c/ocmock/v3/Source/OCMock/OCMock.h" + +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket+Internal.h" + +// A mock GNCNWFrameworkServerSocket used to test the advertising/listening methods on +// GNCNWFramework. +@interface GNCMockNWFrameworkServerSocket : GNCNWFrameworkServerSocket +@property(nonatomic) BOOL startListeningResult; +@property(nonatomic, nullable) NSError *startListeningError; +@property(nonatomic, nullable, copy) NSData *startListeningPSKIdentity; +@property(nonatomic, nullable, copy) NSData *startListeningPSKSharedSecret; +@property(nonatomic) BOOL startListeningIncludePeerToPeer; +@property(nonatomic) BOOL startAdvertisingCalled; +@property(nonatomic, nullable, copy) NSString *startAdvertisingServiceName; +@property(nonatomic, nullable, copy) NSString *startAdvertisingServiceType; +@property(nonatomic, nullable, copy) NSDictionary *startAdvertisingTXTRecords; +@property(nonatomic) BOOL stopAdvertisingCalled; + +- (instancetype)initWithPort:(NSInteger)port NS_DESIGNATED_INITIALIZER; +@end + +@implementation GNCMockNWFrameworkServerSocket +@synthesize startListeningResult; +@synthesize startListeningError; +@synthesize startListeningPSKIdentity; +@synthesize startListeningPSKSharedSecret; +@synthesize startListeningIncludePeerToPeer; +@synthesize startAdvertisingCalled; +@synthesize startAdvertisingServiceName; +@synthesize startAdvertisingServiceType; +@synthesize startAdvertisingTXTRecords; +@synthesize stopAdvertisingCalled; + +- (instancetype)initWithPort:(NSInteger)port { + self = [super initWithPort:port]; + if (self) { + self.startListeningResult = YES; + } + return self; +} + +- (BOOL)startListeningWithError:(NSError **)error + includePeerToPeer:(BOOL)includePeerToPeer { + self.startListeningIncludePeerToPeer = includePeerToPeer; + if (!self.startListeningResult && error != nil) { + *error = self.startListeningError; + } + return self.startListeningResult; +} + +- (BOOL)startListeningWithPSKIdentity:(NSData *)PSKIdentity + PSKSharedSecret:(NSData *)PSKSharedSecret + includePeerToPeer:(BOOL)includePeerToPeer + error:(NSError **)error { + self.startListeningPSKIdentity = PSKIdentity; + self.startListeningPSKSharedSecret = PSKSharedSecret; + self.startListeningIncludePeerToPeer = includePeerToPeer; + if (!self.startListeningResult && error != nil) { + *error = self.startListeningError; + } + return self.startListeningResult; +} + +- (void)startAdvertisingServiceName:(NSString *)serviceName + serviceType:(NSString *)serviceType + txtRecords:(NSDictionary *)txtRecords { + self.startAdvertisingCalled = YES; + self.startAdvertisingServiceName = serviceName; + self.startAdvertisingServiceType = serviceType; + self.startAdvertisingTXTRecords = txtRecords; +} + +- (void)stopAdvertising { + self.stopAdvertisingCalled = YES; +} + +@end + +@interface GNCNWFrameworkTest : XCTestCase +@end + +@implementation GNCNWFrameworkTest + +- (void)testGNCNWFrameworkCanBeInstantiated { + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + XCTAssertNotNil(framework); +} + +- (void)testIsListeningForAnyServiceWhenNoServicesAreListening { + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + XCTAssertFalse([framework isListeningForAnyService]); +} + +- (void)testListenForServiceOnPortSuccess { + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + id mockServerSocket = OCMClassMock([GNCNWFrameworkServerSocket class]); + id mockServerSocketAlloc = OCMClassMock([GNCNWFrameworkServerSocket class]); + OCMStub([mockServerSocketAlloc alloc]).andReturn(mockServerSocketAlloc); + OCMStub([mockServerSocketAlloc initWithPort:1234]).andReturn(mockServerSocket); + OCMStub([mockServerSocket startListeningWithError:[OCMArg anyObjectRef] + includePeerToPeer:NO]) + .andReturn(YES); + + NSError *error = nil; + GNCNWFrameworkServerSocket *serverSocket = + [framework listenForServiceOnPort:1234 includePeerToPeer:NO error:&error]; + XCTAssertNotNil(serverSocket); + XCTAssertNil(error); + XCTAssertTrue([framework isListeningForAnyService]); +} + +- (void)testListenForServiceOnPortFailure { + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + id mockServerSocket = OCMClassMock([GNCNWFrameworkServerSocket class]); + id mockServerSocketAlloc = OCMClassMock([GNCNWFrameworkServerSocket class]); + OCMStub([mockServerSocketAlloc alloc]).andReturn(mockServerSocketAlloc); + OCMStub([mockServerSocketAlloc initWithPort:1234]).andReturn(mockServerSocket); + OCMStub([mockServerSocket startListeningWithError:[OCMArg anyObjectRef] + includePeerToPeer:NO]) + .andDo(^(id localSelf, NSError **error, BOOL includePeerToPeer) { + if (error) { + *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EACCES userInfo:nil]; + } + return NO; + }); + + NSError *error = nil; + GNCNWFrameworkServerSocket *serverSocket = + [framework listenForServiceOnPort:1234 includePeerToPeer:NO error:&error]; + XCTAssertNil(serverSocket); + XCTAssertNotNil(error); + XCTAssertFalse([framework isListeningForAnyService]); +} + +- (void)testListenForServiceWithPSKIdentityPSKSharedSecretSuccess { + NSData *pskIdentity = [@"testIdentity" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *pskSharedSecret = [@"testSharedSecret" dataUsingEncoding:NSUTF8StringEncoding]; + + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + id mockServerSocket = OCMClassMock([GNCNWFrameworkServerSocket class]); + id mockServerSocketAlloc = OCMClassMock([GNCNWFrameworkServerSocket class]); + OCMStub([mockServerSocketAlloc alloc]).andReturn(mockServerSocketAlloc); + OCMStub([mockServerSocketAlloc initWithPort:1234]).andReturn(mockServerSocket); + OCMStub([mockServerSocket startListeningWithPSKIdentity:pskIdentity + PSKSharedSecret:pskSharedSecret + includePeerToPeer:YES + error:[OCMArg anyObjectRef]]) + .andReturn(YES); + + NSError *error = nil; + GNCNWFrameworkServerSocket *serverSocket = [framework + listenForServiceWithPSKIdentity:pskIdentity + PSKSharedSecret:pskSharedSecret + port:1234 + includePeerToPeer:YES + error:&error]; + XCTAssertNotNil(serverSocket); + XCTAssertNil(error); + XCTAssertTrue([framework isListeningForAnyService]); +} + +- (void)testListenForServiceWithPSKIdentityPSKSharedSecretFailure { + NSData *pskIdentity = [@"testIdentity" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *pskSharedSecret = [@"testSharedSecret" dataUsingEncoding:NSUTF8StringEncoding]; + + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + id mockServerSocket = OCMClassMock([GNCNWFrameworkServerSocket class]); + id mockServerSocketAlloc = OCMClassMock([GNCNWFrameworkServerSocket class]); + OCMStub([mockServerSocketAlloc alloc]).andReturn(mockServerSocketAlloc); + OCMStub([mockServerSocketAlloc initWithPort:1234]).andReturn(mockServerSocket); + OCMStub([mockServerSocket startListeningWithPSKIdentity:pskIdentity + PSKSharedSecret:pskSharedSecret + includePeerToPeer:NO + error:[OCMArg anyObjectRef]]) + .andDo(^(id localSelf, NSData *PSKIdentity, NSData *PSKSharedSecret, BOOL includePeerToPeer, + NSError **error) { + if (error) { + *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EACCES userInfo:nil]; + } + return NO; + }); + + NSError *error = nil; + GNCNWFrameworkServerSocket *serverSocket = [framework + listenForServiceWithPSKIdentity:pskIdentity + PSKSharedSecret:pskSharedSecret + port:1234 + includePeerToPeer:NO + error:&error]; + XCTAssertNil(serverSocket); + XCTAssertNotNil(error); + XCTAssertFalse([framework isListeningForAnyService]); +} + +- (void)testStartAdvertisingPort { + NSInteger port = 1234; + NSString *serviceName = @"TestService"; + NSString *serviceType = @"_test._tcp."; + NSDictionary *txtRecords = @{@"key": @"value"}; + + GNCMockNWFrameworkServerSocket *mockServerSocket = + [[GNCMockNWFrameworkServerSocket alloc] initWithPort:port]; + + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + NSMapTable *serverSockets = + [framework valueForKey:@"_serverSockets"]; + [serverSockets setObject:mockServerSocket forKey:@(port)]; + + [framework startAdvertisingPort:port + serviceName:serviceName + serviceType:serviceType + txtRecords:txtRecords]; + + XCTAssertTrue(mockServerSocket.startAdvertisingCalled); + XCTAssertEqualObjects(mockServerSocket.startAdvertisingServiceName, serviceName); + XCTAssertEqualObjects(mockServerSocket.startAdvertisingServiceType, serviceType); + XCTAssertEqualObjects(mockServerSocket.startAdvertisingTXTRecords, txtRecords); +} + +- (void)testStopAdvertisingPort { + NSInteger port = 1234; + GNCMockNWFrameworkServerSocket *mockServerSocket = + [[GNCMockNWFrameworkServerSocket alloc] initWithPort:port]; + + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + NSMapTable *serverSockets = + [framework valueForKey:@"_serverSockets"]; + [serverSockets setObject:mockServerSocket forKey:@(port)]; + + XCTAssertTrue([[[serverSockets keyEnumerator] allObjects] containsObject:@(port)]); + + [framework stopAdvertisingPort:port]; + + XCTAssertTrue(mockServerSocket.stopAdvertisingCalled); + XCTAssertFalse([[[serverSockets keyEnumerator] allObjects] containsObject:@(port)]); +} + +- (void)testIsDiscoveringAnyServiceWhenNoServicesAreDiscovering { + GNCNWFramework *framework = [[GNCNWFramework alloc] init]; + XCTAssertFalse([framework isDiscoveringAnyService]); +} + +@end diff --git a/internal/platform/implementation/apple/Tests/GNCNWParametersTest.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWParametersTest.m similarity index 78% rename from internal/platform/implementation/apple/Tests/GNCNWParametersTest.m rename to internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWParametersTest.m index 8ad55469..df1b81e4 100644 --- a/internal/platform/implementation/apple/Tests/GNCNWParametersTest.m +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWParametersTest.m @@ -15,8 +15,13 @@ #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWParameters.h" #import +#import #import +// Declare the C function here to make it visible for testing. +FOUNDATION_EXPORT BOOL GNCConfigureTLSOptions(sec_protocol_options_t _Nullable options, NSData *PSK, + NSData *identity); + @interface GNCNWParametersTest : XCTestCase @end @@ -27,6 +32,12 @@ XCTAssertTrue(nw_parameters_get_include_peer_to_peer(params)); } +- (void)testConfigureTLSOptionsWithNilOptions { + BOOL result = GNCConfigureTLSOptions(nil, [@"12345678" dataUsingEncoding:NSUTF8StringEncoding], + [@"nearby" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertFalse(result); +} + - (void)testTLSParametersWithEmptyPSK { nw_parameters_t params = GNCBuildTLSParameters([@"" dataUsingEncoding:NSUTF8StringEncoding], diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index 258639ca..343923a5 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -47,9 +47,7 @@ objc_library( "GNCFakePeripheral.m", "GNCFakePeripheralManager.h", "GNCFakePeripheralManager.m", - "GNCIPAddressTest.mm", "GNCMultiThreadExecutorTest.mm", - "GNCNWParametersTest.m", "GNCPlatformTest.mm", "GNCScheduledExecutorTest.mm", "GNCSingleThreadExecutorTest.mm",