Skip to content

Commit dce798c

Browse files
committed
Allow skipping tests with a flag, instead of the environment variable
1 parent 13d60ca commit dce798c

File tree

2 files changed

+39
-36
lines changed

2 files changed

+39
-36
lines changed

Documentation/Development.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ $ swift test --parallel
4747

4848
# Run a single test.
4949
$ swift test --filter PackageGraphTests.DependencyResolverTests/testBasics
50+
51+
# Run tests for the test targets BuildTests and WorkspaceTests, but skip some test cases.
52+
$ swift test --filter BuildTests --skip BuildPlanTests --filter WorkspaceTests --skip InitTests
5053
```
5154

5255
Note: PackageDescription v4 is not available when developing using this method.

Sources/Commands/SwiftTestTool.swift

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -83,50 +83,25 @@ public class TestToolOptions: ToolOptions {
8383
/// If the path of the exported code coverage JSON should be printed.
8484
var shouldPrintCodeCovPath = false
8585

86-
var testCaseSpecifier: TestCaseSpecifier {
87-
testCaseSpecifierOverride() ?? _testCaseSpecifier
88-
}
86+
var testCaseSpecifier: TestCaseSpecifier = .none
8987

90-
var _testCaseSpecifier: TestCaseSpecifier = .none
88+
var testCaseSkip: TestCaseSpecifier = .none
9189

9290
/// Path where the xUnit xml file should be generated.
9391
var xUnitOutput: AbsolutePath?
9492

9593
/// The test product to use. This is useful when there are multiple test products
9694
/// to choose from (usually in multiroot packages).
9795
public var testProduct: String?
98-
99-
/// Returns the test case specifier if overridden in the env.
100-
private func testCaseSpecifierOverride() -> TestCaseSpecifier? {
101-
guard let override = ProcessEnv.vars["_SWIFTPM_SKIP_TESTS_LIST"] else {
102-
return nil
103-
}
104-
105-
do {
106-
let skipTests: [String.SubSequence]
107-
// Read from the file if it exists.
108-
if let path = try? AbsolutePath(validating: override), localFileSystem.exists(path) {
109-
let contents = try localFileSystem.readFileContents(path).cString
110-
skipTests = contents.split(separator: "\n", omittingEmptySubsequences: true)
111-
} else {
112-
// Otherwise, read the env variable.
113-
skipTests = override.split(separator: ":", omittingEmptySubsequences: true)
114-
}
115-
116-
return .skip(skipTests.map(String.init))
117-
} catch {
118-
// FIXME: We should surface errors from here.
119-
}
120-
return nil
121-
}
12296
}
12397

12498
/// Tests filtering specifier
12599
///
126100
/// This is used to filter tests to run
127101
/// .none => No filtering
128102
/// .specific => Specify test with fully quantified name
129-
/// .regex => RegEx patterns
103+
/// .regex => RegEx patterns for tests to run
104+
/// .skip => RegEx patterns for tests to skip
130105
public enum TestCaseSpecifier {
131106
case none
132107
case specific(String)
@@ -168,7 +143,9 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
168143
case .listTests:
169144
let testProducts = try buildTestsIfNeeded()
170145
let testSuites = try getTestSuites(in: testProducts)
171-
let tests = testSuites.filteredTests(specifier: options.testCaseSpecifier)
146+
let tests = testSuites
147+
.filteredTests(specifier: options.testCaseSpecifier)
148+
.skippedTests(specifier: options.testCaseSkip)
172149

173150
// Print the tests.
174151
for test in tests {
@@ -218,7 +195,9 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
218195

219196
// Find the tests we need to run.
220197
let testSuites = try getTestSuites(in: testProducts)
221-
let tests = testSuites.filteredTests(specifier: options.testCaseSpecifier)
198+
let tests = testSuites
199+
.filteredTests(specifier: options.testCaseSpecifier)
200+
.skippedTests(specifier: options.testCaseSkip)
222201

223202
// If there were no matches, emit a warning.
224203
if tests.isEmpty {
@@ -252,7 +231,9 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
252231
let toolchain = try getToolchain()
253232
let testProducts = try buildTestsIfNeeded()
254233
let testSuites = try getTestSuites(in: testProducts)
255-
let tests = testSuites.filteredTests(specifier: options.testCaseSpecifier)
234+
let tests = testSuites
235+
.filteredTests(specifier: options.testCaseSpecifier)
236+
.skippedTests(specifier: options.testCaseSkip)
256237
let buildParameters = try self.buildParameters()
257238

258239
// If there were no matches, emit a warning and exit.
@@ -408,7 +389,7 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
408389

409390
binder.bind(
410391
option: parser.add(option: "--specifier", shortName: "-s", kind: String.self),
411-
to: { $0._testCaseSpecifier = .specific($1) })
392+
to: { $0.testCaseSpecifier = .specific($1) })
412393

413394
binder.bind(
414395
option: parser.add(option: "--xunit-output", kind: PathArgument.self),
@@ -418,7 +399,12 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
418399
option: parser.add(option: "--filter", kind: [String].self,
419400
usage: "Run test cases matching regular expression, Format: <test-target>.<test-case> or " +
420401
"<test-target>.<test-case>/<test>"),
421-
to: { $0._testCaseSpecifier = .regex($1) })
402+
to: { $0.testCaseSpecifier = .regex($1) })
403+
404+
binder.bind(
405+
option: parser.add(option: "--skip", kind: [String].self,
406+
usage: "Skip test cases matching regular expression, Example: --skip PerformanceTests"),
407+
to: { $0.testCaseSkip = .skip($1) })
422408

423409
binder.bind(
424410
option: parser.add(option: "--enable-code-coverage", kind: Bool.self,
@@ -967,14 +953,28 @@ fileprivate extension Dictionary where Key == AbsolutePath, Value == [TestSuite]
967953
})
968954
case .specific(let name):
969955
return allTests.filter{ $0.specifier == name }
956+
case .skip:
957+
fatalError("Tests to skip should never have been passed here.")
958+
}
959+
}
960+
}
961+
962+
fileprivate extension Array where Element == UnitTest {
963+
/// Skip tests matching the provided specifier
964+
func skippedTests(specifier: TestCaseSpecifier) -> [UnitTest] {
965+
switch specifier {
966+
case .none:
967+
return self
970968
case .skip(let skippedTests):
971-
var result = allTests
969+
var result = self
972970
for skippedTest in skippedTests {
973971
result = result.filter{
974972
$0.specifier.range(of: skippedTest, options: .regularExpression) == nil
975973
}
976974
}
977975
return result
976+
case .regex, .specific:
977+
fatalError("Tests to filter should never have been passed here.")
978978
}
979979
}
980980
}
@@ -1086,6 +1086,6 @@ final class XUnitGenerator {
10861086

10871087
private extension Diagnostic.Message {
10881088
static var noMatchingTests: Diagnostic.Message {
1089-
.warning("'--filter' predicate did not match any test case")
1089+
.warning("No matching test cases were run")
10901090
}
10911091
}

0 commit comments

Comments
 (0)