Files
sourcekit-lsp/Tests/SourceKitLSPTests/CompilationDatabaseTests.swift
Alex Hoppen 996df8c597 Introduce a BarrierRequest that ensures all messages are handled before it replies
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).
2023-10-26 18:23:41 -07:00

94 lines
3.0 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//===----------------------------------------------------------------------===//
//
// 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)
}
}