Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix decoding 'flag' URL query params via .decode(StructType.self) #3164

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions Sources/Vapor/URLEncodedForm/URLEncodedFormDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ private struct _Decoder: Decoder {
var configuration: URLEncodedFormDecoder.Configuration

var allKeys: [Key] {
self.data.children.keys.compactMap { Key(stringValue: String($0)) }
(self.data.children.keys + self.data.values.compactMap { try? $0.asUrlDecoded() }).compactMap { Key(stringValue: String($0)) }
}

init(
Expand All @@ -226,11 +226,11 @@ private struct _Decoder: Decoder {
}

func contains(_ key: Key) -> Bool {
self.data.children[key.stringValue] != nil
self.data.children[key.stringValue] != nil || self.data.values.contains(.init(stringLiteral: key.stringValue))
}

func decodeNil(forKey key: Key) throws -> Bool {
self.data.children[key.stringValue] == nil
self.data.children[key.stringValue] == nil && !self.data.values.contains(.init(stringLiteral: key.stringValue))
}

private func decodeDate(forKey key: Key, child: URLEncodedFormData) throws -> Date {
Expand Down
15 changes: 15 additions & 0 deletions Tests/VaporTests/QueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,32 @@ final class QueryTests: XCTestCase {
url: URI(string: "/"),
on: app.eventLoopGroup.next()
)
struct BarStruct : Content {
let bar: Bool
}
struct OptionalBarStruct : Content {
let bar: Bool?
let baz: String?
}

req.url = .init(path: "/foo?bar")
XCTAssertTrue(try req.query.get(Bool.self, at: "bar"))
XCTAssertTrue(try req.query.decode(BarStruct.self).bar)
XCTAssertEqual(try req.query.decode(OptionalBarStruct.self).bar, true)

req.url = .init(path: "/foo?bar&baz=bop")
XCTAssertTrue(try req.query.get(Bool.self, at: "bar"))
XCTAssertTrue(try req.query.decode(BarStruct.self).bar)
XCTAssertEqual(try req.query.decode(OptionalBarStruct.self).bar, true)

req.url = .init(path: "/foo")
XCTAssertFalse(try req.query.get(Bool.self, at: "bar"))
XCTAssertFalse(try req.query.decode(BarStruct.self).bar)
XCTAssertNil(try req.query.decode(OptionalBarStruct.self).bar)

req.url = .init(path: "/foo?baz=bop")
XCTAssertFalse(try req.query.get(Bool.self, at: "bar"))
XCTAssertFalse(try req.query.decode(BarStruct.self).bar)
XCTAssertNil(try req.query.decode(OptionalBarStruct.self).bar)
}
}
16 changes: 16 additions & 0 deletions Tests/VaporTests/URLEncodedFormTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,22 @@ final class URLEncodedFormTests: XCTestCase {
XCTAssertEqual(foo.flag, true)
}

func testFlagDecodingAsOptionalBool() throws {
struct Foo: Codable {
var flag: Bool?
}
let foo1 = try URLEncodedFormDecoder().decode(Foo.self, from: "flag")
XCTAssertEqual(foo1.flag, true)
let foo2 = try URLEncodedFormDecoder().decode(Foo.self, from: "somethingelse")
XCTAssertEqual(foo2.flag, nil)
let foo3 = try URLEncodedFormDecoder().decode(Foo.self, from: "")
XCTAssertEqual(foo3.flag, nil)
let foo4 = try URLEncodedFormDecoder().decode(Foo.self, from: "flag=true")
XCTAssertEqual(foo4.flag, true)
let foo5 = try URLEncodedFormDecoder().decode(Foo.self, from: "flag=false")
XCTAssertEqual(foo5.flag, false)
}

func testFlagIsOnDecodingAsBool() throws {
struct Foo: Codable {
var flag: Bool
Expand Down