Skip to content

Commit 19d8054

Browse files
authored
Support for TestScoping. (#39)
* Support for TestScoping. * fix * update docs
1 parent 0b80a09 commit 19d8054

File tree

8 files changed

+209
-179
lines changed

8 files changed

+209
-179
lines changed

[email protected]

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// swift-tools-version: 6.0
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "swift-macro-testing",
7+
platforms: [
8+
.iOS(.v13),
9+
.macOS(.v10_15),
10+
.tvOS(.v13),
11+
.watchOS(.v6),
12+
],
13+
products: [
14+
.library(
15+
name: "MacroTesting",
16+
targets: ["MacroTesting"]
17+
)
18+
],
19+
dependencies: [
20+
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.17.4"),
21+
.package(url: "https://github.com/swiftlang/swift-syntax", "509.0.0"..<"601.0.0-prerelease"),
22+
],
23+
targets: [
24+
.target(
25+
name: "MacroTesting",
26+
dependencies: [
27+
.product(name: "InlineSnapshotTesting", package: "swift-snapshot-testing"),
28+
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
29+
.product(name: "SwiftOperators", package: "swift-syntax"),
30+
.product(name: "SwiftParserDiagnostics", package: "swift-syntax"),
31+
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
32+
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
33+
]
34+
),
35+
.testTarget(
36+
name: "MacroTestingTests",
37+
dependencies: [
38+
"MacroTesting"
39+
]
40+
),
41+
],
42+
swiftLanguageModes: [.v6]
43+
)

README.md

Lines changed: 17 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@ do is write the following:
3636

3737
```swift
3838
import MacroTesting
39-
import XCTest
39+
import Testing
4040

41-
class StringifyTests: XCTestCase {
42-
func testStringify() {
43-
assertMacro(["stringify": StringifyMacro.self]) {
41+
@Suite(.macros([StringifyMacro.self]))
42+
struct StringifyTests {
43+
@Test func stringify() {
44+
assertMacro {
4445
"""
4546
#stringify(a + b)
4647
"""
@@ -53,8 +54,10 @@ When you run this test the library will automatically expand the macros in the s
5354
and write the expansion into the test file:
5455

5556
```swift
56-
func testStringify() {
57-
assertMacro(["stringify": StringifyMacro.self]) {
57+
@Suite(.macros([StringifyMacro.self]))
58+
struct StringifyTests {
59+
@Test func stringify() {
60+
assertMacro {
5861
"""
5962
#stringify(a + b)
6063
"""
@@ -71,74 +74,23 @@ That is all it takes.
7174
If in the future the macro's output changes, such as adding labels to the tuple's arguments, then
7275
running the test again will produce a nicely formatted message:
7376

74-
> ❌ failed - Actual output (+) differed from expected output (−). Difference: …
75-
>
76-
> ```diff
77-
> - (a + b, "a + b")
78-
> + (result: a + b, code: "a + b")
79-
> ```
77+
```diff
78+
Actual output (+) differed from expected output (). Difference:
79+
80+
- (a + b, "a + b")
81+
+ (result: a + b, code: "a + b")
82+
```
8083

8184
You can even have the library automatically re-record the macro expansion directly into your test
82-
file by providing the `record` argument to `assertMacro`:
85+
file by providing the `record` argument to ``Testing/Trait/macros(_:indentationWidth:record:)``:
8386

8487
```swift
85-
assertMacro(["stringify": StringifyMacro.self], record: .all) {
86-
"""
87-
#stringify(a + b)
88-
"""
89-
} expansion: {
90-
"""
91-
(a + b, "a + b")
92-
"""
93-
}
88+
@Suite(.macros([StringifyMacro.self], record: .all))
9489
```
9590

9691
Now when you run the test again the freshest expanded macro will be written to the `expansion`
9792
trailing closure.
9893

99-
If you're writing many tests for a macro, you can avoid the repetitive work of specifying the macros
100-
in each assertion by using XCTest's `invokeTest` method to wrap each test with Macro Testing
101-
configuration:
102-
103-
```swift
104-
class StringifyMacroTests: XCTestCase {
105-
override func invokeTest() {
106-
withMacroTesting(
107-
macros: ["stringify": StringifyMacro.self]
108-
) {
109-
super.invokeTest()
110-
}
111-
}
112-
113-
func testStringify() {
114-
assertMacro { // 👈 No need to specify the macros being tested
115-
"""
116-
#stringify(a + b)
117-
"""
118-
} expansion: {
119-
"""
120-
(a + b, "a + b")
121-
"""
122-
}
123-
}
124-
125-
// ...
126-
}
127-
```
128-
129-
You can pass the `record` parameter to `withMacroTesting` to re-record every assertion in the
130-
test case (or suite, if you're using your own custom base test case class):
131-
132-
```swift
133-
override func invokeTest() {
134-
withMacroTesting(
135-
record: .all
136-
) {
137-
super.invokeTest()
138-
}
139-
}
140-
```
141-
14294
Macro Testing can also test diagnostics, such as warnings, errors, notes, and fix-its. When a macro
14395
expansion emits a diagnostic, it will render inline in the test. For example, a macro that adds
14496
completion handler functions to async functions may emit an error and fix-it when it is applied to a

Sources/MacroTesting/AssertMacro.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import InlineSnapshotTesting
2-
@_spi(Internals) import SnapshotTesting
2+
@_spi(Internals) @preconcurrency import SnapshotTesting
33
import SwiftDiagnostics
44
import SwiftOperators
55
import SwiftParser
@@ -139,7 +139,7 @@ public func assertMacro(
139139
var record =
140140
record
141141
?? SnapshotTestingConfiguration.current?.record
142-
#if canImport(Testing)
142+
#if canImport(Testing) && swift(<6.1)
143143
indentationWidth =
144144
indentationWidth
145145
?? Test.current?.indentationWidth
@@ -207,7 +207,9 @@ public func assertMacro(
207207
macros: macros,
208208
contextGenerator: { syntax in
209209
BasicMacroExpansionContext(
210-
sharingWith: context, lexicalContext: syntax.allMacroLexicalContexts())
210+
sharingWith: context,
211+
lexicalContext: syntax.allMacroLexicalContexts()
212+
)
211213
},
212214
indentationWidth: indentationWidth
213215
)
@@ -305,7 +307,8 @@ public func assertMacro(
305307
var fixedSourceFile = origSourceFile
306308
fixedSourceFile = Parser.parse(
307309
source: FixItApplier.apply(
308-
edits: edits, to: origSourceFile
310+
edits: edits,
311+
to: origSourceFile
309312
)
310313
.description
311314
)
@@ -449,15 +452,19 @@ extension FixIt.Change {
449452
case .replaceLeadingTrivia(let token, let newTrivia):
450453
let start = expansionContext.position(of: token.position, anchoredAt: token)
451454
let end = expansionContext.position(
452-
of: token.positionAfterSkippingLeadingTrivia, anchoredAt: token)
455+
of: token.positionAfterSkippingLeadingTrivia,
456+
anchoredAt: token
457+
)
453458
return SourceEdit(
454459
range: start..<end,
455460
replacement: newTrivia.description
456461
)
457462

458463
case .replaceTrailingTrivia(let token, let newTrivia):
459464
let start = expansionContext.position(
460-
of: token.endPositionBeforeTrailingTrivia, anchoredAt: token)
465+
of: token.endPositionBeforeTrailingTrivia,
466+
anchoredAt: token
467+
)
461468
let end = expansionContext.position(of: token.endPosition, anchoredAt: token)
462469
return SourceEdit(
463470
range: start..<end,

Sources/MacroTesting/Documentation.docc/MacroTesting.md

Lines changed: 12 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ do is write the following:
1313

1414
```swift
1515
import MacroTesting
16-
import XCTest
16+
import Testing
1717

18-
class StringifyTests: XCTestCase {
19-
func testStringify() {
20-
assertMacro(["stringify": StringifyMacro.self]) {
18+
@Suite(.macros([StringifyMacro.self]))
19+
struct StringifyTests {
20+
@Test func stringify() {
21+
assertMacro {
2122
"""
2223
#stringify(a + b)
2324
"""
@@ -30,8 +31,10 @@ When you run this test the library will automatically expand the macros in the s
3031
and write the expansion into the test file:
3132

3233
```swift
33-
func testStringify() {
34-
assertMacro(["stringify": StringifyMacro.self]) {
34+
@Suite(.macros([StringifyMacro.self]))
35+
struct StringifyTests {
36+
@Test func stringify() {
37+
assertMacro {
3538
"""
3639
#stringify(a + b)
3740
"""
@@ -56,67 +59,15 @@ running the test again will produce a nicely formatted message:
5659
```
5760

5861
You can even have the library automatically re-record the macro expansion directly into your test
59-
file by providing the `record` argument to
60-
``assertMacro(_:indentationWidth:record:of:diagnostics:fixes:expansion:fileID:file:function:line:column:)-8zqk4``
62+
file by providing the `record` argument to ``Testing/Trait/macros(_:indentationWidth:record:)``:
63+
6164
```swift
62-
assertMacro(["stringify": StringifyMacro.self], record: .all) {
63-
"""
64-
#stringify(a + b)
65-
"""
66-
} expansion: {
67-
"""
68-
(a + b, "a + b")
69-
"""
70-
}
65+
@Suite(.macros([StringifyMacro.self], record: .all))
7166
```
7267

7368
Now when you run the test again the freshest expanded macro will be written to the `expansion`
7469
trailing closure.
7570

76-
If you're writing many tests for a macro, you can avoid the repetitive work of specifying the macros
77-
in each assertion by using XCTest's `invokeTest` method to wrap each test with Macro Testing
78-
configuration:
79-
80-
```swift
81-
class StringifyMacroTests: XCTestCase {
82-
override func invokeTest() {
83-
withMacroTesting(
84-
macros: ["stringify": StringifyMacro.self]
85-
) {
86-
super.invokeTest()
87-
}
88-
}
89-
90-
func testStringify() {
91-
assertMacro { // 👈 No need to specify the macros being tested
92-
"""
93-
#stringify(a + b)
94-
"""
95-
} expansion: {
96-
"""
97-
(a + b, "a + b")
98-
"""
99-
}
100-
}
101-
102-
// ...
103-
}
104-
```
105-
106-
You can pass the `record` parameter to
107-
``withMacroTesting(indentationWidth:record:macros:operation:)-7cm1s`` to re-record every assertion in the test
108-
case (or suite, if you're using your own custom base test case class):
109-
110-
```swift
111-
override func invokeTest() {
112-
withMacroTesting(
113-
record: .all
114-
) {
115-
super.invokeTest()
116-
}
117-
}
118-
```
119-
12071
Macro Testing can also test diagnostics, such as warnings, errors, notes, and fix-its. When a macro
12172
expansion emits a diagnostic, it will render inline in the test. For example, a macro that adds
12273
completion handler functions to async functions may emit an error and fix-it when it is applied to a

0 commit comments

Comments
 (0)