Files

149 lines
4.7 KiB
Swift

@testable import ShadowsocksX_NG2
/// 系统代理相关替身:从 ProxyRuntimeFixture 主文件分出,
/// 保持 `ProxyRuntimeFixture.` 限定名不变。
extension ProxyRuntimeFixture {
@MainActor
final class FakeSystemProxy: SystemProxyControlling {
private(set) var applied: [SystemProxyConfiguration] = []
private(set) var clearCount = 0
var services: [SystemProxyServiceState] = [
SystemProxyServiceState(
identifier: SystemProxyServiceIdentifier(locationID: "home", serviceID: "wifi"),
configuration: nil, name: "Wi-Fi")
]
var readError: Error?
var beforeRead: (@MainActor () async -> Void)?
private(set) var readCount = 0
private(set) var repairedServices: [SystemProxyServiceIdentifier] = []
var beforeRepair: (@MainActor () async -> Void)?
var preserveConfigurationOnApply = false
var applyError: Error?
var clearError: Error?
var onClear: (@MainActor () -> Void)?
/// 注入返回值:模拟系统值已与期望等价的免授权跳过路径。
var applyOutcome: SystemProxyWriteOutcome = .written
/// 可选共享事件日志(次序断言用)。
weak var eventLog: ProxyRuntimeEventLog?
func apply(
_ configuration: SystemProxyConfiguration
) async throws -> SystemProxyWriteOutcome {
eventLog?.record("apply")
if let applyError { throw applyError }
applied.append(configuration)
if !preserveConfigurationOnApply {
let plan = try SystemProxyPlanner.makeApplyPlan(
services: services, configuration: configuration)
for write in plan.writes {
if let index = services.firstIndex(where: { $0.identifier == write.identifier }) {
services[index] = SystemProxyServiceState(
identifier: write.identifier, configuration: write.configuration,
name: services[index].name)
}
}
}
return applyOutcome
}
func readServices() async throws -> [SystemProxyServiceState] {
readCount += 1
if let readError { throw readError }
let snapshot = services
await beforeRead?()
return snapshot
}
func repair(_ configuration: SystemProxyConfiguration) async throws {
await beforeRepair?()
let plan = try SystemProxyPlanner.makeApplyPlan(
services: services, configuration: configuration)
repairedServices = plan.writes.map(\.identifier)
_ = try await apply(configuration)
}
func clear() async throws {
clearCount += 1
eventLog?.record("clear")
onClear?()
if let clearError { throw clearError }
services = services.map {
SystemProxyServiceState(identifier: $0.identifier, configuration: nil, name: $0.name)
}
}
}
/// 特权 helper 注册/审批状态可编程替身。
@MainActor
final class FakeSystemProxyHelperService: SystemProxyHelperServicing {
private(set) var currentStatus: SystemProxyHelperStatus
private(set) var registerCount = 0
private(set) var unregisterCount = 0
private(set) var registerError: Error?
private(set) var unregisterError: Error?
private(set) var openApprovalPathCount = 0
/// register 成功后迁移到的状态(模拟 BTM 批准立即达成)。
var statusAfterRegister: SystemProxyHelperStatus = .approved
init(initialStatus: SystemProxyHelperStatus = .approved) {
currentStatus = initialStatus
}
var status: SystemProxyHelperStatus { currentStatus }
func setStatus(_ status: SystemProxyHelperStatus) {
currentStatus = status
}
func setRegisterError(_ error: Error?) {
registerError = error
}
func setUnregisterError(_ error: Error?) {
unregisterError = error
}
func register() throws {
registerCount += 1
if let registerError { throw registerError }
currentStatus = statusAfterRegister
}
func unregister() throws {
unregisterCount += 1
if let unregisterError { throw unregisterError }
currentStatus = .notRegistered
}
func openApprovalPath() {
openApprovalPathCount += 1
}
}
@MainActor
final class FakeSystemProxyNetworkChangeMonitor: SystemProxyNetworkChangeMonitoring {
private(set) var startCount = 0
private(set) var stopCount = 0
private(set) var isObserving = false
private var handler: (@MainActor @Sendable (SystemProxyNetworkChange) -> Void)?
func start(
handler: @escaping @MainActor @Sendable (SystemProxyNetworkChange) -> Void
) {
startCount += 1
isObserving = true
self.handler = handler
}
func stop() {
stopCount += 1
isObserving = false
handler = nil
}
func emit(_ change: SystemProxyNetworkChange) {
handler?(change)
}
}
}