Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added unit tests for array and dictionary properties #7

Merged
merged 2 commits into from Dec 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 14 additions & 16 deletions Sources/XMLCoder/Decoder/XMLDecoder.swift
Expand Up @@ -286,7 +286,7 @@ internal class _XMLDecoder: Decoder {
debugDescription: "Cannot get keyed decoding container -- found null value instead."))
}

guard let topContainer = self.storage.topContainer as? [String: Any] else {
guard let topContainer = storage.topContainer as? [String: Any] else {
throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: storage.topContainer)
}

Expand All @@ -303,12 +303,10 @@ internal class _XMLDecoder: Decoder {

let topContainer: [Any]

if let container = self.storage.topContainer as? [Any] {
if let container = storage.topContainer as? [Any] {
topContainer = container
} else if let container = self.storage.topContainer as? [AnyHashable: Any] {
topContainer = [container]
} else {
throw DecodingError._typeMismatch(at: codingPath, expectation: [Any].self, reality: storage.topContainer)
topContainer = [storage.topContainer]
}

return _XMLUnkeyedDecodingContainer(referencing: self, wrapping: topContainer)
Expand Down Expand Up @@ -727,7 +725,7 @@ extension _XMLDecoder {
switch options.dateDecodingStrategy {
case .deferredToDate:
storage.push(container: value)
defer { self.storage.popContainer() }
defer { storage.popContainer() }
return try Date(from: self)

case .secondsSince1970:
Expand All @@ -740,9 +738,9 @@ extension _XMLDecoder {

case .iso8601:
if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
let string = try self.unbox(value, as: String.self)!
let string = try unbox(value, as: String.self)!
guard let date = _iso8601Formatter.date(from: string) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected date string to be ISO8601-formatted."))
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: codingPath, debugDescription: "Expected date string to be ISO8601-formatted."))
}

return date
Expand All @@ -760,7 +758,7 @@ extension _XMLDecoder {

case let .custom(closure):
storage.push(container: value)
defer { self.storage.popContainer() }
defer { storage.popContainer() }
return try closure(self)
}
}
Expand All @@ -771,7 +769,7 @@ extension _XMLDecoder {
switch options.dataDecodingStrategy {
case .deferredToData:
storage.push(container: value)
defer { self.storage.popContainer() }
defer { storage.popContainer() }
return try Data(from: self)

case .base64:
Expand All @@ -787,7 +785,7 @@ extension _XMLDecoder {

case let .custom(closure):
storage.push(container: value)
defer { self.storage.popContainer() }
defer { storage.popContainer() }
return try closure(self)
}
}
Expand All @@ -803,13 +801,13 @@ extension _XMLDecoder {
internal func unbox<T: Decodable>(_ value: Any, as type: T.Type) throws -> T? {
let decoded: T
if type == Date.self || type == NSDate.self {
guard let date = try self.unbox(value, as: Date.self) else { return nil }
guard let date = try unbox(value, as: Date.self) else { return nil }
decoded = date as! T
} else if type == Data.self || type == NSData.self {
guard let data = try self.unbox(value, as: Data.self) else { return nil }
guard let data = try unbox(value, as: Data.self) else { return nil }
decoded = data as! T
} else if type == URL.self || type == NSURL.self {
guard let urlString = try self.unbox(value, as: String.self) else {
guard let urlString = try unbox(value, as: String.self) else {
return nil
}

Expand All @@ -820,11 +818,11 @@ extension _XMLDecoder {

decoded = (url as! T)
} else if type == Decimal.self || type == NSDecimalNumber.self {
guard let decimal = try self.unbox(value, as: Decimal.self) else { return nil }
guard let decimal = try unbox(value, as: Decimal.self) else { return nil }
decoded = decimal as! T
} else {
storage.push(container: value)
defer { self.storage.popContainer() }
defer { storage.popContainer() }
return try type.init(from: self)
}

Expand Down
12 changes: 6 additions & 6 deletions Sources/XMLCoder/Decoder/XMLDecodingStorage.swift
Expand Up @@ -15,29 +15,29 @@ internal struct _XMLDecodingStorage {

/// The container stack.
/// Elements may be any one of the XML types (String, [String : Any]).
internal private(set) var containers: [Any] = []
private var containers: [Any] = []

// MARK: - Initialization

/// Initializes `self` with no containers.
internal init() {}
init() {}

// MARK: - Modifying the Stack

internal var count: Int {
var count: Int {
return containers.count
}

internal var topContainer: Any {
var topContainer: Any {
precondition(!containers.isEmpty, "Empty container stack.")
return containers.last!
}

internal mutating func push(container: Any) {
mutating func push(container: Any) {
containers.append(container)
}

internal mutating func popContainer() {
mutating func popContainer() {
precondition(!containers.isEmpty, "Empty container stack.")
containers.removeLast()
}
Expand Down
61 changes: 37 additions & 24 deletions Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift
Expand Up @@ -8,6 +8,15 @@

import Foundation

/// Type-erased protocol helper for a metatype check in generic `decode`
/// overload.
private protocol AnyEmptySequence {
init()
}

extension Array: AnyEmptySequence {}
extension Dictionary: AnyEmptySequence {}

// MARK: Decoding Containers

internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtocol {
Expand Down Expand Up @@ -78,15 +87,15 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decodeNil(forKey key: Key) throws -> Bool {
if let entry = self.container[key.stringValue] {
if let entry = container[key.stringValue] {
return entry is NSNull
} else {
return true
}
}

public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -101,7 +110,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -116,7 +125,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -131,7 +140,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -146,7 +155,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -161,7 +170,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -176,7 +185,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -191,7 +200,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -206,7 +215,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -221,22 +230,22 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }

guard let value = try self.decoder.unbox(entry, as: UInt32.self) else {
guard let value = try decoder.unbox(entry, as: UInt32.self) else {
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
}

return value
}

public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -251,22 +260,22 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }

guard let value = try self.decoder.unbox(entry, as: Float.self) else {
guard let value = try decoder.unbox(entry, as: Float.self) else {
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
}

return value
}

public func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

Expand All @@ -281,29 +290,33 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer
}

public func decode(_ type: String.Type, forKey key: Key) throws -> String {
guard let entry = self.container[key.stringValue] else {
guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }

guard let value = try self.decoder.unbox(entry, as: String.self) else {
guard let value = try decoder.unbox(entry, as: String.self) else {
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
}

return value
}

public func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
guard let entry = self.container[key.stringValue] else {
if type is AnyEmptySequence.Type && container[key.stringValue] == nil {
return (type as! AnyEmptySequence.Type).init() as! T
}

guard let entry = container[key.stringValue] else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key))."))
}

decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
defer { decoder.codingPath.removeLast() }

guard let value = try self.decoder.unbox(entry, as: type) else {
guard let value = try decoder.unbox(entry, as: type) else {
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead."))
}

Expand All @@ -312,7 +325,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer

public func nestedContainer<NestedKey>(keyedBy _: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
defer { decoder.codingPath.removeLast() }

guard let value = self.container[key.stringValue] else {
throw DecodingError.keyNotFound(key,
Expand All @@ -330,7 +343,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer

public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
defer { decoder.codingPath.removeLast() }

guard let value = self.container[key.stringValue] else {
throw DecodingError.keyNotFound(key,
Expand All @@ -347,7 +360,7 @@ internal struct _XMLKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainer

private func _superDecoder(forKey key: CodingKey) throws -> Decoder {
decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
defer { decoder.codingPath.removeLast() }

let value: Any = container[key.stringValue] ?? NSNull()
return _XMLDecoder(referencing: value, at: decoder.codingPath, options: decoder.options)
Expand Down
4 changes: 2 additions & 2 deletions Sources/XMLCoder/Encoder/XMLEncoder.swift
Expand Up @@ -341,7 +341,7 @@ internal class _XMLEncoder: Encoder {
// We haven't yet pushed a container at this level; do so here.
topContainer = storage.pushKeyedContainer()
} else {
guard let container = self.storage.containers.last as? NSMutableDictionary else {
guard let container = storage.lastContainer as? NSMutableDictionary else {
preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.")
}

Expand All @@ -359,7 +359,7 @@ internal class _XMLEncoder: Encoder {
// We haven't yet pushed a container at this level; do so here.
topContainer = storage.pushUnkeyedContainer()
} else {
guard let container = self.storage.containers.last as? NSMutableArray else {
guard let container = storage.lastContainer as? NSMutableArray else {
preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.")
}

Expand Down