mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 11:14:51 +00:00
114 lines
3.9 KiB
Swift
114 lines
3.9 KiB
Swift
import XCTest
|
|
|
|
@testable import ShadowsocksX_NG2
|
|
|
|
/// 激活缝测试共享夹具:受管插件替身与完整记录、无插件叶子、
|
|
/// 激活与重展开的便捷调用、原子失败断言。
|
|
enum ActivationFixture {
|
|
/// 受管插件测试集:只提供表内程序,值即写入文档的 bundle 内路径。
|
|
struct TestManagedPlugins: PluginExecutableResolving {
|
|
let pathsByProgram: [String: String]
|
|
|
|
func resolve(program: String) -> ResolvedPlugin? {
|
|
pathsByProgram[program].map { ResolvedPlugin(path: $0, arguments: []) }
|
|
}
|
|
}
|
|
|
|
static let plugins = TestManagedPlugins(pathsByProgram: [
|
|
"v2ray-plugin": "/bundle/Helpers/Plugins/v2ray-plugin"
|
|
])
|
|
|
|
static let listen = ProxyListeningConfiguration()
|
|
|
|
/// 无插件叶子字段(插件语义单独覆盖)。
|
|
static func plainFields(remark: String, password: String = "password") -> ServerFields {
|
|
ServerFields(
|
|
address: "203.0.113.7", port: 8388, encryptionMethod: "aes-256-gcm",
|
|
password: password, remark: remark)
|
|
}
|
|
|
|
@discardableResult
|
|
static func addPlainServer(
|
|
_ remark: String, to parent: NodeID? = nil, in catalog: inout ConfigurationCatalog
|
|
) throws -> NodeID {
|
|
try catalog.addServer(plainFields(remark: remark, password: "pw-\(remark)"), to: parent)
|
|
}
|
|
|
|
static func activate(
|
|
_ machine: inout ActivationStateMachine,
|
|
_ target: NodeID,
|
|
in catalog: ConfigurationCatalog
|
|
) throws -> RuntimeConfiguration {
|
|
try machine.activate(
|
|
target, in: catalog, plugins: plugins,
|
|
options: RuntimeDocumentOptions(listen: listen))
|
|
}
|
|
|
|
static func commit(
|
|
_ machine: inout ActivationStateMachine,
|
|
_ catalog: ConfigurationCatalog
|
|
) -> ActivationEffect? {
|
|
machine.catalogDidCommit(
|
|
catalog, plugins: plugins,
|
|
options: RuntimeDocumentOptions(listen: listen))
|
|
}
|
|
|
|
/// 断言激活以指定原因原子失败(错误类型与值都点名)。
|
|
static func assertThrows(
|
|
_ expected: ActivationFailure,
|
|
_ activation: () throws -> RuntimeConfiguration,
|
|
file: StaticString = #filePath,
|
|
line: UInt = #line
|
|
) {
|
|
do {
|
|
_ = try activation()
|
|
XCTFail("应被拒绝:\(expected)", file: file, line: line)
|
|
} catch let failure as ActivationFailure {
|
|
XCTAssertEqual(failure, expected, file: file, line: line)
|
|
} catch {
|
|
XCTFail("错误应为 ActivationFailure,实际 \(error)", file: file, line: line)
|
|
}
|
|
}
|
|
|
|
enum FixtureError: Error {
|
|
case unexpectedEffect
|
|
}
|
|
|
|
/// 解包「原子更新」效应;否则 XCTFail 并抛错终止用例。
|
|
static func requireDeployed(
|
|
_ effect: ActivationEffect?, file: StaticString = #filePath, line: UInt = #line
|
|
) throws -> RuntimeConfiguration {
|
|
guard case .deployed(let configuration)? = effect else {
|
|
XCTFail("应产出原子更新,实际 \(String(describing: effect))", file: file, line: line)
|
|
throw FixtureError.unexpectedEffect
|
|
}
|
|
return configuration
|
|
}
|
|
|
|
/// 解包「清除并停止」效应的点名原因;否则 XCTFail 并抛错终止用例。
|
|
static func requireCleared(
|
|
_ effect: ActivationEffect?, file: StaticString = #filePath, line: UInt = #line
|
|
) throws -> ActivationFailure {
|
|
guard case .clearedAndStopped(let failure)? = effect else {
|
|
XCTFail("应清除并停止,实际 \(String(describing: effect))", file: file, line: line)
|
|
throw FixtureError.unexpectedEffect
|
|
}
|
|
return failure
|
|
}
|
|
|
|
/// 取叶子当前的服务器字段(非叶子即夹具错误)。
|
|
static func serverFields(
|
|
of leaf: NodeID,
|
|
in catalog: ConfigurationCatalog,
|
|
file: StaticString = #filePath,
|
|
line: UInt = #line
|
|
) throws -> ServerFields {
|
|
let kind = try XCTUnwrap(catalog.entry(for: leaf)?.kind, file: file, line: line)
|
|
guard case .server(let fields) = kind else {
|
|
XCTFail("夹具应是服务器叶子", file: file, line: line)
|
|
throw FixtureError.unexpectedEffect
|
|
}
|
|
return fields
|
|
}
|
|
}
|