11import Foundation
2- import XCTest
2+ import Testing
33import SystemPackage
4+ import Logging
45@testable import Socket
56
6- final class SocketTests : XCTestCase {
7+ @Suite ( " Socket Tests " )
8+ struct SocketTests {
9+
10+ static let logger = Logger ( label: " logger " ) { label in
11+ var handler = StreamLogHandler . standardOutput ( label: label)
12+ // handler.logLevel = .debug
13+ return handler
14+ }
715
816 #if os(Linux)
9- func _testUnixSocket( ) async throws {
17+ @Test ( " Unix Socket Communication " )
18+ func testUnixSocket( ) async throws {
1019 let address = UnixSocketAddress ( path: FilePath ( " /tmp/testsocket.sock " ) )
11- NSLog ( " Using path \( address. path. description) " )
20+ Self . logger . info ( " Using path \( address. path. description) " )
1221 let socketA = try await Socket (
1322 UnixProtocol . raw
1423 )
15- NSLog ( " Created socket A " )
24+ Self . logger . info ( " Created socket A " )
1625 let option : GenericSocketOption . ReuseAddress = true
1726 try socketA. fileDescriptor. setSocketOption ( option)
1827 do { try socketA. fileDescriptor. bind ( address) }
@@ -22,57 +31,58 @@ final class SocketTests: XCTestCase {
2231 let socketB = try await Socket (
2332 UnixProtocol . raw
2433 )
25- NSLog ( " Created socket B " )
34+ Self . logger . info ( " Created socket B " )
2635 try socketB. fileDescriptor. setSocketOption ( option)
2736 try socketB. fileDescriptor. bind ( address)
2837 defer { Task { await socketB. close ( ) } }
2938
3039 let data = Data ( " Test \( UUID ( ) ) " . utf8)
3140
3241 try await socketA. write ( data)
33- NSLog ( " Socket A wrote data " )
42+ Self . logger . info ( " Socket A wrote data " )
3443 let read = try await socketB. read ( data. count)
35- NSLog ( " Socket B read data " )
36- XCTAssertEqual ( data, read)
44+ Self . logger . info ( " Socket B read data " )
45+ #expect ( data == read)
3746 }
3847 #endif
3948
49+ @Test ( " IPv4 TCP Socket Communication " )
4050 func testIPv4TCPSocket( ) async throws {
4151 let port = UInt16 . random ( in: 8080 ..< . max)
42- print ( " Using port \( port) " )
52+ Self . logger . info ( " Using port \( port) " )
4353 let address = IPv4SocketAddress ( address: . any, port: port)
4454 let data = Data ( " Test \( UUID ( ) ) " . utf8)
4555 let server = try await Socket (
4656 IPv4Protocol . tcp,
4757 bind: address
4858 )
4959 let newConnectionTask = Task {
50- XCTAssertEqual ( try server. fileDescriptor. address ( IPv4SocketAddress . self) , address)
51- NSLog ( " Server: Created server socket \( server. fileDescriptor) " )
60+ #expect ( try server. fileDescriptor. address ( IPv4SocketAddress . self) == address)
61+ Self . logger . info ( " Server: Created server socket \( server. fileDescriptor) " )
5262 try await server. listen ( )
5363
54- NSLog ( " Server: Waiting on incoming connection " )
64+ Self . logger . info ( " Server: Waiting on incoming connection " )
5565 let newConnection = try await server. accept ( )
56- NSLog ( " Server: Got incoming connection \( newConnection. fileDescriptor) " )
57- XCTAssertEqual ( try newConnection. fileDescriptor. address ( IPv4SocketAddress . self) . address. rawValue, " 127.0.0.1 " )
66+ Self . logger . info ( " Server: Got incoming connection \( newConnection. fileDescriptor) " )
67+ #expect ( try newConnection. fileDescriptor. address ( IPv4SocketAddress . self) . address. rawValue == " 127.0.0.1 " )
5868 let eventsTask = Task {
5969 var events = [ Socket . Event] ( )
6070 for try await event in newConnection. event {
6171 events. append ( event)
62- NSLog ( " Server Connection: \( event) " )
72+ Self . logger . info ( " Server Connection: \( event) " )
6373 }
6474 return events
6575 }
6676 try await Task . sleep ( nanoseconds: 10_000_000 )
6777 let _ = try await newConnection. write ( data)
68- NSLog ( " Server: Wrote outgoing data " )
78+ Self . logger . info ( " Server: Wrote outgoing data " )
6979 return try await eventsTask. value
7080 }
7181 let serverEventsTask = Task {
7282 var events = [ Socket . Event] ( )
7383 for try await event in server. event {
7484 events. append ( event)
75- NSLog ( " Server: \( event) " )
85+ Self . logger . info ( " Server: \( event) " )
7686 }
7787 return events
7888 }
@@ -84,39 +94,40 @@ final class SocketTests: XCTestCase {
8494 var events = [ Socket . Event] ( )
8595 for try await event in client. event {
8696 events. append ( event)
87- NSLog ( " Client: \( event) " )
97+ Self . logger . info ( " Client: \( event) " )
8898 }
8999 return events
90100 }
91- XCTAssertEqual ( try client. fileDescriptor. address ( IPv4SocketAddress . self) . address, . any)
92- NSLog ( " Client: Created client socket \( client. fileDescriptor) " )
101+ #expect ( try client. fileDescriptor. address ( IPv4SocketAddress . self) . address == . any)
102+ Self . logger . info ( " Client: Created client socket \( client. fileDescriptor) " )
93103
94- NSLog ( " Client: Will connect to server " )
104+ Self . logger . info ( " Client: Will connect to server " )
95105 do { try await client. connect ( to: address) }
96106 catch Errno . socketIsConnected { }
97- NSLog ( " Client: Connected to server " )
98- XCTAssertEqual ( try client. fileDescriptor. address ( IPv4SocketAddress . self) . address. rawValue, " 127.0.0.1 " )
99- XCTAssertEqual ( try client. fileDescriptor. peerAddress ( IPv4SocketAddress . self) . address. rawValue, " 127.0.0.1 " )
107+ Self . logger . info ( " Client: Connected to server " )
108+ #expect ( try client. fileDescriptor. address ( IPv4SocketAddress . self) . address. rawValue == " 127.0.0.1 " )
109+ #expect ( try client. fileDescriptor. peerAddress ( IPv4SocketAddress . self) . address. rawValue == " 127.0.0.1 " )
100110 let read = try await client. read ( data. count)
101- NSLog ( " Client: Read incoming data " )
102- XCTAssertEqual ( data, read)
111+ Self . logger . info ( " Client: Read incoming data " )
112+ #expect ( data == read)
103113 try await Task . sleep ( nanoseconds: 2_000_000_000 )
104114 await client. close ( )
105115 let clientEvents = try await clientEventsTask. value
106- XCTAssertEqual ( clientEvents. count, 4 )
107- XCTAssertEqual ( " \( clientEvents) " , " [Socket.Socket.Event.write, Socket.Socket.Event.read, Socket.Socket.Event.didRead(41), Socket.Socket.Event.close] " )
116+ #expect ( clientEvents. count == 4 )
117+ #expect ( " \( clientEvents) " == " [Socket.Socket.Event.write, Socket.Socket.Event.read, Socket.Socket.Event.didRead(41), Socket.Socket.Event.close] " )
108118 await server. close ( )
109119 let serverEvents = try await serverEventsTask. value
110- XCTAssertEqual ( serverEvents. count, 2 )
111- XCTAssertEqual ( " \( serverEvents) " , " [Socket.Socket.Event.connection, Socket.Socket.Event.close] " )
120+ #expect ( serverEvents. count == 2 )
121+ #expect ( " \( serverEvents) " == " [Socket.Socket.Event.connection, Socket.Socket.Event.close] " )
112122 let newConnectionEvents = try await newConnectionTask. value
113- XCTAssertEqual ( newConnectionEvents. count, 5 )
114- XCTAssertEqual ( " \( newConnectionEvents) " , " [Socket.Socket.Event.write, Socket.Socket.Event.didWrite(41), Socket.Socket.Event.write, Socket.Socket.Event.read, Socket.Socket.Event.close] " )
123+ #expect ( newConnectionEvents. count == 5 )
124+ #expect ( " \( newConnectionEvents) " == " [Socket.Socket.Event.write, Socket.Socket.Event.didWrite(41), Socket.Socket.Event.write, Socket.Socket.Event.read, Socket.Socket.Event.close] " )
115125 }
116126
127+ @Test ( " IPv4 UDP Socket Communication " )
117128 func testIPv4UDPSocket( ) async throws {
118129 let port = UInt16 . random ( in: 8080 ..< . max)
119- print ( " Using port \( port) " )
130+ Self . logger . info ( " Using port \( port) " )
120131 let address = IPv4SocketAddress (
121132 address: . any,
122133 port: port
@@ -129,78 +140,114 @@ final class SocketTests: XCTestCase {
129140 bind: address
130141 )
131142 defer { Task { await server. close ( ) } }
132- NSLog ( " Server: Created server socket \( server. fileDescriptor) " )
143+ Self . logger . info ( " Server: Created server socket \( server. fileDescriptor) " )
133144
134145 do {
135- NSLog ( " Server: Waiting to receive incoming message " )
146+ Self . logger . info ( " Server: Waiting to receive incoming message " )
136147 let ( read, clientAddress) = try await server. receiveMessage ( data. count, fromAddressOf: type ( of: address) )
137- NSLog ( " Server: Received incoming message " )
138- XCTAssertEqual ( data, read)
148+ Self . logger . info ( " Server: Received incoming message " )
149+ #expect ( data == read)
139150
140- NSLog ( " Server: Waiting to send outgoing message " )
151+ Self . logger . info ( " Server: Waiting to send outgoing message " )
141152 try await server. sendMessage ( data, to: clientAddress)
142- NSLog ( " Server: Sent outgoing message " )
153+ Self . logger . info ( " Server: Sent outgoing message " )
143154 } catch {
144- print ( " Server: " , error)
145- XCTFail ( " \( error) " )
155+ Self . logger . error ( " Server error: \( error) " )
156+ Issue . record ( " Server error: \( error) " )
146157 }
147158 }
148159
149160 let client = try await Socket (
150161 IPv4Protocol . udp
151162 )
152163 defer { Task { await client. close ( ) } }
153- NSLog ( " Client: Created client socket \( client. fileDescriptor) " )
164+ Self . logger . info ( " Client: Created client socket \( client. fileDescriptor) " )
154165
155- NSLog ( " Client: Waiting to send outgoing message " )
166+ Self . logger . info ( " Client: Waiting to send outgoing message " )
156167 try await client. sendMessage ( data, to: address)
157- NSLog ( " Client: Sent outgoing message " )
168+ Self . logger . info ( " Client: Sent outgoing message " )
158169
159- NSLog ( " Client: Waiting to receive incoming message " )
170+ Self . logger . info ( " Client: Waiting to receive incoming message " )
160171 let ( read, _) = try await client. receiveMessage ( data. count, fromAddressOf: type ( of: address) )
161- NSLog ( " Client: Received incoming message " )
162- XCTAssertEqual ( data, read)
172+ Self . logger . info ( " Client: Received incoming message " )
173+ #expect ( data == read)
163174 }
164175
176+ @Test ( " Network Interface IPv4 Enumeration " )
165177 func testNetworkInterfaceIPv4( ) throws {
166178 let interfaces = try NetworkInterface< IPv4SocketAddress> . interfaces
167179 if !isRunningInCI {
168- XCTAssert ( interfaces. isEmpty == false )
180+ #expect ( ! interfaces. isEmpty)
169181 }
170182 for interface in interfaces {
171- print ( " \( interface. id. index) . \( interface. id. name) " )
172- print ( " \( interface. address. address) \( interface. address. port) " )
183+ Self . logger . info ( " \( interface. id. index) . \( interface. id. name) " )
184+ Self . logger . info ( " \( interface. address. address) \( interface. address. port) " )
173185 if let netmask = interface. netmask {
174- print ( " \( netmask. address) \( netmask. port) " )
186+ Self . logger . info ( " \( netmask. address) \( netmask. port) " )
175187 }
176188 }
177189 }
178190
191+ @Test ( " Network Interface IPv6 Enumeration " )
179192 func testNetworkInterfaceIPv6( ) throws {
180193 let interfaces = try NetworkInterface< IPv6SocketAddress> . interfaces
181194 if !isRunningInCI {
182- XCTAssert ( interfaces. isEmpty == false )
195+ #expect ( ! interfaces. isEmpty)
183196 }
184197 for interface in interfaces {
185- print ( " \( interface. id. index) . \( interface. id. name) " )
186- print ( " \( interface. address. address) \( interface. address. port) " )
198+ Self . logger . info ( " \( interface. id. index) . \( interface. id. name) " )
199+ Self . logger . info ( " \( interface. address. address) \( interface. address. port) " )
187200 if let netmask = interface. netmask {
188- print ( " \( netmask. address) \( netmask. port) " )
201+ Self . logger . info ( " \( netmask. address) \( netmask. port) " )
189202 }
190203 }
191204 }
192205
193206 #if canImport(Darwin) || os(Linux)
207+ @Test ( " Network Interface Link Layer Enumeration " )
194208 func testNetworkInterfaceLinkLayer( ) throws {
195209 let interfaces = try NetworkInterface< LinkLayerSocketAddress> . interfaces
196210 for interface in interfaces {
197- print ( " \( interface. id. index) . \( interface. id. name) " )
198- print ( interface. address. address)
211+ Self . logger . info ( " \( interface. id. index) . \( interface. id. name) " )
212+ Self . logger . info ( " \( interface. address. address) " )
199213 assert ( interface. id. index == numericCast ( interface. address. index) )
200214 }
201215 }
202216 #endif
203217
218+ @Test ( " IPv4 Loopback Address Byte Order Fix " , . tags( . bugfix) )
219+ func testIPv4LoopbackAddress( ) async throws {
220+ // Test the loopback address byte order issue from GitHub issue #18
221+ let loopback = IPv4Address . loopback
222+ #expect( loopback. rawValue == " 127.0.0.1 " , " IPv4Address.loopback should return '127.0.0.1', not '1.0.0.127' " )
223+
224+ // Test that loopback is equivalent to manually constructed 127.0.0.1
225+ let manualLoopback = IPv4Address ( 127 , 0 , 0 , 1 )
226+ #expect( loopback == manualLoopback, " IPv4Address.loopback should equal manually constructed IPv4Address(127, 0, 0, 1) " )
227+
228+ // Test that loopback is equivalent to string-constructed address
229+ let stringLoopback = IPv4Address ( rawValue: " 127.0.0.1 " ) !
230+ #expect( loopback == stringLoopback, " IPv4Address.loopback should equal string-constructed address " )
231+
232+ // Test that we can actually bind to loopback for TCP
233+ // This should not throw "Can't assign requested address" error
234+ let tcpAddress = IPv4SocketAddress ( address: . loopback, port: 0 )
235+ let tcpSocket = try await Socket ( IPv4Protocol . tcp, bind: tcpAddress)
236+ defer { Task { await tcpSocket. close ( ) } }
237+
238+ // Test that we can also bind to loopback for UDP
239+ let udpAddress = IPv4SocketAddress ( address: . loopback, port: 0 )
240+ let udpSocket = try await Socket ( IPv4Protocol . udp, bind: udpAddress)
241+ defer { Task { await udpSocket. close ( ) } }
242+
243+ // Verify the bound addresses are actually loopback
244+ let boundTcpAddress = try tcpSocket. fileDescriptor. address ( IPv4SocketAddress . self)
245+ #expect( boundTcpAddress. address. rawValue == " 127.0.0.1 " , " Bound TCP socket should be on loopback address " )
246+
247+ let boundUdpAddress = try udpSocket. fileDescriptor. address ( IPv4SocketAddress . self)
248+ #expect( boundUdpAddress. address. rawValue == " 127.0.0.1 " , " Bound UDP socket should be on loopback address " )
249+ }
250+
204251 func testTCPNoDelay( ) async throws {
205252 // Create a TCP socket
206253 let socket = try await Socket ( IPv4Protocol . tcp)
@@ -294,3 +341,7 @@ var isRunningInCI: Bool {
294341 }
295342 return false
296343}
344+
345+ extension Tag {
346+ @Tag static var bugfix : Self
347+ }
0 commit comments