Skip to content

Commit 8f8e50e

Browse files
authored
Merge pull request #1191 from plemarquand/tag-member-access-syntax
Support member access in tags
2 parents e0f7221 + 7015084 commit 8f8e50e

File tree

2 files changed

+98
-29
lines changed

2 files changed

+98
-29
lines changed

Sources/SourceKitLSP/Swift/SwiftTestingScanner.swift

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,18 @@ struct TestingAttributeData {
9595
return false
9696
}
9797
}.flatMap(\.arguments)
98-
.compactMap { $0.expression.as(StringLiteralExprSyntax.self)?.representedLiteralValue }
98+
.compactMap {
99+
if let memberAccess = $0.expression.as(MemberAccessExprSyntax.self) {
100+
var components = memberAccess.components[...]
101+
if components.starts(with: ["Testing", "Tag"]) {
102+
components = components.dropFirst(2)
103+
} else if components.starts(with: ["Tag"]) {
104+
components = components.dropFirst(1)
105+
}
106+
return components.joined(separator: ".")
107+
}
108+
return nil
109+
}
99110

100111
self.isDisabled = traitArguments.lazy
101112
.compactMap { $0.as(FunctionCallExprSyntax.self) }
@@ -328,36 +339,32 @@ fileprivate extension AttributeSyntax {
328339
}
329340

330341
fileprivate extension MemberAccessExprSyntax {
331-
/// The base name of this instance, i.e. the string value of `base` joined
332-
/// with any preceding base names.
342+
/// The fully-qualified name of this instance (subject to available
343+
/// information.)
333344
///
334-
/// For example, if this instance represents the expression `x.y.z(123)`,
335-
/// the value of this property is `"x.y"`. If the value of `base` is `nil`,
336-
/// the value of this property is also `nil`.
337-
var baseName: String? {
338-
if let declReferenceExpr = base?.as(DeclReferenceExprSyntax.self) {
339-
return declReferenceExpr.baseName.text
340-
} else if let baseMemberAccessExpr = base?.as(MemberAccessExprSyntax.self) {
341-
if let baseBaseName = baseMemberAccessExpr.baseName {
342-
return "\(baseBaseName).\(baseMemberAccessExpr.declName.baseName.text)"
343-
}
344-
return baseMemberAccessExpr.declName.baseName.text
345-
}
346-
347-
return nil
345+
/// The value of this property are all the components of the based name
346+
/// name joined together with `.`.
347+
var fullyQualifiedName: String {
348+
components.joined(separator: ".")
348349
}
349350

350-
/// The fully-qualified name of this instance (subject to available
351+
/// The name components of this instance (subject to available
351352
/// information.)
352353
///
353-
/// The value of this property is this instance's `baseName` property joined
354-
/// with its `name` property. For example, if this instance represents the
355-
/// expression `x.y.z(123)`, the value of this property is `"x.y.z"`.
356-
var fullyQualifiedName: String {
357-
if let baseName {
358-
return "\(baseName).\(declName.baseName.text)"
354+
/// The value of this property is this base name of this instance,
355+
/// i.e. the string value of `base` preceeded with any preceding base names
356+
/// and followed by its `name` property.
357+
///
358+
/// For example, if this instance represents
359+
/// the expression `x.y.z(123)`, the value of this property is
360+
/// `["x", "y", "z"]`.
361+
var components: [String] {
362+
if let declReferenceExpr = base?.as(DeclReferenceExprSyntax.self) {
363+
return [declReferenceExpr.baseName.text, declName.baseName.text]
364+
} else if let baseMemberAccessExpr = base?.as(MemberAccessExprSyntax.self) {
365+
return baseMemberAccessExpr.components + [declName.baseName.text]
359366
}
360-
return declName.baseName.text
367+
return [declName.baseName.text]
361368
}
362369
}
363370

Tests/SourceKitLSPTests/DocumentTestDiscoveryTests.swift

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -593,9 +593,9 @@ final class DocumentTestDiscoveryTests: XCTestCase {
593593
"""
594594
import Testing
595595
596-
1️⃣@Suite(.tags("Suites"))
596+
1️⃣@Suite(.tags(.green))
597597
struct MyTests {
598-
2️⃣@Test(.tags("one", "two"))
598+
2️⃣@Test(.tags(.red, .blue))
599599
func oneIsTwo() {
600600
#expect(1 == 2)
601601
}3️⃣
@@ -622,10 +622,72 @@ final class DocumentTestDiscoveryTests: XCTestCase {
622622
style: TestStyle.swiftTesting,
623623
location: Location(uri: uri, range: positions["2️⃣"]..<positions["3️⃣"]),
624624
children: [],
625-
tags: [TestTag(id: "one"), TestTag(id: "two")]
625+
tags: [TestTag(id: "red"), TestTag(id: "blue")]
626626
)
627627
],
628-
tags: [TestTag(id: "Suites")]
628+
tags: [TestTag(id: "green")]
629+
)
630+
]
631+
)
632+
}
633+
634+
func testSwiftTestingTestWithCustomTags() async throws {
635+
let testClient = try await TestSourceKitLSPClient()
636+
let uri = DocumentURI.for(.swift)
637+
638+
let positions = testClient.openDocument(
639+
"""
640+
import Testing
641+
642+
extension Tag {
643+
@Tag static var suite: Self
644+
@Tag static var foo: Self
645+
@Tag static var bar: Self
646+
@Tag static var baz: Self
647+
648+
struct Nested {
649+
@Tag static var foo: Tag
650+
}
651+
}
652+
653+
1️⃣@Suite(.tags(.suite))
654+
struct MyTests {
655+
2️⃣@Test(.tags(.foo, Nested.foo, Testing.Tag.bar, Tag.baz))
656+
func oneIsTwo() {
657+
#expect(1 == 2)
658+
}3️⃣
659+
}4️⃣
660+
""",
661+
uri: uri
662+
)
663+
664+
let tests = try await testClient.send(DocumentTestsRequest(textDocument: TextDocumentIdentifier(uri)))
665+
XCTAssertEqual(
666+
tests,
667+
[
668+
TestItem(
669+
id: "MyTests",
670+
label: "MyTests",
671+
disabled: false,
672+
style: TestStyle.swiftTesting,
673+
location: Location(uri: uri, range: positions["1️⃣"]..<positions["4️⃣"]),
674+
children: [
675+
TestItem(
676+
id: "MyTests/oneIsTwo()",
677+
label: "oneIsTwo()",
678+
disabled: false,
679+
style: TestStyle.swiftTesting,
680+
location: Location(uri: uri, range: positions["2️⃣"]..<positions["3️⃣"]),
681+
children: [],
682+
tags: [
683+
TestTag(id: "foo"),
684+
TestTag(id: "Nested.foo"),
685+
TestTag(id: "bar"),
686+
TestTag(id: "baz"),
687+
]
688+
)
689+
],
690+
tags: [TestTag(id: "suite")]
629691
)
630692
]
631693
)

0 commit comments

Comments
 (0)