From 0de508facb046d6b00558ee55f2606a8eee6d0ad Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 6 Apr 2022 13:26:43 +0200 Subject: [PATCH 1/5] Add TopLevelDecoderTests.testDecodeOptionalTypes() to reproduce jpsim/Yams#301 --- Tests/YamsTests/TopLevelDecoderTests.swift | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Tests/YamsTests/TopLevelDecoderTests.swift b/Tests/YamsTests/TopLevelDecoderTests.swift index b6bdd37d..d463437c 100644 --- a/Tests/YamsTests/TopLevelDecoderTests.swift +++ b/Tests/YamsTests/TopLevelDecoderTests.swift @@ -32,5 +32,51 @@ class TopLevelDecoderTests: XCTestCase { ) XCTAssertEqual(foo?.name, "Bird") } + + func testDecodeOptionalTypes() throws { + let yaml = """ + A: '' + B: + C: null + D: ~ + E: "" + json: { + "F": "", + "G": "null" + } + array: + - one + - '' + - null + - 'null' + - '~' + """ + + struct Container: Codable, Equatable { + struct JSON: Codable, Equatable { + var F: String? + var G: String? + } + + var A: String? + var B: String? + var C: Int? + var D: String? + var E: String? + var json: JSON + var array: [String?] + } + + let container = try YAMLDecoder().decode(Container.self, from: yaml) + + XCTAssertEqual(container.A, "") + XCTAssertEqual(container.B, nil) + XCTAssertEqual(container.C, nil) + XCTAssertEqual(container.D, nil) + XCTAssertEqual(container.E, "") + XCTAssertEqual(container.json.F, "") + XCTAssertEqual(container.json.G, "null") + XCTAssertEqual(container.array, ["one", "", nil, "null", "~"]) + } } #endif From 89679a216a6c949fb15861173776bb5ac6f5d8e0 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 6 Apr 2022 13:28:06 +0200 Subject: [PATCH 2/5] Update ConstructorTests.testNull() to include assertions about handling of null specifiers that are wrapped in quotes --- Tests/YamsTests/ConstructorTests.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Tests/YamsTests/ConstructorTests.swift b/Tests/YamsTests/ConstructorTests.swift index 805d2a6f..0aa1ec62 100644 --- a/Tests/YamsTests/ConstructorTests.swift +++ b/Tests/YamsTests/ConstructorTests.swift @@ -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)) @@ -234,7 +236,9 @@ class ConstructorTests: XCTestCase { // swiftlint:disable:this type_body_length "2nd entry", NSNull(), "4th entry", - NSNull() + NSNull(), + "null", + "" ] ] ] From 3aaed2423d95a1e41217b1bad27f84d78ae24d27 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 6 Apr 2022 13:29:01 +0200 Subject: [PATCH 3/5] Update NSNull.construct(from:) to only return NSNull if the style is .plain since non-plain style scalars don't represent null (fixes bug) --- Sources/Yams/Constructor.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Yams/Constructor.swift b/Sources/Yams/Constructor.swift index 29aa3c59..41b8a587 100644 --- a/Sources/Yams/Constructor.swift +++ b/Sources/Yams/Constructor.swift @@ -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() From 94ad299d096df8ca923d27a889ea2d98b35f252c Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 6 Apr 2022 13:29:29 +0200 Subject: [PATCH 4/5] Update assertion in NodeTests to explicitly require .plain style when making assertion --- Tests/YamsTests/NodeTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/YamsTests/NodeTests.swift b/Tests/YamsTests/NodeTests.swift index 5257e0a2..933de986 100644 --- a/Tests/YamsTests/NodeTests.swift +++ b/Tests/YamsTests/NodeTests.swift @@ -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" From 108a304bbabc60d6c57acf6b94498684afc0a120 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Mon, 11 Apr 2022 10:28:47 +0200 Subject: [PATCH 5/5] Correct SwiftLint violations --- Tests/YamsTests/TopLevelDecoderTests.swift | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Tests/YamsTests/TopLevelDecoderTests.swift b/Tests/YamsTests/TopLevelDecoderTests.swift index d463437c..718b1b19 100644 --- a/Tests/YamsTests/TopLevelDecoderTests.swift +++ b/Tests/YamsTests/TopLevelDecoderTests.swift @@ -35,14 +35,14 @@ class TopLevelDecoderTests: XCTestCase { func testDecodeOptionalTypes() throws { let yaml = """ - A: '' - B: - C: null - D: ~ - E: "" + AAA: '' + BBB: + CCC: null + DDD: ~ + EEE: "" json: { - "F": "", - "G": "null" + "FFF": "", + "GGG": "null" } array: - one @@ -54,28 +54,28 @@ class TopLevelDecoderTests: XCTestCase { struct Container: Codable, Equatable { struct JSON: Codable, Equatable { - var F: String? - var G: String? + var FFF: String? + var GGG: String? } - var A: String? - var B: String? - var C: Int? - var D: String? - var E: 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.A, "") - XCTAssertEqual(container.B, nil) - XCTAssertEqual(container.C, nil) - XCTAssertEqual(container.D, nil) - XCTAssertEqual(container.E, "") - XCTAssertEqual(container.json.F, "") - XCTAssertEqual(container.json.G, "null") + 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", "~"]) } }