1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
import ISDBTestSupport
import LSPTestSupport
import LanguageServerProtocol
@_spi(Testing) import SKCore
import SKSupport
import SKTestSupport
import SourceKitD
import TSCBasic
import XCTest
import enum PackageLoading.Platform
import class TSCBasic.Process
final class SourceKitDTests: XCTestCase {
func testMultipleNotificationHandlers() async throws {
let sourcekitdPath = await ToolchainRegistry.forTesting.default!.sourcekitd!
let sourcekitd = try await DynamicallyLoadedSourceKitD.getOrCreate(dylibPath: sourcekitdPath)
let keys = sourcekitd.keys
let path = DocumentURI(for: .swift).pseudoPath
let isExpectedNotification = { @Sendable (response: SKDResponse) -> Bool in
if let notification: sourcekitd_api_uid_t = response.value?[keys.notification],
let name: String = response.value?[keys.name]
{
return name == path && notification == sourcekitd.values.documentUpdateNotification
}
return false
}
let expectation1 = expectation(description: "handler 1")
let handler1 = ClosureNotificationHandler { response in
if isExpectedNotification(response) {
expectation1.fulfill()
}
}
// DynamicallyLoadedSourceKitD weakly references handlers
defer {
_fixLifetime(handler1)
}
await sourcekitd.addNotificationHandler(handler1)
let expectation2 = expectation(description: "handler 2")
let handler2 = ClosureNotificationHandler { response in
if isExpectedNotification(response) {
expectation2.fulfill()
}
}
// DynamicallyLoadedSourceKitD weakly references handlers
defer {
_fixLifetime(handler2)
}
await sourcekitd.addNotificationHandler(handler2)
let args = SKDRequestArray(sourcekitd: sourcekitd)
if case .darwin? = Platform.current,
let sdkpath = try? await Process.checkNonZeroExit(args: "/usr/bin/xcrun", "--show-sdk-path", "--sdk", "macosx")
.trimmingCharacters(in: .whitespacesAndNewlines)
{
args += ["-sdk", sdkpath]
}
args.append(path)
let req = sourcekitd.dictionary([
keys.request: sourcekitd.requests.editorOpen,
keys.name: path,
keys.sourceText: """
func foo() {}
""",
keys.compilerArgs: args,
])
_ = try await sourcekitd.send(req, timeout: .seconds(defaultTimeout), fileContents: nil)
try await fulfillmentOfOrThrow([expectation1, expectation2])
let close = sourcekitd.dictionary([
keys.request: sourcekitd.requests.editorClose,
keys.name: path,
])
_ = try await sourcekitd.send(close, timeout: .seconds(defaultTimeout), fileContents: nil)
}
}
private final class ClosureNotificationHandler: SKDNotificationHandler {
let f: @Sendable (SKDResponse) -> Void
init(_ f: @Sendable @escaping (SKDResponse) -> Void) {
self.f = f
}
func notification(_ response: SKDResponse) {
f(response)
}
}
|