mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
We could get into a race condition in `testAddFile` where the `DidChangeWatchedFilesNotification` would get handled after we try getting completion results that rely on it. In a real-world use case, this is OK. Completion might still be incorrect until `DidChangeWatchedFilesNotification` gets handled but it will catch up eventually - usually earlier than later because in real-world scenarios the `DidChangeWatchedFilesNotification` and completion request are more than a few milliseconds apart. In test, however, we need to guarantee deterministic ordering. Introduce a `BarrierRequest` that has `TaskMetadata.globalConfigurationChange` and thus ensures that all notifications and requests before it have finished before returning. We can run this fake request after sending the `DidChangeWatchedFilesNotification` to make sure that it is handled. An alternative would be to mark `DidChangeWatchedFilesNotification` as `TaskMetadata.globalConfigurationChange`. But I would really like to avoid introducing a global ordering barrier between requests for a notification that is, for example, sent whenever a `.swift` file in the `.build` directory changes (e.g. on every package update).
94 lines
3.0 KiB
Swift
94 lines
3.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
||
//
|
||
// This source file is part of the Swift.org open source project
|
||
//
|
||
// Copyright (c) 2014 - 2022 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 LanguageServerProtocol
|
||
import SKCore
|
||
import SKTestSupport
|
||
import TSCBasic
|
||
import XCTest
|
||
|
||
final class CompilationDatabaseTests: XCTestCase {
|
||
func testModifyCompilationDatabase() async throws {
|
||
let ws = try await MultiFileTestWorkspace(files: [
|
||
"main.cpp": """
|
||
#if FOO
|
||
void 1️⃣foo2️⃣() {}
|
||
#else
|
||
void 3️⃣foo4️⃣() {}
|
||
#endif
|
||
|
||
int main() {
|
||
5️⃣foo6️⃣();
|
||
}
|
||
""",
|
||
"compile_flags.txt": """
|
||
-DFOO
|
||
""",
|
||
])
|
||
|
||
let (mainUri, positions) = try ws.openDocument("main.cpp")
|
||
|
||
// Do a sanity check and verify that we get the expected result from a hover response before modifing the compile commands.
|
||
|
||
let highlightRequest = DocumentHighlightRequest(
|
||
textDocument: TextDocumentIdentifier(mainUri),
|
||
position: positions["5️⃣"]
|
||
)
|
||
let preChangeHighlightResponse = try await ws.testClient.send(highlightRequest)
|
||
XCTAssertEqual(
|
||
preChangeHighlightResponse,
|
||
[
|
||
DocumentHighlight(range: positions["1️⃣"]..<positions["2️⃣"], kind: .text),
|
||
DocumentHighlight(range: positions["5️⃣"]..<positions["6️⃣"], kind: .text),
|
||
]
|
||
)
|
||
|
||
// Remove -DFOO from the compile commands.
|
||
|
||
let compileFlagsUri = try ws.uri(for: "compile_flags.txt")
|
||
try "".write(to: compileFlagsUri.fileURL!, atomically: false, encoding: .utf8)
|
||
|
||
ws.testClient.send(
|
||
DidChangeWatchedFilesNotification(changes: [
|
||
FileEvent(uri: compileFlagsUri, type: .changed)
|
||
])
|
||
)
|
||
|
||
// Ensure that the DidChangeWatchedFilesNotification is handled before we continue.
|
||
_ = try await ws.testClient.send(BarrierRequest())
|
||
|
||
// DocumentHighlight should now point to the definition in the `#else` block.
|
||
|
||
let expectedPostEditHighlight = [
|
||
DocumentHighlight(range: positions["3️⃣"]..<positions["4️⃣"], kind: .text),
|
||
DocumentHighlight(range: positions["5️⃣"]..<positions["6️⃣"], kind: .text),
|
||
]
|
||
|
||
var didReceiveCorrectHighlight = false
|
||
|
||
// Updating the build settings takes a few seconds.
|
||
// Send highlight requests every second until we receive correct results.
|
||
for _ in 0..<30 {
|
||
let postChangeHighlightResponse = try await ws.testClient.send(highlightRequest)
|
||
|
||
if postChangeHighlightResponse == expectedPostEditHighlight {
|
||
didReceiveCorrectHighlight = true
|
||
break
|
||
}
|
||
try await Task.sleep(nanoseconds: 1_000_000_000)
|
||
}
|
||
|
||
XCTAssert(didReceiveCorrectHighlight)
|
||
}
|
||
}
|