File: ExitTest.Condition.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (233 lines) | stat: -rw-r--r-- 8,014 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024–2025 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
//

private import _TestingInternals

#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
extension ExitTest {
  /// The possible conditions under which an exit test will complete.
  ///
  /// Values of this type are used to describe the conditions under which an
  /// exit test is expected to pass or fail by passing them to
  /// ``expect(processExitsWith:observing:_:sourceLocation:performing:)`` or
  /// ``require(processExitsWith:observing:_:sourceLocation:performing:)``.
  ///
  /// ## Topics
  ///
  /// ### Successful exit conditions
  ///
  /// - ``success``
  ///
  /// ### Failing exit conditions
  ///
  /// - ``failure``
  /// - ``exitCode(_:)``
  /// - ``signal(_:)``
  ///
  /// @Metadata {
  ///   @Available(Swift, introduced: 6.2)
  ///   @Available(Xcode, introduced: 26.0)
  /// }
  public struct Condition: Sendable {
    /// An enumeration describing the possible conditions for an exit test.
    private enum _Kind: Sendable, Equatable {
      /// The exit test must exit with a particular exit status.
      case exitStatus(ExitStatus)

      /// The exit test must exit successfully.
      case success

      /// The exit test must exit with any failure.
      case failure
    }

    /// The kind of condition.
    private var _kind: _Kind
  }
}

// MARK: -

#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
extension ExitTest.Condition {
  /// A condition that matches when a process exits normally.
  ///
  /// This condition matches the exit code `EXIT_SUCCESS`.
  ///
  /// @Metadata {
  ///   @Available(Swift, introduced: 6.2)
  ///   @Available(Xcode, introduced: 26.0)
  /// }
  public static var success: Self {
    Self(_kind: .success)
  }

  /// A condition that matches when a process exits abnormally
  ///
  /// This condition matches any exit code other than `EXIT_SUCCESS` or any
  /// signal that causes the process to exit.
  ///
  /// @Metadata {
  ///   @Available(Swift, introduced: 6.2)
  ///   @Available(Xcode, introduced: 26.0)
  /// }
  public static var failure: Self {
    Self(_kind: .failure)
  }

  /// Initialize an instance of this type that matches the specified exit
  /// status.
  ///
  /// - Parameters:
  ///   - exitStatus: The particular exit status this condition should match.
  ///
  /// @Metadata {
  ///   @Available(Swift, introduced: 6.2)
  ///   @Available(Xcode, introduced: 26.0)
  /// }
  public init(_ exitStatus: ExitStatus) {
    self.init(_kind: .exitStatus(exitStatus))
  }

  /// Creates a condition that matches when a process terminates with a given
  /// exit code.
  ///
  /// - Parameters:
  ///   - exitCode: The exit code reported by the process.
  ///
  /// The C programming language defines two standard exit codes, `EXIT_SUCCESS`
  /// and `EXIT_FAILURE`. Platforms may additionally define their own
  /// non-standard exit codes:
  ///
  /// | Platform | Header |
  /// |-|-|
  /// | macOS | [`<stdlib.h>`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/_Exit.3.html), [`<sysexits.h>`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sysexits.3.html) |
  /// | Linux | [`<stdlib.h>`](https://www.kernel.org/doc/man-pages/online/pages/man3/exit.3.html), [`<sysexits.h>`](https://www.kernel.org/doc/man-pages/online/pages/man3/sysexits.h.3head.html) |
  /// | FreeBSD | [`<stdlib.h>`](https://man.freebsd.org/cgi/man.cgi?exit(3)), [`<sysexits.h>`](https://man.freebsd.org/cgi/man.cgi?sysexits(3)) |
  /// | OpenBSD | [`<stdlib.h>`](https://man.openbsd.org/exit.3), [`<sysexits.h>`](https://man.openbsd.org/sysexits.3) |
  /// | Windows | [`<stdlib.h>`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure) |
  ///
  /// @Comment {
  ///   See https://en.cppreference.com/w/c/program/EXIT_status for more
  ///   information about exit codes defined by the C standard.
  /// }
  ///
  /// On macOS, FreeBSD, OpenBSD, and Windows, the full exit code reported by
  /// the process is reported to the parent process. Linux and other POSIX-like
  /// systems may only reliably report the low unsigned 8 bits (0&ndash;255) of
  /// the exit code.
  ///
  /// @Metadata {
  ///   @Available(Swift, introduced: 6.2)
  ///   @Available(Xcode, introduced: 26.0)
  /// }
  public static func exitCode(_ exitCode: CInt) -> Self {
#if !SWT_NO_EXIT_TESTS
    Self(.exitCode(exitCode))
#else
    swt_unreachable()
#endif
  }

  /// Creates a condition that matches when a process exits with a given signal.
  ///
  /// - Parameters:
  ///   - signal: The signal that caused the process to exit.
  ///
  /// The C programming language defines a number of standard signals. Platforms
  /// may additionally define their own non-standard signal codes:
  ///
  /// | Platform | Header |
  /// |-|-|
  /// | macOS | [`<signal.h>`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/signal.3.html) |
  /// | Linux | [`<signal.h>`](https://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html) |
  /// | FreeBSD | [`<signal.h>`](https://man.freebsd.org/cgi/man.cgi?signal(3)) |
  /// | OpenBSD | [`<signal.h>`](https://man.openbsd.org/signal.3) |
  /// | Windows | [`<signal.h>`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/signal-constants) |
  ///
  /// @Comment {
  ///   See https://en.cppreference.com/w/c/program/SIG_types for more
  ///   information about signals defined by the C standard.
  /// }
  ///
  /// @Metadata {
  ///   @Available(Swift, introduced: 6.2)
  ///   @Available(Xcode, introduced: 26.0)
  /// }
  public static func signal(_ signal: CInt) -> Self {
#if !SWT_NO_EXIT_TESTS
    Self(.signal(signal))
#else
    swt_unreachable()
#endif
  }
}

// MARK: - CustomStringConvertible

@_spi(Experimental)
#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
extension ExitTest.Condition: CustomStringConvertible {
  public var description: String {
#if !SWT_NO_EXIT_TESTS
    switch _kind {
    case .failure:
      ".failure"
    case .success:
      ".success"
    case let .exitStatus(exitStatus):
      String(describing: exitStatus)
    }
#else
    swt_unreachable()
#endif
  }
}

// MARK: - Comparison

#if SWT_NO_EXIT_TESTS
@available(*, unavailable, message: "Exit tests are not available on this platform.")
#endif
extension ExitTest.Condition {
  /// Check whether or not an exit test condition matches a given exit status.
  ///
  /// - Parameters:
  ///   - exitStatus: An exit status to compare against.
  ///
  /// - Returns: Whether or not `self` and `exitStatus` represent the same exit
  ///   condition.
  ///
  /// Two exit test conditions can be compared; if either instance is equal to
  /// ``failure``, it will compare equal to any instance except ``success``.
  func isApproximatelyEqual(to exitStatus: ExitStatus) -> Bool {
    // Strictly speaking, the C standard treats 0 as a successful exit code and
    // potentially distinct from EXIT_SUCCESS. To my knowledge, no modern
    // operating system defines EXIT_SUCCESS to any value other than 0, so the
    // distinction is academic.
    return switch (self._kind, exitStatus) {
    case let (.success, .exitCode(exitCode)):
      exitCode == EXIT_SUCCESS
    case let (.failure, .exitCode(exitCode)):
      exitCode != EXIT_SUCCESS
    case (.failure, .signal):
      // All terminating signals are considered failures.
      true
    default:
      self._kind == .exitStatus(exitStatus)
    }
  }
}