106 lines
3.7 KiB
Swift
106 lines
3.7 KiB
Swift
import XCTest
|
|
@testable import suixinkan
|
|
|
|
/// 回归验证相机配置期间启动、快速关闭和重复启动的顺序。
|
|
final class QRCodeCaptureSessionControllerTests: XCTestCase {
|
|
func testStartWaitsForConfigurationCommit() {
|
|
let session = RecordingCaptureSession()
|
|
let queue = DispatchQueue(label: "qr-capture-test")
|
|
let controller = QRCodeCaptureSessionController(session: session, queue: queue)
|
|
let entered = DispatchSemaphore(value: 0)
|
|
let release = DispatchSemaphore(value: 0)
|
|
let completed = expectation(description: "configuration committed")
|
|
|
|
controller.configure({
|
|
entered.signal()
|
|
_ = release.wait(timeout: .now() + 5)
|
|
return true
|
|
}, completion: { succeeded in
|
|
XCTAssertTrue(Thread.isMainThread)
|
|
XCTAssertTrue(succeeded)
|
|
completed.fulfill()
|
|
})
|
|
XCTAssertEqual(entered.wait(timeout: .now() + 5), .success)
|
|
controller.setRunning(true)
|
|
release.signal()
|
|
queue.sync {
|
|
XCTAssertEqual(session.events, ["begin", "commit", "start"])
|
|
XCTAssertFalse(session.startedDuringConfiguration)
|
|
}
|
|
wait(for: [completed], timeout: 5)
|
|
}
|
|
|
|
func testImmediateCloseStopsPendingStart() {
|
|
let session = RecordingCaptureSession()
|
|
let queue = DispatchQueue(label: "qr-capture-test")
|
|
let controller = QRCodeCaptureSessionController(session: session, queue: queue)
|
|
controller.configure({ true }, completion: { _ in })
|
|
controller.setRunning(true)
|
|
controller.setRunning(false)
|
|
queue.sync {
|
|
XCTAssertEqual(session.events, ["begin", "commit", "start", "stop"])
|
|
XCTAssertFalse(session.isRunning)
|
|
}
|
|
}
|
|
|
|
func testRepeatedStartAndStopAreIdempotent() {
|
|
let session = RecordingCaptureSession()
|
|
let queue = DispatchQueue(label: "qr-capture-test")
|
|
let controller = QRCodeCaptureSessionController(session: session, queue: queue)
|
|
controller.configure({ true }, completion: { _ in })
|
|
controller.setRunning(true)
|
|
controller.setRunning(true)
|
|
controller.setRunning(false)
|
|
controller.setRunning(false)
|
|
queue.sync {
|
|
XCTAssertEqual(session.events, ["begin", "commit", "start", "stop"])
|
|
}
|
|
}
|
|
|
|
func testFailedConfigurationCommitsButDoesNotStart() {
|
|
let session = RecordingCaptureSession()
|
|
let queue = DispatchQueue(label: "qr-capture-test")
|
|
let controller = QRCodeCaptureSessionController(session: session, queue: queue)
|
|
let completed = expectation(description: "configuration failed")
|
|
controller.configure({ false }, completion: { succeeded in
|
|
XCTAssertFalse(succeeded)
|
|
completed.fulfill()
|
|
})
|
|
controller.setRunning(true)
|
|
queue.sync {
|
|
XCTAssertEqual(session.events, ["begin", "commit"])
|
|
XCTAssertFalse(session.isRunning)
|
|
}
|
|
wait(for: [completed], timeout: 5)
|
|
}
|
|
}
|
|
|
|
/// 记录调用顺序并检测配置事务内启动的会话替身,仅在测试串行队列读写。
|
|
private final class RecordingCaptureSession: QRCodeCaptureSession {
|
|
var isRunning = false
|
|
var events: [String] = []
|
|
var startedDuringConfiguration = false
|
|
private var configuring = false
|
|
|
|
func beginConfiguration() {
|
|
configuring = true
|
|
events.append("begin")
|
|
}
|
|
|
|
func commitConfiguration() {
|
|
configuring = false
|
|
events.append("commit")
|
|
}
|
|
|
|
func startRunning() {
|
|
startedDuringConfiguration = configuring
|
|
isRunning = true
|
|
events.append("start")
|
|
}
|
|
|
|
func stopRunning() {
|
|
isRunning = false
|
|
events.append("stop")
|
|
}
|
|
}
|