Skip to content

Commit

Permalink
Merge pull request #1390 from ahoppen/6.0/re-apply-1227
Browse files Browse the repository at this point in the history
  • Loading branch information
ahoppen committed Jun 4, 2024
2 parents d69b762 + 38e2d01 commit 677487b
Show file tree
Hide file tree
Showing 6 changed files with 509 additions and 74 deletions.
2 changes: 1 addition & 1 deletion Sources/SourceKitLSP/LanguageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public protocol LanguageService: AnyObject, Sendable {
/// This is used as a fallback to show the test cases in a file if the index for a given file is not up-to-date.
///
/// A return value of `nil` indicates that this language service does not support syntactic test discovery.
func syntacticDocumentTests(for uri: DocumentURI, in workspace: Workspace) async throws -> [TestItem]?
func syntacticDocumentTests(for uri: DocumentURI, in workspace: Workspace) async throws -> [AnnotatedTestItem]?

/// Crash the language server. Should be used for crash recovery testing only.
func _crash() async
Expand Down
55 changes: 35 additions & 20 deletions Sources/SourceKitLSP/Swift/SwiftTestingScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,13 @@ final class SyntacticSwiftTestingTestScanner: SyntaxVisitor {
private let parentTypeNames: [String]

/// The discovered test items.
private var result: [TestItem] = []
private var result: [AnnotatedTestItem] = []

private init(snapshot: DocumentSnapshot, allTestsDisabled: Bool, parentTypeNames: [String]) {
private init(
snapshot: DocumentSnapshot,
allTestsDisabled: Bool,
parentTypeNames: [String]
) {
self.snapshot = snapshot
self.allTestsDisabled = allTestsDisabled
self.parentTypeNames = parentTypeNames
Expand All @@ -190,7 +194,7 @@ final class SyntacticSwiftTestingTestScanner: SyntaxVisitor {
public static func findTestSymbols(
in snapshot: DocumentSnapshot,
syntaxTreeManager: SyntaxTreeManager
) async -> [TestItem] {
) async -> [AnnotatedTestItem] {
guard snapshot.text.contains("Suite") || snapshot.text.contains("Test") else {
// If the file contains swift-testing tests, it must contain a `@Suite` or `@Test` attribute.
// Only check for the attribute name because the attribute may be module qualified and contain an arbitrary amount
Expand All @@ -199,7 +203,11 @@ final class SyntacticSwiftTestingTestScanner: SyntaxVisitor {
return []
}
let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot)
let visitor = SyntacticSwiftTestingTestScanner(snapshot: snapshot, allTestsDisabled: false, parentTypeNames: [])
let visitor = SyntacticSwiftTestingTestScanner(
snapshot: snapshot,
allTestsDisabled: false,
parentTypeNames: []
)
visitor.walk(syntaxTree)
return visitor.result
}
Expand Down Expand Up @@ -241,14 +249,18 @@ final class SyntacticSwiftTestingTestScanner: SyntaxVisitor {
}

let range = snapshot.range(of: node.positionAfterSkippingLeadingTrivia..<node.endPositionBeforeTrailingTrivia)
let testItem = TestItem(
id: (parentTypeNames + typeNames).joined(separator: "/"),
label: attributeData?.displayName ?? typeNames.last!,
disabled: (attributeData?.isDisabled ?? false) || allTestsDisabled,
style: TestStyle.swiftTesting,
location: Location(uri: snapshot.uri, range: range),
children: memberScanner.result,
tags: attributeData?.tags.map(TestTag.init(id:)) ?? []
// Members won't be extensions since extensions will only be at the top level.
let testItem = AnnotatedTestItem(
testItem: TestItem(
id: (parentTypeNames + typeNames).joined(separator: "/"),
label: attributeData?.displayName ?? typeNames.last!,
disabled: (attributeData?.isDisabled ?? false) || allTestsDisabled,
style: TestStyle.swiftTesting,
location: Location(uri: snapshot.uri, range: range),
children: memberScanner.result.map(\.testItem),
tags: attributeData?.tags.map(TestTag.init(id:)) ?? []
),
isExtension: node.is(ExtensionDeclSyntax.self)
)
result.append(testItem)
return .skipChildren
Expand Down Expand Up @@ -295,14 +307,17 @@ final class SyntacticSwiftTestingTestScanner: SyntaxVisitor {
node.name.text + "(" + node.signature.parameterClause.parameters.map { "\($0.firstName.text):" }.joined() + ")"

let range = snapshot.range(of: node.positionAfterSkippingLeadingTrivia..<node.endPositionBeforeTrailingTrivia)
let testItem = TestItem(
id: (parentTypeNames + [name]).joined(separator: "/"),
label: attributeData.displayName ?? name,
disabled: attributeData.isDisabled || allTestsDisabled,
style: TestStyle.swiftTesting,
location: Location(uri: snapshot.uri, range: range),
children: [],
tags: attributeData.tags.map(TestTag.init(id:))
let testItem = AnnotatedTestItem(
testItem: TestItem(
id: (parentTypeNames + [name]).joined(separator: "/"),
label: attributeData.displayName ?? name,
disabled: attributeData.isDisabled || allTestsDisabled,
style: TestStyle.swiftTesting,
location: Location(uri: snapshot.uri, range: range),
children: [],
tags: attributeData.tags.map(TestTag.init(id:))
),
isExtension: false
)
result.append(testItem)
return .visitChildren
Expand Down
7 changes: 4 additions & 3 deletions Sources/SourceKitLSP/Swift/SyntacticTestIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fileprivate enum TaskMetadata: DependencyTracker, Equatable {
/// Data from a syntactic scan of a source file for tests.
fileprivate struct IndexedTests {
/// The tests within the source file.
let tests: [TestItem]
let tests: [AnnotatedTestItem]

/// The modification date of the source file when it was scanned. A file won't get re-scanned if its modification date
/// is older or the same as this date.
Expand All @@ -63,7 +63,7 @@ fileprivate struct IndexedTests {
/// Does not write the results to the index.
///
/// The order of the returned tests is not defined. The results should be sorted before being returned to the editor.
fileprivate func testItems(in url: URL) async -> [TestItem] {
fileprivate func testItems(in url: URL) async -> [AnnotatedTestItem] {
guard url.pathExtension == "swift" else {
return []
}
Expand All @@ -79,6 +79,7 @@ fileprivate func testItems(in url: URL) async -> [TestItem] {
syntaxTreeManager: syntaxTreeManager
)
async let xcTests = SyntacticSwiftXCTestScanner.findTestSymbols(in: snapshot, syntaxTreeManager: syntaxTreeManager)

return await swiftTestingTests + xcTests
}

Expand Down Expand Up @@ -206,7 +207,7 @@ actor SyntacticTestIndex {
/// Gets all the tests in the syntactic index.
///
/// This waits for any pending document updates to be indexed before returning a result.
nonisolated func tests() async -> [TestItem] {
nonisolated func tests() async -> [AnnotatedTestItem] {
let readTask = indexingQueue.async(metadata: .read) {
return await self.indexedTests.values.flatMap { $0.tests }
}
Expand Down
Loading

0 comments on commit 677487b

Please sign in to comment.