Skip to content

Commit

Permalink
[SWT-NNNN] Exit tests
Browse files Browse the repository at this point in the history
One of the first enhancement requests we received for swift-testing was the
ability to test for precondition failures and other critical failures that
terminate the current process when they occur. This feature is also frequently
requested for XCTest. With swift-testing, we have the opportunity to build such
a feature in an ergonomic way.

Read the full proposal [here](https://github.com/apple/swift-testing/blob/jgrynspan/exit-tests-proposal/Documentation/Proposals/NNNN-exit-tests.md).
  • Loading branch information
grynspan committed Oct 23, 2024
1 parent e6abba8 commit 38b0650
Show file tree
Hide file tree
Showing 24 changed files with 1,003 additions and 16 deletions.
723 changes: 723 additions & 0 deletions Documentation/Proposals/NNNN-exit-tests.md

Large diffs are not rendered by default.

33 changes: 27 additions & 6 deletions Sources/Testing/ExitTests/ExitCondition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,34 @@ private import _TestingInternals
/// test is expected to pass or fail by passing them to
/// ``expect(exitsWith:observing:_:sourceLocation:performing:)`` or
/// ``require(exitsWith:observing:_:sourceLocation:performing:)``.
@_spi(Experimental)
///
/// ## Topics
///
/// ### Successful exit conditions
///
/// - ``success``
///
/// ### Failing exit conditions
///
/// - ``failure``
/// - ``exitCode(_:)``
/// - ``signal(_:)``
///
/// ### Comparing exit conditions
///
/// - ``/Swift/Optional/==(_:_:)``
/// - ``/Swift/Optional/!=(_:_:)``
/// - ``/Swift/Optional/===(_:_:)``
/// - ``/Swift/Optional/!==(_:_:)``
#if SWT_NO_PROCESS_SPAWNING
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
public enum ExitCondition: Sendable {
/// The process terminated successfully with status `EXIT_SUCCESS`.
///
/// The C programming language defines two [standard exit codes](https://en.cppreference.com/w/c/program/EXIT_status),
/// `EXIT_SUCCESS` and `EXIT_FAILURE` as well as `0` (as a synonym for
/// `EXIT_SUCCESS`.)
public static var success: Self {
// Strictly speaking, the C standard treats 0 as a successful exit code and
// potentially distinct from EXIT_SUCCESS. To my knowledge, no modern
Expand Down Expand Up @@ -76,7 +98,6 @@ public enum ExitCondition: Sendable {

// MARK: - Equatable

@_spi(Experimental)
#if SWT_NO_PROCESS_SPAWNING
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
Expand Down Expand Up @@ -107,7 +128,7 @@ extension Optional<ExitCondition> {
/// or [`Hashable`](https://developer.apple.com/documentation/swift/hashable).
///
/// For any values `a` and `b`, `a == b` implies that `a != b` is `false`.
public static func ==(lhs: Self, rhs: Self) -> Bool {
public static func ==(lhs: ExitCondition?, rhs: ExitCondition?) -> Bool {
#if !SWT_NO_PROCESS_SPAWNING
return switch (lhs, rhs) {
case let (.failure, .exitCode(exitCode)), let (.exitCode(exitCode), .failure):
Expand Down Expand Up @@ -149,7 +170,7 @@ extension Optional<ExitCondition> {
/// or [`Hashable`](https://developer.apple.com/documentation/swift/hashable).
///
/// For any values `a` and `b`, `a == b` implies that `a != b` is `false`.
public static func !=(lhs: Self, rhs: Self) -> Bool {
public static func !=(lhs: ExitCondition?, rhs: ExitCondition?) -> Bool {
#if !SWT_NO_PROCESS_SPAWNING
!(lhs == rhs)
#else
Expand Down Expand Up @@ -183,7 +204,7 @@ extension Optional<ExitCondition> {
/// or [`Hashable`](https://developer.apple.com/documentation/swift/hashable).
///
/// For any values `a` and `b`, `a === b` implies that `a !== b` is `false`.
public static func ===(lhs: Self, rhs: Self) -> Bool {
public static func ===(lhs: ExitCondition?, rhs: ExitCondition?) -> Bool {
return switch (lhs, rhs) {
case (.none, .none):
true
Expand Down Expand Up @@ -224,7 +245,7 @@ extension Optional<ExitCondition> {
/// or [`Hashable`](https://developer.apple.com/documentation/swift/hashable).
///
/// For any values `a` and `b`, `a === b` implies that `a !== b` is `false`.
public static func !==(lhs: Self, rhs: Self) -> Bool {
public static func !==(lhs: ExitCondition?, rhs: ExitCondition?) -> Bool {
#if !SWT_NO_PROCESS_SPAWNING
!(lhs === rhs)
#else
Expand Down
3 changes: 1 addition & 2 deletions Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private import _TestingInternals
///
/// Instances of this type describe an exit test defined by the test author and
/// discovered or called at runtime.
@_spi(Experimental) @_spi(ForToolsIntegrationOnly)
@_spi(ForToolsIntegrationOnly)
#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
Expand Down Expand Up @@ -170,7 +170,6 @@ extension ExitTest {
/// - Warning: This protocol is used to implement the `#expect(exitsWith:)`
/// macro. Do not use it directly.
@_alwaysEmitConformanceMetadata
@_spi(Experimental)
public protocol __ExitTestContainer {
/// The expected exit condition of the exit test.
static var __expectedExitCondition: ExitCondition { get }
Expand Down
1 change: 0 additions & 1 deletion Sources/Testing/ExitTests/ExitTestArtifacts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
/// instances of this type.
///
/// - Warning: The name of this type is still unstable and subject to change.
@_spi(Experimental)
#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
Expand Down
8 changes: 4 additions & 4 deletions Sources/Testing/Expectations/Expectation+Macro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -511,12 +511,12 @@ public macro require<R>(
/// ```
///
/// An exit test cannot run within another exit test.
@_spi(Experimental)
#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
@discardableResult
@freestanding(expression) public macro expect(
@freestanding(expression)
public macro expect(
exitsWith expectedExitCondition: ExitCondition,
observing observedValues: [PartialKeyPath<ExitTestArtifacts>] = [],
_ comment: @autoclosure () -> Comment? = nil,
Expand Down Expand Up @@ -623,12 +623,12 @@ public macro require<R>(
/// ```
///
/// An exit test cannot run within another exit test.
@_spi(Experimental)
#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
@discardableResult
@freestanding(expression) public macro require(
@freestanding(expression)
public macro require(
exitsWith expectedExitCondition: ExitCondition,
observing observedValues: [PartialKeyPath<ExitTestArtifacts>] = [],
_ comment: @autoclosure () -> Comment? = nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,6 @@ public func __checkClosureCall<R>(
///
/// - Warning: This function is used to implement the `#expect()` and
/// `#require()` macros. Do not call it directly.
@_spi(Experimental)
public func __checkClosureCall(
exitsWith expectedExitCondition: ExitCondition,
observing observedValues: [PartialKeyPath<ExitTestArtifacts>],
Expand Down
1 change: 0 additions & 1 deletion Sources/Testing/Running/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ public struct Configuration: Sendable {
/// When using the `swift test` command from Swift Package Manager, this
/// property is pre-configured. Otherwise, the default value of this property
/// records an issue indicating that it has not been configured.
@_spi(Experimental)
public var exitTestHandler: ExitTest.Handler = { _ in
throw SystemError(description: "Exit test support has not been implemented by the current testing infrastructure.")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitCondition``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``/Swift/Optional/!=(_:_:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``/Swift/Optional/!==(_:_:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``/Swift/Optional/==(_:_:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``/Swift/Optional/===(_:_:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitCondition/exitCode(_:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitCondition/failure``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitCondition/signal(_:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitCondition/success``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitTestArtifacts``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitTestArtifacts/exitCondition``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitTestArtifacts/standardErrorContent``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/ExitTestArtifacts/standardOutputContent``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ``Testing/expect(exitsWith:observing:_:sourceLocation:performing:)``

<!--
This source file is part of the Swift.org open source project
Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

@Metadata {
@Available(Xcode, introduced: 999.0)
@Available(Swift, introduced: 999.0)
}
Loading

0 comments on commit 38b0650

Please sign in to comment.