diff --git a/Sources/Parameters.swift b/Sources/Parameters.swift index 2a3ce9cf..9ac82d38 100644 --- a/Sources/Parameters.swift +++ b/Sources/Parameters.swift @@ -9,6 +9,7 @@ import Foundation public enum ParametersError: Error { case invalidSyntax(value: String) case invalidKey(key: String, value: String) + case invalidStructure(key: String, oldValue: Any, newValue: Any) } public enum Parameters { @@ -33,25 +34,31 @@ public enum Parameters { private static func parse(item: Parameter, result: StringDict) throws -> StringDict { let parts = item.key.components(separatedBy: ".") let key = parts.first ?? "" + var result = result // validate key guard validate(key: key) else { throw ParametersError.invalidKey(key: item.key, value: item.value) } - // no sub keys, may need to convert to array if repeat key + // no sub keys, may need to convert to array if repeat key if possible if parts.count == 1 { if let current = result[key] as? [String] { result[key] = current + [item.value] - } else if let current = result[item.key] { + } else if let current = result[key] as? String { result[key] = [current, item.value] + } else if let current = result[key] { + throw ParametersError.invalidStructure(key: key, oldValue: current, newValue: item.value) } else { result[key] = item.value } } else if parts.count > 1 { + guard result[key] is StringDict || result[key] == nil else { + throw ParametersError.invalidStructure(key: key, oldValue: result[key], newValue: item.value) + } + // recurse into sub keys - let sub = (key: parts.suffix(from: 1).joined(separator: "."), value: item.value) let current = result[key] as? StringDict ?? StringDict() - + let sub = (key: parts.suffix(from: 1).joined(separator: "."), value: item.value) result[key] = try parse(item: sub, result: current) } diff --git a/Tests/TestSuites/ParametersTests.swift b/Tests/TestSuites/ParametersTests.swift index 1379e693..7ce86a4f 100644 --- a/Tests/TestSuites/ParametersTests.swift +++ b/Tests/TestSuites/ParametersTests.swift @@ -108,4 +108,33 @@ class ParametersTests: XCTestCase { XCTFail("Unexpected error occured while parsing: \(error)") } } + + func testInvalidStructure() { + do { + let items = ["foo=1", "foo.bar=1"] + _ = try Parameters.parse(items: items) + } catch ParametersError.invalidStructure { + // That's the expected exception we want to happen + } catch let error { + XCTFail("Unexpected error occured while parsing: \(error)") + } + + do { + let items = ["foo.bar=1", "foo=1"] + _ = try Parameters.parse(items: items) + } catch ParametersError.invalidStructure { + // That's the expected exception we want to happen + } catch let error { + XCTFail("Unexpected error occured while parsing: \(error)") + } + + do { + let items = ["foo=1", "foo=2", "foo.bar=1"] + _ = try Parameters.parse(items: items) + } catch ParametersError.invalidStructure { + // That's the expected exception we want to happen + } catch let error { + XCTFail("Unexpected error occured while parsing: \(error)") + } + } }