Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions Sources/Testing/Running/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,26 +149,23 @@ public struct Configuration: Sendable {
public var testFilter: TestFilter?

/// The granularity to enforce test filtering.
///
/// By default, all tests are run and no filter is set.
/// - Parameters:
/// - selection: An set of test ids to be filtered.
/// - selection: A set of test IDs to be filtered. If `nil`, the current
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some editorial cleanup here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

/// selection is cleared.
///
/// By default, all tests are run and no filter is set.
public mutating func setTestFilter(toMatch selection: Set<Test.ID>?) {
self.setTestFilter(toMatch: selection.map(Test.ID.Selection.init))
setTestFilter(toMatch: selection.map(Test.ID.Selection.init))
}

/// The granularity to enforce test filtering.
///
/// By default, all tests are run and no filter is set.
/// - Parameters:
/// - selection: An selection of test ids to be filtered.
/// - selection: A selection of test IDs to be filtered. If `nil`, the
/// current selection is cleared.
///
/// By default, all tests are run and no filter is set.
mutating func setTestFilter(toMatch selection: Test.ID.Selection?) {
guard let selectedTests = selection else {
self.testFilter = nil
return
}
self.testFilter = { test in
selectedTests.contains(test)
}
testFilter = selection.map { $0.contains }
}
}
41 changes: 41 additions & 0 deletions Sources/Testing/Running/XCTestScaffold.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,33 @@ public enum XCTestScaffold: Sendable {
/// testing library with existing tools such as Swift Package Manager. It
/// will be removed in a future release.
///
/// ### Filtering tests
///
/// This function does not support the `--filter` argument passed to
/// `swift test`. Instead, set the `SWT_SELECTED_TEST_IDS` environment
/// variable to the ``Test/ID`` of the test that should run (or, if multiple
/// tests should be run, their IDs separated by `";"`.)
///
/// A test ID is composed of its module name, containing type name, and (if
/// the test is a function rather than a suite), the name of the function
/// including parentheses and any parameter labels. For example, given the
/// following test functions in a module named `"MyTests"`:
///
/// ```swift
/// struct MySuite {
/// @Test func hello() { ... }
/// @Test(arguments: 0 ..< 10) func world(i: Int) { ... }
/// }
/// ```
///
/// Their IDs are the strings `"MyTests/MySuite/hello()"` and
/// `"MyTests/MySuite/world(i:)"` respectively, and they can be passed as the
/// environment variable value
/// `"MyTests/MySuite/hello();MyTests/MySuite/world(i:)"`.
///
/// - Note: The module name of a test target in a Swift package is typically
/// the name of the test target.
///
/// ### Configuring output
///
/// By default, this function uses
Expand Down Expand Up @@ -168,6 +195,20 @@ public enum XCTestScaffold: Sendable {
#endif
}

// If the SWT_SELECTED_TEST_IDS environment variable is set, split it into
// test IDs (separated by ";", test ID components separated by "/") and set
// the configuration's test filter to match it.
//
// This environment variable stands in for `swift test --filter`.
let testIDs: [Test.ID]? = Environment.variable(named: "SWT_SELECTED_TEST_IDS").map { testIDs in
testIDs.split(separator: ";", omittingEmptySubsequences: true).map { testID in
Test.ID(testID.split(separator: "/", omittingEmptySubsequences: true).map(String.init))
}
}
if let testIDs {
configuration.setTestFilter(toMatch: Set(testIDs))
}

let runner = await Runner(configuration: configuration)
await runner.run()
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Testing/Test.ID.Selection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ extension Test.ID {
/// A test ID is considered contained in the selection if it has been
/// explicitly added or if it has a descendant or ancestor which has been
/// explicitly added.
func contains(_ test: Test) -> Bool {
@Sendable func contains(_ test: Test) -> Bool {
contains(test.id)
}

Expand All @@ -69,7 +69,7 @@ extension Test.ID {
/// A test ID is considered contained in the selection if it has been
/// explicitly added or if it has a descendant or ancestor which has been
/// explicitly added.
func contains(_ testID: Test.ID) -> Bool {
@Sendable func contains(_ testID: Test.ID) -> Bool {
contains(testID.keyPathRepresentation)
}

Expand Down
8 changes: 2 additions & 6 deletions Tests/TestingTests/PlanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ struct PlanTests {

var configuration = Configuration()
let selection = Test.ID.Selection(testIDs: [outerTestType.id, deeplyNestedTest.id])
configuration.testFilter = { test in
selection.contains(test)
}
configuration.setTestFilter(toMatch: selection)

let plan = await Runner.Plan(tests: tests, configuration: configuration)

Expand All @@ -94,9 +92,7 @@ struct PlanTests {

var configuration = Configuration()
let selection = Test.ID.Selection(testIDs: [testSuiteA.id])
configuration.testFilter = { test in
selection.contains(test)
}
configuration.setTestFilter(toMatch: selection)

let plan = await Runner.Plan(tests: tests, configuration: configuration)
let testFuncXWithTraits = try #require(plan.steps.map(\.test).first { $0.name == "x()" })
Expand Down
8 changes: 2 additions & 6 deletions Tests/TestingTests/RunnerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,7 @@ final class RunnerTests: XCTestCase {

var configuration = Configuration()
let selection = Test.ID.Selection(testIDs: [testSuite.id])
configuration.testFilter = { test in
selection.contains(test)
}
configuration.setTestFilter(toMatch: selection)

let runner = await Runner(testing: [
testSuite,
Expand Down Expand Up @@ -304,9 +302,7 @@ final class RunnerTests: XCTestCase {

var configuration = Configuration()
let selection = Test.ID.Selection(testIDs: selectedTestIDs)
configuration.testFilter = { test in
selection.contains(test)
}
configuration.setTestFilter(toMatch: selection)

let runner = await Runner(configuration: configuration)
let plan = runner.plan
Expand Down
10 changes: 3 additions & 7 deletions Tests/TestingTests/TestSupport/TestingAdditions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,8 @@ func runTest(for containingType: Any.Type, configuration: Configuration = .init(
/// If no test is found representing `containingType`, nothing is run.
func runTestFunction(named name: String, in containingType: Any.Type, configuration: Configuration = .init()) async {
var configuration = configuration
let testID = Test.ID.Selection(testIDs: [Test.ID(type: containingType).child(named: name)])
configuration.testFilter = { test in
testID.contains(test)
}
let selection = Test.ID.Selection(testIDs: [Test.ID(type: containingType).child(named: name)])
configuration.setTestFilter(toMatch: selection)

let runner = await Runner(configuration: configuration)
await runner.run()
Expand Down Expand Up @@ -109,9 +107,7 @@ extension Runner.Plan {
init(selecting containingType: Any.Type, configuration: Configuration = .init()) async {
var configuration = configuration
let selection = Test.ID.Selection(testIDs: [Test.ID(type: containingType)])
configuration.testFilter = { test in
selection.contains(test)
}
configuration.setTestFilter(toMatch: selection)

await self.init(configuration: configuration)
}
Expand Down