Skip to content

Commit

Permalink
fix: validate each not taking required parameter into account (#2859)
Browse files Browse the repository at this point in the history
  • Loading branch information
BasPeter committed Jul 20, 2022
1 parent cd91a66 commit d35d98a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 11 deletions.
30 changes: 19 additions & 11 deletions Sources/Vapor/Validation/Validation.swift
Expand Up @@ -52,18 +52,26 @@ public struct Validation {
self.init { container in
let result: ValidatorResult
do {
var results: [[ValidatorResult]] = []
var array = try container.nestedUnkeyedContainer(forKey: key)
var i = 0
while !array.isAtEnd {
defer { i += 1 }
var validations = Validations()
factory(i, &validations)
let nested = try array.nestedContainer(keyedBy: ValidationKey.self)
let result = validations.validate(nested)
results.append(result.results)
if container.contains(key), !required, try container.decodeNil(forKey: key) {
result = ValidatorResults.Skipped()
} else if container.contains(key) {
var results: [[ValidatorResult]] = []
var array = try container.nestedUnkeyedContainer(forKey: key)
var i = 0
while !array.isAtEnd {
defer { i += 1 }
var validations = Validations()
factory(i, &validations)
let nested = try array.nestedContainer(keyedBy: ValidationKey.self)
let result = validations.validate(nested)
results.append(result.results)
}
result = ValidatorResults.NestedEach(results: results)
} else if required {
result = ValidatorResults.Missing()
} else {
result = ValidatorResults.Skipped()
}
result = ValidatorResults.NestedEach(results: results)
} catch {
result = ValidatorResults.Codable(error: error)
}
Expand Down
59 changes: 59 additions & 0 deletions Tests/VaporTests/ValidationTests.swift
Expand Up @@ -233,13 +233,21 @@ class ValidationTests: XCTestCase {
var name: String
var age: Int
var hobbies: [Hobby]
var allergies: [Allergy]?

struct Hobby: Codable {
var title: String
init(title: String) {
self.title = title
}
}

struct Allergy: Codable {
var title: String
init(title: String) {
self.title = title
}
}

static func validations(_ v: inout Validations) {
v.add("name", as: String.self, is: .count(5...) && .alphanumeric)
Expand All @@ -248,6 +256,9 @@ class ValidationTests: XCTestCase {
hobby.add("title", as: String.self, is: .count(5...) && .characterSet(.alphanumerics + .whitespaces))
}
v.add("hobbies", as: [Hobby].self, is: !.empty)
v.add(each: "allergies", required: false) { i, allergy in
allergy.add("title", as: String.self, is: .characterSet(.letters))
}
}
}

Expand All @@ -268,6 +279,54 @@ class ValidationTests: XCTestCase {
XCTAssertThrowsError(try User.validate(json: invalidNestedArray)) { error in
XCTAssertEqual("\(error)", "hobbies at index 0 title contains '€' (allowed: whitespace, A-Z, a-z, 0-9) and at index 1 title is less than minimum of 5 character(s)")
}

let invalidNestedArray2 = """
{
"name": "Tanner",
"age": 24,
"allergies": [
{
"title": "Peanuts"
}
]
}
"""
XCTAssertThrowsError(try User.validate(json: invalidNestedArray2)) { error in
XCTAssertEqual("\(error)", "hobbies is required, hobbies is required")
}

let invalidNestedArray3 = """
{
"name": "Tanner",
"age": 24,
"hobbies": [
{
"title": "Football"
}
],
"allergies": [
{
"title": "Peanuts€"
}
]
}
"""
XCTAssertThrowsError(try User.validate(json: invalidNestedArray3)) { error in
XCTAssertEqual("\(error)", "allergies at index 0 title contains '€' (allowed: A-Z, a-z)")
}

let validNestedArray = """
{
"name": "Tanner",
"age": 24,
"hobbies": [
{
"title": "Football"
}
],
}
"""
XCTAssertNoThrow(try User.validate(json: validNestedArray))
}

func testValidateNestedEachIndex() throws {
Expand Down

0 comments on commit d35d98a

Please sign in to comment.