130 lines
3.5 KiB
Swift
Executable file
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
|
|
}
|
|
}
|