From f2ce40644edf05025101f942bfbf3012571d79f7 Mon Sep 17 00:00:00 2001 From: James Bean Date: Sun, 29 Sep 2019 10:57:39 -0400 Subject: [PATCH 01/17] Treat corner case of empty string value intrinsic --- .../Decoder/XMLKeyedDecodingContainer.swift | 7 ++++ .../EmptyElementEmptyStringTests.swift | 35 +++++++++++++++++++ Tests/XMLCoderTests/Minimal/StringTests.swift | 9 ----- XMLCoder.xcodeproj/project.pbxproj | 4 +++ .../xcshareddata/xcschemes/XMLCoder.xcscheme | 9 ++--- 5 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index e236db91..e4cfd016 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -282,6 +282,13 @@ 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 == "value" || key.stringValue == "") { + return "" as! T + } + switch strategy(key) { case .attribute: guard diff --git a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift new file mode 100644 index 00000000..54c1992f --- /dev/null +++ b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift @@ -0,0 +1,35 @@ +// +// EmptyElementEmptyStringTests.swift +// XMLCoderTests +// +// Created by James Bean on 9/29/19. +// + +import XCTest +import XMLCoder + +class EmptyElementEmptyStringTests: XCTestCase { + + struct Container: Equatable, Codable { + let attribute: String? + let value: String + } + + func testEmptyElementEmptyStringDecoding() throws { + let xml = """ + + """ + let expected = Container(attribute: nil, value: "") + let result = try XMLDecoder().decode(Container.self, from: xml.data(using: .utf8)!) + XCTAssertEqual(expected, result) + } + + func testEmptyElementEmptyStringWithAttributeDecoding() throws { + let xml = """ + + """ + let expected = Container(attribute: "x", value: "") + let result = try XMLDecoder().decode(Container.self, from: xml.data(using: .utf8)!) + XCTAssertEqual(expected, result) + } +} diff --git a/Tests/XMLCoderTests/Minimal/StringTests.swift b/Tests/XMLCoderTests/Minimal/StringTests.swift index ea5d6981..54ea2206 100644 --- a/Tests/XMLCoderTests/Minimal/StringTests.swift +++ b/Tests/XMLCoderTests/Minimal/StringTests.swift @@ -25,15 +25,6 @@ class StringTests: XCTestCase { ("foobar", "foobar"), ] - func testMissing() { - let decoder = XMLDecoder() - - let xmlString = "" - let xmlData = xmlString.data(using: .utf8)! - - XCTAssertThrowsError(try decoder.decode(Container.self, from: xmlData)) - } - func testAttribute() throws { let decoder = XMLDecoder() let encoder = XMLEncoder() diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 76e0aed0..a1c96ca6 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 07E441BA2340F14B00890F46 /* EmptyElementEmptyStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */; }; OBJ_148 /* BoolBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* BoolBox.swift */; }; OBJ_149 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Box.swift */; }; OBJ_150 /* ChoiceBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* ChoiceBox.swift */; }; @@ -152,6 +153,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyElementEmptyStringTests.swift; sourceTree = ""; }; OBJ_100 /* DecimalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = ""; }; OBJ_101 /* EmptyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTests.swift; sourceTree = ""; }; OBJ_102 /* FloatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatTests.swift; sourceTree = ""; }; @@ -440,6 +442,7 @@ OBJ_119 /* NoteTest.swift */, OBJ_120 /* PlantCatalog.swift */, OBJ_121 /* PlantTest.swift */, + 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */, OBJ_122 /* RJISample.swift */, OBJ_123 /* RJITest.swift */, OBJ_124 /* RelationshipsTest.swift */, @@ -716,6 +719,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 */, OBJ_255 /* UIntTests.swift in Sources */, OBJ_256 /* URLTests.swift in Sources */, diff --git a/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme b/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme index c117e5d6..11fc7feb 100644 --- a/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme +++ b/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme @@ -37,10 +37,13 @@ BlueprintName = "XMLCoderTests" ReferencedContainer = "container:XMLCoder.xcodeproj"> + + + + - - - - Date: Sun, 29 Sep 2019 10:59:36 -0400 Subject: [PATCH 02/17] Remove xcodeproj junk --- XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme | 5 ----- 1 file changed, 5 deletions(-) diff --git a/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme b/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme index 11fc7feb..59df07f8 100644 --- a/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme +++ b/XMLCoder.xcodeproj/xcshareddata/xcschemes/XMLCoder.xcscheme @@ -37,11 +37,6 @@ BlueprintName = "XMLCoderTests" ReferencedContainer = "container:XMLCoder.xcodeproj"> - - - - From e544f76a7b692e5ae78c2e63ee9446bcca2c07b2 Mon Sep 17 00:00:00 2001 From: James Bean Date: Sun, 29 Sep 2019 13:32:47 -0400 Subject: [PATCH 03/17] Add some logging to assess where we're at --- Sources/XMLCoder/Decoder/XMLDecoder.swift | 2 + .../Decoder/XMLDecoderImplementation.swift | 4 ++ .../Decoder/XMLKeyedDecodingContainer.swift | 20 ++++++-- .../EmptyElementEmptyStringTests.swift | 50 ++++++++++++++++--- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 024b9935..81c590ff 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -349,6 +349,8 @@ open class XMLDecoder { trimValueWhitespaces: trimValueWhitespaces ) + print("decoder.decode(\(type), from: \(data), top level: \(topLevel)") + let decoder = XMLDecoderImplementation( referencing: topLevel, options: options, diff --git a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift index f3ae46f3..82ea6277 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift @@ -408,6 +408,7 @@ extension XMLDecoderImplementation { } func unbox(_ box: Box) throws -> T { + let decoded: T? let type = T.self @@ -433,7 +434,10 @@ extension XMLDecoderImplementation { storage.popContainer() } + print("type: \(type), box: \(box)") + do { + print("try decoding in init") decoded = try type.init(from: self) } catch { guard case DecodingError.valueNotFound = error, diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index e4cfd016..7ee1bae1 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -249,9 +249,12 @@ extension XMLKeyedDecodingContainer { return [] } } else { + #warning("TODO: just return keyedBox.elements[key.stringValue]") return keyedBox.elements[key.stringValue].map { if let singleKeyed = $0 as? SingleKeyedBox { - return singleKeyed.element + #warning("Don't get rid of key info just yet!") + // return singleKeyed.element + return singleKeyed } else { return $0 } @@ -321,10 +324,22 @@ extension XMLKeyedDecodingContainer { box = anyBox } + print(box) + 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 { + print("single keyed here?: \(singleKeyed.element)") + 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) } @@ -341,7 +356,6 @@ extension XMLKeyedDecodingContainer { "Expected \(type) value but found null instead." )) } - return unwrapped } diff --git a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift index 54c1992f..ea2683dc 100644 --- a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift +++ b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift @@ -10,26 +10,62 @@ import XMLCoder class EmptyElementEmptyStringTests: XCTestCase { - struct Container: Equatable, Codable { + struct Parent: Equatable, Codable { + let thing: Thing + } + + struct Thing: Equatable, Codable { let attribute: String? let value: String } func testEmptyElementEmptyStringDecoding() throws { let xml = """ - + """ - let expected = Container(attribute: nil, value: "") - let result = try XMLDecoder().decode(Container.self, from: xml.data(using: .utf8)!) + 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 = """ - + + """ + 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 = """ + + + + + """ - let expected = Container(attribute: "x", value: "") - let result = try XMLDecoder().decode(Container.self, from: xml.data(using: .utf8)!) + 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 = """ + + + + """ + let expected = Parent(thing: Thing(attribute: nil, value: "")) + let result = try XMLDecoder().decode(Parent.self, from: xml.data(using: .utf8)!) + XCTAssertEqual(expected, result) + } + + func testNestedArrayOfEmptyElementEmptyStringDecoding() throws { + + } } From 5ea4fa76d786aa2a3bd8d81258bd1911ed31cb99 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 30 Sep 2019 10:08:36 -0700 Subject: [PATCH 04/17] Add cases for empty string as null element decoding --- .../XMLCoder/Decoder/XMLDecoderImplementation.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift index 82ea6277..5aeb1885 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift @@ -101,6 +101,13 @@ class XMLDecoderImplementation: Decoder { attributes: KeyedStorage() )) )) + case let containsEmpty as SingleKeyedBox: + precondition(containsEmpty.element is NullBox) + return KeyedDecodingContainer(XMLKeyedDecodingContainer( + referencing: self, wrapping: SharedBox(KeyedBox( + elements: KeyedStorage([("value", StringBox(""))]), attributes: KeyedStorage() + )) + )) case let keyed as SharedBox: return KeyedDecodingContainer(XMLKeyedDecodingContainer( referencing: self, @@ -212,6 +219,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: From f9fc2f4a0a156befbc65209c436f9e9e393e83ec Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 30 Sep 2019 10:39:58 -0700 Subject: [PATCH 05/17] Swiftformat --- Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift | 3 +-- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 2 +- Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift | 7 ++----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift index 5aeb1885..b0284f9a 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift @@ -221,7 +221,7 @@ extension XMLDecoderImplementation { return value case let singleKeyedBox as SingleKeyedBox: guard let value = singleKeyedBox.element as? B - else { throw error} + else { throw error } return value case is NullBox: throw error @@ -419,7 +419,6 @@ extension XMLDecoderImplementation { } func unbox(_ box: Box) throws -> T { - let decoded: T? let type = T.self diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 7ee1bae1..9d937a0d 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -288,7 +288,7 @@ extension XMLKeyedDecodingContainer { // 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 == "value" || key.stringValue == "") { + key.stringValue == "value" || key.stringValue == "" { return "" as! T } diff --git a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift index ea2683dc..bdc57fbf 100644 --- a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift +++ b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift @@ -9,7 +9,6 @@ import XCTest import XMLCoder class EmptyElementEmptyStringTests: XCTestCase { - struct Parent: Equatable, Codable { let thing: Thing } @@ -48,7 +47,7 @@ class EmptyElementEmptyStringTests: XCTestCase { let expected = [ Thing(attribute: nil, value: ""), Thing(attribute: "x", value: ""), - Thing(attribute: nil, value: "") + Thing(attribute: nil, value: ""), ] let result = try XMLDecoder().decode([Thing].self, from: xml.data(using: .utf8)!) XCTAssertEqual(expected, result) @@ -65,7 +64,5 @@ class EmptyElementEmptyStringTests: XCTestCase { XCTAssertEqual(expected, result) } - func testNestedArrayOfEmptyElementEmptyStringDecoding() throws { - - } + func testNestedArrayOfEmptyElementEmptyStringDecoding() throws {} } From 3ccbfb36afcbd63ad77e8c3d7c211f246d4d3e16 Mon Sep 17 00:00:00 2001 From: James Bean Date: Mon, 30 Sep 2019 13:52:39 -0400 Subject: [PATCH 06/17] Transform precondition to where clause in switch statement --- Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift index b0284f9a..2e77d663 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift @@ -101,8 +101,7 @@ class XMLDecoderImplementation: Decoder { attributes: KeyedStorage() )) )) - case let containsEmpty as SingleKeyedBox: - precondition(containsEmpty.element is NullBox) + case let containsEmpty as SingleKeyedBox where containsEmpty.element is NullBox: return KeyedDecodingContainer(XMLKeyedDecodingContainer( referencing: self, wrapping: SharedBox(KeyedBox( elements: KeyedStorage([("value", StringBox(""))]), attributes: KeyedStorage() From 800a26a367a8eb045159250bc61571220d925707 Mon Sep 17 00:00:00 2001 From: James Bean Date: Mon, 30 Sep 2019 13:53:58 -0400 Subject: [PATCH 07/17] Remove print statements --- Sources/XMLCoder/Decoder/XMLDecoder.swift | 2 -- Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift | 3 --- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 3 --- 3 files changed, 8 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 81c590ff..024b9935 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -349,8 +349,6 @@ open class XMLDecoder { trimValueWhitespaces: trimValueWhitespaces ) - print("decoder.decode(\(type), from: \(data), top level: \(topLevel)") - let decoder = XMLDecoderImplementation( referencing: topLevel, options: options, diff --git a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift index 2e77d663..a88d3189 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift @@ -443,10 +443,7 @@ extension XMLDecoderImplementation { storage.popContainer() } - print("type: \(type), box: \(box)") - do { - print("try decoding in init") decoded = try type.init(from: self) } catch { guard case DecodingError.valueNotFound = error, diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 9d937a0d..0c486114 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -324,14 +324,11 @@ extension XMLKeyedDecodingContainer { box = anyBox } - print(box) - let value: T? if !(type is AnySequence.Type), let unkeyedBox = box as? UnkeyedBox, let first = unkeyedBox.first { // Handle case where we have held onto a `SingleKeyedBox` if let singleKeyed = first as? SingleKeyedBox { - print("single keyed here?: \(singleKeyed.element)") if singleKeyed.element.isNull { value = try decoder.unbox(singleKeyed) } else { From c4dabbadad4957cc10353d7f1c07a2fe13a85ff3 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Tue, 15 Oct 2019 18:26:28 -0700 Subject: [PATCH 08/17] Remove nested syntax test --- Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift index bdc57fbf..0ed78db8 100644 --- a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift +++ b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift @@ -63,6 +63,4 @@ class EmptyElementEmptyStringTests: XCTestCase { let result = try XMLDecoder().decode(Parent.self, from: xml.data(using: .utf8)!) XCTAssertEqual(expected, result) } - - func testNestedArrayOfEmptyElementEmptyStringDecoding() throws {} } From 4bac4910bedd9a9eb0b2fc36c8241471208b9396 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sat, 2 Nov 2019 11:53:32 -0700 Subject: [PATCH 09/17] Fix forcecast (cherry picked from commit e6ec42af77c4f328f0930fcdfd671b527620e93f) --- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 0c486114..f8a8393d 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -288,8 +288,8 @@ extension XMLKeyedDecodingContainer { // 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 == "value" || key.stringValue == "" { - return "" as! T + (key.stringValue == "value" || key.stringValue == ""), let emptyString = "" as? T { + return emptyString } switch strategy(key) { From e14594b6fc484424eb2b086329a14fc9897f5eaf Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sat, 2 Nov 2019 12:05:05 -0700 Subject: [PATCH 10/17] Fix formatting --- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index f8a8393d..562009aa 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -288,7 +288,7 @@ extension XMLKeyedDecodingContainer { // 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 == "value" || key.stringValue == ""), let emptyString = "" as? T { + key.stringValue == "value" || key.stringValue == "", let emptyString = "" as? T { return emptyString } From 8b99000556fed73d27611e81a7a9633419d6e375 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sat, 2 Nov 2019 12:12:41 -0700 Subject: [PATCH 11/17] Update LinuxMain --- Tests/XMLCoderTests/XCTestManifests.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Tests/XMLCoderTests/XCTestManifests.swift b/Tests/XMLCoderTests/XCTestManifests.swift index ea083786..a92d58fc 100644 --- a/Tests/XMLCoderTests/XCTestManifests.swift +++ b/Tests/XMLCoderTests/XCTestManifests.swift @@ -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` @@ -635,7 +647,6 @@ extension StringTests { static let __allTests__StringTests = [ ("testAttribute", testAttribute), ("testElement", testElement), - ("testMissing", testMissing), ] } @@ -796,6 +807,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), From 0222d2482e96325eb2cca8b0905ff9bc1f2844ca Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sat, 2 Nov 2019 12:25:48 -0700 Subject: [PATCH 12/17] Remove warnings --- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 562009aa..8a4fc734 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -249,11 +249,8 @@ extension XMLKeyedDecodingContainer { return [] } } else { - #warning("TODO: just return keyedBox.elements[key.stringValue]") return keyedBox.elements[key.stringValue].map { if let singleKeyed = $0 as? SingleKeyedBox { - #warning("Don't get rid of key info just yet!") - // return singleKeyed.element return singleKeyed } else { return $0 From 27cbb5d008c2c2ab251d96857c3b4e0881ab063c Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 11 Nov 2019 09:19:04 -0800 Subject: [PATCH 13/17] Add fix for new empty string issue --- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 0269c4a9..b49162d0 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -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 } From 085a12bdab6956120a2dc3250eb24fb85ed8f288 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 11 Nov 2019 09:27:49 -0800 Subject: [PATCH 14/17] Add back missing missingTest - remove "value" special casing from implementation --- Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift | 2 +- Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift | 3 +-- Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift | 5 +++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift index 9cbff03a..04fdb023 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoderImplementation.swift @@ -104,7 +104,7 @@ class XMLDecoderImplementation: Decoder { case let containsEmpty as SingleKeyedBox where containsEmpty.element is NullBox: return KeyedDecodingContainer(XMLKeyedDecodingContainer( referencing: self, wrapping: SharedBox(KeyedBox( - elements: KeyedStorage([("value", StringBox(""))]), attributes: KeyedStorage() + elements: KeyedStorage([("", StringBox(""))]), attributes: KeyedStorage() )) )) case let keyed as SharedBox: diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index b49162d0..3a0fb39c 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -266,8 +266,7 @@ extension XMLKeyedDecodingContainer { // 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 == "value" || key.stringValue == "", let emptyString = "" as? T { + if strategy(key) != .attribute, elements.isEmpty, attributes.isEmpty, type == String.self, key.stringValue == "", let emptyString = "" as? T { return emptyString } diff --git a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift index 0ed78db8..01e76286 100644 --- a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift +++ b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift @@ -16,6 +16,11 @@ class EmptyElementEmptyStringTests: XCTestCase { struct Thing: Equatable, Codable { let attribute: String? let value: String + + enum CodingKeys: String, CodingKey { + case attribute + case value = "" + } } func testEmptyElementEmptyStringDecoding() throws { From 86912145d80f1bd7063df5c77380878aa758e815 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 11 Nov 2019 09:48:11 -0800 Subject: [PATCH 15/17] Fix formatting --- Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift index 01e76286..554663f1 100644 --- a/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift +++ b/Tests/XMLCoderTests/EmptyElementEmptyStringTests.swift @@ -16,7 +16,7 @@ class EmptyElementEmptyStringTests: XCTestCase { struct Thing: Equatable, Codable { let attribute: String? let value: String - + enum CodingKeys: String, CodingKey { case attribute case value = "" From f4209dd56ae645944309ad5176d36efba5f54645 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Tue, 12 Nov 2019 16:25:03 -0800 Subject: [PATCH 16/17] Recover missing test! --- Tests/XMLCoderTests/Minimal/StringTests.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/XMLCoderTests/Minimal/StringTests.swift b/Tests/XMLCoderTests/Minimal/StringTests.swift index 54ea2206..ea5d6981 100644 --- a/Tests/XMLCoderTests/Minimal/StringTests.swift +++ b/Tests/XMLCoderTests/Minimal/StringTests.swift @@ -25,6 +25,15 @@ class StringTests: XCTestCase { ("foobar", "foobar"), ] + func testMissing() { + let decoder = XMLDecoder() + + let xmlString = "" + let xmlData = xmlString.data(using: .utf8)! + + XCTAssertThrowsError(try decoder.decode(Container.self, from: xmlData)) + } + func testAttribute() throws { let decoder = XMLDecoder() let encoder = XMLEncoder() From e7347b391308dce36a528936174b332666bdfe02 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Tue, 12 Nov 2019 16:35:40 -0800 Subject: [PATCH 17/17] Update linuxmain --- Tests/XMLCoderTests/XCTestManifests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/XMLCoderTests/XCTestManifests.swift b/Tests/XMLCoderTests/XCTestManifests.swift index a92d58fc..dc012d82 100644 --- a/Tests/XMLCoderTests/XCTestManifests.swift +++ b/Tests/XMLCoderTests/XCTestManifests.swift @@ -647,6 +647,7 @@ extension StringTests { static let __allTests__StringTests = [ ("testAttribute", testAttribute), ("testElement", testElement), + ("testMissing", testMissing), ] }