Skip to content

Commit

Permalink
Follow the 'required' argument for nested validations (#2382)
Browse files Browse the repository at this point in the history
* Add validation tests for optional nested objects

* Improve nested validator to follow the required argument

Co-authored-by: seeppp <jonas.schoch@naptics.ch>
Co-authored-by: Joannis Orlandos <joannis@orlandos.nl>
Co-authored-by: Jari (LotU) <j.koopman@jarict.nl>
  • Loading branch information
4 people committed Jun 24, 2020
1 parent 6810c21 commit de17edc
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 3 deletions.
14 changes: 11 additions & 3 deletions Sources/Vapor/Validation/Validation.swift
Expand Up @@ -29,9 +29,17 @@ public struct Validation {
self.init { container in
let result: ValidatorResult
do {
let nested = try container.nestedContainer(keyedBy: ValidationKey.self, forKey: key)
let results = validations.validate(nested)
result = ValidatorResults.Nested(results: results.results)
if container.contains(key), !required, try container.decodeNil(forKey: key) {
result = ValidatorResults.Skipped()
} else if container.contains(key) {
let nested = try container.nestedContainer(keyedBy: ValidationKey.self, forKey: key)
let results = validations.validate(nested)
result = ValidatorResults.Nested(results: results.results)
} else if required {
result = ValidatorResults.Missing()
} else {
result = ValidatorResults.Skipped()
}
} catch {
result = ValidatorResults.Codable(error: error)
}
Expand Down
55 changes: 55 additions & 0 deletions Tests/VaporTests/ValidationTests.swift
Expand Up @@ -16,6 +16,7 @@ class ValidationTests: XCTestCase {
"name": "Zizek",
"age": 3
},
"favoritePet": null,
"isAdmin": true
}
"""
Expand Down Expand Up @@ -80,6 +81,53 @@ class ValidationTests: XCTestCase {
XCTAssertEqual("\(error)",
"isAdmin is not a(n) Bool")
}

let validOptionalFavoritePet = """
{
"name": "Tanner",
"age": 24,
"gender": "male",
"email": "me@tanner.xyz",
"luckyNumber": 5,
"profilePictureURL": "https://foo.jpg",
"preferredColors": ["blue"],
"pet": {
"name": "Zizek",
"age": 3
},
"favoritePet": {
"name": "Zizek",
"age": 3
},
"isAdmin": true
}
"""
XCTAssertNoThrow(try User.validate(json: validOptionalFavoritePet))

let invalidOptionalFavoritePet = """
{
"name": "Tanner",
"age": 24,
"gender": "male",
"email": "me@tanner.xyz",
"luckyNumber": 5,
"profilePictureURL": "https://foo.jpg",
"preferredColors": ["blue"],
"pet": {
"name": "Zizek",
"age": 3
},
"favoritePet": {
"name": "Zi!zek",
"age": 3
},
"isAdmin": true
}
"""
XCTAssertThrowsError(try User.validate(json: invalidOptionalFavoritePet)) { error in
XCTAssertEqual("\(error)",
"favoritePet name contains '!' (allowed: whitespace, A-Z, a-z, 0-9)")
}
}

func testCatchError() throws {
Expand Down Expand Up @@ -310,6 +358,7 @@ private final class User: Validatable, Codable {
var gender: Gender
var email: String?
var pet: Pet
var favoritePet: Pet?
var luckyNumber: Int?
var profilePictureURL: String?
var preferredColors: [String]
Expand Down Expand Up @@ -358,6 +407,12 @@ private final class User: Validatable, Codable {
is: .count(5...) && .characterSet(.alphanumerics + .whitespaces))
pet.add("age", as: Int.self, is: .range(3...))
}
// optional favorite pet validations
v.add("favoritePet", required: false) { pet in
pet.add("name", as: String.self,
is: .count(5...) && .characterSet(.alphanumerics + .whitespaces))
pet.add("age", as: Int.self, is: .range(3...))
}
v.add("isAdmin", as: Bool.self)
}
}

0 comments on commit de17edc

Please sign in to comment.