@@ -17,8 +17,8 @@ import { reduceTestItemChildren } from "./TestUtils";
17
17
18
18
type ProcessResult = {
19
19
testItems : vscode . TestItem [ ] ;
20
- xcTestArgs : string [ ] ;
21
- swiftTestArgs : string [ ] ;
20
+ xcTestArgs : vscode . TestItem [ ] ;
21
+ swiftTestArgs : vscode . TestItem [ ] ;
22
22
} ;
23
23
24
24
/**
@@ -30,14 +30,11 @@ export class TestRunArguments {
30
30
public xcTestArgs : string [ ] ;
31
31
public swiftTestArgs : string [ ] ;
32
32
33
- constructor (
34
- request : vscode . TestRunRequest ,
35
- private isDebug : boolean
36
- ) {
37
- const { testItems, xcTestArgs, swiftTestArgs } = this . createTestLists ( request ) ;
33
+ constructor ( request : vscode . TestRunRequest , isDebug : boolean ) {
34
+ const { testItems, xcTestArgs, swiftTestArgs } = this . createTestLists ( request , isDebug ) ;
38
35
this . testItems = testItems ;
39
- this . xcTestArgs = xcTestArgs ;
40
- this . swiftTestArgs = swiftTestArgs ;
36
+ this . xcTestArgs = this . annotateTestArgs ( xcTestArgs , isDebug ) ;
37
+ this . swiftTestArgs = this . annotateTestArgs ( swiftTestArgs , isDebug ) ;
41
38
}
42
39
43
40
public get hasXCTests ( ) : boolean {
@@ -52,9 +49,10 @@ export class TestRunArguments {
52
49
* Construct test item list from TestRequest
53
50
* @returns list of test items to run and list of test for XCTest arguments
54
51
*/
55
- private createTestLists ( request : vscode . TestRunRequest ) : ProcessResult {
52
+ private createTestLists ( request : vscode . TestRunRequest , isDebug : boolean ) : ProcessResult {
56
53
const includes = request . include ?? [ ] ;
57
- return includes . reduce ( this . createTestItemReducer ( request . include , request . exclude ) , {
54
+ const excludes = request . exclude ?? [ ] ;
55
+ return includes . reduce ( this . createTestItemReducer ( includes , excludes , isDebug ) , {
58
56
testItems : this . createIncludeParentList ( includes ) ,
59
57
xcTestArgs : [ ] ,
60
58
swiftTestArgs : [ ] ,
@@ -78,15 +76,42 @@ export class TestRunArguments {
78
76
return Array . from ( parents . values ( ) ) ;
79
77
}
80
78
79
+ /**
80
+ * Converts a list of TestItems to a regex test item ID. Depending on the TestItem's
81
+ * tags and whether it is a debug run the ID is converted to a regex pattern that will
82
+ * match the correct tests when passed to the `--filter` argument of `swift test`.
83
+ */
84
+ private annotateTestArgs ( testArgs : vscode . TestItem [ ] , isDebug : boolean ) : string [ ] {
85
+ return testArgs . map ( arg => {
86
+ const isTestTarget = ! ! arg . tags . find ( tag => tag . id === "test-target" ) ;
87
+ if ( isTestTarget ) {
88
+ return `${ arg . id } .*` ;
89
+ }
90
+ const isXCTest = ! ! arg . tags . find ( tag => tag . id === "XCTest" ) ;
91
+ const hasChildren = arg . children . size > 0 ;
92
+ if ( isXCTest ) {
93
+ const terminator = hasChildren ? "/" : "$" ;
94
+ // Debugging XCTests requires exact matches, so we don't need a trailing terminator.
95
+ return isDebug ? arg . id : `${ arg . id } ${ terminator } ` ;
96
+ } else {
97
+ // Append a trailing slash to match a suite name exactly.
98
+ // This prevents TestTarget.MySuite matching TestTarget.MySuite2.
99
+ return `${ arg . id } /` ;
100
+ }
101
+ } ) ;
102
+ }
103
+
81
104
private createTestItemReducer (
82
- include : readonly vscode . TestItem [ ] | undefined ,
83
- exclude : readonly vscode . TestItem [ ] | undefined
105
+ include : readonly vscode . TestItem [ ] ,
106
+ exclude : readonly vscode . TestItem [ ] ,
107
+ isDebug : boolean
84
108
) : ( previousValue : ProcessResult , testItem : vscode . TestItem ) => ProcessResult {
85
109
return ( previousValue , testItem ) => {
86
110
const { testItems, swiftTestArgs, xcTestArgs } = this . processTestItem (
87
111
testItem ,
88
112
include ,
89
- exclude
113
+ exclude ,
114
+ isDebug
90
115
) ;
91
116
92
117
// If no children were added we can skip adding this parent.
@@ -119,63 +144,53 @@ export class TestRunArguments {
119
144
120
145
private itemContainsAllArgs (
121
146
testItem : vscode . TestItem ,
122
- xcTestArgs : string [ ] ,
123
- swiftTestArgs : string [ ]
147
+ xcTestArgs : vscode . TestItem [ ] ,
148
+ swiftTestArgs : vscode . TestItem [ ]
124
149
) : boolean {
125
- return xcTestArgs . length + swiftTestArgs . length === testItem . children . size ;
150
+ return (
151
+ testItem . children . size > 0 &&
152
+ xcTestArgs . length + swiftTestArgs . length === testItem . children . size
153
+ ) ;
126
154
}
127
155
128
156
private simplifyTestArgs (
129
157
testItem : vscode . TestItem ,
130
- xcTestArgs : string [ ] ,
131
- swiftTestArgs : string [ ]
132
- ) : { xcTestResult : string [ ] ; swiftTestResult : string [ ] } {
133
- if (
134
- testItem . parent &&
135
- this . itemContainsAllArgs ( testItem . parent , xcTestArgs , swiftTestArgs )
136
- ) {
137
- return this . simplifyTestArgs ( testItem . parent , xcTestArgs , swiftTestArgs ) ;
138
- } else {
139
- // If we've worked all the way up to a test target, it may have both swift-testing
140
- // and XCTests.
141
- const isTestTarget = ! ! testItem . tags . find ( tag => tag . id === "test-target" ) ;
142
- if ( isTestTarget ) {
143
- return {
144
- // Add a trailing .* to match a test target name exactly.
145
- // This prevents TestTarget matching TestTarget2.
146
- xcTestResult : xcTestArgs . length > 0 ? [ `${ testItem . id } .*` ] : [ ] ,
147
- swiftTestResult : swiftTestArgs . length > 0 ? [ `${ testItem . id } .*` ] : [ ] ,
148
- } ;
149
- }
150
-
151
- // If we've added all the children to the list of arguments, just add
152
- // the parent instead of each individual child. This crafts a minimal set
153
- // of test/suites that run all the test cases requested with the smallest list
154
- // of arguments. The testItem has to have a parent to perform this optimization.
155
- // If it does not we break the ability to run both swift testing tests and XCTests
156
- // in the same run, since test targets can have both types of tests in them.
157
- const isXCTest = ! ! testItem . tags . find ( tag => tag . id === "XCTest" ) ;
158
+ xcTestArgs : vscode . TestItem [ ] ,
159
+ swiftTestArgs : vscode . TestItem [ ]
160
+ ) : { xcTestResult : vscode . TestItem [ ] ; swiftTestResult : vscode . TestItem [ ] } {
161
+ // If we've worked all the way up to a test target, it may have both swift-testing
162
+ // and XCTests.
163
+ const isTestTarget = ! ! testItem . tags . find ( tag => tag . id === "test-target" ) ;
164
+ if ( isTestTarget ) {
158
165
return {
159
- swiftTestResult : [
160
- // Append a trailing slash to match a suite name exactly.
161
- // This prevents TestTarget.MySuite matching TestTarget.MySuite2.
162
- ...( ! isXCTest ? [ `${ testItem . id } /` ] : [ ] ) ,
163
- ] ,
164
- xcTestResult : [
165
- // Debugging XCTests require exact matches, so we don't ned a trailing slash.
166
- ...( isXCTest ? [ this . isDebug ? testItem . id : `${ testItem . id } /` ] : [ ] ) ,
167
- ] ,
166
+ // Add a trailing .* to match a test target name exactly.
167
+ // This prevents TestTarget matching TestTarget2.
168
+ xcTestResult : xcTestArgs . length > 0 ? [ testItem ] : [ ] ,
169
+ swiftTestResult : swiftTestArgs . length > 0 ? [ testItem ] : [ ] ,
168
170
} ;
169
171
}
172
+
173
+ // If we've added all the children to the list of arguments, just add
174
+ // the parent instead of each individual child. This crafts a minimal set
175
+ // of test/suites that run all the test cases requested with the smallest list
176
+ // of arguments. The testItem has to have a parent to perform this optimization.
177
+ // If it does not we break the ability to run both swift testing tests and XCTests
178
+ // in the same run, since test targets can have both types of tests in them.
179
+ const isXCTest = ! ! testItem . tags . find ( tag => tag . id === "XCTest" ) ;
180
+ return {
181
+ xcTestResult : isXCTest ? [ testItem ] : [ ] ,
182
+ swiftTestResult : ! isXCTest ? [ testItem ] : [ ] ,
183
+ } ;
170
184
}
171
185
172
186
private processTestItem (
173
187
testItem : vscode . TestItem ,
174
- include ?: readonly vscode . TestItem [ ] ,
175
- exclude ?: readonly vscode . TestItem [ ]
188
+ include : readonly vscode . TestItem [ ] ,
189
+ exclude : readonly vscode . TestItem [ ] ,
190
+ isDebug : boolean
176
191
) : ProcessResult {
177
192
// Skip tests the user asked to exclude
178
- if ( exclude ? .includes ( testItem ) ) {
193
+ if ( exclude . includes ( testItem ) ) {
179
194
return {
180
195
testItems : [ ] ,
181
196
xcTestArgs : [ ] ,
@@ -184,12 +199,13 @@ export class TestRunArguments {
184
199
}
185
200
186
201
const testItems : vscode . TestItem [ ] = [ ] ;
187
- const xcTestArgs : string [ ] = [ ] ;
188
- const swiftTestArgs : string [ ] = [ ] ;
202
+ const xcTestArgs : vscode . TestItem [ ] = [ ] ;
203
+ const swiftTestArgs : vscode . TestItem [ ] = [ ] ;
189
204
190
205
// If this test item is included or we are including everything
191
- if ( include ? .includes ( testItem ) || ! include ) {
206
+ if ( include . includes ( testItem ) || include . length === 0 ) {
192
207
const isXCTest = testItem . tags . find ( tag => tag . id === "XCTest" ) ;
208
+ const isSwiftTestingTest = testItem . tags . find ( tag => tag . id === "swift-testing" ) ;
193
209
194
210
// Collect up a list of all the test items involved in the run
195
211
// from the TestExplorer tree and store them in `testItems`. Exclude
@@ -200,20 +216,17 @@ export class TestRunArguments {
200
216
// Only add leaf items to the list of arguments to pass to the test runner.
201
217
if ( this . isLeafTestItem ( testItem , ! ! isXCTest ) ) {
202
218
if ( isXCTest ) {
203
- // Tests in debug are specified exactly, otherwise
204
- // add the regex line ending character to avoid capturing
205
- // unwanted tests.
206
- xcTestArgs . push ( this . isDebug ? testItem . id : `${ testItem . id } $` ) ;
207
- } else {
208
- swiftTestArgs . push ( testItem . id ) ;
219
+ xcTestArgs . push ( testItem ) ;
220
+ } else if ( isSwiftTestingTest ) {
221
+ swiftTestArgs . push ( testItem ) ;
209
222
}
210
223
}
211
224
}
212
225
}
213
226
214
227
return reduceTestItemChildren (
215
228
testItem . children ,
216
- this . createTestItemReducer ( undefined , exclude ) ,
229
+ this . createTestItemReducer ( [ ] , exclude , isDebug ) ,
217
230
{
218
231
testItems,
219
232
xcTestArgs,
0 commit comments