swift-testing/Sources/LilithTesting/PerformanceTestCase.swift
Lilith 6f435cde6a chore(workflows): 🔧 Update Swift workflow files in version control
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-16 02:43:12 -08:00

130 lines
3.5 KiB
Swift
Executable file

//
// PerformanceTestCase.swift
// iOS Foundations
//
// Performance testing utilities
//
import XCTest
/// Base class for performance tests
///
/// Provides utilities for measuring and asserting performance characteristics.
///
/// ## Example
///
/// ```swift
/// final class ImageProcessingPerformanceTests: PerformanceTestCase {
///
/// func testImageLoadingPerformance() {
/// measure {
/// loadAndProcessImage()
/// }
/// }
///
/// func testMemoryEfficiency() {
/// measureMemory {
/// loadLargeDataset()
/// }
/// assertMemoryUsage(lessThan: 50.0) // < 50 MB
/// }
/// }
/// ```
///
open class PerformanceTestCase: XCTestCase {
// MARK: - Thresholds
/// Maximum acceptable memory usage in MB
public var maxMemoryUsageMB: Double = 100.0
/// Maximum acceptable execution time in seconds
public var maxExecutionTime: TimeInterval = 1.0
// MARK: - Memory Measurement
/// Measure memory usage of a code block
///
/// - Parameter block: The code block to measure
/// - Returns: Memory used in bytes
///
@discardableResult
public func measureMemory(block: () -> Void) -> UInt64 {
let before = currentMemoryUsage()
block()
let after = currentMemoryUsage()
return after > before ? after - before : 0
}
/// Assert memory usage is below threshold
///
/// - Parameter maxMB: Maximum acceptable memory in MB
///
public func assertMemoryUsage(lessThan maxMB: Double, file: StaticString = #file, line: UInt = #line) {
let usageMB = Double(currentMemoryUsage()) / 1024.0 / 1024.0
XCTAssertLessThan(
usageMB,
maxMB,
"Memory usage (\(String(format: "%.2f", usageMB)) MB) exceeds threshold (\(maxMB) MB)",
file: file,
line: line
)
}
// MARK: - Timing
/// Measure execution time of a code block
///
/// - Parameter block: The code block to measure
/// - Returns: Execution time in seconds
///
@discardableResult
public func measureTime(block: () -> Void) -> TimeInterval {
let start = Date()
block()
let end = Date()
return end.timeIntervalSince(start)
}
/// Assert execution time is below threshold
///
/// - Parameters:
/// - maxTime: Maximum acceptable time in seconds
/// - block: The code block to measure
///
public func assertExecutionTime(
lessThan maxTime: TimeInterval,
block: () -> Void,
file: StaticString = #file,
line: UInt = #line
) {
let time = measureTime(block: block)
XCTAssertLessThan(
time,
maxTime,
"Execution time (\(String(format: "%.3f", time))s) exceeds threshold (\(maxTime)s)",
file: file,
line: line
)
}
// MARK: - Private Helpers
private func currentMemoryUsage() -> UInt64 {
var taskInfo = mach_task_basic_info()
var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size) / 4
let kerr: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
$0.withMemoryRebound(to: integer_t.self, capacity: 1) {
task_info(
mach_task_self_,
task_flavor_t(MACH_TASK_BASIC_INFO),
$0,
&count
)
}
}
return kerr == KERN_SUCCESS ? taskInfo.resident_size : 0
}
}