Skip to content

Commit d2ebc53

Browse files
authored
Fix YAMLDecoder's handling when decoding empty strings into optional types (#1)
* Add TopLevelDecoderTests.testDecodeOptionalTypes() to reproduce jpsim#301 * Update ConstructorTests.testNull() to include assertions about handling of null specifiers that are wrapped in quotes * Update NSNull.construct(from:) to only return NSNull if the style is .plain since non-plain style scalars don't represent null (fixes bug) * Update assertion in NodeTests to explicitly require .plain style when making assertion * Correct SwiftLint violations
1 parent acbdf11 commit d2ebc53

File tree

4 files changed

+58
-4
lines changed

4 files changed

+58
-4
lines changed

Sources/Yams/Constructor.swift

+4
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ extension NSNull/*: ScalarConstructible*/ {
396396
///
397397
/// - returns: An instance of `NSNull`, if one was successfully extracted from the scalar.
398398
public static func construct(from scalar: Node.Scalar) -> NSNull? {
399+
// When constructing from a Scalar, only plain style scalars should be recognized.
400+
// For example #"key: 'null'"# or #"key: ''"# should not be considered as null.
401+
guard case .plain = scalar.style else { return nil }
402+
399403
switch scalar.string {
400404
case "", "~", "null", "Null", "NULL":
401405
return NSNull()

Tests/YamsTests/ConstructorTests.swift

+7-3
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,16 @@ class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length
210210
english: null
211211
~: null key
212212
---
213-
# This sequence has five
214-
# entries, two have values.
213+
# This sequence has seven
214+
# entries, four have values.
215215
sparse:
216216
- ~
217217
- 2nd entry
218218
-
219219
- 4th entry
220220
- Null
221+
- 'null'
222+
- ''
221223
222224
"""
223225
let objects = Array(try Yams.load_all(yaml: example))
@@ -234,7 +236,9 @@ class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length
234236
"2nd entry",
235237
NSNull(),
236238
"4th entry",
237-
NSNull()
239+
NSNull(),
240+
"null",
241+
""
238242
]
239243
]
240244
]

Tests/YamsTests/NodeTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class NodeTests: XCTestCase {
5959
let scalarFloat: Node = "1.0"
6060
XCTAssertEqual(scalarFloat.float, 1.0)
6161

62-
let scalarNull: Node = "null"
62+
let scalarNull = Node("null", .implicit, .plain)
6363
XCTAssertEqual(scalarNull.null, NSNull())
6464

6565
let scalarInt: Node = "1"

Tests/YamsTests/TopLevelDecoderTests.swift

+46
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,51 @@ class TopLevelDecoderTests: XCTestCase {
3232
)
3333
XCTAssertEqual(foo?.name, "Bird")
3434
}
35+
36+
func testDecodeOptionalTypes() throws {
37+
let yaml = """
38+
AAA: ''
39+
BBB:
40+
CCC: null
41+
DDD: ~
42+
EEE: ""
43+
json: {
44+
"FFF": "",
45+
"GGG": "null"
46+
}
47+
array:
48+
- one
49+
- ''
50+
- null
51+
- 'null'
52+
- '~'
53+
"""
54+
55+
struct Container: Codable, Equatable {
56+
struct JSON: Codable, Equatable {
57+
var FFF: String?
58+
var GGG: String?
59+
}
60+
61+
var AAA: String?
62+
var BBB: String?
63+
var CCC: Int?
64+
var DDD: String?
65+
var EEE: String?
66+
var json: JSON
67+
var array: [String?]
68+
}
69+
70+
let container = try YAMLDecoder().decode(Container.self, from: yaml)
71+
72+
XCTAssertEqual(container.AAA, "")
73+
XCTAssertEqual(container.BBB, nil)
74+
XCTAssertEqual(container.CCC, nil)
75+
XCTAssertEqual(container.DDD, nil)
76+
XCTAssertEqual(container.EEE, "")
77+
XCTAssertEqual(container.json.FFF, "")
78+
XCTAssertEqual(container.json.GGG, "null")
79+
XCTAssertEqual(container.array, ["one", "", nil, "null", "~"])
80+
}
3581
}
3682
#endif

0 commit comments

Comments
 (0)