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

Made sure node encoding strategy is considered for values inside unkeyed containers #2

Merged
merged 2 commits into from Nov 20, 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
10 changes: 9 additions & 1 deletion Sources/XMLCoder/Encoder/XMLEncoder.swift
Expand Up @@ -796,7 +796,15 @@ fileprivate struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer {

public mutating func encode<T : Encodable>(_ value: T) throws {
self.encoder.codingPath.append(_XMLKey(index: self.count))
defer { self.encoder.codingPath.removeLast() }
let nodeEncodings = self.encoder.options.nodeEncodingStrategy.nodeEncodings(
forType: T.self,
with: self.encoder
)
self.encoder.nodeEncodings.append(nodeEncodings)
defer {
let _ = self.encoder.nodeEncodings.removeLast()
self.encoder.codingPath.removeLast()
}
self.container.add(try self.encoder.box(value))
}

Expand Down
192 changes: 192 additions & 0 deletions Tests/XMLCoderTests/NodeEncodingStrategyTests.swift
@@ -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),
]
}
4 changes: 4 additions & 0 deletions XMLCoder.xcodeproj/project.pbxproj
Expand Up @@ -21,6 +21,7 @@
/* End PBXAggregateTarget section */

/* Begin PBXBuildFile section */
BFE1C59121A4242300EA0458 /* NodeEncodingStrategyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE1C58F21A4232100EA0458 /* NodeEncodingStrategyTests.swift */; };
OBJ_35 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
OBJ_41 /* XMLCoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* XMLCoderTests.swift */; };
OBJ_43 /* XMLCoder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "XMLParsing::XMLParsing::Product" /* XMLCoder.framework */; };
Expand Down Expand Up @@ -56,6 +57,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
BFE1C58F21A4232100EA0458 /* NodeEncodingStrategyTests.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = NodeEncodingStrategyTests.swift; sourceTree = "<group>"; tabWidth = 4; };
D1BCEBCF21943CA6000B550F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D1BCEBD021943F09000B550F /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = "<group>"; };
D1BCEBD12194416E000B550F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
Expand Down Expand Up @@ -124,6 +126,7 @@
isa = PBXGroup;
children = (
OBJ_25 /* XMLCoderTests.swift */,
BFE1C58F21A4232100EA0458 /* NodeEncodingStrategyTests.swift */,
);
name = XMLCoderTests;
path = Tests/XMLCoderTests;
Expand Down Expand Up @@ -290,6 +293,7 @@
buildActionMask = 0;
files = (
OBJ_41 /* XMLCoderTests.swift in Sources */,
BFE1C59121A4242300EA0458 /* NodeEncodingStrategyTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down