Skip to content

Commit c6a92a1

Browse files
authored
Always set the XCTest bundle path on Darwin when running exit tests. (#422)
Xcode is a complicated beast and there are code paths that lead to us running a test hosted by XCTest that isn't discoverable by the existing exit test implementation. This PR makes that implementation more robust in these scenarios and fixes spurious exit test failures that were resulting. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 741cfed commit c6a92a1

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

Sources/Testing/ExitTests/ExitTest.swift

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,18 +235,42 @@ extension ExitTest {
235235
// We only need to pass arguments when hosted by XCTest.
236236
let childArguments: [String] = {
237237
var result = [String]()
238-
if let xcTestCaseIdentifier {
238+
lazy var xctestTargetPath = Environment.variable(named: "XCTestBundlePath")
239+
?? CommandLine.arguments().dropFirst().last
239240
#if SWT_TARGET_OS_APPLE
240-
result += ["-XCTest", xcTestCaseIdentifier]
241+
// If the running executable appears to be the XCTest runner executable in
242+
// Xcode, figure out the path to the running XCTest bundle. If we can find
243+
// it, then we can re-run the host XCTestCase instance.
244+
// TODO: use basename_r() instead of parsing the path.
245+
var isHostedByXCTest = false
246+
if let executablePath = try? childProcessExecutablePath.get() {
247+
executablePath.withCString { childProcessExecutablePath in
248+
withUnsafeTemporaryAllocation(of: CChar.self, capacity: strlen(childProcessExecutablePath) + 1) { baseName in
249+
if nil != basename_r(childProcessExecutablePath, baseName.baseAddress!) {
250+
isHostedByXCTest = 0 == strcmp(baseName.baseAddress!, "xctest")
251+
}
252+
}
253+
}
254+
}
255+
256+
if isHostedByXCTest, let xctestTargetPath {
257+
// HACK: if the current test is being run from within Xcode, we don't
258+
// always know we're being hosted by an XCTestCase instance. In cases
259+
// where we don't, but the XCTest environment variable specifying the
260+
// test bundle is set, assume we _are_ being hosted and specify a
261+
// blank test identifier ("/") to force the xctest command-line tool
262+
// to run.
263+
let xcTestCaseIdentifier = xcTestCaseIdentifier ?? "/"
264+
result += ["-XCTest", xcTestCaseIdentifier, xctestTargetPath]
265+
}
241266
#else
267+
if let xcTestCaseIdentifier {
242268
result.append(xcTestCaseIdentifier)
243-
#endif
244-
if let xctestTargetPath = Environment.variable(named: "XCTestBundlePath") {
245-
result.append(xctestTargetPath)
246-
} else if let xctestTargetPath = CommandLine.arguments().last {
269+
if let xctestTargetPath {
247270
result.append(xctestTargetPath)
248271
}
249272
}
273+
#endif
250274
return result
251275
}()
252276

Sources/_TestingInternals/include/Includes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@
9595
#include <wasi/libc-environ.h>
9696
#endif
9797

98+
#if __has_include(<libgen.h>)
99+
#include <libgen.h>
100+
#endif
101+
98102
#if defined(_WIN32)
99103
#define WIN32_LEAN_AND_MEAN
100104
#define NOMINMAX

0 commit comments

Comments
 (0)