Skip to content

Commit

Permalink
Fix YAMLDecoder's handling when decoding empty strings into optiona…
Browse files Browse the repository at this point in the history
…l 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
  • Loading branch information
liamnichols authored Jun 9, 2022
1 parent acbdf11 commit d2ebc53
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Sources/Yams/Constructor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ extension NSNull/*: ScalarConstructible*/ {
///
/// - returns: An instance of `NSNull`, if one was successfully extracted from the scalar.
public static func construct(from scalar: Node.Scalar) -> NSNull? {
// When constructing from a Scalar, only plain style scalars should be recognized.
// For example #"key: 'null'"# or #"key: ''"# should not be considered as null.
guard case .plain = scalar.style else { return nil }

switch scalar.string {
case "", "~", "null", "Null", "NULL":
return NSNull()
Expand Down
10 changes: 7 additions & 3 deletions Tests/YamsTests/ConstructorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,14 +210,16 @@ class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length
english: null
~: null key
---
# This sequence has five
# entries, two have values.
# This sequence has seven
# entries, four have values.
sparse:
- ~
- 2nd entry
-
- 4th entry
- Null
- 'null'
- ''
"""
let objects = Array(try Yams.load_all(yaml: example))
Expand All @@ -234,7 +236,9 @@ class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length
"2nd entry",
NSNull(),
"4th entry",
NSNull()
NSNull(),
"null",
""
]
]
]
Expand Down
2 changes: 1 addition & 1 deletion Tests/YamsTests/NodeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class NodeTests: XCTestCase {
let scalarFloat: Node = "1.0"
XCTAssertEqual(scalarFloat.float, 1.0)

let scalarNull: Node = "null"
let scalarNull = Node("null", .implicit, .plain)
XCTAssertEqual(scalarNull.null, NSNull())

let scalarInt: Node = "1"
Expand Down
46 changes: 46 additions & 0 deletions Tests/YamsTests/TopLevelDecoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,51 @@ class TopLevelDecoderTests: XCTestCase {
)
XCTAssertEqual(foo?.name, "Bird")
}

func testDecodeOptionalTypes() throws {
let yaml = """
AAA: ''
BBB:
CCC: null
DDD: ~
EEE: ""
json: {
"FFF": "",
"GGG": "null"
}
array:
- one
- ''
- null
- 'null'
- '~'
"""

struct Container: Codable, Equatable {
struct JSON: Codable, Equatable {
var FFF: String?
var GGG: String?
}

var AAA: String?
var BBB: String?
var CCC: Int?
var DDD: String?
var EEE: String?
var json: JSON
var array: [String?]
}

let container = try YAMLDecoder().decode(Container.self, from: yaml)

XCTAssertEqual(container.AAA, "")
XCTAssertEqual(container.BBB, nil)
XCTAssertEqual(container.CCC, nil)
XCTAssertEqual(container.DDD, nil)
XCTAssertEqual(container.EEE, "")
XCTAssertEqual(container.json.FFF, "")
XCTAssertEqual(container.json.GGG, "null")
XCTAssertEqual(container.array, ["one", "", nil, "null", "~"])
}
}
#endif

0 comments on commit d2ebc53

Please sign in to comment.