[NC Apple coverage] Test implementation for Wifi LAN medium.

PiperOrigin-RevId: 802829901
This commit is contained in:
Edwin Wu
2025-09-03 20:39:01 -07:00
committed by Copybara-Service
parent 6e1fd931b7
commit f0d164fc40
14 changed files with 658 additions and 0 deletions
@@ -35,10 +35,15 @@
byte3:(uint8_t)byte3
byte4:(uint8_t)byte4 NS_DESIGNATED_INITIALIZER;
/** Creates an IPv4 address from a 4 byte integer. */
+ (nonnull instancetype)addressFromFourByteInt:(uint32_t)address;
/** Creates an IPv4 address from a 4 byte data object. */
+ (nonnull instancetype)addressFromData:(nonnull NSData *)address;
/** Creates an IPv4 address from a human readable dotted representation. */
+ (nullable instancetype)addressWithDottedRepresentation:(nonnull NSString *)address;
/** The first byte of the IP address. */
@property(nonatomic, readonly) uint8_t byte1;
@@ -47,6 +47,33 @@
byte4:bytes[3]];
}
+ (nullable instancetype)addressWithDottedRepresentation:(NSString *)address {
NSArray<NSString *> *components = [address componentsSeparatedByString:@"."];
if (components.count != 4) {
return nil;
}
uint8_t bytes[4];
for (int i = 0; i < 4; ++i) {
NSScanner *scanner = [NSScanner scannerWithString:components[i]];
int value;
// The string must be a valid integer and must not contain any other characters.
if (![scanner scanInt:&value] || ![scanner isAtEnd]) {
return nil;
}
if (value < 0 || value > 255) {
return nil;
}
bytes[i] = (uint8_t)value;
}
return [[GNCIPv4Address alloc] initWithByte1:bytes[0]
byte2:bytes[1]
byte3:bytes[2]
byte4:bytes[3]];
}
- (NSData *)binaryRepresentation {
const uint8_t bytes[] = {_byte1, _byte2, _byte3, _byte4};
return [NSData dataWithBytes:bytes length:4];
@@ -20,6 +20,25 @@ licenses(["notice"])
package(default_visibility = ["//:__subpackages__"])
objc_library(
name = "FakeNWFramework",
testonly = True,
srcs = [
"GNCFakeNWFramework.m",
"GNCFakeNWFrameworkServerSocket.m",
"GNCFakeNWFrameworkSocket.m",
],
hdrs = [
"GNCFakeNWFramework.h",
"GNCFakeNWFrameworkServerSocket.h",
"GNCFakeNWFrameworkSocket.h",
],
deps = [
"//internal/platform/implementation/apple/Mediums/WiFiCommon",
"//third_party/apple_frameworks:Foundation",
],
)
objc_library(
name = "WiFiCommonTestsLib",
testonly = True,
@@ -0,0 +1,46 @@
// 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class GNCFakeNWFrameworkSocket;
@class GNCFakeNWFrameworkServerSocket;
/** A fake implementation of @c GNCNWFramework to inject for testing. */
@interface GNCFakeNWFramework : GNCNWFramework
@property(nonatomic, nullable) NSNumber* startedAdvertisingPort;
@property(nonatomic, nullable) NSString* startedAdvertisingServiceName;
@property(nonatomic, nullable) NSString* startedAdvertisingServiceType;
@property(nonatomic, nullable) NSNumber* stoppedAdvertisingPort;
@property(nonatomic, nullable) NSString* startedDiscoveryServiceType;
@property(nonatomic) BOOL startedDiscoveryIncludePeerToPeer;
@property(nonatomic, nullable) NSString* stoppedDiscoveryServiceType;
@property(nonatomic, nullable) NSString* connectedToServiceName;
@property(nonatomic, nullable) NSString* connectedToServiceType;
@property(nonatomic, nullable) GNCIPv4Address* connectedToHost;
@property(nonatomic) NSInteger connectedToPort;
@property(nonatomic) BOOL connectedToIncludePeerToPeer;
@property(nonatomic) NSInteger listenedForServiceOnPort;
@property(nonatomic) BOOL listenedForServiceIncludePeerToPeer;
@property(nonatomic, readonly) NSMutableArray<GNCFakeNWFrameworkSocket *>* sockets;
@property(nonatomic, readonly) NSMutableArray<GNCFakeNWFrameworkServerSocket *>* serverSockets;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,94 @@
// 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/Tests/GNCFakeNWFramework.h"
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkServerSocket.h"
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.h"
@implementation GNCFakeNWFramework
- (instancetype)init {
self = [super init];
if (self) {
_sockets = [NSMutableArray array];
_serverSockets = [NSMutableArray array];
}
return self;
}
- (void)startAdvertisingPort:(NSInteger)port
serviceName:(NSString*)serviceName
serviceType:(NSString*)serviceType
txtRecords:(NSDictionary<NSString*, NSString*>*)txtRecords {
self.startedAdvertisingPort = @(port);
self.startedAdvertisingServiceName = serviceName;
self.startedAdvertisingServiceType = serviceType;
}
- (void)stopAdvertisingPort:(NSInteger)port {
self.stoppedAdvertisingPort = @(port);
}
- (BOOL)startDiscoveryForServiceType:(NSString*)serviceType
serviceFoundHandler:(nonnull ServiceUpdateHandler)serviceFoundHandler
serviceLostHandler:(nonnull ServiceUpdateHandler)serviceLostHandler
includePeerToPeer:(BOOL)includePeerToPeer
error:(NSError**)error {
self.startedDiscoveryServiceType = serviceType;
self.startedDiscoveryIncludePeerToPeer = includePeerToPeer;
return YES;
}
- (void)stopDiscoveryForServiceType:(NSString*)serviceType {
self.stoppedDiscoveryServiceType = serviceType;
}
- (GNCNWFrameworkSocket*)connectToServiceName:(NSString*)serviceName
serviceType:(NSString*)serviceType
error:(NSError**)error {
self.connectedToServiceName = serviceName;
self.connectedToServiceType = serviceType;
nw_connection_t connection = (nw_connection_t) @"mock connection";
GNCFakeNWFrameworkSocket* socket =
[[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection];
[self.sockets addObject:socket];
return socket;
}
- (GNCNWFrameworkSocket*)connectToHost:(GNCIPv4Address*)host
port:(NSInteger)port
includePeerToPeer:(BOOL)includePeerToPeer
error:(NSError**)error {
self.connectedToHost = host;
self.connectedToPort = port;
self.connectedToIncludePeerToPeer = includePeerToPeer;
nw_connection_t connection = (nw_connection_t) @"mock connection";
GNCFakeNWFrameworkSocket* socket =
[[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection];
[self.sockets addObject:socket];
return socket;
}
- (GNCNWFrameworkServerSocket*)listenForServiceOnPort:(NSInteger)port
includePeerToPeer:(BOOL)includePeerToPeer
error:(NSError**)error {
self.listenedForServiceOnPort = port;
self.listenedForServiceIncludePeerToPeer = includePeerToPeer;
GNCFakeNWFrameworkServerSocket* serverSocket =
[[GNCFakeNWFrameworkServerSocket alloc] initWithPort:port];
[self.serverSockets addObject:serverSocket];
return serverSocket;
}
@end
@@ -0,0 +1,32 @@
// 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/GNCNWFrameworkServerSocket.h"
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class GNCFakeNWFrameworkSocket;
/** A fake implementation of @c GNCNWFrameworkServerSocket to inject for testing. */
@interface GNCFakeNWFrameworkServerSocket : GNCNWFrameworkServerSocket
@property(nonatomic) BOOL isClosed;
@property(nonatomic, nullable) NSError* acceptError;
@property(nonatomic, nullable) GNCFakeNWFrameworkSocket* socketToReturnOnAccept;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,54 @@
// 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/Tests/GNCFakeNWFrameworkServerSocket.h"
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h"
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.h"
@implementation GNCFakeNWFrameworkServerSocket {
GNCIPv4Address *_ipAddress;
}
- (instancetype)initWithPort:(NSInteger)port {
self = [super initWithPort:port];
if (self) {
_ipAddress = [[GNCIPv4Address alloc] initWithByte1:192 byte2:168 byte3:1 byte4:1];
}
return self;
}
- (GNCIPv4Address *)ipAddress {
return _ipAddress;
}
- (nullable GNCNWFrameworkSocket *)acceptWithError:(NSError **)error {
if (self.acceptError) {
if (error) {
*error = self.acceptError;
}
return nil;
}
if (self.socketToReturnOnAccept) {
return self.socketToReturnOnAccept;
}
nw_connection_t connection = (nw_connection_t) @"mock connection";
return [[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection];
}
- (void)close {
self.isClosed = YES;
}
@end
@@ -0,0 +1,32 @@
// 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/GNCNWFrameworkSocket.h"
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/** A fake implementation of @c GNCNWFrameworkSocket to inject for testing. */
@interface GNCFakeNWFrameworkSocket : GNCNWFrameworkSocket
@property(nonatomic, nullable) NSData* dataToRead;
@property(nonatomic, readonly) NSMutableData* writtenData;
@property(nonatomic) BOOL isClosed;
@property(nonatomic, nullable) NSError* readError;
@property(nonatomic, nullable) NSError* writeError;
@end
NS_ASSUME_NONNULL_END
@@ -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.
#import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.h"
@implementation GNCFakeNWFrameworkSocket
- (instancetype)initWithConnection:(nw_connection_t)connection {
self = [super initWithConnection:connection];
if (self) {
_writtenData = [NSMutableData data];
}
return self;
}
- (nullable NSData *)readMaxLength:(NSUInteger)length error:(NSError **)error {
if (self.readError) {
if (error) {
*error = self.readError;
}
return nil;
}
if (self.dataToRead) {
NSData *data = self.dataToRead;
self.dataToRead = nil;
return data;
}
return [NSData data];
}
- (BOOL)write:(NSData *)data error:(NSError **)error {
if (self.writeError) {
if (error) {
*error = self.writeError;
}
return NO;
}
[self.writtenData appendData:data];
return YES;
}
- (void)close {
self.isClosed = YES;
}
@end
@@ -111,4 +111,32 @@
XCTAssertEqual(bytes[3], 171);
}
- (void)testAddressWithDottedRepresentationWithValidAddress {
GNCIPv4Address *address =
[GNCIPv4Address addressWithDottedRepresentation:@"192.168.1.1"];
XCTAssertNotNil(address);
XCTAssertEqual(address.byte1, 192);
XCTAssertEqual(address.byte2, 168);
XCTAssertEqual(address.byte3, 1);
XCTAssertEqual(address.byte4, 1);
}
- (void)testAddressWithDottedRepresentationWithOutOfRangeAddress {
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"256.1.1.1"]);
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"-1.1.1.1"]);
}
- (void)testAddressWithDottedRepresentationWithNonNumericAddress {
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"foo.1.1.1"]);
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"1.foo.1.1"]);
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"1.1.foo.1"]);
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"1.1.1.foo"]);
}
- (void)testAddressWithDottedRepresentationWithInvalidFormatAddress {
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"1.1.1"]);
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@"1.1.1.1.1"]);
XCTAssertNil([GNCIPv4Address addressWithDottedRepresentation:@""]);
}
@end