import XCTest @testable import ShadowsocksX_NG2 /// 受管插件目录与 Vendor 清单的稳定身份和打包事实保持一致。 final class ManagedPluginCatalogTests: XCTestCase { private struct Manifest: Decodable { var project: String var binary: String var bundleSubpath: String var signIdentifier: String } private static let vendorRoot = TestSourceTree.ng2Root().appendingPathComponent("Vendor") /// Vendor 下所有插件类清单(bundleSubpath 落在 Helpers/Plugins 的目录)。 private static var vendorPluginManifests: [(directory: String, manifest: Manifest)] { guard let directories = try? FileManager.default.contentsOfDirectory(atPath: vendorRoot.path) else { return [] } return directories.sorted().compactMap { directory in let url = vendorRoot.appendingPathComponent(directory).appendingPathComponent("manifest.json") guard let data = try? Data(contentsOf: url), let manifest = try? JSONDecoder().decode(Manifest.self, from: data), manifest.bundleSubpath == "Helpers/Plugins" else { return nil } return (directory, manifest) } } func testCatalogMatchesVendorPluginManifests() throws { let manifests = Self.vendorPluginManifests XCTAssertFalse(manifests.isEmpty, "Vendor 下应至少有一个插件清单") XCTAssertEqual( ManagedPluginCatalog.plugins.count, manifests.count, "派生插件目录与 Vendor 插件清单数量不一致(须重新生成派生目录)") for (directory, manifest) in manifests { let info = try XCTUnwrap( ManagedPluginCatalog.plugins.first { $0.program == directory }, "\(directory): 清单里的记录「\(directory)」不在派生插件目录内") XCTAssertEqual(info.executableName, manifest.binary, "\(directory): 打包文件名漂移") XCTAssertEqual(info.signIdentifier, manifest.signIdentifier, "\(directory): 重签标识漂移") } } func testEveryCatalogEntryHasVendorManifest() { for info in ManagedPluginCatalog.plugins { let match = Self.vendorPluginManifests.first { $0.manifest.binary == info.program } XCTAssertNotNil(match, "「\(info.program)」在派生插件目录内但缺少 Vendor 插件清单") } } func testProgramLookup() { XCTAssertNotNil(ManagedPluginCatalog.info(forProgram: "v2ray-plugin")) XCTAssertNil(ManagedPluginCatalog.info(forProgram: "obfs-local"), "集外程序名不在受管集") XCTAssertNil(ManagedPluginCatalog.info(forProgram: ""), "空程序名不在受管集") } }