Skip to content
This repository has been archived by the owner on Jun 18, 2019. It is now read-only.

Fix unboxing of key path with same last two components #199

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions Sources/Unboxer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -222,27 +222,28 @@ private extension Unboxer {
let value = try self.dictionary[key].orThrow(UnboxPathError.missingKey(key))
return try transform(value).orThrow(UnboxPathError.invalidValue(value, key))
case .keyPath(let keyPath):
var node: UnboxPathNode = self.dictionary
let components = keyPath.components(separatedBy: ".")
let lastKey = components.last

for key in components {
guard let lastKey = components.last, !lastKey.isEmpty else {
throw UnboxPathError.emptyKeyPath
}

let lastPathNode = try components.dropLast().reduce(dictionary) { (node: UnboxPathNode, key: String) -> UnboxPathNode in
guard let nextValue = node.unboxPathValue(forKey: key) else {
throw UnboxPathError.missingKey(key)
}

if key == lastKey {
return try transform(nextValue).orThrow(UnboxPathError.invalidValue(nextValue, key))
}

guard let nextNode = nextValue as? UnboxPathNode else {
throw UnboxPathError.invalidValue(nextValue, key)
}

node = nextNode
return nextNode
}

throw UnboxPathError.emptyKeyPath
guard let value = lastPathNode.unboxPathValue(forKey: lastKey) else {
throw UnboxPathError.missingKey(lastKey)
}
return try transform(value).orThrow(UnboxPathError.invalidValue(value, lastKey))
}
} catch {
if let publicError = error as? UnboxError {
Expand Down
23 changes: 23 additions & 0 deletions Tests/UnboxTests/UnboxTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,29 @@ class UnboxTests: XCTestCase {
XCTFail("\(error)")
}
}

func testKeyPathWithSameLastTwoComponens() {
struct Model: Unboxable {
let message: String

init(unboxer: Unboxer) throws {
self.message = try unboxer.unbox(keyPath: "message.message")
}
}

let dictionary: UnboxableDictionary = [
"message": [
"message": "value"
]
]

do {
let unboxed: Model = try unbox(dictionary: dictionary)
XCTAssertEqual("value", unboxed.message)
} catch {
XCTFail("\(error)")
}
}
}

private func UnboxTestDictionaryWithAllRequiredKeysWithValidValues(nested: Bool) -> UnboxableDictionary {
Expand Down