import Foundation import JSONUtilities public struct TestableTargetReference: Hashable { public var name: String public var location: Location public var targetReference: TargetReference { switch location { case .local: return TargetReference(name: name, location: .local) case .project(let projectName): return TargetReference(name: name, location: .project(projectName)) case .package: fatalError("Package target is only available for testable") } } public enum Location: Hashable { case local case project(String) case package(String) } public init(name: String, location: Location) { self.name = name self.location = location } } extension TestableTargetReference { public init(_ string: String) throws { let paths = string.split(separator: "/") switch paths.count { case 2: location = .project(String(paths[0])) name = String(paths[1]) case 1: location = .local name = String(paths[0]) default: throw SpecParsingError.invalidTargetReference(string) } } public init?(value: Any) throws { if let string = value as? String { try self.init(string) } else if let dictionary = value as? JSONDictionary, let reference = try? TestableTargetReference(jsonDictionary: dictionary) { self = reference } else { return nil } } public static func local(_ name: String) -> TestableTargetReference { TestableTargetReference(name: name, location: .local) } } extension TestableTargetReference: ExpressibleByStringLiteral { public init(stringLiteral value: String) { try! self.init(value) } } extension TestableTargetReference: CustomStringConvertible { public var reference: String { switch location { case .local: return name case .project(let root), .package(let root): return "\(root)/\(name)" } } public var description: String { reference } } extension TestableTargetReference: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { if let project: String = jsonDictionary.json(atKeyPath: "project") { let paths = project.split(separator: "/") name = String(paths[1]) location = .project(String(paths[0])) } else if let project: String = jsonDictionary.json(atKeyPath: "package") { let paths = project.split(separator: "/") name = String(paths[1]) location = .package(String(paths[0])) } else if let name: String = jsonDictionary.json(atKeyPath: "name") { self = try TestableTargetReference(name) } else { name = try jsonDictionary.json(atKeyPath: "local") location = .local } } } extension TestableTargetReference: JSONEncodable { public func toJSONValue() -> Any { var dictionary: JSONDictionary = [:] switch self.location { case .package(let packageName): dictionary["package"] = "\(packageName)/\(name)" case .project(let projectName): dictionary["project"] = "\(projectName)/\(name)" case .local: dictionary["local"] = name } return dictionary } }