Skip to content
20 changes: 15 additions & 5 deletions Sources/Testing/Traits/ConditionTrait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public struct ConditionTrait: TestTrait, SuiteTrait {
///
/// - Parameters:
/// - body: The function to call. The result of this function determines
/// if the condition is satisfied or not.
case conditional(_ body: @Sendable () async throws -> Bool)

/// The trait is unconditional and always has the same result.
Expand Down Expand Up @@ -62,16 +61,27 @@ public struct ConditionTrait: TestTrait, SuiteTrait {

/// The source location where this trait is specified.
public var sourceLocation: SourceLocation

public func prepare(for test: Test) async throws {
let result = switch kind {

/// Evaluate this instance's underlying condition.
///
/// - Returns: The result of evaluating this instance's underlying condition.
///
/// The evaluation is performed each time this function is called, and is not
/// cached.
@_spi(Experimental)
public func evaluate() async throws -> Bool {
switch kind {
case let .conditional(condition):
try await condition()
case let .unconditional(unconditionalValue):
unconditionalValue
}
}

public func prepare(for test: Test) async throws {
let isEnabled = try await evaluate()

if !result {
if !isEnabled {
// We don't need to consider including a backtrace here because it will
// primarily contain frames in the testing library, not user code. If an
// error was thrown by a condition evaluated above, the caller _should_
Expand Down
17 changes: 17 additions & 0 deletions Tests/TestingTests/RunnerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,23 @@ final class RunnerTests: XCTestCase {
let test2 = Test(.disabled(if: Bool.random())) { }
XCTAssertTrue(test2.traits.compactMap { $0 as? ConditionTrait }.allSatisfy { !$0.isConstant })
}

func testEvaluateConditionTrait() async throws {
let trueUnconditional = ConditionTrait(kind: .unconditional(true), comments: [], sourceLocation: #_sourceLocation)
let falseUnconditional = ConditionTrait.disabled()
let enabledTrue = ConditionTrait.enabled(if: true)
let enabledFalse = ConditionTrait.enabled(if: false)
var result: Bool

result = try await trueUnconditional.evaluate()
XCTAssertTrue(result)
result = try await falseUnconditional.evaluate()
XCTAssertFalse(result)
result = try await enabledTrue.evaluate()
XCTAssertTrue(result)
result = try await enabledFalse.evaluate()
XCTAssertFalse(result)
}

func testGeneratedPlan() async throws {
let tests: [(Any.Type, String)] = [
Expand Down