From b35daeb1bce70300bfe0caa5d93853b1b3c89c8b Mon Sep 17 00:00:00 2001 From: Kostis Stefanou Date: Tue, 29 Oct 2024 11:23:56 +0200 Subject: [PATCH] Update URIValueFromNodeDecoder for DeepObject. ### Motivation As discussed in [[Generator] Add support of deepObject style in query params #538](https://github.com/apple/swift-openapi-generator/pull/538#discussion_r1817872441), there is a misimplementation of the `decodeRootIfPresent` method in `URIValueFromNodeDecoder`. When using the `deepObject` style, the node for `rootValue` is correctly empty, containing only the sub-objects. Without this PR, the tests for [Add support of deepObject style in query params #538](https://github.com/apple/swift-openapi-generator/pull/538) are failing. ### Modifications - Updated the `decodeRootIfPresent(_ type:) throws -> T` method to ignore whether `currentElementAsArray` is empty or not. ### Result - Enables the tests in the [Generator part of the PR](https://github.com/apple/swift-openapi-generator/pull/538) to pass successfully. ### Test Plan This PR includes unit tests that validate the change to `decodeRootIfPresent(_ type:) throws -> T` within `Test_Converter+Server` as well as in `Test_serverConversionExtensions`. --- .../Decoding/URIValueFromNodeDecoder.swift | 4 +++- .../Conversion/Test_Converter+Server.swift | 24 +++++++++++++++++++ .../Test_URIValueFromNodeDecoder.swift | 13 ++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Sources/OpenAPIRuntime/URICoder/Decoding/URIValueFromNodeDecoder.swift b/Sources/OpenAPIRuntime/URICoder/Decoding/URIValueFromNodeDecoder.swift index 55982755..e4d60e0b 100644 --- a/Sources/OpenAPIRuntime/URICoder/Decoding/URIValueFromNodeDecoder.swift +++ b/Sources/OpenAPIRuntime/URICoder/Decoding/URIValueFromNodeDecoder.swift @@ -82,7 +82,9 @@ final class URIValueFromNodeDecoder { /// - Throws: When a decoding error occurs. func decodeRootIfPresent(_ type: T.Type = T.self) throws -> T? { // The root is only nil if the node is empty. - if try currentElementAsArray().isEmpty { return nil } + if style != .deepObject, try currentElementAsArray().isEmpty { + return nil + } return try decodeRoot(type) } } diff --git a/Tests/OpenAPIRuntimeTests/Conversion/Test_Converter+Server.swift b/Tests/OpenAPIRuntimeTests/Conversion/Test_Converter+Server.swift index b2305a08..16ac7374 100644 --- a/Tests/OpenAPIRuntimeTests/Conversion/Test_Converter+Server.swift +++ b/Tests/OpenAPIRuntimeTests/Conversion/Test_Converter+Server.swift @@ -171,6 +171,18 @@ final class Test_ServerConverterExtensions: Test_Runtime { XCTAssertEqual(value, ["foo", "bar"]) } + func test_getOptionalQueryItemAsURI_deepObject_exploded() throws { + let query: Substring = "sort%5Bid%5D=ascending&sort%5Bname%5D=descending" + let value: [String: String]? = try converter.getOptionalQueryItemAsURI( + in: query, + style: .deepObject, + explode: true, + name: "sort", + as: [String: String].self + ) + XCTAssertEqual(value, ["id": "ascending", "name": "descending"]) + } + func test_getRequiredQueryItemAsURI_arrayOfStrings() throws { let query: Substring = "search=foo&search=bar" let value: [String] = try converter.getRequiredQueryItemAsURI( @@ -195,6 +207,18 @@ final class Test_ServerConverterExtensions: Test_Runtime { XCTAssertEqual(value, ["foo", "bar"]) } + func test_getRequiredQueryItemAsURI_deepObject_exploded() throws { + let query: Substring = "sort%5Bid%5D=ascending&sort%5Bname%5D=descending" + let value: [String: String] = try converter.getRequiredQueryItemAsURI( + in: query, + style: .deepObject, + explode: true, + name: "sort", + as: [String: String].self + ) + XCTAssertEqual(value, ["id": "ascending", "name": "descending"]) + } + func test_getOptionalQueryItemAsURI_date() throws { let query: Substring = "search=\(testDateEscapedString)" let value: Date? = try converter.getOptionalQueryItemAsURI( diff --git a/Tests/OpenAPIRuntimeTests/URICoder/Decoder/Test_URIValueFromNodeDecoder.swift b/Tests/OpenAPIRuntimeTests/URICoder/Decoder/Test_URIValueFromNodeDecoder.swift index f1236cb9..8bfcf2b5 100644 --- a/Tests/OpenAPIRuntimeTests/URICoder/Decoder/Test_URIValueFromNodeDecoder.swift +++ b/Tests/OpenAPIRuntimeTests/URICoder/Decoder/Test_URIValueFromNodeDecoder.swift @@ -35,6 +35,11 @@ final class Test_URIValueFromNodeDecoder: Test_Runtime { case blue } + struct SimpleDeepObject: Decodable, Equatable { + let id: String + let name: String + } + // An empty string. try test(["root": [""]], "", key: "root") @@ -88,6 +93,14 @@ final class Test_URIValueFromNodeDecoder: Test_Runtime { key: "root" ) + try test( + ["id": ["ascending"], "name": ["descending"]], + SimpleDeepObject(id: "ascending", name: "descending"), + key: "sort", + style: .deepObject, + explode: true + ) + func test( _ node: URIParsedNode, _ expectedValue: T,