- 实现EPUB阅读器搜索功能及选中注释功能 - 优化CFI模块,修复代码审查发现的11个问题 - 实现大书远距目录跳转与后台补全优化方案 - 优化设置面板与章节运行时联动 - 重构及大量改进优化
94 lines
4.0 KiB
Swift
94 lines
4.0 KiB
Swift
import XCTest
|
|
|
|
struct DemoReaderState {
|
|
let rawValue: String
|
|
let fields: [String: String]
|
|
|
|
init(rawValue: String) {
|
|
self.rawValue = rawValue
|
|
var parsed: [String: String] = [:]
|
|
let separators = CharacterSet.whitespacesAndNewlines.union(CharacterSet(charactersIn: ";"))
|
|
for token in rawValue.components(separatedBy: separators) where !token.isEmpty {
|
|
guard let delimiterIndex = token.firstIndex(of: "=") else { continue }
|
|
let key = String(token[..<delimiterIndex])
|
|
let value = String(token[token.index(after: delimiterIndex)...])
|
|
parsed[key] = value
|
|
}
|
|
fields = parsed
|
|
}
|
|
|
|
subscript(key: String) -> String? {
|
|
fields[key]
|
|
}
|
|
|
|
private func decodedField(_ key: String) -> String? {
|
|
guard let rawValue = fields[key], rawValue != "nil" else { return nil }
|
|
return rawValue.removingPercentEncoding ?? rawValue
|
|
}
|
|
|
|
var isOpened: Bool { fields["reader"] == "opened" }
|
|
var page: Int? { fields["page"].flatMap(Int.init) }
|
|
var display: String? { fields["display"] }
|
|
var toolbar: String? { fields["toolbar"] }
|
|
var highlights: Int? { fields["highlights"].flatMap(Int.init) }
|
|
var bookmarks: Int? { fields["bookmarks"].flatMap(Int.init) }
|
|
var selection: Int? { fields["selection"].flatMap(Int.init) }
|
|
var href: String? { decodedField("href") }
|
|
var progression: Double? { fields["progression"].flatMap(Double.init) }
|
|
var cfi: String? { decodedField("cfi") }
|
|
var lastCFI: String? { decodedField("lastCFI") }
|
|
var rangeCFI: String? { decodedField("rangeCFI") }
|
|
var mode: String? { fields["mode"] }
|
|
var pagination: String? { fields["pagination"] }
|
|
var knownPages: Int? { fields["knownPages"].flatMap(Int.init) }
|
|
var knownChapters: Int? { fields["knownChapters"].flatMap(Int.init) }
|
|
var buildableChapters: Int? { fields["buildableChapters"].flatMap(Int.init) }
|
|
var avoidWidows: Int? { fields["avoidWidows"].flatMap(Int.init) }
|
|
var avoidOrphans: Int? { fields["avoidOrphans"].flatMap(Int.init) }
|
|
var windowSize: Int? { fields["windowSize"].flatMap(Int.init) }
|
|
var parseMs: Int? { fields["parseMs"].flatMap(Int.init) }
|
|
var parseConcurrency: Int? { fields["parseConcurrency"].flatMap(Int.init) }
|
|
var inspectable: Int? { fields["inspectable"].flatMap(Int.init) }
|
|
var streamedResources: Int? { fields["streamedResources"].flatMap(Int.init) }
|
|
var inMemoryResources: Int? { fields["inMemoryResources"].flatMap(Int.init) }
|
|
var resourceFailures: Int? { fields["resourceFailures"].flatMap(Int.init) }
|
|
var cacheFiles: Int? { fields["cacheFiles"].flatMap(Int.init) }
|
|
var cacheBytes: Int? { fields["cacheBytes"].flatMap(Int.init) }
|
|
var externalLinks: Int? { fields["externalLinks"].flatMap(Int.init) }
|
|
var lastExternalURL: String? { decodedField("lastExternalURL") }
|
|
var lastError: String? { decodedField("lastError") }
|
|
var searchMatchText: String? { decodedField("searchMatchText") }
|
|
}
|
|
|
|
extension XCUIApplication {
|
|
func currentDemoReaderState() -> DemoReaderState? {
|
|
let state = staticTexts[IDs.demoReaderState]
|
|
guard state.exists else { return nil }
|
|
return DemoReaderState(rawValue: state.label)
|
|
}
|
|
|
|
@discardableResult
|
|
func waitForDemoReaderState(
|
|
timeout: TimeInterval = 8,
|
|
description: String,
|
|
where predicate: (DemoReaderState) -> Bool
|
|
) -> DemoReaderState {
|
|
let stateElement = staticTexts[IDs.demoReaderState]
|
|
let deadline = Date().addingTimeInterval(timeout)
|
|
var lastState = DemoReaderState(rawValue: "<missing>")
|
|
|
|
while Date() < deadline {
|
|
if stateElement.exists {
|
|
lastState = DemoReaderState(rawValue: stateElement.label)
|
|
if predicate(lastState) {
|
|
return lastState
|
|
}
|
|
}
|
|
RunLoop.current.run(until: Date().addingTimeInterval(0.1))
|
|
}
|
|
|
|
XCTFail("阅读器状态未满足条件: \(description),当前:\(lastState.rawValue)")
|
|
return lastState
|
|
}
|
|
}
|