With XCTest I can add an atexit handler to run leaks on the xctest process to check for leaks.
// Only build when built through SPM, as tests run through Xcode don't like this.
// Add LEAKS flag once we figure out a way to automate this.
// Can run by invoking swift test -c debug -Xswiftc -DLEAKS in the Alamofire directory.
// Sample code from the Swift forums: https://forums.swift.org/t/test-for-memory-leaks-in-ci/36526/19
#if SWIFT_PACKAGE && LEAKS && os(macOS)
final class LeaksTests: XCTestCase {
@MainActor
func testForLeaks() {
// Sets up an atexit handler that invokes the leaks tool.
atexit {
@discardableResult
func leaksTo(_ file: String) -> Process {
let out = FileHandle(forWritingAtPath: file)!
defer {
try! out.close()
}
let process = Process()
process.launchPath = "/usr/bin/leaks"
process.arguments = ["\(getpid())"]
process.standardOutput = out
process.standardError = out
process.launch()
process.waitUntilExit()
return process
}
let process = leaksTo("/dev/null")
guard process.terminationReason == .exit && [0, 1].contains(process.terminationStatus) else {
print("Process terminated: \(process.terminationReason): \(process.terminationStatus)")
exit(255)
}
if process.terminationStatus == 1 {
print("================")
print("Leaks Detected!!!")
leaksTo("/dev/tty")
}
exit(process.terminationStatus)
}
}
}
#endif
This works fine and I've used it to find leaks in my code and my tests. However, attempting the same thing for Swift Testing fails due to a restriction on the test helper.
@Suite
struct SwiftTestingLeaksTest {
@Test
func forLeaks() {
// Sets up an atexit handler that invokes the leaks tool.
atexit {
@discardableResult
func leaksTo(_ file: String) -> Process {
let out = FileHandle(forWritingAtPath: file)!
defer {
try! out.close()
}
let process = Process()
process.launchPath = "/usr/bin/leaks"
process.arguments = ["\(getpid())"]
process.standardOutput = out
process.standardError = out
process.launch()
process.waitUntilExit()
return process
}
let process = leaksTo("/dev/null")
guard process.terminationReason == .exit && [0, 1].contains(process.terminationStatus) else {
print("Process terminated: \(process.terminationReason): \(process.terminationStatus)")
exit(255)
}
if process.terminationStatus == 1 {
print("================")
print("Leaks Detected!!!")
leaksTo("/dev/tty")
}
exit(process.terminationStatus)
}
}
}
Process 34426 is not debuggable. Due to security restrictions, leaks can only show or save contents of readonly memory of restricted processes.
Process: swiftpm-testing-helper [34426]
Is there any alternative for Swift Testing?