@@ -69,7 +69,11 @@ public final class TestSourceKitLSPClient: MessageHandler {
69
69
///
70
70
/// Conceptually, this is an array of `RequestHandler<any RequestType>` but
71
71
/// since we can't express this in the Swift type system, we use `[Any]`.
72
- private nonisolated ( unsafe) var requestHandlers = ThreadSafeBox < [ Any ] > ( initialValue: [ ] )
72
+ ///
73
+ /// `isOneShort` if the request handler should only serve a single request and should be removed from
74
+ /// `requestHandlers` after it has been called.
75
+ private nonisolated ( unsafe) var requestHandlers: ThreadSafeBox < [ ( requestHandler: Any , isOneShot: Bool ) ] > =
76
+ ThreadSafeBox ( initialValue: [ ] )
73
77
74
78
/// A closure that is called when the `TestSourceKitLSPClient` is destructed.
75
79
///
@@ -147,7 +151,7 @@ public final class TestSourceKitLSPClient: MessageHandler {
147
151
throw ConflictingDiagnosticsError ( )
148
152
}
149
153
capabilities. textDocument!. diagnostic = . init( dynamicRegistration: true )
150
- self . handleNextRequest { ( request: RegisterCapabilityRequest ) in
154
+ self . handleSingleRequest { ( request: RegisterCapabilityRequest ) in
151
155
XCTAssertEqual ( request. registrations. only? . method, DocumentDiagnosticsRequest . method)
152
156
return VoidResponse ( )
153
157
}
@@ -258,22 +262,22 @@ public final class TestSourceKitLSPClient: MessageHandler {
258
262
}
259
263
}
260
264
261
- /// Handle the next request that is sent to the client with the given handler.
262
- ///
263
- /// By default, `TestSourceKitLSPClient` emits an `XCTFail` if a request is sent
264
- /// to the client, since it doesn't know how to handle it. This allows the
265
- /// simulation of a single request's handling on the client.
265
+ /// Handle the next request of the given type that is sent to the client.
266
266
///
267
- /// If the next request that is sent to the client is of a different kind than
268
- /// the given handler, `TestSourceKitLSPClient` will emit an `XCTFail`.
269
- public func handleNextRequest< R: RequestType > ( _ requestHandler: @escaping RequestHandler < R > ) {
270
- requestHandlers. value. append ( requestHandler)
267
+ /// The request handler will only handle a single request. If the request is called again, the request handler won't
268
+ /// call again
269
+ public func handleSingleRequest< R: RequestType > ( _ requestHandler: @escaping RequestHandler < R > ) {
270
+ requestHandlers. value. append ( ( requestHandler: requestHandler, isOneShot: true ) )
271
+ }
272
+
273
+ /// Handle all requests of the given type that are sent to the client.
274
+ public func handleMultipleRequests< R: RequestType > ( _ requestHandler: @escaping RequestHandler < R > ) {
275
+ requestHandlers. value. append ( ( requestHandler: requestHandler, isOneShot: false ) )
271
276
}
272
277
273
278
// MARK: - Conformance to MessageHandler
274
279
275
- /// - Important: Implementation detail of `TestSourceKitLSPServer`. Do not call
276
- /// from tests.
280
+ /// - Important: Implementation detail of `TestSourceKitLSPServer`. Do not call from tests.
277
281
public func handle( _ params: some NotificationType ) {
278
282
notificationYielder. yield ( params)
279
283
}
@@ -285,19 +289,21 @@ public final class TestSourceKitLSPClient: MessageHandler {
285
289
reply: @escaping ( LSPResult < Request . Response > ) -> Void
286
290
) {
287
291
requestHandlers. withLock { requestHandlers in
288
- let requestHandlerAndIndex = requestHandlers. enumerated ( ) . compactMap {
289
- ( index, handler ) -> ( RequestHandler < Request > , Int ) ? in
290
- guard let handler = handler as? RequestHandler < Request > else {
292
+ let requestHandlerIndexAndIsOneShot = requestHandlers. enumerated ( ) . compactMap {
293
+ ( index, handlerAndIsOneShot ) -> ( RequestHandler < Request > , Int , Bool ) ? in
294
+ guard let handler = handlerAndIsOneShot . requestHandler as? RequestHandler < Request > else {
291
295
return nil
292
296
}
293
- return ( handler, index)
297
+ return ( handler, index, handlerAndIsOneShot . isOneShot )
294
298
} . first
295
- guard let ( requestHandler, index) = requestHandlerAndIndex else {
299
+ guard let ( requestHandler, index, isOneShot ) = requestHandlerIndexAndIsOneShot else {
296
300
reply ( . failure( . methodNotFound( Request . method) ) )
297
301
return
298
302
}
299
303
reply ( . success( requestHandler ( params) ) )
300
- requestHandlers. remove ( at: index)
304
+ if isOneShot {
305
+ requestHandlers. remove ( at: index)
306
+ }
301
307
}
302
308
}
303
309
0 commit comments