From bf971db1bb1e6eb7ff5add9ac2495ad1fa67e3d4 Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Wed, 29 Oct 2025 18:24:58 -0700 Subject: [PATCH] [NC Apple coverage] Add unit tests for `network_utils.h`. PiperOrigin-RevId: 825792828 --- .../WiFiCommon/Tests/GNCFakeNWFramework.h | 21 +++ .../WiFiCommon/Tests/GNCFakeNWFramework.m | 16 ++ .../platform/implementation/apple/Tests/BUILD | 3 + .../apple/Tests/network_utils_test.mm | 158 ++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 internal/platform/implementation/apple/Tests/network_utils_test.mm diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.h b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.h index 30c048a1..4d56fbca 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.h +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.h @@ -42,6 +42,27 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, readonly) NSMutableArray* serverSockets; @property(nonatomic, nullable) dispatch_source_t connectedWithCancelSource; @property(nonatomic, nullable) dispatch_queue_t connectedWithQueue; +/** The service found handler block to call when a service is "found". */ +@property(nonatomic, nullable, copy) ServiceUpdateHandler serviceFoundHandler; +/** The service lost handler block to call when a service is "lost". */ +@property(nonatomic, nullable, copy) ServiceUpdateHandler serviceLostHandler; + +/** + * Triggers the service found handler with the given service info. + * + * @param serviceName The name of the service found. + * @param txtRecords The TXT records of the service found. + */ +- (void)triggerServiceFound:(NSString*)serviceName + txtRecords:(NSDictionary*)txtRecords; +/** + * Triggers the service lost handler with the given service info. + * + * @param serviceName The name of the service lost. + * @param txtRecords The TXT records of the service lost. + */ +- (void)triggerServiceLost:(NSString*)serviceName + txtRecords:(NSDictionary*)txtRecords; @end diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.m index 44ce46d6..76f7eb2f 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.m +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.m @@ -48,6 +48,8 @@ error:(NSError **)error { self.startedDiscoveryServiceType = serviceType; self.startedDiscoveryIncludePeerToPeer = includePeerToPeer; + self.serviceFoundHandler = serviceFoundHandler; + self.serviceLostHandler = serviceLostHandler; return YES; } @@ -120,4 +122,18 @@ return serverSocket; } +- (void)triggerServiceFound:(NSString *)serviceName + txtRecords:(NSDictionary *)txtRecords { + if (self.serviceFoundHandler) { + self.serviceFoundHandler(serviceName, txtRecords); + } +} + +- (void)triggerServiceLost:(NSString *)serviceName + txtRecords:(NSDictionary *)txtRecords { + if (self.serviceLostHandler) { + self.serviceLostHandler(serviceName, txtRecords); + } +} + @end diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index caedf5b3..8c998ab8 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -41,15 +41,18 @@ objc_library( "ble_medium_test.mm", "ble_peripheral_test.mm", "ble_socket_test.mm", + "network_utils_test.mm", ], deps = [ "//internal/platform:base", + "//internal/platform:cancellation_flag", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", "//internal/platform/implementation/apple", # buildcleaner: keep "//internal/platform/implementation/apple:Shared", "//internal/platform/implementation/apple:ble_v2", + "//internal/platform/implementation/apple:network_utils", "//internal/platform/implementation/apple/Mediums/BLE", "//internal/platform/implementation/apple/Mediums/BLE/Tests:BLETestsLib", "//internal/platform/implementation/apple/Mediums/CoreLocation/CLLocationManager/Fake", diff --git a/internal/platform/implementation/apple/Tests/network_utils_test.mm b/internal/platform/implementation/apple/Tests/network_utils_test.mm new file mode 100644 index 00000000..026597c9 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/network_utils_test.mm @@ -0,0 +1,158 @@ +// 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. + +#include "internal/platform/implementation/apple/network_utils.h" + +#import + +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/nsd_service_info.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkServerSocket.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h" +#import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFramework.h" + +namespace { +static NSString *const kServiceName = @"service_name"; +static NSString *const kServiceType = @"_test._tcp"; +} // namespace + +@interface GNCNetworkUtilsTest : XCTestCase +@end + +@implementation GNCNetworkUtilsTest { + GNCFakeNWFramework *_fakeNWFramework; +} + +- (void)setUp { + [super setUp]; + _fakeNWFramework = [[GNCFakeNWFramework alloc] init]; +} + +- (void)tearDown { + _fakeNWFramework = nil; + [super tearDown]; +} + +- (void)testStartAdvertising { + nearby::NsdServiceInfo serviceInfo; + serviceInfo.SetServiceName(kServiceName.UTF8String); + serviceInfo.SetServiceType(kServiceType.UTF8String); + serviceInfo.SetPort(1234); + serviceInfo.SetTxtRecord("key", "value"); + + BOOL result = nearby::apple::network_utils::StartAdvertising(_fakeNWFramework, serviceInfo); + + XCTAssertTrue(result); + XCTAssertEqualObjects(_fakeNWFramework.startedAdvertisingPort, @1234); + XCTAssertEqualObjects(_fakeNWFramework.startedAdvertisingServiceName, kServiceName); + XCTAssertEqualObjects(_fakeNWFramework.startedAdvertisingServiceType, kServiceType); +} + +- (void)testStopAdvertising { + nearby::NsdServiceInfo serviceInfo; + serviceInfo.SetPort(1234); + nearby::apple::network_utils::StopAdvertising(_fakeNWFramework, serviceInfo); + XCTAssertEqualObjects(_fakeNWFramework.stoppedAdvertisingPort, @1234); +} + +- (void)testStartDiscovery { + nearby::apple::network_utils::NetworkDiscoveredServiceCallback callback; + BOOL result = nearby::apple::network_utils::StartDiscovery( + _fakeNWFramework, kServiceType.UTF8String, std::move(callback), YES); + + XCTAssertTrue(result); + XCTAssertEqualObjects(_fakeNWFramework.startedDiscoveryServiceType, kServiceType); + XCTAssertTrue(_fakeNWFramework.startedDiscoveryIncludePeerToPeer); +} + +- (void)testStartDiscoveryNoPeerToPeer { + nearby::apple::network_utils::NetworkDiscoveredServiceCallback callback; + BOOL result = nearby::apple::network_utils::StartDiscovery( + _fakeNWFramework, kServiceType.UTF8String, std::move(callback), NO); + + XCTAssertTrue(result); + XCTAssertFalse(_fakeNWFramework.startedDiscoveryIncludePeerToPeer); +} + +- (void)testStopDiscovery { + nearby::apple::network_utils::StopDiscovery(_fakeNWFramework, kServiceType.UTF8String); + XCTAssertEqualObjects(_fakeNWFramework.stoppedDiscoveryServiceType, kServiceType); +} + +- (void)testConnectToServiceByName { + nearby::NsdServiceInfo serviceInfo; + serviceInfo.SetServiceName(kServiceName.UTF8String); + serviceInfo.SetServiceType(kServiceType.UTF8String); + nearby::CancellationFlag flag; + + GNCNWFrameworkSocket *socket = + nearby::apple::network_utils::ConnectToService(_fakeNWFramework, serviceInfo, &flag); + + XCTAssertNotNil(socket); + XCTAssertEqualObjects(_fakeNWFramework.connectedToServiceName, kServiceName); + XCTAssertEqualObjects(_fakeNWFramework.connectedToServiceType, kServiceType); +} + +- (void)testConnectToServiceByIP { + nearby::CancellationFlag flag; + char ip[] = {127, 0, 0, 1}; + std::string ipAddress(ip, 4); + + GNCNWFrameworkSocket *socket = + nearby::apple::network_utils::ConnectToService(_fakeNWFramework, ipAddress, 1234, YES, &flag); + + XCTAssertNotNil(socket); + XCTAssertEqual(_fakeNWFramework.connectedToPort, 1234); +} + +- (void)testListenForService { + GNCNWFrameworkServerSocket *serverSocket = + nearby::apple::network_utils::ListenForService(_fakeNWFramework, 1234, YES); + XCTAssertNotNil(serverSocket); + XCTAssertEqual(_fakeNWFramework.listenedForServiceOnPort, 1234); +} + +- (void)testStartDiscoveryCallbacks { + XCTestExpectation *foundExpectation = [self expectationWithDescription:@"Service found callback"]; + XCTestExpectation *lostExpectation = [self expectationWithDescription:@"Service lost callback"]; + + nearby::apple::network_utils::NetworkDiscoveredServiceCallback callback; + callback.network_service_discovered_cb = [&](const nearby::NsdServiceInfo &service_info) { + XCTAssertEqual(service_info.GetServiceName(), kServiceName.UTF8String); + XCTAssertEqual(service_info.GetServiceType(), kServiceType.UTF8String); + XCTAssertEqual(service_info.GetTxtRecords().size(), 1); + XCTAssertEqual(service_info.GetTxtRecord("key"), std::string("value")); + [foundExpectation fulfill]; + }; + callback.network_service_lost_cb = [&](const nearby::NsdServiceInfo &service_info) { + XCTAssertEqual(service_info.GetServiceName(), kServiceName.UTF8String); + XCTAssertEqual(service_info.GetServiceType(), kServiceType.UTF8String); + XCTAssertEqual(service_info.GetTxtRecords().size(), 1); + XCTAssertEqual(service_info.GetTxtRecord("key"), std::string("value")); + [lostExpectation fulfill]; + }; + + BOOL result = nearby::apple::network_utils::StartDiscovery( + _fakeNWFramework, kServiceType.UTF8String, std::move(callback), YES); + XCTAssertTrue(result); + + NSDictionary *txtRecords = @{@"key" : @"value"}; + [_fakeNWFramework triggerServiceFound:kServiceName txtRecords:txtRecords]; + [_fakeNWFramework triggerServiceLost:kServiceName txtRecords:txtRecords]; + + [self waitForExpectationsWithTimeout:1.0 handler:nil]; +} + +@end