1+ import XCTest
2+ import Logging
3+ import HTTPTypes
4+ @testable import SwiftAPIClient
5+
6+ final class LoggingAndListenerTests : XCTestCase {
7+
8+ // MARK: - Configuration Tests
9+
10+ func testLoggingConfiguration( ) {
11+ let logger = Logger ( label: " test " )
12+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
13+ . logger ( logger)
14+ . log ( level: . debug)
15+ . loggingComponents ( . standart)
16+ . logMaskedHeaders ( [ HTTPField . Name ( " Authorization " ) !] )
17+
18+ let configs = client. configs ( )
19+
20+ XCTAssertEqual ( configs. logLevel, . debug)
21+ XCTAssertEqual ( configs. loggingComponents, . standart)
22+ XCTAssertTrue ( configs. logMaskedHeaders. contains ( HTTPField . Name ( " Authorization " ) !) )
23+ }
24+
25+ func testErrorLoggingConfiguration( ) {
26+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
27+ . errorLog ( level: . error)
28+ . errorLoggingComponents ( . basic)
29+
30+ let configs = client. configs ( )
31+
32+ XCTAssertEqual ( configs. errorLogLevel, . error)
33+ XCTAssertEqual ( configs. errorLogginComponents, . basic)
34+ }
35+
36+ func testListenerConfiguration( ) {
37+ let listener = MockAPIClientListener ( )
38+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
39+ . listener ( listener)
40+
41+ let configs = client. configs ( )
42+
43+ // Verify listener is configured (basic structural test)
44+ XCTAssertTrue ( configs. listener is MultiplexAPIClientListener )
45+ }
46+
47+ func testMultipleListenersConfiguration( ) {
48+ let listener1 = MockAPIClientListener ( )
49+ let listener2 = MockAPIClientListener ( )
50+
51+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
52+ . listener ( listener1)
53+ . listener ( listener2)
54+
55+ let configs = client. configs ( )
56+
57+ // Verify multiple listeners are configured
58+ if let multiplexListener = configs. listener as? MultiplexAPIClientListener {
59+ XCTAssertEqual ( multiplexListener. listeners. count, 2 )
60+ } else {
61+ XCTFail ( " Expected MultiplexAPIClientListener " )
62+ }
63+ }
64+
65+ // MARK: - Mock API Caller Tests (Lightweight)
66+
67+ func testMockAPICallerWithListener( ) throws {
68+ let mockListener = MockAPIClientListener ( )
69+ let mockData = " test response " . data ( using: . utf8) !
70+
71+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
72+ . path ( " /listen " )
73+ . listener ( mockListener)
74+ . mock ( mockData)
75+ . usingMocks ( policy: . require)
76+
77+ // Test with simplified call that doesn't trigger metrics linking issues
78+ let result : Data = try client. configs ( ) . getMockIfNeeded ( for: Data . self, serializer: . data) ?? Data ( )
79+
80+ XCTAssertEqual ( result, mockData)
81+ }
82+
83+ // MARK: - Logging Components Tests
84+
85+ func testLoggingComponentsOptions( ) {
86+ // Test different logging component combinations
87+ let basicComponents : LoggingComponents = . basic
88+ let standartComponents : LoggingComponents = . standart
89+ let fullComponents : LoggingComponents = . full
90+
91+ XCTAssertTrue ( basicComponents. contains ( . method) )
92+ XCTAssertTrue ( basicComponents. contains ( . path) )
93+ XCTAssertTrue ( basicComponents. contains ( . statusCode) )
94+
95+ XCTAssertTrue ( standartComponents. contains ( . basic) )
96+ XCTAssertTrue ( standartComponents. contains ( . headers) )
97+ XCTAssertTrue ( standartComponents. contains ( . uuid) )
98+
99+ XCTAssertTrue ( fullComponents. contains ( . standart) )
100+ XCTAssertTrue ( fullComponents. contains ( . body) )
101+ XCTAssertTrue ( fullComponents. contains ( . baseURL) )
102+ }
103+
104+ func testMaskedHeaders( ) {
105+ let defaultMasked = Set< HTTPField . Name> . defaultMaskedHeaders
106+
107+ XCTAssertTrue ( defaultMasked. contains ( . authorization) )
108+ XCTAssertTrue ( defaultMasked. contains ( . cookie) )
109+ XCTAssertTrue ( defaultMasked. contains ( . setCookie) )
110+ XCTAssertTrue ( defaultMasked. contains ( HTTPField . Name ( " X-API-Key " ) !) )
111+ }
112+
113+ // MARK: - HTTP Client Configuration Tests
114+
115+ func testHTTPClientConfiguration( ) {
116+ let mockHTTPClient = HTTPClient { _, _ in
117+ ( Data ( ) , HTTPResponse ( status: . ok) )
118+ }
119+
120+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
121+ . httpClient ( mockHTTPClient)
122+
123+ let configs = client. configs ( )
124+
125+ // Test that HTTP client is configured (basic structural test)
126+ XCTAssertNotNil ( configs. httpClient)
127+ }
128+
129+ // MARK: - Error Handling Configuration Tests
130+
131+ func testErrorDecodingConfiguration( ) {
132+ let errorDecoder = ErrorDecoder { data, _ in
133+ let errorString = String ( data: data, encoding: . utf8) ?? " Unknown error "
134+ return Errors . custom ( errorString)
135+ }
136+
137+ let client = APIClient ( baseURL: URL ( string: " https://example.com " ) !)
138+ . errorDecoder ( errorDecoder)
139+
140+ let configs = client. configs ( )
141+ let testData = " Test error " . data ( using: . utf8) !
142+ let decodedError = configs. errorDecoder. decodeError ( testData, configs)
143+
144+ XCTAssertEqual ( ( decodedError as? Errors ) ? . description, " Test error " )
145+ }
146+ }
147+
148+ // MARK: - Mock Types
149+
150+ private class MockAPIClientListener : APIClientListener {
151+ struct RequestStartedCall {
152+ let id : UUID
153+ let request : HTTPRequestComponents
154+ let configs : APIClient . Configs
155+ }
156+
157+ struct ResponseReceivedCall {
158+ let id : UUID
159+ let response : Any
160+ let configs : APIClient . Configs
161+ }
162+
163+ struct ResponseSerializedCall {
164+ let id : UUID
165+ let response : Any
166+ let configs : APIClient . Configs
167+ }
168+
169+ struct ErrorCall {
170+ let id : UUID
171+ let error : Error
172+ let configs : APIClient . Configs
173+ }
174+
175+ var requestStartedCalls : [ RequestStartedCall ] = [ ]
176+ var responseReceivedCalls : [ ResponseReceivedCall ] = [ ]
177+ var responseSerializedCalls : [ ResponseSerializedCall ] = [ ]
178+ var errorCalls : [ ErrorCall ] = [ ]
179+
180+ func onRequestStarted( id: UUID , request: HTTPRequestComponents , configs: APIClient . Configs ) {
181+ requestStartedCalls. append ( RequestStartedCall ( id: id, request: request, configs: configs) )
182+ }
183+
184+ func onResponseReceived< R> ( id: UUID , response: R , configs: APIClient . Configs ) {
185+ responseReceivedCalls. append ( ResponseReceivedCall ( id: id, response: response, configs: configs) )
186+ }
187+
188+ func onResponseSerialized< T> ( id: UUID , response: T , configs: APIClient . Configs ) {
189+ responseSerializedCalls. append ( ResponseSerializedCall ( id: id, response: response, configs: configs) )
190+ }
191+
192+ func onError( id: UUID , error: Error , configs: APIClient . Configs ) {
193+ errorCalls. append ( ErrorCall ( id: id, error: error, configs: configs) )
194+ }
195+ }
0 commit comments