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

Fix Decoding of Empty String #145

Merged
merged 23 commits into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f2ce406
Treat corner case of empty string value intrinsic
jsbean Sep 29, 2019
3adaa40
Remove xcodeproj junk
jsbean Sep 29, 2019
e544f76
Add some logging to assess where we're at
jsbean Sep 29, 2019
5ea4fa7
Add cases for empty string as null element decoding
bwetherfield Sep 30, 2019
f9fc2f4
Swiftformat
bwetherfield Sep 30, 2019
2e40e6a
Merge pull request #47 from bwetherfield/wetherfield/empty-element-em…
jsbean Sep 30, 2019
3ccbfb3
Transform precondition to where clause in switch statement
jsbean Sep 30, 2019
800a26a
Remove print statements
jsbean Sep 30, 2019
c4dabba
Remove nested syntax test
bwetherfield Oct 16, 2019
64f016c
Merge branch 'master' into fix-empty-string-empty-elt
bwetherfield Oct 16, 2019
29ee5d9
Merge branch 'master' into fix-empty-string-empty-elt
MaxDesiatov Oct 17, 2019
4bac491
Fix forcecast
bwetherfield Nov 2, 2019
882eca2
Merge branch 'master' into fix-empty-string-empty-elt
bwetherfield Nov 2, 2019
e14594b
Fix formatting
bwetherfield Nov 2, 2019
a966be6
Merge branch 'fix-empty-string-empty-elt' of https://github.com/bweth…
bwetherfield Nov 2, 2019
8b99000
Update LinuxMain
bwetherfield Nov 2, 2019
0222d24
Remove warnings
bwetherfield Nov 2, 2019
023dc0d
Merge branch 'master' into fix-empty-string-empty-elt
bwetherfield Nov 11, 2019
27cbb5d
Add fix for new empty string issue
bwetherfield Nov 11, 2019
085a12b
Add back missing missingTest - remove "value" special casing from imp…
bwetherfield Nov 11, 2019
8691214
Fix formatting
bwetherfield Nov 11, 2019
f4209dd
Recover missing test!
bwetherfield Nov 13, 2019
e7347b3
Update linuxmain
bwetherfield Nov 13, 2019
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: 10 additions & 0 deletions Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ class XMLDecoderImplementation: Decoder {
attributes: KeyedStorage()
))
))
case let containsEmpty as SingleKeyedBox where containsEmpty.element is NullBox:
return KeyedDecodingContainer(XMLKeyedDecodingContainer<Key>(
referencing: self, wrapping: SharedBox(KeyedBox(
elements: KeyedStorage([("", StringBox(""))]), attributes: KeyedStorage()
))
))
case let keyed as SharedBox<KeyedBox>:
return KeyedDecodingContainer(XMLKeyedDecodingContainer<Key>(
referencing: self,
Expand Down Expand Up @@ -212,6 +218,10 @@ extension XMLDecoderImplementation {
let value = keyedBox.withShared({ $0.value as? B })
else { throw error }
return value
case let singleKeyedBox as SingleKeyedBox:
guard let value = singleKeyedBox.element as? B
else { throw error }
return value
case is NullBox:
throw error
case let keyedBox as KeyedBox:
Expand Down
20 changes: 17 additions & 3 deletions Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ extension XMLKeyedDecodingContainer {
.withShared { keyedBox -> [KeyedBox.Element] in
keyedBox.elements[key.stringValue].map {
if let singleKeyed = $0 as? SingleKeyedBox {
return singleKeyed.element
return singleKeyed.element.isNull ? singleKeyed : singleKeyed.element
} else {
return $0
}
Expand Down Expand Up @@ -264,6 +264,12 @@ extension XMLKeyedDecodingContainer {
return empty
}

// If we are looking at a coding key value intrinsic where the expected type is `String` and
// the value is empty, return `""`.
if strategy(key) != .attribute, elements.isEmpty, attributes.isEmpty, type == String.self, key.stringValue == "", let emptyString = "" as? T {
return emptyString
}

switch strategy(key) {
case .attribute:
guard
Expand Down Expand Up @@ -299,7 +305,16 @@ extension XMLKeyedDecodingContainer {
let value: T?
if !(type is AnySequence.Type), let unkeyedBox = box as? UnkeyedBox,
let first = unkeyedBox.first {
value = try decoder.unbox(first)
// Handle case where we have held onto a `SingleKeyedBox`
if let singleKeyed = first as? SingleKeyedBox {
if singleKeyed.element.isNull {
value = try decoder.unbox(singleKeyed)
} else {
value = try decoder.unbox(singleKeyed.element)
}
} else {
value = try decoder.unbox(first)
}
} else {
value = try decoder.unbox(box)
}
Expand All @@ -316,7 +331,6 @@ extension XMLKeyedDecodingContainer {
"Expected \(type) value but found null instead."
))
}

return unwrapped
}

Expand Down
71 changes: 71 additions & 0 deletions Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// EmptyElementEmptyStringTests.swift
// XMLCoderTests
//
// Created by James Bean on 9/29/19.
//

import XCTest
import XMLCoder

class EmptyElementEmptyStringTests: XCTestCase {
struct Parent: Equatable, Codable {
let thing: Thing
}

struct Thing: Equatable, Codable {
let attribute: String?
let value: String

enum CodingKeys: String, CodingKey {
case attribute
case value = ""
}
}

func testEmptyElementEmptyStringDecoding() throws {
let xml = """
<thing></thing>
"""
let expected = Thing(attribute: nil, value: "")
let result = try XMLDecoder().decode(Thing.self, from: xml.data(using: .utf8)!)
XCTAssertEqual(expected, result)
}

func testEmptyElementEmptyStringWithAttributeDecoding() throws {
let xml = """
<thing attribute="x"></thing>
"""
let expected = Thing(attribute: "x", value: "")
let result = try XMLDecoder().decode(Thing.self, from: xml.data(using: .utf8)!)
XCTAssertEqual(expected, result)
}

func testArrayOfEmptyElementStringDecoding() throws {
let xml = """
<container>
<thing></thing>
<thing attribute="x"></thing>
<thing></thing>
</container>
"""
let expected = [
Thing(attribute: nil, value: ""),
Thing(attribute: "x", value: ""),
Thing(attribute: nil, value: ""),
]
let result = try XMLDecoder().decode([Thing].self, from: xml.data(using: .utf8)!)
XCTAssertEqual(expected, result)
}

func testNestedEmptyElementEmptyStringDecoding() throws {
let xml = """
<parent>
<thing/>
</parent>
"""
let expected = Parent(thing: Thing(attribute: nil, value: ""))
let result = try XMLDecoder().decode(Parent.self, from: xml.data(using: .utf8)!)
XCTAssertEqual(expected, result)
}
}
13 changes: 13 additions & 0 deletions Tests/XMLCoderTests/XCTestManifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@ extension DynamicNodeEncodingTest {
]
}

extension EmptyElementEmptyStringTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__EmptyElementEmptyStringTests = [
("testArrayOfEmptyElementStringDecoding", testArrayOfEmptyElementStringDecoding),
("testEmptyElementEmptyStringDecoding", testEmptyElementEmptyStringDecoding),
("testEmptyElementEmptyStringWithAttributeDecoding", testEmptyElementEmptyStringWithAttributeDecoding),
("testNestedEmptyElementEmptyStringDecoding", testNestedEmptyElementEmptyStringDecoding),
]
}

extension EmptyTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
Expand Down Expand Up @@ -796,6 +808,7 @@ public func __allTests() -> [XCTestCaseEntry] {
testCase(DecodingContainerTests.__allTests__DecodingContainerTests),
testCase(DynamicNodeDecodingTest.__allTests__DynamicNodeDecodingTest),
testCase(DynamicNodeEncodingTest.__allTests__DynamicNodeEncodingTest),
testCase(EmptyElementEmptyStringTests.__allTests__EmptyElementEmptyStringTests),
testCase(EmptyTests.__allTests__EmptyTests),
testCase(EnumAssociatedValueTestComposite.__allTests__EnumAssociatedValueTestComposite),
testCase(ErrorContextTest.__allTests__ErrorContextTest),
Expand Down
4 changes: 4 additions & 0 deletions XMLCoder.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
/* End PBXAggregateTarget section */

/* Begin PBXBuildFile section */
07E441BA2340F14B00890F46 /* EmptyElementEmptyStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */; };
4A062D4F2341924E009BCAC1 /* CombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A062D4E2341924E009BCAC1 /* CombineTests.swift */; };
B5EA3BB6230F237800D8D69B /* NestedChoiceArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */; };
B5F74472233F74E400BBDB15 /* RootLevelAttributeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */; };
Expand Down Expand Up @@ -158,6 +159,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyElementEmptyStringTests.swift; sourceTree = "<group>"; };
4A062D4E2341924E009BCAC1 /* CombineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombineTests.swift; sourceTree = "<group>"; };
B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedChoiceArrayTest.swift; sourceTree = "<group>"; };
B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootLevelAttributeTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -456,6 +458,7 @@
OBJ_119 /* NoteTest.swift */,
OBJ_120 /* PlantCatalog.swift */,
OBJ_121 /* PlantTest.swift */,
07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */,
D18FBFB72348FAE500FA4F65 /* QuoteDecodingTest.swift */,
OBJ_124 /* RelationshipsTest.swift */,
OBJ_122 /* RJISample.swift */,
Expand Down Expand Up @@ -738,6 +741,7 @@
OBJ_251 /* KeyedTests.swift in Sources */,
OBJ_252 /* NullTests.swift in Sources */,
OBJ_253 /* OptionalTests.swift in Sources */,
07E441BA2340F14B00890F46 /* EmptyElementEmptyStringTests.swift in Sources */,
OBJ_254 /* StringTests.swift in Sources */,
B5EA3BB6230F237800D8D69B /* NestedChoiceArrayTest.swift in Sources */,
OBJ_255 /* UIntTests.swift in Sources */,
Expand Down
4 changes: 0 additions & 4 deletions XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand All @@ -61,8 +59,6 @@
ReferencedContainer = "container:XMLCoder.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down