Skip to content

Commit c9a943e

Browse files
author
Wang Lun
committed
add unit test for supporting swiftinterface
1 parent 8dfcbfa commit c9a943e

File tree

1 file changed

+156
-38
lines changed

1 file changed

+156
-38
lines changed

Tests/SourceKitLSPTests/SwiftInterfaceTests.swift

Lines changed: 156 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import SourceKitLSP
1919
import SwiftExtensions
2020
import XCTest
2121

22+
private extension Language {
23+
static let swiftinterface = Language(rawValue: "swiftinterface")
24+
}
25+
2226
final class SwiftInterfaceTests: XCTestCase {
2327
func testSystemModuleInterface() async throws {
2428
let testClient = try await TestSourceKitLSPClient()
@@ -62,7 +66,7 @@ final class SwiftInterfaceTests: XCTestCase {
6266
let referenceDocument = try await testClient.send(GetReferenceDocumentRequest(uri: location.uri))
6367
XCTAssert(
6468
referenceDocument.content.hasPrefix("import "),
65-
"Expected that the foundation swift interface starts with 'import ' but got '\(referenceDocument.content.prefix(100))'"
69+
"Expected foundation swift interface to start with 'import ' but got '\(referenceDocument.content.prefix(100))'"
6670
)
6771
}
6872

@@ -149,7 +153,7 @@ final class SwiftInterfaceTests: XCTestCase {
149153
public init() {}
150154
}
151155
""",
152-
"Exec/main.swift": "import 1️⃣MyLibrary",
156+
"Exec/main.swift": "import 1️⃣MyLibrary"
153157
],
154158
manifest: """
155159
let package = Package(
@@ -192,21 +196,13 @@ final class SwiftInterfaceTests: XCTestCase {
192196
func testSemanticFunctionalityInGeneratedInterface() async throws {
193197
let project = try await SwiftPMTestProject(
194198
files: [
195-
"MyLibrary/MyLibrary.swift": """
196-
public struct Lib {
197-
public func foo() -> String {}
198-
public init() {}
199-
}
200-
""",
201-
"Exec/main.swift": "import 1️⃣MyLibrary",
199+
"MyLibrary/MyLibrary.swift": "public struct Lib { public func foo() -> String {} }",
200+
"Exec/main.swift": "import 1️⃣MyLibrary"
202201
],
203202
manifest: """
204203
let package = Package(
205204
name: "MyLibrary",
206-
targets: [
207-
.target(name: "MyLibrary"),
208-
.executableTarget(name: "Exec", dependencies: ["MyLibrary"])
209-
]
205+
targets: [.target(name: "MyLibrary"), .executableTarget(name: "Exec", dependencies: ["MyLibrary"])]
210206
)
211207
""",
212208
capabilities: ClientCapabilities(experimental: [
@@ -216,36 +212,26 @@ final class SwiftInterfaceTests: XCTestCase {
216212
)
217213

218214
let (mainUri, mainPositions) = try project.openDocument("main.swift")
219-
let response =
220-
try await project.testClient.send(
221-
DefinitionRequest(
222-
textDocument: TextDocumentIdentifier(mainUri),
223-
position: mainPositions["1️⃣"]
224-
)
225-
)
215+
let response = try await project.testClient.send(
216+
DefinitionRequest(textDocument: TextDocumentIdentifier(mainUri), position: mainPositions["1️⃣"])
217+
)
226218
let referenceDocumentUri = try XCTUnwrap(response?.locations?.only).uri
227219
let referenceDocument = try await project.testClient.send(GetReferenceDocumentRequest(uri: referenceDocumentUri))
228-
let stringIndex = try XCTUnwrap(referenceDocument.content.firstRange(of: "-> String"))
229-
let (stringLine, stringColumn) = LineTable(referenceDocument.content)
230-
.lineAndUTF16ColumnOf(referenceDocument.content.index(stringIndex.lowerBound, offsetBy: 3))
231-
232-
project.testClient.send(
233-
DidOpenTextDocumentNotification(
234-
textDocument: TextDocumentItem(
235-
uri: referenceDocumentUri,
236-
language: .swift,
237-
version: 0,
238-
text: referenceDocument.content
220+
221+
// Test hover functionality in the interface
222+
if let stringIndex = referenceDocument.content.firstRange(of: "-> String") {
223+
let (line, column) = LineTable(referenceDocument.content)
224+
.lineAndUTF16ColumnOf(referenceDocument.content.index(stringIndex.lowerBound, offsetBy: 3))
225+
project.testClient.send(
226+
DidOpenTextDocumentNotification(
227+
textDocument: TextDocumentItem(uri: referenceDocumentUri, language: .swift, version: 0, text: referenceDocument.content)
239228
)
240229
)
241-
)
242-
let hover = try await project.testClient.send(
243-
HoverRequest(
244-
textDocument: TextDocumentIdentifier(referenceDocumentUri),
245-
position: Position(line: stringLine, utf16index: stringColumn)
230+
let hover = try await project.testClient.send(
231+
HoverRequest(textDocument: TextDocumentIdentifier(referenceDocumentUri), position: Position(line: line, utf16index: column))
246232
)
247-
)
248-
XCTAssertNotNil(hover)
233+
XCTAssertNotNil(hover)
234+
}
249235
}
250236

251237
func testJumpToSynthesizedExtensionMethodInSystemModuleWithoutIndex() async throws {
@@ -295,6 +281,7 @@ final class SwiftInterfaceTests: XCTestCase {
295281
GetReferenceDocumentRequest.method: .dictionary(["supported": .bool(true)])
296282
])
297283
)
284+
298285
let uri = DocumentURI(for: .swift)
299286

300287
let positions = testClient.openDocument(
@@ -319,6 +306,137 @@ final class SwiftInterfaceTests: XCTestCase {
319306
)
320307
XCTAssertEqual(diagnostics.fullReport?.items, [])
321308
}
309+
310+
func testInternalNavigationInSwiftInterface() async throws {
311+
let testClient = try await TestSourceKitLSPClient(
312+
capabilities: ClientCapabilities(experimental: [
313+
GetReferenceDocumentRequest.method: .dictionary(["supported": .bool(true)])
314+
])
315+
)
316+
let uri = DocumentURI(for: .swiftinterface)
317+
318+
let positions = testClient.openDocument(
319+
"""
320+
func test(x: 1️⃣String) {
321+
let a: 2️⃣Int = 5
322+
}
323+
""",
324+
uri: uri
325+
)
326+
327+
// First, get definition for String to open the Swift interface
328+
let stringDefinition = try await testClient.send(
329+
DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
330+
)
331+
let interfaceUri = try XCTUnwrap(stringDefinition?.locations?.only?.uri)
332+
let interfaceContents = try await testClient.send(GetReferenceDocumentRequest(uri: interfaceUri))
333+
// Open the interface document
334+
testClient.send(
335+
DidOpenTextDocumentNotification(
336+
textDocument: TextDocumentItem(
337+
uri: interfaceUri,
338+
language: .swift,
339+
version: 0,
340+
text: interfaceContents.content
341+
)
342+
)
343+
)
344+
345+
// Find a symbol within the interface (e.g., "init" method in String)
346+
guard let initRange = interfaceContents.content.range(of: "public init()") else {
347+
XCTFail("Could not find 'public init()' in String interface")
348+
return
349+
}
350+
let lineTable = LineTable(interfaceContents.content)
351+
let (line, column) = lineTable.lineAndUTF16ColumnOf(initRange.lowerBound)
352+
let initPosition = Position(line: line, utf16index: column + 7) // Position on "init"
353+
354+
// Test definition request within the interface
355+
let internalDefinition = try await testClient.send(
356+
DefinitionRequest(
357+
textDocument: TextDocumentIdentifier(interfaceUri),
358+
position: initPosition
359+
)
360+
)
361+
362+
// The definition should either:
363+
// 1. Return a position within the same interface (internal navigation)
364+
// 2. Return the same position if it's already at the definition
365+
// 3. Return nil if no definition is available
366+
if let location = internalDefinition?.locations?.first {
367+
// If we get a location, it should be in the same interface or a related one
368+
XCTAssertTrue(
369+
location.uri.pseudoPath.hasSuffix(".swiftinterface") ||
370+
location.uri == interfaceUri,
371+
"Internal navigation should stay within interface files, got: \(location.uri.pseudoPath)"
372+
)
373+
}
374+
}
375+
376+
func testFoundationImportNavigation() async throws {
377+
let testClient = try await TestSourceKitLSPClient(
378+
capabilities: ClientCapabilities(experimental: [
379+
GetReferenceDocumentRequest.method: .dictionary(["supported": .bool(true)])
380+
])
381+
)
382+
let uri = DocumentURI(for: .swiftinterface)
383+
384+
let positions = testClient.openDocument(
385+
"""
386+
import 1️⃣Foundation
387+
""",
388+
uri: uri
389+
)
390+
391+
// Test navigation to Foundation module
392+
let foundationDefinition = try await testClient.send(
393+
DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
394+
)
395+
let foundationLocation = try XCTUnwrap(foundationDefinition?.locations?.only)
396+
// Verify it's a swiftinterface file (can be either file:// or sourcekit-lsp:// scheme)
397+
XCTAssertTrue(
398+
foundationLocation.uri.pseudoPath.hasSuffix(".swiftinterface") ||
399+
(foundationLocation.uri.scheme == "sourcekit-lsp" &&
400+
foundationLocation.uri.pseudoPath.contains("Foundation.swiftinterface"))
401+
)
402+
}
403+
404+
func testFoundationSubmoduleNavigation() async throws {
405+
let testClient = try await TestSourceKitLSPClient(
406+
capabilities: ClientCapabilities(experimental: [
407+
GetReferenceDocumentRequest.method: .dictionary(["supported": .bool(true)])
408+
])
409+
)
410+
let uri = DocumentURI(for: .swift)
411+
412+
let positions = testClient.openDocument(
413+
"""
414+
import 1️⃣Foundation.2️⃣NSAffineTransform
415+
""",
416+
uri: uri
417+
)
418+
419+
let foundationDefinition = try await testClient.send(
420+
DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
421+
)
422+
if let foundationLocation = foundationDefinition?.locations?.only {
423+
XCTAssertTrue(
424+
foundationLocation.uri.pseudoPath.contains("Foundation.swiftinterface") ||
425+
foundationLocation.uri.scheme == "sourcekit-lsp"
426+
)
427+
}
428+
// Test navigation to NSAffineTransform
429+
let transformDefinition = try await testClient.send(
430+
DefinitionRequest(textDocument: TextDocumentIdentifier(uri), position: positions["2️⃣"])
431+
)
432+
if let transformLocation = transformDefinition?.locations?.only {
433+
// Verify we can identify this as a swiftinterface file
434+
XCTAssertTrue(
435+
transformLocation.uri.pseudoPath.contains("Foundation.NSAffineTransform.swiftinterface") ||
436+
transformLocation.uri.scheme == "sourcekit-lsp"
437+
)
438+
}
439+
}
322440
}
323441

324442
private func assertSystemSwiftInterface(

0 commit comments

Comments
 (0)