Skip to content

Commit b9eeb1a

Browse files
authored
Don't restrict helpers to DEBUG builds (#9)
1 parent 152390e commit b9eeb1a

File tree

1 file changed

+65
-67
lines changed

1 file changed

+65
-67
lines changed
Lines changed: 65 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,72 @@
1-
#if DEBUG
2-
#if canImport(ObjectiveC)
3-
import Foundation
1+
#if canImport(ObjectiveC)
2+
import Foundation
43

5-
/// This function generates a failure immediately and unconditionally.
6-
///
7-
/// Dynamically creates and records an `XCTIssue` under the hood that captures the source code
8-
/// context of the caller. Useful for defining assertion helpers that fail in indirect code
9-
/// paths, where the `file` and `line` of the failure have not been realized.
10-
///
11-
/// - Parameter message: An optional description of the assertion, for inclusion in test
12-
/// results.
13-
public func XCTFail(_ message: String = "") {
14-
if let XCTestObservationCenter = NSClassFromString("XCTestObservationCenter")
4+
/// This function generates a failure immediately and unconditionally.
5+
///
6+
/// Dynamically creates and records an `XCTIssue` under the hood that captures the source code
7+
/// context of the caller. Useful for defining assertion helpers that fail in indirect code
8+
/// paths, where the `file` and `line` of the failure have not been realized.
9+
///
10+
/// - Parameter message: An optional description of the assertion, for inclusion in test
11+
/// results.
12+
public func XCTFail(_ message: String = "") {
13+
if let XCTestObservationCenter = NSClassFromString("XCTestObservationCenter")
14+
as Any as? NSObjectProtocol,
15+
String(describing: XCTestObservationCenter) != "<null>",
16+
let shared = XCTestObservationCenter.perform(Selector(("sharedTestObservationCenter")))?
17+
.takeUnretainedValue(),
18+
let observers = shared.perform(Selector(("observers")))?
19+
.takeUnretainedValue() as? [AnyObject],
20+
let observer =
21+
observers
22+
.first(where: { NSStringFromClass(type(of: $0)) == "XCTestMisuseObserver" }),
23+
let currentTestCase = observer.perform(Selector(("currentTestCase")))?
24+
.takeUnretainedValue(),
25+
let XCTIssue = NSClassFromString("XCTIssue")
1526
as Any as? NSObjectProtocol,
16-
String(describing: XCTestObservationCenter) != "<null>",
17-
let shared = XCTestObservationCenter.perform(Selector(("sharedTestObservationCenter")))?
18-
.takeUnretainedValue(),
19-
let observers = shared.perform(Selector(("observers")))?
20-
.takeUnretainedValue() as? [AnyObject],
21-
let observer =
22-
observers
23-
.first(where: { NSStringFromClass(type(of: $0)) == "XCTestMisuseObserver" }),
24-
let currentTestCase = observer.perform(Selector(("currentTestCase")))?
25-
.takeUnretainedValue(),
26-
let XCTIssue = NSClassFromString("XCTIssue")
27-
as Any as? NSObjectProtocol,
28-
let alloc = XCTIssue.perform(NSSelectorFromString("alloc"))?
29-
.takeUnretainedValue(),
30-
let issue =
31-
alloc
32-
.perform(
33-
Selector(("initWithType:compactDescription:")),
34-
with: 0,
35-
with: message.isEmpty ? "failed" : message
36-
)?
37-
.takeUnretainedValue()
38-
{
39-
_ = currentTestCase.perform(Selector(("recordIssue:")), with: issue)
40-
return
41-
}
27+
let alloc = XCTIssue.perform(NSSelectorFromString("alloc"))?
28+
.takeUnretainedValue(),
29+
let issue =
30+
alloc
31+
.perform(
32+
Selector(("initWithType:compactDescription:")),
33+
with: 0,
34+
with: message.isEmpty ? "failed" : message
35+
)?
36+
.takeUnretainedValue()
37+
{
38+
_ = currentTestCase.perform(Selector(("recordIssue:")), with: issue)
39+
return
4240
}
41+
}
4342

44-
/// This function generates a failure immediately and unconditionally.
45-
///
46-
/// Dynamically calls `XCTFail` with the given file and line. Useful for defining assertion
47-
/// helpers that have the source code context at hand and want to highlight the direct caller
48-
/// of the helper.
49-
///
50-
/// - Parameter message: An optional description of the assertion, for inclusion in test
51-
/// results.
52-
public func XCTFail(_ message: String = "", file: StaticString, line: UInt) {
53-
guard let _XCTFailureHandler = _XCTFailureHandler
54-
else { return }
43+
/// This function generates a failure immediately and unconditionally.
44+
///
45+
/// Dynamically calls `XCTFail` with the given file and line. Useful for defining assertion
46+
/// helpers that have the source code context at hand and want to highlight the direct caller
47+
/// of the helper.
48+
///
49+
/// - Parameter message: An optional description of the assertion, for inclusion in test
50+
/// results.
51+
public func XCTFail(_ message: String = "", file: StaticString, line: UInt) {
52+
guard let _XCTFailureHandler = _XCTFailureHandler
53+
else { return }
5554

56-
_XCTFailureHandler(nil, true, "\(file)", line, "\(message.isEmpty ? "failed" : message)", nil)
57-
}
55+
_XCTFailureHandler(nil, true, "\(file)", line, "\(message.isEmpty ? "failed" : message)", nil)
56+
}
5857

59-
private typealias XCTFailureHandler = @convention(c) (
60-
AnyObject?, Bool, UnsafePointer<CChar>, UInt, String, String?
61-
) -> Void
62-
private let XCTest = NSClassFromString("XCTest")
63-
.flatMap(Bundle.init(for:))
64-
.flatMap { $0.executablePath }
65-
.flatMap { dlopen($0, RTLD_NOW) }
66-
private let _XCTFailureHandler =
67-
XCTest
68-
.flatMap { dlsym($0, "_XCTFailureHandler") }
69-
.map { unsafeBitCast($0, to: XCTFailureHandler.self) }
70-
#else
71-
// NB: It seems to be safe to import XCTest on Linux
72-
@_exported import func XCTest.XCTFail
73-
#endif
58+
private typealias XCTFailureHandler = @convention(c) (
59+
AnyObject?, Bool, UnsafePointer<CChar>, UInt, String, String?
60+
) -> Void
61+
private let XCTest = NSClassFromString("XCTest")
62+
.flatMap(Bundle.init(for:))
63+
.flatMap { $0.executablePath }
64+
.flatMap { dlopen($0, RTLD_NOW) }
65+
private let _XCTFailureHandler =
66+
XCTest
67+
.flatMap { dlsym($0, "_XCTFailureHandler") }
68+
.map { unsafeBitCast($0, to: XCTFailureHandler.self) }
69+
#else
70+
// NB: It seems to be safe to import XCTest on Linux
71+
@_exported import func XCTest.XCTFail
7472
#endif

0 commit comments

Comments
 (0)