@@ -69,7 +69,11 @@ public final class TestSourceKitLSPClient: MessageHandler {
6969 ///
7070 /// Conceptually, this is an array of `RequestHandler<any RequestType>` but
7171 /// 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: [ ] )
7377
7478 /// A closure that is called when the `TestSourceKitLSPClient` is destructed.
7579 ///
@@ -147,7 +151,7 @@ public final class TestSourceKitLSPClient: MessageHandler {
147151 throw ConflictingDiagnosticsError ( )
148152 }
149153 capabilities. textDocument!. diagnostic = . init( dynamicRegistration: true )
150- self . handleNextRequest { ( request: RegisterCapabilityRequest ) in
154+ self . handleSingleRequest { ( request: RegisterCapabilityRequest ) in
151155 XCTAssertEqual ( request. registrations. only? . method, DocumentDiagnosticsRequest . method)
152156 return VoidResponse ( )
153157 }
@@ -258,22 +262,22 @@ public final class TestSourceKitLSPClient: MessageHandler {
258262 }
259263 }
260264
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.
266266 ///
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 ) )
271276 }
272277
273278 // MARK: - Conformance to MessageHandler
274279
275- /// - Important: Implementation detail of `TestSourceKitLSPServer`. Do not call
276- /// from tests.
280+ /// - Important: Implementation detail of `TestSourceKitLSPServer`. Do not call from tests.
277281 public func handle( _ params: some NotificationType ) {
278282 notificationYielder. yield ( params)
279283 }
@@ -285,19 +289,21 @@ public final class TestSourceKitLSPClient: MessageHandler {
285289 reply: @escaping ( LSPResult < Request . Response > ) -> Void
286290 ) {
287291 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 {
291295 return nil
292296 }
293- return ( handler, index)
297+ return ( handler, index, handlerAndIsOneShot . isOneShot )
294298 } . first
295- guard let ( requestHandler, index) = requestHandlerAndIndex else {
299+ guard let ( requestHandler, index, isOneShot ) = requestHandlerIndexAndIsOneShot else {
296300 reply ( . failure( . methodNotFound( Request . method) ) )
297301 return
298302 }
299303 reply ( . success( requestHandler ( params) ) )
300- requestHandlers. remove ( at: index)
304+ if isOneShot {
305+ requestHandlers. remove ( at: index)
306+ }
301307 }
302308 }
303309
0 commit comments