Skip to content

Commit

Permalink
Change how empty strings are decoded into nullable properties
Browse files Browse the repository at this point in the history
Add TopLevelDecoderTests.testDecodeOptionalTypes() to reproduce #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

Add changelog entry
  • Loading branch information
liamnichols authored and jpsim committed Oct 15, 2023
1 parent 680a93b commit 0c4ff78
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 5 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@

##### Breaking

* None.
* Change how empty strings are decoded into nullable properties.
`key: ""` previously decoded into
`struct Value: Codable { let key: String? }` as `Value(key: nil)`
whereas after this change it decodes as `Value(key: "")`.
This could be a breaking change if you were relying on the previous
semantics.
[Liam Nichols](https://github.com/liamnichols)
[#301](https://github.com/jpsim/Yams/issues/301)

##### Enhancements

Expand Down
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 @@ -235,7 +237,9 @@ class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length
"2nd entry",
NSNull(),
"4th entry",
NSNull()
NSNull(),
"null",
""
] as [Any]
]
]
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 0c4ff78

Please sign in to comment.