From 66d13bfab64597b6d8befbaa5f526bec90b8a0d1 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Sat, 29 Jun 2024 10:26:12 -0400 Subject: [PATCH] Add `Test.isRunning` to let code determine if Swift Testing is active. This PR adds a `Test.isRunning` static property that tells the caller if _any_ thread/task/queue/etc. is currently running Swift Testing code. This property is distinct from `Test.current` because that property has a value of `nil` on detached tasks. Resolves #475. --- .../Testing/Running/Runner.RuntimeState.swift | 20 +++++++++++++++++++ Tests/TestingTests/RunnerTests.swift | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/Sources/Testing/Running/Runner.RuntimeState.swift b/Sources/Testing/Running/Runner.RuntimeState.swift index 3928a5e6b..05049aca7 100644 --- a/Sources/Testing/Running/Runner.RuntimeState.swift +++ b/Sources/Testing/Running/Runner.RuntimeState.swift @@ -106,6 +106,14 @@ extension Configuration { _all.rawValue.instances.values } + /// The number of instances of this type that are currently set as the current + /// configuration for a task. + static var currentCount: Int { + _all.withLock { all in + all.instances.count + } + } + /// Add this instance to ``Configuration/all``. /// /// - Returns: A unique number identifying `self` that can be @@ -147,6 +155,9 @@ extension Test { /// by using [`Thread.detachNewThread(_:)`](https://developer.apple.com/documentation/foundation/thread/2088563-detachnewthread) /// or [`DispatchQueue.async(execute:)`](https://developer.apple.com/documentation/dispatch/dispatchqueue/2016103-async)), /// the value of this property may be `nil`. + /// + /// To determine if any test is running on any task in the current process, + /// use ``Test/isRunning``. public static var current: Self? { Runner.RuntimeState.current?.test } @@ -165,6 +176,15 @@ extension Test { runtimeState.test = test return try await Runner.RuntimeState.$current.withValue(runtimeState, operation: body) } + + /// Whether or not any test is running in the current process. + /// + /// To get an instance of ``Test`` representing the test running on the + /// current task, use ``Test/current``. + @_spi(Experimental) + public static var isRunning: Bool { + Configuration.currentCount > 0 + } } extension Test.Case { diff --git a/Tests/TestingTests/RunnerTests.swift b/Tests/TestingTests/RunnerTests.swift index 13f21ed88..bbb15ad29 100644 --- a/Tests/TestingTests/RunnerTests.swift +++ b/Tests/TestingTests/RunnerTests.swift @@ -878,5 +878,14 @@ final class RunnerTests: XCTestCase { await runTest(for: DeprecatedVersionTests.self, configuration: configuration) await fulfillment(of: [testStarted, testSkipped], timeout: 0.0) } + + func testTestIsRunning() async { + // Only XCTest is running here. + XCTAssertFalse(Test.isRunning) + + await Test { + XCTAssertTrue(Test.isRunning) + }.run(configuration: .init()) + } } #endif