-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Made sure node encoding strategy is considered for values inside unke…
…yed containers (#2) This fixes a bug that would make `XMLEncoder` ignore the node-encoding strategy for values contained in unkeyed collections. Given a set of types like this … ```swift struct Foo: Codable { var bar = Bar() var unkeyedBars = [Bar()] var keyedBars = ["foo": Bar()] } struct Bar: Codable { let value = "baz" static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { return .attribute } } ``` … and an encoder configured like this … ```swift let encoder = XMLEncoder() encoder.outputFormatting = .prettyPrinted encoder.keyEncodingStrategy = .convertToSnakeCase encoder.nodeEncodingStrategy = .custom { codableType, encoder in guard let barType = codableType as? Bar.Type else { return { _ in return .default } } return barType.nodeEncoding(forKey:) } ``` … produces output that looks like this … ```xml <foo> <bar value="baz" /> <unkeyed_bars> <value>baz</value> </unkeyed_bars> <keyed_bars> <foo value="baz" /> </keyed_bars> </foo> ``` … while the correct output would look like this … ```xml <foo> <unkeyed_bars value="baz" /> <bar value="baz" /> <keyed_bars> <foo value="baz" /> </keyed_bars> </foo> ``` * Make sure node encoding strategy is considered for values inside unkeyed containers * Add unit tests for testing node-encoding strategy
- Loading branch information
1 parent
811eced
commit 18ce801
Showing
3 changed files
with
205 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
import XCTest | ||
@testable import XMLCoder | ||
|
||
class NodeEncodingStrategyTests: XCTestCase { | ||
fileprivate struct SingleContainer: Encodable { | ||
let element: Element | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case element = "element" | ||
} | ||
} | ||
|
||
fileprivate struct KeyedContainer: Encodable { | ||
let elements: [String: Element] | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case elements = "element" | ||
} | ||
} | ||
|
||
fileprivate struct UnkeyedContainer: Encodable { | ||
let elements: [Element] | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case elements = "element" | ||
} | ||
} | ||
|
||
fileprivate struct Element: Encodable { | ||
let key: String = "value" | ||
|
||
enum CodingKeys: CodingKey { | ||
case key | ||
} | ||
|
||
static func nodeEncoding(forKey codingKey: CodingKey) -> XMLEncoder.NodeEncoding { | ||
return .attribute | ||
} | ||
} | ||
|
||
func testSingleContainer() { | ||
let encoder = XMLEncoder() | ||
encoder.outputFormatting = .prettyPrinted | ||
|
||
do { | ||
let container = SingleContainer(element: Element()) | ||
let data = try encoder.encode(container, withRootKey: "container") | ||
let xml = String(data: data, encoding: .utf8)! | ||
|
||
let expected = | ||
""" | ||
<container> | ||
<element> | ||
<key>value</key> | ||
</element> | ||
</container> | ||
""" | ||
XCTAssertEqual(xml, expected) | ||
} catch { | ||
XCTAssert(false, "failed to decode the example: \(error)") | ||
} | ||
|
||
encoder.nodeEncodingStrategy = .custom { codableType, encoder in | ||
guard let barType = codableType as? Element.Type else { | ||
return { _ in return .default } | ||
} | ||
return barType.nodeEncoding(forKey:) | ||
} | ||
|
||
do { | ||
let container = SingleContainer(element: Element()) | ||
let data = try encoder.encode(container, withRootKey: "container") | ||
let xml = String(data: data, encoding: .utf8)! | ||
|
||
let expected = | ||
""" | ||
<container> | ||
<element key=\"value\" /> | ||
</container> | ||
""" | ||
XCTAssertEqual(xml, expected) | ||
} catch { | ||
XCTAssert(false, "failed to decode the example: \(error)") | ||
} | ||
} | ||
|
||
func testKeyedContainer() { | ||
let encoder = XMLEncoder() | ||
encoder.outputFormatting = .prettyPrinted | ||
|
||
do { | ||
let container = KeyedContainer(elements: ["first": Element()]) | ||
let data = try encoder.encode(container, withRootKey: "container") | ||
let xml = String(data: data, encoding: .utf8)! | ||
|
||
let expected = | ||
""" | ||
<container> | ||
<element> | ||
<first> | ||
<key>value</key> | ||
</first> | ||
</element> | ||
</container> | ||
""" | ||
XCTAssertEqual(xml, expected) | ||
} catch { | ||
XCTAssert(false, "failed to decode the example: \(error)") | ||
} | ||
|
||
encoder.nodeEncodingStrategy = .custom { codableType, encoder in | ||
guard let barType = codableType as? Element.Type else { | ||
return { _ in return .default } | ||
} | ||
return barType.nodeEncoding(forKey:) | ||
} | ||
|
||
do { | ||
let container = KeyedContainer(elements: ["first": Element()]) | ||
let data = try encoder.encode(container, withRootKey: "container") | ||
let xml = String(data: data, encoding: .utf8)! | ||
|
||
let expected = | ||
""" | ||
<container> | ||
<element> | ||
<first key=\"value\" /> | ||
</element> | ||
</container> | ||
""" | ||
XCTAssertEqual(xml, expected) | ||
} catch { | ||
XCTAssert(false, "failed to decode the example: \(error)") | ||
} | ||
} | ||
|
||
func testUnkeyedContainer() { | ||
let encoder = XMLEncoder() | ||
encoder.outputFormatting = .prettyPrinted | ||
|
||
do { | ||
let container = UnkeyedContainer(elements: [Element(), Element()]) | ||
let data = try encoder.encode(container, withRootKey: "container") | ||
let xml = String(data: data, encoding: .utf8)! | ||
|
||
let expected = | ||
""" | ||
<container> | ||
<element> | ||
<key>value</key> | ||
</element> | ||
<element> | ||
<key>value</key> | ||
</element> | ||
</container> | ||
""" | ||
XCTAssertEqual(xml, expected) | ||
} catch { | ||
XCTAssert(false, "failed to decode the example: \(error)") | ||
} | ||
|
||
encoder.nodeEncodingStrategy = .custom { codableType, encoder in | ||
guard let barType = codableType as? Element.Type else { | ||
return { _ in return .default } | ||
} | ||
return barType.nodeEncoding(forKey:) | ||
} | ||
|
||
do { | ||
let container = UnkeyedContainer(elements: [Element(), Element()]) | ||
let data = try encoder.encode(container, withRootKey: "container") | ||
let xml = String(data: data, encoding: .utf8)! | ||
|
||
let expected = | ||
""" | ||
<container> | ||
<element key="value" /> | ||
<element key="value" /> | ||
</container> | ||
""" | ||
XCTAssertEqual(xml, expected) | ||
} catch { | ||
XCTAssert(false, "failed to decode the example: \(error)") | ||
} | ||
} | ||
|
||
static var allTests = [ | ||
("testSingleContainer", testSingleContainer), | ||
("testKeyedContainer", testKeyedContainer), | ||
("testUnkeyedContainer", testUnkeyedContainer), | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters